From 8d6f7bc7837a4d0c1a912cdc9cf66177b04b1740 Mon Sep 17 00:00:00 2001 From: hernani Date: Thu, 8 Apr 2010 15:20:37 +0000 Subject: [PATCH] cleaning the repo git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@11 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- .project | 23 - .pydevproject | 10 - HOW_TO_DEBUG | 39 - INSTALL | 314 -- PENDING | 28 - README | 6 - ROADMAP.rst | 32 - WISH_LIST | 10 - __init__.py | 0 context.py | 47 - cron/send_email_alerts | 4 - dos2unix.sh | 12 - forum/__init__.py | 1 - forum/admin.py | 74 - forum/auth.py | 498 --- forum/authentication/__init__.py | 27 - forum/authentication/base.py | 40 - forum/authentication/forms.py | 31 - forum/const.py | 92 - forum/feed.py | 43 - forum/forms.py | 359 -- forum/management/__init__.py | 3 - forum/management/commands/__init__.py | 0 forum/management/commands/base_command.py | 35 - .../management/commands/clean_award_badges.py | 59 - .../commands/message_to_everyone.py | 12 - .../management/commands/multi_award_badges.py | 348 -- .../management/commands/once_award_badges.py | 350 -- forum/management/commands/sample_command.py | 7 - .../management/commands/send_email_alerts.py | 192 - .../management/commands/subscribe_everyone.py | 32 - forum/middleware/__init__.py | 0 forum/middleware/anon_user.py | 35 - forum/middleware/cancel.py | 15 - forum/middleware/pagesize.py | 33 - forum/models/__init__.py | 343 -- forum/models/answer.py | 134 - forum/models/base.py | 139 - forum/models/meta.py | 89 - forum/models/question.py | 336 -- forum/models/repute.py | 109 - forum/models/tag.py | 85 - forum/models/user.py | 77 - forum/modules.py | 79 - forum/sitemap.py | 14 - forum/skins/README | 22 - forum/skins/__init__.py | 57 - forum/skins/common/media/README | 1 - .../media/images/blue-up-arrow-h18px.png | Bin 593 -> 0 bytes .../skins/default/media/images/box-arrow.gif | Bin 69 -> 0 bytes .../default/media/images/bullet_green.gif | Bin 64 -> 0 bytes forum/skins/default/media/images/cc-88x31.png | Bin 5460 -> 0 bytes forum/skins/default/media/images/cc-wiki.png | Bin 2333 -> 0 bytes .../default/media/images/close-small-dark.png | Bin 226 -> 0 bytes .../media/images/close-small-hover.png | Bin 337 -> 0 bytes .../default/media/images/close-small.png | Bin 293 -> 0 bytes forum/skins/default/media/images/dash.gif | Bin 44 -> 0 bytes .../media/images/djangomade124x25_grey.gif | Bin 2035 -> 0 bytes forum/skins/default/media/images/dot-g.gif | Bin 61 -> 0 bytes forum/skins/default/media/images/dot-list.gif | Bin 56 -> 0 bytes forum/skins/default/media/images/edit.png | Bin 758 -> 0 bytes .../media/images/expander-arrow-hide.gif | Bin 126 -> 0 bytes .../media/images/expander-arrow-show.gif | Bin 135 -> 0 bytes forum/skins/default/media/images/favicon.gif | Bin 3918 -> 0 bytes .../default/media/images/feed-icon-small.png | Bin 689 -> 0 bytes .../media/images/gray-up-arrow-h18px.png | Bin 383 -> 0 bytes forum/skins/default/media/images/grippie.png | Bin 162 -> 0 bytes .../skins/default/media/images/indicator.gif | Bin 2545 -> 0 bytes forum/skins/default/media/images/logo.gif | Bin 2114 -> 0 bytes forum/skins/default/media/images/logo.png | Bin 2081 -> 0 bytes forum/skins/default/media/images/logo1.png | Bin 2752 -> 0 bytes forum/skins/default/media/images/logo2.png | Bin 2124 -> 0 bytes forum/skins/default/media/images/medala.gif | Bin 801 -> 0 bytes .../skins/default/media/images/medala_on.gif | Bin 957 -> 0 bytes forum/skins/default/media/images/new.gif | Bin 635 -> 0 bytes forum/skins/default/media/images/nophoto.png | Bin 696 -> 0 bytes forum/skins/default/media/images/openid.gif | Bin 910 -> 0 bytes .../skins/default/media/images/openid/aol.gif | Bin 2205 -> 0 bytes .../default/media/images/openid/blogger.ico | Bin 3638 -> 0 bytes .../default/media/images/openid/claimid.ico | Bin 3638 -> 0 bytes .../default/media/images/openid/facebook.gif | Bin 2075 -> 0 bytes .../default/media/images/openid/flickr.ico | Bin 1150 -> 0 bytes .../default/media/images/openid/google.gif | Bin 1596 -> 0 bytes .../media/images/openid/livejournal.ico | Bin 5222 -> 0 bytes .../default/media/images/openid/myopenid.ico | Bin 2862 -> 0 bytes .../media/images/openid/openid-inputicon.gif | Bin 237 -> 0 bytes .../default/media/images/openid/openid.gif | Bin 740 -> 0 bytes .../media/images/openid/technorati.ico | Bin 2294 -> 0 bytes .../default/media/images/openid/twitter.png | Bin 3130 -> 0 bytes .../default/media/images/openid/verisign.ico | Bin 4710 -> 0 bytes .../default/media/images/openid/vidoop.ico | Bin 1406 -> 0 bytes .../default/media/images/openid/wordpress.ico | Bin 1150 -> 0 bytes .../default/media/images/openid/yahoo.gif | Bin 1510 -> 0 bytes forum/skins/default/media/images/quest-bg.gif | Bin 294 -> 0 bytes .../default/media/images/vote-accepted-on.png | Bin 1124 -> 0 bytes .../default/media/images/vote-accepted.png | Bin 1058 -> 0 bytes .../media/images/vote-arrow-down-on.png | Bin 905 -> 0 bytes .../default/media/images/vote-arrow-down.png | Bin 876 -> 0 bytes .../default/media/images/vote-arrow-up-on.png | Bin 906 -> 0 bytes .../default/media/images/vote-arrow-up.png | Bin 843 -> 0 bytes .../media/images/vote-favorite-off.png | Bin 930 -> 0 bytes .../default/media/images/vote-favorite-on.png | Bin 1023 -> 0 bytes .../media/jquery-openid/images/aol.gif | Bin 2205 -> 0 bytes .../media/jquery-openid/images/blogger-1.png | Bin 432 -> 0 bytes .../media/jquery-openid/images/blogger.ico | Bin 3638 -> 0 bytes .../media/jquery-openid/images/claimid-0.png | Bin 629 -> 0 bytes .../media/jquery-openid/images/claimid.ico | Bin 3638 -> 0 bytes .../media/jquery-openid/images/facebook.gif | Bin 2075 -> 0 bytes .../media/jquery-openid/images/flickr.ico | Bin 1150 -> 0 bytes .../media/jquery-openid/images/flickr.png | Bin 426 -> 0 bytes .../media/jquery-openid/images/google.gif | Bin 1596 -> 0 bytes .../jquery-openid/images/livejournal-1.png | Bin 713 -> 0 bytes .../jquery-openid/images/livejournal.ico | Bin 5222 -> 0 bytes .../media/jquery-openid/images/myopenid-2.png | Bin 511 -> 0 bytes .../media/jquery-openid/images/myopenid.ico | Bin 2862 -> 0 bytes .../jquery-openid/images/openid-inputicon.gif | Bin 237 -> 0 bytes .../media/jquery-openid/images/openid.gif | Bin 740 -> 0 bytes .../media/jquery-openid/images/openidico.png | Bin 654 -> 0 bytes .../jquery-openid/images/openidico16.png | Bin 554 -> 0 bytes .../jquery-openid/images/technorati-1.png | Bin 606 -> 0 bytes .../media/jquery-openid/images/technorati.ico | Bin 2294 -> 0 bytes .../media/jquery-openid/images/verisign-2.png | Bin 859 -> 0 bytes .../media/jquery-openid/images/verisign.ico | Bin 4710 -> 0 bytes .../media/jquery-openid/images/vidoop.ico | Bin 1406 -> 0 bytes .../media/jquery-openid/images/vidoop.png | Bin 499 -> 0 bytes .../media/jquery-openid/images/wordpress.ico | Bin 1150 -> 0 bytes .../media/jquery-openid/images/wordpress.png | Bin 566 -> 0 bytes .../media/jquery-openid/images/yahoo.gif | Bin 1682 -> 0 bytes .../media/jquery-openid/jquery.openid.js | 111 - .../default/media/jquery-openid/openid.css | 75 - .../default/media/js/com.cnprog.admin.js | 13 - .../default/media/js/com.cnprog.editor.js | 68 - .../skins/default/media/js/com.cnprog.i18n.js | 159 - .../skins/default/media/js/com.cnprog.post.js | 691 ---- .../media/js/com.cnprog.tag_selector.js | 171 - .../default/media/js/com.cnprog.utils.js | 132 - forum/skins/default/media/js/compress.bat | 5 - forum/skins/default/media/js/excanvas.pack.js | 1 - forum/skins/default/media/js/flot-build.bat | 3 - forum/skins/default/media/js/jquery-1.2.6.js | 3549 ----------------- .../default/media/js/jquery-1.2.6.min.js | 32 - .../default/media/js/jquery.ajaxfileupload.js | 195 - forum/skins/default/media/js/jquery.flot.js | 2421 ----------- .../default/media/js/jquery.flot.pack.js | 1 - forum/skins/default/media/js/jquery.form.js | 654 --- forum/skins/default/media/js/jquery.i18n.js | 133 - forum/skins/default/media/js/jquery.openid.js | 176 - .../default/media/js/jquery.validate.pack.js | 15 - forum/skins/default/media/js/se_hilite.js | 1 - forum/skins/default/media/js/se_hilite_src.js | 273 -- .../media/js/wmd/images/wmd-buttons.png | Bin 7465 -> 0 bytes .../default/media/js/wmd/showdown-min.js | 1 - forum/skins/default/media/js/wmd/showdown.js | 1309 ------ forum/skins/default/media/js/wmd/wmd-min.js | 1 - .../skins/default/media/js/wmd/wmd-test.html | 158 - forum/skins/default/media/js/wmd/wmd.css | 129 - forum/skins/default/media/js/wmd/wmd.js | 2388 ----------- .../default/media/js/yuicompressor-2.4.2.jar | Bin 851219 -> 0 bytes forum/skins/default/media/style/auth.css | 48 - forum/skins/default/media/style/default.css | 1754 -------- .../media/style/jquery.autocomplete.css | 49 - forum/skins/default/media/style/openid.css | 45 - forum/skins/default/media/style/prettify.css | 27 - forum/skins/default/media/style/style.css | 2459 ------------ forum/skins/default/templates/404.html | 49 - forum/skins/default/templates/500.html | 35 - forum/skins/default/templates/about.html | 36 - .../default/templates/account_settings.html | 45 - .../skins/default/templates/answer_edit.html | 85 - .../default/templates/answer_edit_tips.html | 55 - forum/skins/default/templates/ask.html | 134 - .../default/templates/auth/complete.html | 95 - .../skins/default/templates/auth/signin.html | 161 - .../skins/default/templates/auth/signup.html | 32 - forum/skins/default/templates/badge.html | 37 - forum/skins/default/templates/badges.html | 76 - forum/skins/default/templates/base.html | 83 - .../skins/default/templates/base_content.html | 74 - forum/skins/default/templates/book.html | 152 - forum/skins/default/templates/changepw.html | 18 - forum/skins/default/templates/close.html | 36 - .../templates/edit_user_email_feeds_form.html | 4 - forum/skins/default/templates/faq.html | 146 - .../templates/fbconnect/xd_receiver.html | 10 - forum/skins/default/templates/feedback.html | 55 - .../default/templates/feedback_email.txt | 19 - .../templates/feeds/rss_description.html | 1 - .../default/templates/feeds/rss_title.html | 1 - forum/skins/default/templates/footer.html | 48 - forum/skins/default/templates/header.html | 65 - forum/skins/default/templates/index.html | 124 - forum/skins/default/templates/logout.html | 23 - forum/skins/default/templates/notarobot.html | 15 - forum/skins/default/templates/pagesize.html | 27 - forum/skins/default/templates/paginator.html | 38 - .../templates/post_contributor_info.html | 55 - forum/skins/default/templates/privacy.html | 42 - forum/skins/default/templates/question.html | 508 --- .../default/templates/question_edit.html | 131 - .../default/templates/question_edit_tips.html | 53 - .../default/templates/question_retag.html | 106 - .../templates/question_summary_list_roll.html | 55 - forum/skins/default/templates/questions.html | 235 -- forum/skins/default/templates/reopen.html | 37 - .../default/templates/revisions_answer.html | 83 - .../default/templates/revisions_question.html | 83 - .../skins/default/templates/tag_selector.html | 42 - forum/skins/default/templates/tags.html | 67 - forum/skins/default/templates/user.html | 39 - forum/skins/default/templates/user_edit.html | 95 - .../templates/user_email_subscriptions.html | 26 - .../default/templates/user_favorites.html | 8 - .../skins/default/templates/user_footer.html | 4 - forum/skins/default/templates/user_info.html | 116 - .../skins/default/templates/user_recent.html | 26 - .../default/templates/user_reputation.html | 42 - .../default/templates/user_responses.html | 23 - forum/skins/default/templates/user_stats.html | 138 - forum/skins/default/templates/user_tabs.html | 32 - forum/skins/default/templates/user_votes.html | 32 - forum/skins/default/templates/users.html | 73 - .../default/templates/users_questions.html | 66 - forum/templatetags/__init__.py | 0 forum/templatetags/extra_filters.py | 98 - forum/templatetags/extra_tags.py | 357 -- forum/templatetags/smart_if.py | 401 -- forum/upfiles/README | 2 - forum/urls.py | 114 - forum/user_messages/__init__.py | 36 - forum/user_messages/context_processors.py | 52 - forum/utils/__init__.py | 0 forum/utils/cache.py | 92 - forum/utils/decorators.py | 25 - forum/utils/diff.py | 66 - forum/utils/forms.py | 151 - forum/utils/html.py | 51 - forum/utils/lists.py | 86 - forum/utils/odict.py | 1399 ------- forum/views/README | 12 - forum/views/__init__.py | 6 - forum/views/auth.py | 212 - forum/views/commands.py | 335 -- forum/views/meta.py | 91 - forum/views/readers.py | 588 --- forum/views/users.py | 1009 ----- forum/views/writers.py | 442 -- forum_modules/__init__.py | 0 forum_modules/books/__init__.py | 3 - forum_modules/books/models.py | 63 - forum_modules/books/urls.py | 10 - forum_modules/books/views.py | 142 - forum_modules/facebookauth/__init__.py | 0 forum_modules/facebookauth/authentication.py | 85 - forum_modules/facebookauth/settings.py | 3 - .../facebookauth/templates/button.html | 38 - .../facebookauth/templates/xd_receiver.html | 1 - forum_modules/facebookauth/urls.py | 9 - forum_modules/facebookauth/views.py | 11 - forum_modules/localauth/__init__.py | 0 forum_modules/localauth/authentication.py | 18 - forum_modules/localauth/forms.py | 77 - .../localauth/templates/loginform.html | 31 - forum_modules/localauth/urls.py | 8 - forum_modules/localauth/views.py | 30 - forum_modules/oauthauth/__init__.py | 0 forum_modules/oauthauth/authentication.py | 41 - forum_modules/oauthauth/consumer.py | 87 - forum_modules/oauthauth/lib/__init__.py | 0 forum_modules/oauthauth/lib/oauth.py | 594 --- forum_modules/oauthauth/settings.py | 3 - forum_modules/openidauth/__init__.py | 0 forum_modules/openidauth/authentication.py | 196 - forum_modules/openidauth/consumer.py | 112 - forum_modules/openidauth/models.py | 26 - forum_modules/openidauth/settings.py | 9 - forum_modules/openidauth/store.py | 79 - .../openidauth/templates/openidurl.html | 20 - forum_modules/pgfulltext/DISABLED | 0 forum_modules/pgfulltext/__init__.py | 9 - forum_modules/pgfulltext/handlers.py | 11 - forum_modules/pgfulltext/management.py | 29 - forum_modules/pgfulltext/pg_fts_install.sql | 38 - forum_modules/sphinxfulltext/DISABLED | 0 forum_modules/sphinxfulltext/__init__.py | 0 forum_modules/sphinxfulltext/dependencies.py | 2 - forum_modules/sphinxfulltext/handlers.py | 4 - forum_modules/sphinxfulltext/models.py | 10 - forum_modules/sphinxfulltext/settings.py | 5 - locale/en/LC_MESSAGES/django.po | 3496 ---------------- locale/es/LC_MESSAGES/django.mo | Bin 49713 -> 0 bytes locale/es/LC_MESSAGES/django.po | 2695 ------------- locale/zh_CN/LC_MESSAGES/django.mo | Bin 37880 -> 0 bytes locale/zh_CN/LC_MESSAGES/django.po | 2418 ----------- manage.py | 11 - osqa.iml | 19 - osqa.wsgi.dist | 7 - rmpyc | 1 - settings.py | 101 - settings_local.py.dist | 110 - sphinx/sphinx.conf | 127 - sql_scripts/091111_upgrade_evgeny.sql | 1 - sql_scripts/091208_upgrade_evgeny.sql | 1 - sql_scripts/091208_upgrade_evgeny_1.sql | 1 - sql_scripts/100108_upgrade_ef.sql | 4 - sql_scripts/badges.sql | 37 - sql_scripts/cnprog.xml | 1498 ------- sql_scripts/cnprog_new_install.sql | 811 ---- sql_scripts/cnprog_new_install_2009_02_28.sql | 456 --- sql_scripts/cnprog_new_install_2009_03_31.sql | 891 ----- sql_scripts/cnprog_new_install_2009_04_07.sql | 24 - sql_scripts/cnprog_new_install_2009_04_09.sql | 904 ----- sql_scripts/drop-all-tables.sh | 4 - sql_scripts/drop-auth.sql | 8 - sql_scripts/pg_fts_install.sql | 38 - sql_scripts/update_2009_01_13_001.sql | 62 - sql_scripts/update_2009_01_13_002.sql | 1 - sql_scripts/update_2009_01_18_001.sql | 62 - sql_scripts/update_2009_01_24.sql | 2 - sql_scripts/update_2009_01_25_001.sql | 2 - sql_scripts/update_2009_02_26_001.sql | 19 - sql_scripts/update_2009_04_10_001.sql | 3 - sql_scripts/update_2009_07_05_EF.sql | 3 - sql_scripts/update_2009_12_24_001.sql | 5 - sql_scripts/update_2009_12_27_001.sql | 3 - sql_scripts/update_2009_12_27_002.sql | 1 - sql_scripts/update_2010_01_23.sql | 9 - sql_scripts/update_2010_02_22.sql | 1 - urls.py | 11 - 328 files changed, 46815 deletions(-) delete mode 100644 .project delete mode 100644 .pydevproject delete mode 100644 HOW_TO_DEBUG delete mode 100644 INSTALL delete mode 100644 PENDING delete mode 100644 README delete mode 100644 ROADMAP.rst delete mode 100644 WISH_LIST delete mode 100644 __init__.py delete mode 100644 context.py delete mode 100644 cron/send_email_alerts delete mode 100644 dos2unix.sh delete mode 100644 forum/__init__.py delete mode 100644 forum/admin.py delete mode 100644 forum/auth.py delete mode 100755 forum/authentication/__init__.py delete mode 100755 forum/authentication/base.py delete mode 100755 forum/authentication/forms.py delete mode 100644 forum/const.py delete mode 100644 forum/feed.py delete mode 100644 forum/forms.py delete mode 100644 forum/management/__init__.py delete mode 100644 forum/management/commands/__init__.py delete mode 100644 forum/management/commands/base_command.py delete mode 100644 forum/management/commands/clean_award_badges.py delete mode 100644 forum/management/commands/message_to_everyone.py delete mode 100644 forum/management/commands/multi_award_badges.py delete mode 100644 forum/management/commands/once_award_badges.py delete mode 100644 forum/management/commands/sample_command.py delete mode 100644 forum/management/commands/send_email_alerts.py delete mode 100644 forum/management/commands/subscribe_everyone.py delete mode 100644 forum/middleware/__init__.py delete mode 100644 forum/middleware/anon_user.py delete mode 100644 forum/middleware/cancel.py delete mode 100644 forum/middleware/pagesize.py delete mode 100755 forum/models/__init__.py delete mode 100755 forum/models/answer.py delete mode 100755 forum/models/base.py delete mode 100755 forum/models/meta.py delete mode 100755 forum/models/question.py delete mode 100755 forum/models/repute.py delete mode 100755 forum/models/tag.py delete mode 100755 forum/models/user.py delete mode 100755 forum/modules.py delete mode 100644 forum/sitemap.py delete mode 100644 forum/skins/README delete mode 100644 forum/skins/__init__.py delete mode 100644 forum/skins/common/media/README delete mode 100644 forum/skins/default/media/images/blue-up-arrow-h18px.png delete mode 100644 forum/skins/default/media/images/box-arrow.gif delete mode 100644 forum/skins/default/media/images/bullet_green.gif delete mode 100644 forum/skins/default/media/images/cc-88x31.png delete mode 100644 forum/skins/default/media/images/cc-wiki.png delete mode 100644 forum/skins/default/media/images/close-small-dark.png delete mode 100644 forum/skins/default/media/images/close-small-hover.png delete mode 100644 forum/skins/default/media/images/close-small.png delete mode 100644 forum/skins/default/media/images/dash.gif delete mode 100644 forum/skins/default/media/images/djangomade124x25_grey.gif delete mode 100644 forum/skins/default/media/images/dot-g.gif delete mode 100644 forum/skins/default/media/images/dot-list.gif delete mode 100644 forum/skins/default/media/images/edit.png delete mode 100644 forum/skins/default/media/images/expander-arrow-hide.gif delete mode 100644 forum/skins/default/media/images/expander-arrow-show.gif delete mode 100644 forum/skins/default/media/images/favicon.gif delete mode 100644 forum/skins/default/media/images/feed-icon-small.png delete mode 100644 forum/skins/default/media/images/gray-up-arrow-h18px.png delete mode 100644 forum/skins/default/media/images/grippie.png delete mode 100644 forum/skins/default/media/images/indicator.gif delete mode 100644 forum/skins/default/media/images/logo.gif delete mode 100644 forum/skins/default/media/images/logo.png delete mode 100644 forum/skins/default/media/images/logo1.png delete mode 100644 forum/skins/default/media/images/logo2.png delete mode 100644 forum/skins/default/media/images/medala.gif delete mode 100644 forum/skins/default/media/images/medala_on.gif delete mode 100644 forum/skins/default/media/images/new.gif delete mode 100644 forum/skins/default/media/images/nophoto.png delete mode 100644 forum/skins/default/media/images/openid.gif delete mode 100644 forum/skins/default/media/images/openid/aol.gif delete mode 100644 forum/skins/default/media/images/openid/blogger.ico delete mode 100644 forum/skins/default/media/images/openid/claimid.ico delete mode 100644 forum/skins/default/media/images/openid/facebook.gif delete mode 100644 forum/skins/default/media/images/openid/flickr.ico delete mode 100644 forum/skins/default/media/images/openid/google.gif delete mode 100644 forum/skins/default/media/images/openid/livejournal.ico delete mode 100644 forum/skins/default/media/images/openid/myopenid.ico delete mode 100644 forum/skins/default/media/images/openid/openid-inputicon.gif delete mode 100644 forum/skins/default/media/images/openid/openid.gif delete mode 100644 forum/skins/default/media/images/openid/technorati.ico delete mode 100755 forum/skins/default/media/images/openid/twitter.png delete mode 100644 forum/skins/default/media/images/openid/verisign.ico delete mode 100644 forum/skins/default/media/images/openid/vidoop.ico delete mode 100644 forum/skins/default/media/images/openid/wordpress.ico delete mode 100644 forum/skins/default/media/images/openid/yahoo.gif delete mode 100644 forum/skins/default/media/images/quest-bg.gif delete mode 100644 forum/skins/default/media/images/vote-accepted-on.png delete mode 100644 forum/skins/default/media/images/vote-accepted.png delete mode 100644 forum/skins/default/media/images/vote-arrow-down-on.png delete mode 100644 forum/skins/default/media/images/vote-arrow-down.png delete mode 100644 forum/skins/default/media/images/vote-arrow-up-on.png delete mode 100644 forum/skins/default/media/images/vote-arrow-up.png delete mode 100644 forum/skins/default/media/images/vote-favorite-off.png delete mode 100644 forum/skins/default/media/images/vote-favorite-on.png delete mode 100644 forum/skins/default/media/jquery-openid/images/aol.gif delete mode 100644 forum/skins/default/media/jquery-openid/images/blogger-1.png delete mode 100644 forum/skins/default/media/jquery-openid/images/blogger.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/claimid-0.png delete mode 100644 forum/skins/default/media/jquery-openid/images/claimid.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/facebook.gif delete mode 100644 forum/skins/default/media/jquery-openid/images/flickr.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/flickr.png delete mode 100644 forum/skins/default/media/jquery-openid/images/google.gif delete mode 100644 forum/skins/default/media/jquery-openid/images/livejournal-1.png delete mode 100644 forum/skins/default/media/jquery-openid/images/livejournal.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/myopenid-2.png delete mode 100644 forum/skins/default/media/jquery-openid/images/myopenid.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/openid-inputicon.gif delete mode 100644 forum/skins/default/media/jquery-openid/images/openid.gif delete mode 100644 forum/skins/default/media/jquery-openid/images/openidico.png delete mode 100644 forum/skins/default/media/jquery-openid/images/openidico16.png delete mode 100644 forum/skins/default/media/jquery-openid/images/technorati-1.png delete mode 100644 forum/skins/default/media/jquery-openid/images/technorati.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/verisign-2.png delete mode 100644 forum/skins/default/media/jquery-openid/images/verisign.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/vidoop.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/vidoop.png delete mode 100644 forum/skins/default/media/jquery-openid/images/wordpress.ico delete mode 100644 forum/skins/default/media/jquery-openid/images/wordpress.png delete mode 100644 forum/skins/default/media/jquery-openid/images/yahoo.gif delete mode 100644 forum/skins/default/media/jquery-openid/jquery.openid.js delete mode 100644 forum/skins/default/media/jquery-openid/openid.css delete mode 100644 forum/skins/default/media/js/com.cnprog.admin.js delete mode 100644 forum/skins/default/media/js/com.cnprog.editor.js delete mode 100644 forum/skins/default/media/js/com.cnprog.i18n.js delete mode 100644 forum/skins/default/media/js/com.cnprog.post.js delete mode 100644 forum/skins/default/media/js/com.cnprog.tag_selector.js delete mode 100644 forum/skins/default/media/js/com.cnprog.utils.js delete mode 100644 forum/skins/default/media/js/compress.bat delete mode 100644 forum/skins/default/media/js/excanvas.pack.js delete mode 100644 forum/skins/default/media/js/flot-build.bat delete mode 100644 forum/skins/default/media/js/jquery-1.2.6.js delete mode 100644 forum/skins/default/media/js/jquery-1.2.6.min.js delete mode 100644 forum/skins/default/media/js/jquery.ajaxfileupload.js delete mode 100644 forum/skins/default/media/js/jquery.flot.js delete mode 100644 forum/skins/default/media/js/jquery.flot.pack.js delete mode 100644 forum/skins/default/media/js/jquery.form.js delete mode 100644 forum/skins/default/media/js/jquery.i18n.js delete mode 100644 forum/skins/default/media/js/jquery.openid.js delete mode 100644 forum/skins/default/media/js/jquery.validate.pack.js delete mode 100644 forum/skins/default/media/js/se_hilite.js delete mode 100644 forum/skins/default/media/js/se_hilite_src.js delete mode 100644 forum/skins/default/media/js/wmd/images/wmd-buttons.png delete mode 100644 forum/skins/default/media/js/wmd/showdown-min.js delete mode 100644 forum/skins/default/media/js/wmd/showdown.js delete mode 100644 forum/skins/default/media/js/wmd/wmd-min.js delete mode 100644 forum/skins/default/media/js/wmd/wmd-test.html delete mode 100644 forum/skins/default/media/js/wmd/wmd.css delete mode 100644 forum/skins/default/media/js/wmd/wmd.js delete mode 100644 forum/skins/default/media/js/yuicompressor-2.4.2.jar delete mode 100755 forum/skins/default/media/style/auth.css delete mode 100644 forum/skins/default/media/style/default.css delete mode 100644 forum/skins/default/media/style/jquery.autocomplete.css delete mode 100644 forum/skins/default/media/style/openid.css delete mode 100644 forum/skins/default/media/style/prettify.css delete mode 100644 forum/skins/default/media/style/style.css delete mode 100644 forum/skins/default/templates/404.html delete mode 100644 forum/skins/default/templates/500.html delete mode 100644 forum/skins/default/templates/about.html delete mode 100755 forum/skins/default/templates/account_settings.html delete mode 100644 forum/skins/default/templates/answer_edit.html delete mode 100644 forum/skins/default/templates/answer_edit_tips.html delete mode 100644 forum/skins/default/templates/ask.html delete mode 100755 forum/skins/default/templates/auth/complete.html delete mode 100755 forum/skins/default/templates/auth/signin.html delete mode 100755 forum/skins/default/templates/auth/signup.html delete mode 100644 forum/skins/default/templates/badge.html delete mode 100644 forum/skins/default/templates/badges.html delete mode 100755 forum/skins/default/templates/base.html delete mode 100644 forum/skins/default/templates/base_content.html delete mode 100644 forum/skins/default/templates/book.html delete mode 100755 forum/skins/default/templates/changepw.html delete mode 100644 forum/skins/default/templates/close.html delete mode 100644 forum/skins/default/templates/edit_user_email_feeds_form.html delete mode 100644 forum/skins/default/templates/faq.html delete mode 100755 forum/skins/default/templates/fbconnect/xd_receiver.html delete mode 100644 forum/skins/default/templates/feedback.html delete mode 100644 forum/skins/default/templates/feedback_email.txt delete mode 100644 forum/skins/default/templates/feeds/rss_description.html delete mode 100644 forum/skins/default/templates/feeds/rss_title.html delete mode 100644 forum/skins/default/templates/footer.html delete mode 100644 forum/skins/default/templates/header.html delete mode 100755 forum/skins/default/templates/index.html delete mode 100644 forum/skins/default/templates/logout.html delete mode 100644 forum/skins/default/templates/notarobot.html delete mode 100644 forum/skins/default/templates/pagesize.html delete mode 100644 forum/skins/default/templates/paginator.html delete mode 100644 forum/skins/default/templates/post_contributor_info.html delete mode 100644 forum/skins/default/templates/privacy.html delete mode 100644 forum/skins/default/templates/question.html delete mode 100644 forum/skins/default/templates/question_edit.html delete mode 100644 forum/skins/default/templates/question_edit_tips.html delete mode 100644 forum/skins/default/templates/question_retag.html delete mode 100644 forum/skins/default/templates/question_summary_list_roll.html delete mode 100644 forum/skins/default/templates/questions.html delete mode 100644 forum/skins/default/templates/reopen.html delete mode 100644 forum/skins/default/templates/revisions_answer.html delete mode 100644 forum/skins/default/templates/revisions_question.html delete mode 100644 forum/skins/default/templates/tag_selector.html delete mode 100644 forum/skins/default/templates/tags.html delete mode 100644 forum/skins/default/templates/user.html delete mode 100644 forum/skins/default/templates/user_edit.html delete mode 100644 forum/skins/default/templates/user_email_subscriptions.html delete mode 100644 forum/skins/default/templates/user_favorites.html delete mode 100644 forum/skins/default/templates/user_footer.html delete mode 100644 forum/skins/default/templates/user_info.html delete mode 100644 forum/skins/default/templates/user_recent.html delete mode 100644 forum/skins/default/templates/user_reputation.html delete mode 100644 forum/skins/default/templates/user_responses.html delete mode 100644 forum/skins/default/templates/user_stats.html delete mode 100644 forum/skins/default/templates/user_tabs.html delete mode 100644 forum/skins/default/templates/user_votes.html delete mode 100644 forum/skins/default/templates/users.html delete mode 100644 forum/skins/default/templates/users_questions.html delete mode 100644 forum/templatetags/__init__.py delete mode 100644 forum/templatetags/extra_filters.py delete mode 100644 forum/templatetags/extra_tags.py delete mode 100644 forum/templatetags/smart_if.py delete mode 100644 forum/upfiles/README delete mode 100644 forum/urls.py delete mode 100644 forum/user_messages/__init__.py delete mode 100644 forum/user_messages/context_processors.py delete mode 100644 forum/utils/__init__.py delete mode 100644 forum/utils/cache.py delete mode 100644 forum/utils/decorators.py delete mode 100644 forum/utils/diff.py delete mode 100644 forum/utils/forms.py delete mode 100644 forum/utils/html.py delete mode 100644 forum/utils/lists.py delete mode 100644 forum/utils/odict.py delete mode 100644 forum/views/README delete mode 100644 forum/views/__init__.py delete mode 100755 forum/views/auth.py delete mode 100644 forum/views/commands.py delete mode 100644 forum/views/meta.py delete mode 100644 forum/views/readers.py delete mode 100644 forum/views/users.py delete mode 100644 forum/views/writers.py delete mode 100755 forum_modules/__init__.py delete mode 100755 forum_modules/books/__init__.py delete mode 100755 forum_modules/books/models.py delete mode 100755 forum_modules/books/urls.py delete mode 100755 forum_modules/books/views.py delete mode 100755 forum_modules/facebookauth/__init__.py delete mode 100755 forum_modules/facebookauth/authentication.py delete mode 100755 forum_modules/facebookauth/settings.py delete mode 100755 forum_modules/facebookauth/templates/button.html delete mode 100755 forum_modules/facebookauth/templates/xd_receiver.html delete mode 100755 forum_modules/facebookauth/urls.py delete mode 100755 forum_modules/facebookauth/views.py delete mode 100755 forum_modules/localauth/__init__.py delete mode 100755 forum_modules/localauth/authentication.py delete mode 100755 forum_modules/localauth/forms.py delete mode 100755 forum_modules/localauth/templates/loginform.html delete mode 100755 forum_modules/localauth/urls.py delete mode 100755 forum_modules/localauth/views.py delete mode 100755 forum_modules/oauthauth/__init__.py delete mode 100755 forum_modules/oauthauth/authentication.py delete mode 100755 forum_modules/oauthauth/consumer.py delete mode 100755 forum_modules/oauthauth/lib/__init__.py delete mode 100755 forum_modules/oauthauth/lib/oauth.py delete mode 100755 forum_modules/oauthauth/settings.py delete mode 100755 forum_modules/openidauth/__init__.py delete mode 100755 forum_modules/openidauth/authentication.py delete mode 100755 forum_modules/openidauth/consumer.py delete mode 100755 forum_modules/openidauth/models.py delete mode 100755 forum_modules/openidauth/settings.py delete mode 100755 forum_modules/openidauth/store.py delete mode 100755 forum_modules/openidauth/templates/openidurl.html delete mode 100755 forum_modules/pgfulltext/DISABLED delete mode 100755 forum_modules/pgfulltext/__init__.py delete mode 100755 forum_modules/pgfulltext/handlers.py delete mode 100755 forum_modules/pgfulltext/management.py delete mode 100755 forum_modules/pgfulltext/pg_fts_install.sql delete mode 100755 forum_modules/sphinxfulltext/DISABLED delete mode 100755 forum_modules/sphinxfulltext/__init__.py delete mode 100755 forum_modules/sphinxfulltext/dependencies.py delete mode 100755 forum_modules/sphinxfulltext/handlers.py delete mode 100755 forum_modules/sphinxfulltext/models.py delete mode 100755 forum_modules/sphinxfulltext/settings.py delete mode 100644 locale/en/LC_MESSAGES/django.po delete mode 100644 locale/es/LC_MESSAGES/django.mo delete mode 100644 locale/es/LC_MESSAGES/django.po delete mode 100644 locale/zh_CN/LC_MESSAGES/django.mo delete mode 100644 locale/zh_CN/LC_MESSAGES/django.po delete mode 100644 manage.py delete mode 100755 osqa.iml delete mode 100644 osqa.wsgi.dist delete mode 100755 rmpyc delete mode 100755 settings.py delete mode 100755 settings_local.py.dist delete mode 100644 sphinx/sphinx.conf delete mode 100644 sql_scripts/091111_upgrade_evgeny.sql delete mode 100644 sql_scripts/091208_upgrade_evgeny.sql delete mode 100644 sql_scripts/091208_upgrade_evgeny_1.sql delete mode 100644 sql_scripts/100108_upgrade_ef.sql delete mode 100644 sql_scripts/badges.sql delete mode 100644 sql_scripts/cnprog.xml delete mode 100644 sql_scripts/cnprog_new_install.sql delete mode 100644 sql_scripts/cnprog_new_install_2009_02_28.sql delete mode 100644 sql_scripts/cnprog_new_install_2009_03_31.sql delete mode 100644 sql_scripts/cnprog_new_install_2009_04_07.sql delete mode 100644 sql_scripts/cnprog_new_install_2009_04_09.sql delete mode 100644 sql_scripts/drop-all-tables.sh delete mode 100644 sql_scripts/drop-auth.sql delete mode 100644 sql_scripts/pg_fts_install.sql delete mode 100644 sql_scripts/update_2009_01_13_001.sql delete mode 100644 sql_scripts/update_2009_01_13_002.sql delete mode 100644 sql_scripts/update_2009_01_18_001.sql delete mode 100644 sql_scripts/update_2009_01_24.sql delete mode 100644 sql_scripts/update_2009_01_25_001.sql delete mode 100644 sql_scripts/update_2009_02_26_001.sql delete mode 100644 sql_scripts/update_2009_04_10_001.sql delete mode 100644 sql_scripts/update_2009_07_05_EF.sql delete mode 100644 sql_scripts/update_2009_12_24_001.sql delete mode 100644 sql_scripts/update_2009_12_27_001.sql delete mode 100644 sql_scripts/update_2009_12_27_002.sql delete mode 100755 sql_scripts/update_2010_01_23.sql delete mode 100644 sql_scripts/update_2010_02_22.sql delete mode 100644 urls.py diff --git a/.project b/.project deleted file mode 100644 index 8e56b00..0000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - osqa - - - - - - org.eclipse.wst.jsdt.core.javascriptValidator - - - - - org.python.pydev.PyDevBuilder - - - - - - org.python.pydev.pythonNature - org.eclipse.wst.jsdt.core.jsNature - - diff --git a/.pydevproject b/.pydevproject deleted file mode 100644 index f7f3fd1..0000000 --- a/.pydevproject +++ /dev/null @@ -1,10 +0,0 @@ - - - - -Default -python 2.6 - -/osqa - - diff --git a/HOW_TO_DEBUG b/HOW_TO_DEBUG deleted file mode 100644 index ba36198..0000000 --- a/HOW_TO_DEBUG +++ /dev/null @@ -1,39 +0,0 @@ -1) LOGGING -Please remember that log files may contain plaintext passwords, etc. - -Please do not add print statements - at least do not commit them to git -because in some environments printing to stdout causes errors - -Instead use python logging this way: --------------------------------- -#somewere on top of file -import logging - -#anywhere below -logging.debug('this maybe works') -logging.error('have big error!') -#or even -logging.debug('') #this will add time, line number, function and file record -#sometimes useful record for call tracing on its own -#etc - take a look at http://docs.python.org/library/logging.html -------------------------------- - -in OSQA logging is currently set up in settings_local.py.dist -please update it if you need - in older revs logging strings have less info - -messages of interest can be grepped out of the log file by module/file/function name -e.g. to take out all django_authopenid logs run: ->grep 'osqa\/django_authopenid' log/django.osqa.log | sed 's/^.*MSG: //' -in the example above 'sed' call truncates out a long prefix -and makes output look more meaningful - -2) DJANGO DEBUG TOOLBAR -osqa works with django debug toolbar -if debugging under apache server, check -that debug toolbar media is loaded correctly -if toolbar is enabled but you do not see it, possibly some Alias statement -in apache config is wrong in your VirtualHost or elsewhere - -3) If you discover new debugging techniques, please add here. -Possible areas to improve - at this point there is no SQL query logging, -as well as request data and http header. diff --git a/INSTALL b/INSTALL deleted file mode 100644 index f70b3ec..0000000 --- a/INSTALL +++ /dev/null @@ -1,314 +0,0 @@ -CONTENTS ------------------- -A. PREREQUISITES -B. INSTALLATION - 1. Settings file - 2. Database - 3. Running OSQA in the development server - 4. Installation under Apache/WSGI - 5. Full text search - 6. Email subscriptions - 7. Sitemap - 8. Miscellaneous -C. CONFIGURATION PARAMETERS (settings_local.py) -D. CUSTOMIZATION - - -A. PREREQUISITES ------------------------------------------------ -0. We recommend you to use python-setuptools to install pre-requirement libraries. -If you haven't installed it, please try to install it first. -e.g, sudo apt-get install python-setuptools - -1. Python2.5/2.6, MySQL, Django v1.0/1.1 -Note: email subscription sender job requires Django 1.1, everything else works with 1.0 -Make sure mysql for python provider has been installed. -sudo easy_install mysql-python - -2. Python-openid v2.2 -http://openidenabled.com/python-openid/ -sudo easy_install python-openid - -4. html5lib -http://code.google.com/p/html5lib/ -Used for HTML sanitizer -sudo easy_install html5lib - -5. Markdown2 -http://code.google.com/p/python-markdown2/ -sudo easy_install markdown2 - -6. Django Debug Toolbar -http://github.com/robhudson/django-debug-toolbar/tree/master - -7. djangosphinx (optional - for full text questions+answer+tag) -http://github.com/dcramer/django-sphinx/tree/master/djangosphinx - -8. sphinx search engine (optional, works together with djangosphinx) -http://sphinxsearch.com/downloads.html - -9. recaptcha_django -http://code.google.com/p/recaptcha-django/ - -10. python recaptcha module -http://code.google.com/p/recaptcha/ -Notice that you will need to register with recaptcha.net and receive -recaptcha public and private keys that need to be saved in your -settings_local.py file - -NOTES: django_authopenid is included into OSQA code -and is significantly modified. http://code.google.com/p/django-authopenid/ -no need to install this library - -B. INSTALLATION ------------------------------------------------ -0. Make sure you have all above python libraries installed. - - make osqa installation server-readable on Linux command might be: - chown -R yourlogin:apache /path/to/OSQA - - directories templates/upfiles and log must be server writable - - on Linux type chmod - chmod -R g+w /path/to/OSQA/upfiles - chmod -R g+w /path/to/log - - above it is assumed that webserver runs under group named "apache" - -1. Settings file - -Copy settings_local.py.dist to settings_local.py and -update all your settings. Check settings.py and update -it as well if necessory. -Section C explains configuration paramaters. - -2. Database - -Prepare your database by using the same database/account -configuration from above. -e.g, -create database osqa DEFAULT CHARACTER SET UTF8 COLLATE utf8_general_ci; -grant all on osqa.* to 'osqa'@'localhost'; -And then run "python manage.py syncdb" to synchronize your database. - -3. Running OSQA on the development server - -Run "python manage.py runserver" to startup django -development environment. -(Under Linux you can use command "python manage.py runserver `hostname -i`:8000", -where you can use any other available number for the port) - -you might want to have DEBUG=True in the beginning of settings.py -when using the test server - -4. Installation under Apache/WSGI - -4.1 Prepare wsgi script - -Make a file readable by your webserver with the following content: - ---------- -import os -import sys - -sys.path.insert(0,'/one/level/above') #insert to make sure that forum will be found -sys.path.append('/one/level/above/OSQA') #maybe this is not necessary -os.environ['DJANGO_SETTINGS_MODULE'] = 'OSQA.settings' -import django.core.handlers.wsgi -application = django.core.handlers.wsgi.WSGIHandler() ------------ - -insert method is used for path because if the forum directory name -is by accident the same as some other python module -you wull see strange errors - forum won't be found even though -it's in the python path. for example using name "test" is -not a good idea - as there is a module with such name - - -4.2 Configure webserver -Settings below are not perfect but may be a good starting point - ---------- -WSGISocketPrefix /path/to/socket/sock #must be readable and writable by apache -WSGIPythonHome /usr/local #must be readable by apache -WSGIPythonEggs /var/python/eggs #must be readable and writable by apache - -#NOTE: all urs below will need to be adjusted if -#settings.FORUM_SCRIPT_ALIAS !='' (e.g. = 'forum/') -#this allows "rooting" forum at http://example.com/forum, if you like - - ServerAdmin forum@example.com - DocumentRoot /path/to/osqa-site - ServerName example.com - - #run mod_wsgi process for django in daemon mode - #this allows avoiding confused timezone settings when - #another application runs in the same virtual host - WSGIDaemonProcess OSQA - WSGIProcessGroup OSQA - - #force all content to be served as static files - #otherwise django will be crunching images through itself wasting time - Alias /m/ /path/to/osqa-site/forum/skins/ - Alias /upfiles/ /path/to/osqa-site/forum/upfiles/ - - Order deny,allow - Allow from all - - - #this is your wsgi script described in the prev section - WSGIScriptAlias / /path/to/osqa-site/osqa.wsgi - - #this will force admin interface to work only - #through https (optional) - #"nimda" is the secret spelling of "admin" ;) - - RewriteEngine on - RewriteRule /nimda(.*)$ https://example.com/nimda$1 [L,R=301] - - CustomLog /var/log/httpd/OSQA/access_log common - ErrorLog /var/log/httpd/OSQA/error_log - -#(optional) run admin interface under https - - ServerAdmin forum@example.com - DocumentRoot /path/to/osqa-site - ServerName example.com - SSLEngine on - SSLCertificateFile /path/to/ssl-certificate/server.crt - SSLCertificateKeyFile /path/to/ssl-certificate/server.key - WSGIScriptAlias / /path/to/osqa-site/osqa.wsgi - CustomLog /var/log/httpd/OSQA/access_log common - ErrorLog /var/log/httpd/OSQA/error_log - DirectoryIndex index.html - -------------- - -5. Full text search (using sphinx search) - - Currently full text search works only with sphinx search engine - And builtin PostgreSQL (postgres only >= 8.3???) - - 5.1 Instructions for Sphinx search setup - Sphinx at this time supports only MySQL and PostgreSQL databases - to enable this, install sphinx search engine and djangosphinx - - configure sphinx, sample configuration can be found in - sphinx/sphinx.conf file usually goes somewhere in /etc tree - - build osqa index first time manually - - % indexer --config /path/to/sphinx.conf --index osqa - - setup cron job to rebuild index periodically with command - your crontab entry may be something like - - 0 9,15,21 * * * /usr/local/bin/indexer --config /etc/sphinx/sphinx.conf --all --rotate >/dev/null 2>&1 - adjust it as necessary this one will reindex three times a day at 9am 3pm and 9pm - - if your forum grows very big ( good luck with that :) you'll - need to two search indices one diff index and one main - please refer to online sphinx search documentation for the information - on the subject http://sphinxsearch.com/docs/ - - in settings_local.py set - USE_SPHINX_SEARCH=True - adjust other settings that have SPHINX_* prefix accordingly - remember that there must be trailing comma in parentheses for - SHPINX_SEARCH_INDICES tuple - particlarly with just one item! - - in settings.py look for INSTALLED_APPS - and uncomment #'djangosphinx', - - -6. Email subscriptions - - This function at the moment requires Django 1.1 - - edit paths in the file cron/send_email_alerts - set up a cron job to call cron/send_email_alerts once or twice a day - subscription sender may be tested manually in shell - by calling cron/send_email_alerts - -7. Sitemap -Sitemap will be available at /sitemap.xml -e.g yoursite.com/forum/sitemap.xml - -google will be pinged each time question, answer or -comment is saved or a question deleted - -for this to be useful - do register you sitemap with Google at -https://www.google.com/webmasters/tools/ - -8. Miscellaneous - -There are some demo scripts under sql_scripts folder, -including badges and test accounts for CNProg.com. You -don't need them to run your sample. - -C. CONFIGURATION PARAMETERS - -#the only parameter that needs to be touched in settings.py is -DEBUG=False #set to True to enable debug mode - -#all forum parameters are set in file settings_local.py - -LOG_FILENAME = 'osqa.log' #where logging messages should go -DATABASE_NAME = 'osqa' # Or path to database file if using sqlite3. -DATABASE_USER = '' # Not used with sqlite3. -DATABASE_PASSWORD = '' # Not used with sqlite3. -DATABASE_ENGINE = 'mysql' #mysql, etc -SERVER_EMAIL = '' -DEFAULT_FROM_EMAIL = '' -EMAIL_HOST_USER = '' -EMAIL_HOST_PASSWORD = '' #not necessary if mailserver is run on local machine -EMAIL_SUBJECT_PREFIX = '[OSQA] ' -EMAIL_HOST='osqa.com' -EMAIL_PORT='25' -EMAIL_USE_TLS=False -TIME_ZONE = 'America/Tijuana' -APP_TITLE = u'OSQA Q&A Forum' #title of your forum -APP_KEYWORDS = u'OSQA,forum,community' #keywords for search engines -APP_DESCRIPTION = u'Ask and answer questions.' #site description for searche engines -APP_INTRO = u'

Ask and answer questions, make the world better!

' #slogan that goes to front page in logged out mode -APP_COPYRIGHT = '' #copyright message - -#if you set FORUM_SCRIPT_ALIAS= 'forum/' -#then OSQA will run at url http://example.com/forum -#FORUM_SCRIPT_ALIAS cannot have leading slash, otherwise it can be set to anything -FORUM_SCRIPT_ALIAS = '' #no leading slash, default = '' empty string - -LANGUAGE_CODE = 'en' #forum language (see language instructions on the wiki) -EMAIL_VALIDATION = 'off' #string - on|off -MIN_USERNAME_LENGTH = 1 -EMAIL_UNIQUE = False #if True, email addresses must be unique in all accounts -APP_URL = 'http://osqa.com' #used by email notif system and RSS -GOOGLE_SITEMAP_CODE = '' #code for google site crawler (look up google webmaster tools) -GOOGLE_ANALYTICS_KEY = '' #key to enable google analytics on this site -BOOKS_ON = False #if True - books tab will be on -WIKI_ON = True #if False - community wiki feature is disabled - -#experimental - allow password login through external site -#must implement django_authopenid/external_login.py -#included prototype external_login works with Mediawiki -USE_EXTERNAL_LEGACY_LOGIN = True #if false OSQA uses it's own login/password -EXTERNAL_LEGACY_LOGIN_HOST = 'login.osqa.com' -EXTERNAL_LEGACY_LOGIN_PORT = 80 -EXTERNAL_LEGACY_LOGIN_PROVIDER_NAME = 'OSQA' - -FEEDBACK_SITE_URL = None #None or url -LOGIN_URL = '/%s%s%s' % (FORUM_SCRIPT_ALIAS,'account/','signin/') - -DJANGO_VERSION = 1.1 #must be either 1.0 or 1.1 -RESOURCE_REVISION=4 #increment when you update media files - clients will be forced to load new version - -D. Customization - -Other than settings_local.py the following will most likely need customization: -* locale/*/django.po - language files that may also contain your site-specific messages - if you want to start with english messages file - look for words like "forum" and - "OSQA" in the msgstr lines -* templates/header.html and templates/footer.html may contain extra links -* templates/about.html - a place to explain for is your forum for -* templates/faq.html - put answers to users frequent questions -* templates/content/style/style.css - modify style sheet to add disctinctive look to your forum diff --git a/PENDING b/PENDING deleted file mode 100644 index 2931303..0000000 --- a/PENDING +++ /dev/null @@ -1,28 +0,0 @@ -There are two kinds of things that can be done: -refactorings (think of jogging in the morning, going to a spa, well make the code better :) -new features (go to law school, get a job, do something real) -Just a joke - pick yourself a task and work on it. - -==Refactoring== -* validate HTML -* set up loading of default settings from inside the /forum dir -* automatic dependency checking for modules -* propose how to rename directory forum --> osqa - without breaking things and keeping name of the project root - named the same way - osqa - -==New features== -Whoever wants - pick a feature from the WISH_LIST -add it here and start working on it -If you are not starting immediately - leave it on the wishlist :) - -==Notes== -1)after this is done most new suggested features - may be worked on easily since most of them - only require editing view functions and templates - - However, anyone can work on new features anyway - you'll - just have to probably copy-paste your code into - the branch undergoing refactoring which involves - splitting the files. Auto merging across split points - is harder or impossible. diff --git a/README b/README deleted file mode 100644 index 2a209b7..0000000 --- a/README +++ /dev/null @@ -1,6 +0,0 @@ -This is OSQA project - open source Q&A system - -Demo site is http://osqa.net - -OSQA is based on code of CNPROG, originally created by Mike Chen and Sailing Cai. - diff --git a/ROADMAP.rst b/ROADMAP.rst deleted file mode 100644 index 42f2e8c..0000000 --- a/ROADMAP.rst +++ /dev/null @@ -1,32 +0,0 @@ -This document is a map for our activities down the road - therefore ROADMAP. -ROADMAP does not specify deadlines - those belong to the PENDING file - -Intro -========= -ROADMAP aims to streamline activities of the OSQA open source project and -to minimize ad-hoc approaches of "big-picture" level. - -With one exception: under extreme time pressure improvised approaches are perfectly acceptable. - -Items in this document must be discussed in public via dev@osqa.net - -Architecture -============= - -Sub-systems ------------------ -* authentication system -* Q&A system - -Authentication system -------------------------- -* MUST authenticate people visiting the website via web browsers. -* Upon successful authentication must associates the visitor with - his/her Django system user account -* MUST allow multiple methods of authentication to the same account -* MUST support a method to recover lost authentication link by email -* MAY offer an option to "soft-validate" user's email (send a link - with a special key, so that user clicks and we know that email is valid) - "soft" - meaning that lack of validation won't block people - from using the site - diff --git a/WISH_LIST b/WISH_LIST deleted file mode 100644 index 6b10687..0000000 --- a/WISH_LIST +++ /dev/null @@ -1,10 +0,0 @@ -* The wonder bar (integrated the search / ask functionality) -* The authentication system ??? -* allow multiple logins to the same account -* more advanced templating/skinning system -* per-tag email subscriptions -* view for personalized news on the site -* a little flag popping when there are news -* drill-down mode for navigation by tags -* improved admin console -* sort out mess with profile - currently we patch django User diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/context.py b/context.py deleted file mode 100644 index 9e22550..0000000 --- a/context.py +++ /dev/null @@ -1,47 +0,0 @@ -from django.conf import settings -def application_settings(context): - my_settings = { - 'APP_TITLE' : settings.APP_TITLE, - 'APP_SHORT_NAME' : settings.APP_SHORT_NAME, - 'APP_URL' : settings.APP_URL, - 'APP_KEYWORDS' : settings.APP_KEYWORDS, - 'APP_DESCRIPTION' : settings.APP_DESCRIPTION, - 'APP_INTRO' : settings.APP_INTRO, - 'EMAIL_VALIDATION': settings.EMAIL_VALIDATION, - 'LANGUAGE_CODE': settings.LANGUAGE_CODE, - 'GOOGLE_SITEMAP_CODE':settings.GOOGLE_SITEMAP_CODE, - 'GOOGLE_ANALYTICS_KEY':settings.GOOGLE_ANALYTICS_KEY, - 'BOOKS_ON':settings.BOOKS_ON, - 'WIKI_ON':settings.WIKI_ON, - 'USE_EXTERNAL_LEGACY_LOGIN':settings.USE_EXTERNAL_LEGACY_LOGIN, - 'RESOURCE_REVISION':settings.RESOURCE_REVISION, - 'USE_SPHINX_SEARCH':settings.USE_SPHINX_SEARCH, - 'OSQA_SKIN':settings.OSQA_DEFAULT_SKIN, - } - return {'settings':my_settings} - -def auth_processor(request): - """ - Returns context variables required by apps that use Django's authentication - system. - - If there is no 'user' attribute in the request, uses AnonymousUser (from - django.contrib.auth). - """ - if hasattr(request, 'user'): - user = request.user - if user.is_authenticated(): - messages = user.message_set.all() - else: - messages = None - else: - from django.contrib.auth.models import AnonymousUser - user = AnonymousUser() - messages = None - - from django.core.context_processors import PermWrapper - return { - 'user': user, - 'messages': messages, - 'perms': PermWrapper(user), - } diff --git a/cron/send_email_alerts b/cron/send_email_alerts deleted file mode 100644 index 6358b59..0000000 --- a/cron/send_email_alerts +++ /dev/null @@ -1,4 +0,0 @@ -PYTHONPATH=/path/to/dir/above/forum -export PYTHONPATH -APP_ROOT=$PYTHONPATH/nmr-forum2 -/path/to/python $APP_ROOT/manage.py send_email_alerts diff --git a/dos2unix.sh b/dos2unix.sh deleted file mode 100644 index 2864426..0000000 --- a/dos2unix.sh +++ /dev/null @@ -1,12 +0,0 @@ -#please take care not to dos2unix anything in your .git directory -#because that will probably break your repo -dos2unix `find . -name '*.py'` -dos2unix `find . -name '*.po'` -dos2unix `find . -name '*.js'` -dos2unix `find . -name '*.css'` -dos2unix `find . -name '*.txt'` -dos2unix `find ./sphinx -type f` -dos2unix `find ./cron -type f` -dos2unix settings_local.py.dist -dos2unix README -dos2unix INSTALL diff --git a/forum/__init__.py b/forum/__init__.py deleted file mode 100644 index 85cd5d2..0000000 --- a/forum/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['admin','auth','const','feed','forms','managers','models','sitemap','urls','views'] diff --git a/forum/admin.py b/forum/admin.py deleted file mode 100644 index 88643b9..0000000 --- a/forum/admin.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.contrib import admin -from models import * - - -class AnonymousQuestionAdmin(admin.ModelAdmin): - """AnonymousQuestion admin class""" - -class QuestionAdmin(admin.ModelAdmin): - """Question admin class""" - -class TagAdmin(admin.ModelAdmin): - """Tag admin class""" - -class Answerdmin(admin.ModelAdmin): - """Answer admin class""" - -class CommentAdmin(admin.ModelAdmin): - """ admin class""" - -class VoteAdmin(admin.ModelAdmin): - """ admin class""" - -class FlaggedItemAdmin(admin.ModelAdmin): - """ admin class""" - -class FavoriteQuestionAdmin(admin.ModelAdmin): - """ admin class""" - -class QuestionRevisionAdmin(admin.ModelAdmin): - """ admin class""" - -class AnswerRevisionAdmin(admin.ModelAdmin): - """ admin class""" - -class AwardAdmin(admin.ModelAdmin): - """ admin class""" - -class BadgeAdmin(admin.ModelAdmin): - """ admin class""" - -class ReputeAdmin(admin.ModelAdmin): - """ admin class""" - -class ActivityAdmin(admin.ModelAdmin): - """ admin class""" - -#class BookAdmin(admin.ModelAdmin): -# """ admin class""" - -#class BookAuthorInfoAdmin(admin.ModelAdmin): -# """ admin class""" - -#class BookAuthorRssAdmin(admin.ModelAdmin): -# """ admin class""" - - -admin.site.register(Question, QuestionAdmin) -admin.site.register(Tag, TagAdmin) -admin.site.register(Answer, Answerdmin) -admin.site.register(Comment, CommentAdmin) -admin.site.register(Vote, VoteAdmin) -admin.site.register(FlaggedItem, FlaggedItemAdmin) -admin.site.register(FavoriteQuestion, FavoriteQuestionAdmin) -admin.site.register(QuestionRevision, QuestionRevisionAdmin) -admin.site.register(AnswerRevision, AnswerRevisionAdmin) -admin.site.register(Badge, BadgeAdmin) -admin.site.register(Award, AwardAdmin) -admin.site.register(Repute, ReputeAdmin) -admin.site.register(Activity, ActivityAdmin) -#admin.site.register(Book, BookAdmin) -#admin.site.register(BookAuthorInfo, BookAuthorInfoAdmin) -#admin.site.register(BookAuthorRss, BookAuthorRssAdmin) diff --git a/forum/auth.py b/forum/auth.py deleted file mode 100644 index 3533b9c..0000000 --- a/forum/auth.py +++ /dev/null @@ -1,498 +0,0 @@ -""" -Authorisation related functions. - -The actions a User is authorised to perform are dependent on their reputation -and superuser status. -""" -import datetime -from django.contrib.contenttypes.models import ContentType -from django.utils.translation import ugettext as _ -from django.db import transaction -from models import Repute -from models import Question -from models import Answer -from const import TYPE_REPUTATION -import logging -question_type = ContentType.objects.get_for_model(Question) -answer_type = ContentType.objects.get_for_model(Answer) - -VOTE_UP = 15 -FLAG_OFFENSIVE = 15 -POST_IMAGES = 15 -LEAVE_COMMENTS = 50 -UPLOAD_FILES = 60 -VOTE_DOWN = 100 -CLOSE_OWN_QUESTIONS = 250 -RETAG_OTHER_QUESTIONS = 500 -REOPEN_OWN_QUESTIONS = 500 -EDIT_COMMUNITY_WIKI_POSTS = 750 -EDIT_OTHER_POSTS = 2000 -DELETE_COMMENTS = 2000 -VIEW_OFFENSIVE_FLAGS = 2000 -DISABLE_URL_NOFOLLOW = 2000 -CLOSE_OTHER_QUESTIONS = 3000 -LOCK_POSTS = 4000 - -VOTE_RULES = { - 'scope_votes_per_user_per_day' : 30, # how many votes of one user has everyday - 'scope_flags_per_user_per_day' : 5, # how many times user can flag posts everyday - 'scope_warn_votes_left' : 10, # start when to warn user how many votes left - 'scope_deny_unvote_days' : 1, # if 1 days passed, user can't cancel votes. - 'scope_flags_invisible_main_page' : 3, # post doesn't show on main page if has more than 3 offensive flags - 'scope_flags_delete_post' : 5, # post will be deleted if it has more than 5 offensive flags -} - -REPUTATION_RULES = { - 'initial_score' : 1, - 'scope_per_day_by_upvotes' : 200, - 'gain_by_upvoted' : 10, - 'gain_by_answer_accepted' : 15, - 'gain_by_accepting_answer' : 2, - 'gain_by_downvote_canceled' : 2, - 'gain_by_canceling_downvote' : 1, - 'lose_by_canceling_accepted_answer' : -2, - 'lose_by_accepted_answer_cancled' : -15, - 'lose_by_downvoted' : -2, - 'lose_by_flagged' : -2, - 'lose_by_downvoting' : -1, - 'lose_by_flagged_lastrevision_3_times': -30, - 'lose_by_flagged_lastrevision_5_times': -100, - 'lose_by_upvote_canceled' : -10, -} - -def can_moderate_users(user): - return user.is_superuser - -def can_vote_up(user): - """Determines if a User can vote Questions and Answers up.""" - return user.is_authenticated() and ( - user.reputation >= VOTE_UP or - user.is_superuser) - -def can_flag_offensive(user): - """Determines if a User can flag Questions and Answers as offensive.""" - return user.is_authenticated() and ( - user.reputation >= FLAG_OFFENSIVE or - user.is_superuser) - -def can_add_comments(user,subject): - """Determines if a User can add comments to Questions and Answers.""" - if user.is_authenticated(): - if user.id == subject.author.id: - return True - if user.reputation >= LEAVE_COMMENTS: - return True - if user.is_superuser: - return True - if isinstance(subject,Answer) and subject.question.author.id == user.id: - return True - return False - -def can_vote_down(user): - """Determines if a User can vote Questions and Answers down.""" - return user.is_authenticated() and ( - user.reputation >= VOTE_DOWN or - user.is_superuser) - -def can_retag_questions(user): - """Determines if a User can retag Questions.""" - return user.is_authenticated() and ( - RETAG_OTHER_QUESTIONS <= user.reputation < EDIT_OTHER_POSTS or - user.is_superuser) - -def can_edit_post(user, post): - """Determines if a User can edit the given Question or Answer.""" - return user.is_authenticated() and ( - user.id == post.author_id or - (post.wiki and user.reputation >= EDIT_COMMUNITY_WIKI_POSTS) or - user.reputation >= EDIT_OTHER_POSTS or - user.is_superuser) - -def can_delete_comment(user, comment): - """Determines if a User can delete the given Comment.""" - return user.is_authenticated() and ( - user.id == comment.user_id or - user.reputation >= DELETE_COMMENTS or - user.is_superuser) - -def can_view_offensive_flags(user): - """Determines if a User can view offensive flag counts.""" - return user.is_authenticated() and ( - user.reputation >= VIEW_OFFENSIVE_FLAGS or - user.is_superuser) - -def can_close_question(user, question): - """Determines if a User can close the given Question.""" - return user.is_authenticated() and ( - (user.id == question.author_id and - user.reputation >= CLOSE_OWN_QUESTIONS) or - user.reputation >= CLOSE_OTHER_QUESTIONS or - user.is_superuser) - -def can_lock_posts(user): - """Determines if a User can lock Questions or Answers.""" - return user.is_authenticated() and ( - user.reputation >= LOCK_POSTS or - user.is_superuser) - -def can_follow_url(user): - """Determines if the URL link can be followed by Google search engine.""" - return user.reputation >= DISABLE_URL_NOFOLLOW - -def can_accept_answer(user, question, answer): - return (user.is_authenticated() and - question.author != answer.author and - question.author == user) or user.is_superuser - -# now only support to reopen own question except superuser -def can_reopen_question(user, question): - return (user.is_authenticated() and - user.id == question.author_id and - user.reputation >= REOPEN_OWN_QUESTIONS) or user.is_superuser - -def can_delete_post(user, post): - if user.is_superuser: - return True - elif user.is_authenticated() and user == post.author: - if isinstance(post,Answer): - return True - elif isinstance(post,Question): - answers = post.answers.all() - for answer in answers: - if user != answer.author and answer.deleted == False: - return False - return True - else: - return False - else: - return False - -def can_view_deleted_post(user, post): - return user.is_superuser - -# user preferences view permissions -def is_user_self(request_user, target_user): - return (request_user.is_authenticated() and request_user == target_user) - -def can_view_user_votes(request_user, target_user): - return (request_user.is_authenticated() and request_user == target_user) - -def can_view_user_preferences(request_user, target_user): - return (request_user.is_authenticated() and request_user == target_user) - -def can_view_user_edit(request_user, target_user): - return (request_user.is_authenticated() and request_user == target_user) - -def can_upload_files(request_user): - return (request_user.is_authenticated() and request_user.reputation >= UPLOAD_FILES) or \ - request_user.is_superuser - -########################################### -## actions and reputation changes event -########################################### -def calculate_reputation(origin, offset): - result = int(origin) + int(offset) - if (result > 0): - return result - else: - return 1 - -@transaction.commit_on_success -def onFlaggedItem(item, post, user): - - item.save() - post.offensive_flag_count = post.offensive_flag_count + 1 - post.save() - - post.author.reputation = calculate_reputation(post.author.reputation, - int(REPUTATION_RULES['lose_by_flagged'])) - post.author.save() - - question = post - if ContentType.objects.get_for_model(post) == answer_type: - question = post.question - - reputation = Repute(user=post.author, - negative=int(REPUTATION_RULES['lose_by_flagged']), - question=question, reputed_at=datetime.datetime.now(), - reputation_type=-4, - reputation=post.author.reputation) - reputation.save() - - #todo: These should be updated to work on same revisions. - if post.offensive_flag_count == VOTE_RULES['scope_flags_invisible_main_page'] : - post.author.reputation = calculate_reputation(post.author.reputation, - int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times'])) - post.author.save() - - reputation = Repute(user=post.author, - negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=-6, - reputation=post.author.reputation) - reputation.save() - - elif post.offensive_flag_count == VOTE_RULES['scope_flags_delete_post']: - post.author.reputation = calculate_reputation(post.author.reputation, - int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times'])) - post.author.save() - - reputation = Repute(user=post.author, - negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=-7, - reputation=post.author.reputation) - reputation.save() - - post.deleted = True - #post.deleted_at = datetime.datetime.now() - #post.deleted_by = Admin - post.save() - - -@transaction.commit_on_success -def onAnswerAccept(answer, user): - answer.accepted = True - answer.accepted_at = datetime.datetime.now() - answer.question.answer_accepted = True - answer.save() - answer.question.save() - - answer.author.reputation = calculate_reputation(answer.author.reputation, - int(REPUTATION_RULES['gain_by_answer_accepted'])) - answer.author.save() - reputation = Repute(user=answer.author, - positive=int(REPUTATION_RULES['gain_by_answer_accepted']), - question=answer.question, - reputed_at=datetime.datetime.now(), - reputation_type=2, - reputation=answer.author.reputation) - reputation.save() - - user.reputation = calculate_reputation(user.reputation, - int(REPUTATION_RULES['gain_by_accepting_answer'])) - user.save() - reputation = Repute(user=user, - positive=int(REPUTATION_RULES['gain_by_accepting_answer']), - question=answer.question, - reputed_at=datetime.datetime.now(), - reputation_type=3, - reputation=user.reputation) - reputation.save() - -@transaction.commit_on_success -def onAnswerAcceptCanceled(answer, user): - answer.accepted = False - answer.accepted_at = None - answer.question.answer_accepted = False - answer.save() - answer.question.save() - - answer.author.reputation = calculate_reputation(answer.author.reputation, - int(REPUTATION_RULES['lose_by_accepted_answer_cancled'])) - answer.author.save() - reputation = Repute(user=answer.author, - negative=int(REPUTATION_RULES['lose_by_accepted_answer_cancled']), - question=answer.question, - reputed_at=datetime.datetime.now(), - reputation_type=-2, - reputation=answer.author.reputation) - reputation.save() - - user.reputation = calculate_reputation(user.reputation, - int(REPUTATION_RULES['lose_by_canceling_accepted_answer'])) - user.save() - reputation = Repute(user=user, - negative=int(REPUTATION_RULES['lose_by_canceling_accepted_answer']), - question=answer.question, - reputed_at=datetime.datetime.now(), - reputation_type=-1, - reputation=user.reputation) - reputation.save() - -@transaction.commit_on_success -def onUpVoted(vote, post, user): - vote.save() - - post.vote_up_count = int(post.vote_up_count) + 1 - post.score = int(post.score) + 1 - post.save() - - if not post.wiki: - author = post.author - if Repute.objects.get_reputation_by_upvoted_today(author) < int(REPUTATION_RULES['scope_per_day_by_upvotes']): - author.reputation = calculate_reputation(author.reputation, - int(REPUTATION_RULES['gain_by_upvoted'])) - author.save() - - question = post - if ContentType.objects.get_for_model(post) == answer_type: - question = post.question - - reputation = Repute(user=author, - positive=int(REPUTATION_RULES['gain_by_upvoted']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=1, - reputation=author.reputation) - reputation.save() - -@transaction.commit_on_success -def onUpVotedCanceled(vote, post, user): - vote.delete() - - post.vote_up_count = int(post.vote_up_count) - 1 - if post.vote_up_count < 0: - post.vote_up_count = 0 - post.score = int(post.score) - 1 - post.save() - - if not post.wiki: - author = post.author - author.reputation = calculate_reputation(author.reputation, - int(REPUTATION_RULES['lose_by_upvote_canceled'])) - author.save() - - question = post - if ContentType.objects.get_for_model(post) == answer_type: - question = post.question - - reputation = Repute(user=author, - negative=int(REPUTATION_RULES['lose_by_upvote_canceled']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=-8, - reputation=author.reputation) - reputation.save() - -@transaction.commit_on_success -def onDownVoted(vote, post, user): - vote.save() - - post.vote_down_count = int(post.vote_down_count) + 1 - post.score = int(post.score) - 1 - post.save() - - if not post.wiki: - author = post.author - author.reputation = calculate_reputation(author.reputation, - int(REPUTATION_RULES['lose_by_downvoted'])) - author.save() - - question = post - if ContentType.objects.get_for_model(post) == answer_type: - question = post.question - - reputation = Repute(user=author, - negative=int(REPUTATION_RULES['lose_by_downvoted']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=-3, - reputation=author.reputation) - reputation.save() - - user.reputation = calculate_reputation(user.reputation, - int(REPUTATION_RULES['lose_by_downvoting'])) - user.save() - - reputation = Repute(user=user, - negative=int(REPUTATION_RULES['lose_by_downvoting']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=-5, - reputation=user.reputation) - reputation.save() - -@transaction.commit_on_success -def onDownVotedCanceled(vote, post, user): - vote.delete() - - post.vote_down_count = int(post.vote_down_count) - 1 - if post.vote_down_count < 0: - post.vote_down_count = 0 - post.score = post.score + 1 - post.save() - - if not post.wiki: - author = post.author - author.reputation = calculate_reputation(author.reputation, - int(REPUTATION_RULES['gain_by_downvote_canceled'])) - author.save() - - question = post - if ContentType.objects.get_for_model(post) == answer_type: - question = post.question - - reputation = Repute(user=author, - positive=int(REPUTATION_RULES['gain_by_downvote_canceled']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=4, - reputation=author.reputation) - reputation.save() - - user.reputation = calculate_reputation(user.reputation, - int(REPUTATION_RULES['gain_by_canceling_downvote'])) - user.save() - - reputation = Repute(user=user, - positive=int(REPUTATION_RULES['gain_by_canceling_downvote']), - question=question, - reputed_at=datetime.datetime.now(), - reputation_type=5, - reputation=user.reputation) - reputation.save() - -def onDeleteCanceled(post, user): - post.deleted = False - post.deleted_by = None - post.deleted_at = None - post.save() - logging.debug('now restoring something') - if isinstance(post,Answer): - logging.debug('updated answer count on undelete, have %d' % post.question.answer_count) - Question.objects.update_answer_count(post.question) - elif isinstance(post,Question): - for tag in list(post.tags.all()): - if tag.used_count == 1 and tag.deleted: - tag.deleted = False - tag.deleted_by = None - tag.deleted_at = None - tag.save() - -def onDeleted(post, user): - post.deleted = True - post.deleted_by = user - post.deleted_at = datetime.datetime.now() - post.save() - - if isinstance(post, Question): - for tag in list(post.tags.all()): - if tag.used_count == 1: - tag.deleted = True - tag.deleted_by = user - tag.deleted_at = datetime.datetime.now() - else: - tag.used_count = tag.used_count - 1 - tag.save() - - answers = post.answers.all() - if user == post.author: - if len(answers) > 0: - msg = _('Your question and all of it\'s answers have been deleted') - else: - msg = _('Your question has been deleted') - else: - if len(answers) > 0: - msg = _('The question and all of it\'s answers have been deleted') - else: - msg = _('The question has been deleted') - user.message_set.create(message=msg) - logging.debug('posted a message %s' % msg) - for answer in answers: - onDeleted(answer, user) - elif isinstance(post, Answer): - Question.objects.update_answer_count(post.question) - logging.debug('updated answer count to %d' % post.question.answer_count) diff --git a/forum/authentication/__init__.py b/forum/authentication/__init__.py deleted file mode 100755 index e83ba87..0000000 --- a/forum/authentication/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -import re -from forum.modules import get_modules_script_classes -from forum.authentication.base import AuthenticationConsumer, ConsumerTemplateContext - -class ConsumerAndContext(): - def __init__(self, id, consumer, context): - self.id = id - self.consumer = consumer() - - context.id = id - self.context = context - -consumers = dict([ - (re.sub('AuthConsumer$', '', name).lower(), cls) for name, cls - in get_modules_script_classes('authentication', AuthenticationConsumer).items() - if not re.search('AbstractAuthConsumer$', name) - ]) - -contexts = dict([ - (re.sub('AuthContext$', '', name).lower(), cls) for name, cls - in get_modules_script_classes('authentication', ConsumerTemplateContext).items() - ]) - -AUTH_PROVIDERS = dict([ - (name, ConsumerAndContext(name, consumers[name], contexts[name])) for name in consumers.keys() - if name in contexts - ]) \ No newline at end of file diff --git a/forum/authentication/base.py b/forum/authentication/base.py deleted file mode 100755 index 995f7c9..0000000 --- a/forum/authentication/base.py +++ /dev/null @@ -1,40 +0,0 @@ - -class AuthenticationConsumer(object): - - def prepare_authentication_request(self, request, redirect_to): - raise NotImplementedError() - - def process_authentication_request(self, response): - raise NotImplementedError() - - def get_user_data(self, key): - raise NotImplementedError() - - -class ConsumerTemplateContext(object): - """ - Class that provides information about a certain authentication provider context in the signin page. - - class attributes: - - mode - one of BIGICON, SMALLICON, FORM - - human_name - the human readable name of the provider - - extra_js - some providers require us to load extra javascript on the signin page for them to work, - this is the place to add those files in the form of a list - - extra_css - same as extra_js but for css files - """ - mode = '' - weight = 500 - human_name = '' - extra_js = [] - extra_css = [] - show_to_logged_in_user = True - -class InvalidAuthentication(Exception): - def __init__(self, message): - self.message = message - - \ No newline at end of file diff --git a/forum/authentication/forms.py b/forum/authentication/forms.py deleted file mode 100755 index 0484134..0000000 --- a/forum/authentication/forms.py +++ /dev/null @@ -1,31 +0,0 @@ -from forum.utils.forms import NextUrlField, UserNameField, UserEmailField -from forum.models import EmailFeedSetting, Question -from django.contrib.contenttypes.models import ContentType -from django.utils.translation import ugettext as _ -from django import forms -from forum.forms import EditUserEmailFeedsForm -import logging - -class SimpleRegistrationForm(forms.Form): - next = NextUrlField() - username = UserNameField() - email = UserEmailField() - - -class SimpleEmailSubscribeForm(forms.Form): - SIMPLE_SUBSCRIBE_CHOICES = ( - ('y',_('okay, let\'s try!')), - ('n',_('no OSQA community email please, thanks')) - ) - subscribe = forms.ChoiceField(widget=forms.widgets.RadioSelect(), \ - error_messages={'required':_('please choose one of the options above')}, - choices=SIMPLE_SUBSCRIBE_CHOICES) - - def save(self,user=None): - EFF = EditUserEmailFeedsForm - if self.cleaned_data['subscribe'] == 'y': - email_settings_form = EFF() - logging.debug('%s wants to subscribe' % user.username) - else: - email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL) - email_settings_form.save(user,save_unbound=True) diff --git a/forum/const.py b/forum/const.py deleted file mode 100644 index 76fd4a2..0000000 --- a/forum/const.py +++ /dev/null @@ -1,92 +0,0 @@ -# encoding:utf-8 -from django.utils.translation import ugettext as _ -""" -All constants could be used in other modules -For reasons that models, views can't have unicode text in this project, all unicode text go here. -""" -CLOSE_REASONS = ( - (1, _('duplicate question')), - (2, _('question is off-topic or not relevant')), - (3, _('too subjective and argumentative')), - (4, _('is not an answer to the question')), - (5, _('the question is answered, right answer was accepted')), - (6, _('problem is not reproducible or outdated')), - #(7, u'太局部、本地化的问题',) - (7, _('question contains offensive inappropriate, or malicious remarks')), - (8, _('spam or advertising')), -) - -TYPE_REPUTATION = ( - (1, 'gain_by_upvoted'), - (2, 'gain_by_answer_accepted'), - (3, 'gain_by_accepting_answer'), - (4, 'gain_by_downvote_canceled'), - (5, 'gain_by_canceling_downvote'), - (-1, 'lose_by_canceling_accepted_answer'), - (-2, 'lose_by_accepted_answer_cancled'), - (-3, 'lose_by_downvoted'), - (-4, 'lose_by_flagged'), - (-5, 'lose_by_downvoting'), - (-6, 'lose_by_flagged_lastrevision_3_times'), - (-7, 'lose_by_flagged_lastrevision_5_times'), - (-8, 'lose_by_upvote_canceled'), -) - -TYPE_ACTIVITY_ASK_QUESTION=1 -TYPE_ACTIVITY_ANSWER=2 -TYPE_ACTIVITY_COMMENT_QUESTION=3 -TYPE_ACTIVITY_COMMENT_ANSWER=4 -TYPE_ACTIVITY_UPDATE_QUESTION=5 -TYPE_ACTIVITY_UPDATE_ANSWER=6 -TYPE_ACTIVITY_PRIZE=7 -TYPE_ACTIVITY_MARK_ANSWER=8 -TYPE_ACTIVITY_VOTE_UP=9 -TYPE_ACTIVITY_VOTE_DOWN=10 -TYPE_ACTIVITY_CANCEL_VOTE=11 -TYPE_ACTIVITY_DELETE_QUESTION=12 -TYPE_ACTIVITY_DELETE_ANSWER=13 -TYPE_ACTIVITY_MARK_OFFENSIVE=14 -TYPE_ACTIVITY_UPDATE_TAGS=15 -TYPE_ACTIVITY_FAVORITE=16 -TYPE_ACTIVITY_USER_FULL_UPDATED = 17 -TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT = 18 -#TYPE_ACTIVITY_EDIT_QUESTION=17 -#TYPE_ACTIVITY_EDIT_ANSWER=18 - -TYPE_ACTIVITY = ( - (TYPE_ACTIVITY_ASK_QUESTION, _('question')), - (TYPE_ACTIVITY_ANSWER, _('answer')), - (TYPE_ACTIVITY_COMMENT_QUESTION, _('commented question')), - (TYPE_ACTIVITY_COMMENT_ANSWER, _('commented answer')), - (TYPE_ACTIVITY_UPDATE_QUESTION, _('edited question')), - (TYPE_ACTIVITY_UPDATE_ANSWER, _('edited answer')), - (TYPE_ACTIVITY_PRIZE, _('received award')), - (TYPE_ACTIVITY_MARK_ANSWER, _('marked best answer')), - (TYPE_ACTIVITY_VOTE_UP, _('upvoted')), - (TYPE_ACTIVITY_VOTE_DOWN, _('downvoted')), - (TYPE_ACTIVITY_CANCEL_VOTE, _('canceled vote')), - (TYPE_ACTIVITY_DELETE_QUESTION, _('deleted question')), - (TYPE_ACTIVITY_DELETE_ANSWER, _('deleted answer')), - (TYPE_ACTIVITY_MARK_OFFENSIVE, _('marked offensive')), - (TYPE_ACTIVITY_UPDATE_TAGS, _('updated tags')), - (TYPE_ACTIVITY_FAVORITE, _('selected favorite')), - (TYPE_ACTIVITY_USER_FULL_UPDATED, _('completed user profile')), - (TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT, _('email update sent to user')), -) - -TYPE_RESPONSE = { - 'QUESTION_ANSWERED' : 'question_answered', - 'QUESTION_COMMENTED': 'question_commented', - 'ANSWER_COMMENTED' : 'answer_commented', - 'ANSWER_ACCEPTED' : 'answer_accepted', -} - -CONST = { - 'closed' : _('[closed]'), - 'deleted' : _('[deleted]'), - 'default_version' : _('initial version'), - 'retagged' : _('retagged'), -} - -#how to filter questions by tags in email digests? -TAG_EMAIL_FILTER_CHOICES = (('ignored', _('exclude ignored tags')),('interesting',_('allow only selected tags'))) diff --git a/forum/feed.py b/forum/feed.py deleted file mode 100644 index e4b929e..0000000 --- a/forum/feed.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -#encoding:utf-8 -#------------------------------------------------------------------------------- -# Name: Syndication feed class for subsribtion -# Purpose: -# -# Author: Mike -# -# Created: 29/01/2009 -# Copyright: (c) CNPROG.COM 2009 -# Licence: GPL V2 -#------------------------------------------------------------------------------- -from django.contrib.syndication.feeds import Feed, FeedDoesNotExist -from django.utils.translation import ugettext as _ -from models import Question -from django.conf import settings -class RssLastestQuestionsFeed(Feed): - title = settings.APP_TITLE + _(' - ')+ _('latest questions') - link = settings.APP_URL #+ '/' + _('question/') - description = settings.APP_DESCRIPTION - #ttl = 10 - copyright = settings.APP_COPYRIGHT - - def item_link(self, item): - return self.link + item.get_absolute_url() - - def item_author_name(self, item): - return item.author.username - - def item_author_link(self, item): - return item.author.get_profile_url() - - def item_pubdate(self, item): - return item.added_at - - def items(self, item): - return Question.objects.filter(deleted=False).order_by('-last_activity_at')[:30] - -def main(): - pass - -if __name__ == '__main__': - main() diff --git a/forum/forms.py b/forum/forms.py deleted file mode 100644 index c157aa4..0000000 --- a/forum/forms.py +++ /dev/null @@ -1,359 +0,0 @@ -import re -from datetime import date -from django import forms -from models import * -from const import * -from django.utils.translation import ugettext as _ -from django.contrib.auth.models import User -from django.contrib.contenttypes.models import ContentType -from django.utils.safestring import mark_safe -from forum.utils.forms import NextUrlField, UserNameField, SetPasswordForm -from recaptcha_django import ReCaptchaField -from django.conf import settings -import logging - -class TitleField(forms.CharField): - def __init__(self, *args, **kwargs): - super(TitleField, self).__init__(*args, **kwargs) - self.required = True - self.widget = forms.TextInput(attrs={'size' : 70, 'autocomplete' : 'off'}) - self.max_length = 255 - self.label = _('title') - self.help_text = _('please enter a descriptive title for your question') - self.initial = '' - - def clean(self, value): - if len(value) < 10: - raise forms.ValidationError(_('title must be > 10 characters')) - - return value - -class EditorField(forms.CharField): - def __init__(self, *args, **kwargs): - super(EditorField, self).__init__(*args, **kwargs) - self.required = True - self.widget = forms.Textarea(attrs={'id':'editor'}) - self.label = _('content') - self.help_text = u'' - self.initial = '' - - def clean(self, value): - if len(value) < 10: - raise forms.ValidationError(_('question content must be > 10 characters')) - - return value - -class TagNamesField(forms.CharField): - def __init__(self, *args, **kwargs): - super(TagNamesField, self).__init__(*args, **kwargs) - self.required = True - self.widget = forms.TextInput(attrs={'size' : 50, 'autocomplete' : 'off'}) - self.max_length = 255 - self.label = _('tags') - #self.help_text = _('please use space to separate tags (this enables autocomplete feature)') - self.help_text = _('Tags are short keywords, with no spaces within. Up to five tags can be used.') - self.initial = '' - - def clean(self, value): - value = super(TagNamesField, self).clean(value) - data = value.strip() - if len(data) < 1: - raise forms.ValidationError(_('tags are required')) - - split_re = re.compile(r'[ ,]+') - list = split_re.split(data) - list_temp = [] - if len(list) > 5: - raise forms.ValidationError(_('please use 5 tags or less')) - for tag in list: - if len(tag) > 20: - raise forms.ValidationError(_('tags must be shorter than 20 characters')) - #take tag regex from settings - tagname_re = re.compile(r'[a-z0-9]+') - if not tagname_re.match(tag): - raise forms.ValidationError(_('please use following characters in tags: letters \'a-z\', numbers, and characters \'.-_#\'')) - # only keep one same tag - if tag not in list_temp and len(tag.strip()) > 0: - list_temp.append(tag) - return u' '.join(list_temp) - -class WikiField(forms.BooleanField): - def __init__(self, *args, **kwargs): - super(WikiField, self).__init__(*args, **kwargs) - self.required = False - self.label = _('community wiki') - self.help_text = _('if you choose community wiki option, the question and answer do not generate points and name of author will not be shown') - def clean(self,value): - return value and settings.WIKI_ON - -class EmailNotifyField(forms.BooleanField): - def __init__(self, *args, **kwargs): - super(EmailNotifyField, self).__init__(*args, **kwargs) - self.required = False - self.widget.attrs['class'] = 'nomargin' - -class SummaryField(forms.CharField): - def __init__(self, *args, **kwargs): - super(SummaryField, self).__init__(*args, **kwargs) - self.required = False - self.widget = forms.TextInput(attrs={'size' : 50, 'autocomplete' : 'off'}) - self.max_length = 300 - self.label = _('update summary:') - self.help_text = _('enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)') - -class ModerateUserForm(forms.ModelForm): - is_approved = forms.BooleanField(label=_("Automatically accept user's contributions for the email updates"), - required=False) - - def clean_is_approved(self): - if 'is_approved' not in self.cleaned_data: - self.cleaned_data['is_approved'] = False - return self.cleaned_data['is_approved'] - - class Meta: - model = User - fields = ('is_approved',) - -class NotARobotForm(forms.Form): - recaptcha = ReCaptchaField() - -class FeedbackForm(forms.Form): - name = forms.CharField(label=_('Your name:'), required=False) - email = forms.EmailField(label=_('Email (not shared with anyone):'), required=False) - message = forms.CharField(label=_('Your message:'), max_length=800,widget=forms.Textarea(attrs={'cols':60})) - next = NextUrlField() - -class AskForm(forms.Form): - title = TitleField() - text = EditorField() - tags = TagNamesField() - wiki = WikiField() - - openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'})) - user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - -class AnswerForm(forms.Form): - text = EditorField() - wiki = WikiField() - openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'})) - user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - email_notify = EmailNotifyField() - def __init__(self, question, user, *args, **kwargs): - super(AnswerForm, self).__init__(*args, **kwargs) - self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates'; - if question.wiki and settings.WIKI_ON: - self.fields['wiki'].initial = True - if user.is_authenticated(): - if user in question.followed_by.all(): - self.fields['email_notify'].initial = True - return - self.fields['email_notify'].initial = False - - -class CloseForm(forms.Form): - reason = forms.ChoiceField(choices=CLOSE_REASONS) - -class RetagQuestionForm(forms.Form): - tags = TagNamesField() - # initialize the default values - def __init__(self, question, *args, **kwargs): - super(RetagQuestionForm, self).__init__(*args, **kwargs) - self.fields['tags'].initial = question.tagnames - -class RevisionForm(forms.Form): - """ - Lists revisions of a Question or Answer - """ - revision = forms.ChoiceField(widget=forms.Select(attrs={'style' : 'width:520px'})) - - def __init__(self, post, latest_revision, *args, **kwargs): - super(RevisionForm, self).__init__(*args, **kwargs) - revisions = post.revisions.all().values_list( - 'revision', 'author__username', 'revised_at', 'summary') - date_format = '%c' - self.fields['revision'].choices = [ - (r[0], u'%s - %s (%s) %s' % (r[0], r[1], r[2].strftime(date_format), r[3])) - for r in revisions] - self.fields['revision'].initial = latest_revision.revision - -class EditQuestionForm(forms.Form): - title = TitleField() - text = EditorField() - tags = TagNamesField() - summary = SummaryField() - - def __init__(self, question, revision, *args, **kwargs): - super(EditQuestionForm, self).__init__(*args, **kwargs) - self.fields['title'].initial = revision.title - self.fields['text'].initial = revision.text - self.fields['tags'].initial = revision.tagnames - # Once wiki mode is enabled, it can't be disabled - if not question.wiki: - self.fields['wiki'] = WikiField() - -class EditAnswerForm(forms.Form): - text = EditorField() - summary = SummaryField() - - def __init__(self, answer, revision, *args, **kwargs): - super(EditAnswerForm, self).__init__(*args, **kwargs) - self.fields['text'].initial = revision.text - -class EditUserForm(forms.Form): - email = forms.EmailField(label=u'Email', help_text=_('this email does not have to be linked to gravatar'), required=True, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - if settings.EDITABLE_SCREEN_NAME: - username = UserNameField(label=_('Screen name')) - realname = forms.CharField(label=_('Real name'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - website = forms.URLField(label=_('Website'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - city = forms.CharField(label=_('Location'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) - birthday = forms.DateField(label=_('Date of birth'), help_text=_('will not be shown, used to calculate age, format: YYYY-MM-DD'), required=False, widget=forms.TextInput(attrs={'size' : 35})) - about = forms.CharField(label=_('Profile'), required=False, widget=forms.Textarea(attrs={'cols' : 60})) - - def __init__(self, user, *args, **kwargs): - super(EditUserForm, self).__init__(*args, **kwargs) - logging.debug('initializing the form') - if settings.EDITABLE_SCREEN_NAME: - self.fields['username'].initial = user.username - self.fields['username'].user_instance = user - self.fields['email'].initial = user.email - self.fields['realname'].initial = user.real_name - self.fields['website'].initial = user.website - self.fields['city'].initial = user.location - - if user.date_of_birth is not None: - self.fields['birthday'].initial = user.date_of_birth - else: - self.fields['birthday'].initial = '1990-01-01' - self.fields['about'].initial = user.about - self.user = user - - def clean_email(self): - """For security reason one unique email in database""" - if self.user.email != self.cleaned_data['email']: - #todo dry it, there is a similar thing in openidauth - if settings.EMAIL_UNIQUE == True: - if 'email' in self.cleaned_data: - try: - user = User.objects.get(email = self.cleaned_data['email']) - except User.DoesNotExist: - return self.cleaned_data['email'] - except User.MultipleObjectsReturned: - raise forms.ValidationError(_('this email has already been registered, please use another one')) - raise forms.ValidationError(_('this email has already been registered, please use another one')) - return self.cleaned_data['email'] - -class TagFilterSelectionForm(forms.ModelForm): - tag_filter_setting = forms.ChoiceField(choices=TAG_EMAIL_FILTER_CHOICES, #imported from forum/const.py - initial='ignored', - label=_('Choose email tag filter'), - widget=forms.RadioSelect) - class Meta: - model = User - fields = ('tag_filter_setting',) - - def save(self): - before = self.instance.tag_filter_setting - super(TagFilterSelectionForm, self).save() - after = self.instance.tag_filter_setting #User.objects.get(pk=self.instance.id).tag_filter_setting - if before != after: - return True - return False - - -class ChangePasswordForm(SetPasswordForm): - """ change password form """ - oldpw = forms.CharField(widget=forms.PasswordInput(attrs={'class':'required'}), - label=mark_safe(_('Current password'))) - - def __init__(self, data=None, user=None, *args, **kwargs): - if user is None: - raise TypeError("Keyword argument 'user' must be supplied") - super(ChangePasswordForm, self).__init__(data, *args, **kwargs) - self.user = user - - def clean_oldpw(self): - """ test old password """ - if not self.user.check_password(self.cleaned_data['oldpw']): - raise forms.ValidationError(_("Old password is incorrect. \ - Please enter the correct password.")) - return self.cleaned_data['oldpw'] - -class EditUserEmailFeedsForm(forms.Form): - WN = (('w',_('weekly')),('n',_('no email'))) - DWN = (('d',_('daily')),('w',_('weekly')),('n',_('no email'))) - FORM_TO_MODEL_MAP = { - 'all_questions':'q_all', - 'asked_by_me':'q_ask', - 'answered_by_me':'q_ans', - 'individually_selected':'q_sel', - } - NO_EMAIL_INITIAL = { - 'all_questions':'n', - 'asked_by_me':'n', - 'answered_by_me':'n', - 'individually_selected':'n', - } - asked_by_me = forms.ChoiceField(choices=DWN,initial='w', - widget=forms.RadioSelect, - label=_('Asked by me')) - answered_by_me = forms.ChoiceField(choices=DWN,initial='w', - widget=forms.RadioSelect, - label=_('Answered by me')) - individually_selected = forms.ChoiceField(choices=DWN,initial='w', - widget=forms.RadioSelect, - label=_('Individually selected')) - all_questions = forms.ChoiceField(choices=DWN,initial='w', - widget=forms.RadioSelect, - label=_('Entire forum (tag filtered)'),) - - def set_initial_values(self,user=None): - KEY_MAP = dict([(v,k) for k,v in self.FORM_TO_MODEL_MAP.iteritems()]) - if user != None: - settings = EmailFeedSetting.objects.filter(subscriber=user) - initial_values = {} - for setting in settings: - feed_type = setting.feed_type - form_field = KEY_MAP[feed_type] - frequency = setting.frequency - initial_values[form_field] = frequency - self.initial = initial_values - return self - - def reset(self): - self.cleaned_data['all_questions'] = 'n' - self.cleaned_data['asked_by_me'] = 'n' - self.cleaned_data['answered_by_me'] = 'n' - self.cleaned_data['individually_selected'] = 'n' - self.initial = self.NO_EMAIL_INITIAL - return self - - def save(self,user,save_unbound=False): - """ - with save_unbound==True will bypass form validation and save initial values - """ - changed = False - for form_field, feed_type in self.FORM_TO_MODEL_MAP.items(): - s, created = EmailFeedSetting.objects.get_or_create(subscriber=user,\ - feed_type=feed_type) - if save_unbound: - #just save initial values instead - if form_field in self.initial: - new_value = self.initial[form_field] - else: - new_value = self.fields[form_field].initial - else: - new_value = self.cleaned_data[form_field] - if s.frequency != new_value: - s.frequency = new_value - s.save() - changed = True - else: - if created: - s.save() - if form_field == 'individually_selected': - feed_type = ContentType.objects.get_for_model(Question) - user.followed_questions.clear() - return changed - diff --git a/forum/management/__init__.py b/forum/management/__init__.py deleted file mode 100644 index 8266592..0000000 --- a/forum/management/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from forum.modules import get_modules_script - -get_modules_script('management') \ No newline at end of file diff --git a/forum/management/commands/__init__.py b/forum/management/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/forum/management/commands/base_command.py b/forum/management/commands/base_command.py deleted file mode 100644 index c073bf7..0000000 --- a/forum/management/commands/base_command.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -#encoding:utf-8 -#------------------------------------------------------------------------------- -# Name: Award badges command -# Purpose: This is a command file croning in background process regularly to -# query database and award badges for user's special acitivities. -# -# Author: Mike, Sailing -# -# Created: 22/01/2009 -# Copyright: (c) Mike 2009 -# Licence: GPL V2 -#------------------------------------------------------------------------------- - -from datetime import datetime, date -from django.core.management.base import NoArgsCommand -from django.db import connection -from django.shortcuts import get_object_or_404 -from django.contrib.contenttypes.models import ContentType - -from forum.models import * -from forum.const import * - -class BaseCommand(NoArgsCommand): - def update_activities_auditted(self, cursor, activity_ids): - # update processed rows to auditted - if len(activity_ids): - query = "UPDATE activity SET is_auditted = 1 WHERE id in (%s)"\ - % ','.join('%s' % item for item in activity_ids) - cursor.execute(query) - - - - - diff --git a/forum/management/commands/clean_award_badges.py b/forum/management/commands/clean_award_badges.py deleted file mode 100644 index 117e3a5..0000000 --- a/forum/management/commands/clean_award_badges.py +++ /dev/null @@ -1,59 +0,0 @@ -#------------------------------------------------------------------------------- -# Name: Award badges command -# Purpose: This is a command file croning in background process regularly to -# query database and award badges for user's special acitivities. -# -# Author: Mike -# -# Created: 18/01/2009 -# Copyright: (c) Mike 2009 -# Licence: GPL V2 -#------------------------------------------------------------------------------- -#!/usr/bin/env python -#encoding:utf-8 -from django.core.management.base import NoArgsCommand -from django.db import connection -from django.shortcuts import get_object_or_404 -from django.contrib.contenttypes.models import ContentType - -from forum.models import * - -class Command(NoArgsCommand): - def handle_noargs(self, **options): - try: - try: - self.clean_awards() - except Exception, e: - print e - finally: - connection.close() - - def clean_awards(self): - Award.objects.all().delete() - - award_type =ContentType.objects.get_for_model(Award) - Activity.objects.filter(content_type=award_type).delete() - - for user in User.objects.all(): - user.gold = 0 - user.silver = 0 - user.bronze = 0 - user.save() - - for badge in Badge.objects.all(): - badge.awarded_count = 0 - badge.save() - - query = "UPDATE activity SET is_auditted = 0" - cursor = connection.cursor() - try: - cursor.execute(query) - finally: - cursor.close() - connection.close() - -def main(): - pass - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/forum/management/commands/message_to_everyone.py b/forum/management/commands/message_to_everyone.py deleted file mode 100644 index c020c17..0000000 --- a/forum/management/commands/message_to_everyone.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.core.management.base import NoArgsCommand -from django.contrib.auth.models import User -import sys - -class Command(NoArgsCommand): - def handle_noargs(self, **options): - msg = None - if msg == None: - print 'to run this command, please first edit the file %s' % __file__ - sys.exit(1) - for u in User.objects.all(): - u.message_set.create(message = msg % u.username) diff --git a/forum/management/commands/multi_award_badges.py b/forum/management/commands/multi_award_badges.py deleted file mode 100644 index 6b330cf..0000000 --- a/forum/management/commands/multi_award_badges.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/env python -#encoding:utf-8 -#------------------------------------------------------------------------------- -# Name: Award badges command -# Purpose: This is a command file croning in background process regularly to -# query database and award badges for user's special acitivities. -# -# Author: Mike, Sailing -# -# Created: 22/01/2009 -# Copyright: (c) Mike 2009 -# Licence: GPL V2 -#------------------------------------------------------------------------------- - -from datetime import datetime, date -from django.core.management.base import NoArgsCommand -from django.db import connection -from django.shortcuts import get_object_or_404 -from django.contrib.contenttypes.models import ContentType - -from forum.models import * -from forum.const import * -from base_command import BaseCommand -""" -(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0), -(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0), -(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0), -(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0), -(5, '评论家', 3, '评论家', '评论10次以上', 0, 0), -(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0), -(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 0, 0), -(8, '清洁工', 3, '清洁工', '第一次撤销投票', 0, 0), -(9, '批评家', 3, '批评家', '第一次反对票', 0, 0), -(10, '小编', 3, '小编', '第一次编辑更新', 0, 0), -(11, '村长', 3, '村长', '第一次重新标签', 0, 0), -(12, '学者', 3, '学者', '第一次标记答案', 0, 0), -(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0), -(14, '支持者', 3, '支持者', '第一次赞成票', 0, 0), -(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0), -(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 0, 0), -(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0), -(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0), -(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0), -(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0), -(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0), -(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 0, 0), -(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0), -(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0), -(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0), -(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0), -(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0), -(28, '通才', 2, '通才', '在多个标签领域活跃', 0, 0), -(29, '专家', 2, '专家', '在一个标签领域活跃出众', 0, 0), -(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 0, 0), -(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0), -(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0), -(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 0, 0), -(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0), -(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0), -(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0); - - -TYPE_ACTIVITY_ASK_QUESTION=1 -TYPE_ACTIVITY_ANSWER=2 -TYPE_ACTIVITY_COMMENT_QUESTION=3 -TYPE_ACTIVITY_COMMENT_ANSWER=4 -TYPE_ACTIVITY_UPDATE_QUESTION=5 -TYPE_ACTIVITY_UPDATE_ANSWER=6 -TYPE_ACTIVITY_PRIZE=7 -TYPE_ACTIVITY_MARK_ANSWER=8 -TYPE_ACTIVITY_VOTE_UP=9 -TYPE_ACTIVITY_VOTE_DOWN=10 -TYPE_ACTIVITY_CANCEL_VOTE=11 -TYPE_ACTIVITY_DELETE_QUESTION=12 -TYPE_ACTIVITY_DELETE_ANSWER=13 -TYPE_ACTIVITY_MARK_OFFENSIVE=14 -TYPE_ACTIVITY_UPDATE_TAGS=15 -TYPE_ACTIVITY_FAVORITE=16 -TYPE_ACTIVITY_USER_FULL_UPDATED = 17 -""" - -class Command(BaseCommand): - def handle_noargs(self, **options): - try: - try: - self.delete_question_be_voted_up_3() - self.delete_answer_be_voted_up_3() - self.delete_question_be_vote_down_3() - self.delete_answer_be_voted_down_3() - self.answer_be_voted_up_10() - self.question_be_voted_up_10() - self.question_view_1000() - self.answer_self_question_be_voted_up_3() - self.answer_be_voted_up_100() - self.question_be_voted_up_100() - self.question_be_favorited_100() - self.question_view_10000() - self.answer_be_voted_up_25() - self.question_be_voted_up_25() - self.question_be_favorited_25() - self.question_view_2500() - self.answer_be_accepted_and_voted_up_40() - self.question_be_answered_after_60_days_and_be_voted_up_5() - self.created_tag_be_used_in_question_50() - except Exception, e: - print e - finally: - connection.close() - - def delete_question_be_voted_up_3(self): - """ - (1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM activity act, question q WHERE act.object_id = q.id AND\ - act.activity_type = %s AND\ - q.vote_up_count >=3 AND \ - act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_QUESTION) - self.__process_activities_badge(query, 1, Question) - - def delete_answer_be_voted_up_3(self): - """ - (1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM activity act, answer an WHERE act.object_id = an.id AND\ - act.activity_type = %s AND\ - an.vote_up_count >=3 AND \ - act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_ANSWER) - self.__process_activities_badge(query, 1, Answer) - - def delete_question_be_vote_down_3(self): - """ - (2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM activity act, question q WHERE act.object_id = q.id AND\ - act.activity_type = %s AND\ - q.vote_down_count >=3 AND \ - act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_QUESTION) - content_type = ContentType.objects.get_for_model(Question) - self.__process_activities_badge(query, 2, Question) - - def delete_answer_be_voted_down_3(self): - """ - (2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM activity act, answer an WHERE act.object_id = an.id AND\ - act.activity_type = %s AND\ - an.vote_down_count >=3 AND \ - act.is_auditted = 0" % (TYPE_ACTIVITY_DELETE_ANSWER) - self.__process_activities_badge(query, 2, Answer) - - def answer_be_voted_up_10(self): - """ - (3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM \ - activity act, answer a WHERE act.object_id = a.id AND\ - act.activity_type = %s AND \ - a.vote_up_count >= 10 AND\ - act.is_auditted = 0" % (TYPE_ACTIVITY_ANSWER) - self.__process_activities_badge(query, 3, Answer) - - def question_be_voted_up_10(self): - """ - (4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM \ - activity act, question q WHERE act.object_id = q.id AND\ - act.activity_type = %s AND \ - q.vote_up_count >= 10 AND\ - act.is_auditted = 0" % (TYPE_ACTIVITY_ASK_QUESTION) - self.__process_activities_badge(query, 4, Question) - - def question_view_1000(self): - """ - (6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM \ - activity act, question q WHERE act.activity_type = %s AND\ - act.object_id = q.id AND \ - q.view_count >= 1000 AND\ - act.object_id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 6) - self.__process_activities_badge(query, 6, Question, False) - - def answer_self_question_be_voted_up_3(self): - """ - (17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0), - """ - query = "SELECT act.id, act.user_id, act.object_id FROM \ - activity act, answer an WHERE act.activity_type = %s AND\ - act.object_id = an.id AND\ - an.vote_up_count >= 3 AND\ - act.user_id = (SELECT user_id FROM question q WHERE q.id = an.question_id) AND\ - act.object_id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 17) - self.__process_activities_badge(query, 17, Question, False) - - def answer_be_voted_up_100(self): - """ - (18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0), - """ - query = "SELECT an.id, an.author_id FROM answer an WHERE an.vote_up_count >= 100 AND an.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (18) - - self.__process_badge(query, 18, Answer) - - def question_be_voted_up_100(self): - """ - (19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.vote_up_count >= 100 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (19) - - self.__process_badge(query, 19, Question) - - def question_be_favorited_100(self): - """ - (20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.favourite_count >= 100 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (20) - - self.__process_badge(query, 20, Question) - - def question_view_10000(self): - """ - (21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.view_count >= 10000 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (21) - - self.__process_badge(query, 21, Question) - - def answer_be_voted_up_25(self): - """ - (23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0), - """ - query = "SELECT a.id, a.author_id FROM answer a WHERE a.vote_up_count >= 25 AND a.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (23) - - self.__process_badge(query, 23, Answer) - - def question_be_voted_up_25(self): - """ - (24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.vote_up_count >= 25 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (24) - - self.__process_badge(query, 24, Question) - - def question_be_favorited_25(self): - """ - (25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.favourite_count >= 25 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (25) - - self.__process_badge(query, 25, Question) - - def question_view_2500(self): - """ - (31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0), - """ - query = "SELECT q.id, q.author_id FROM question q WHERE q.view_count >= 2500 AND q.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (31) - - self.__process_badge(query, 31, Question) - - def answer_be_accepted_and_voted_up_40(self): - """ - (34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0), - """ - query = "SELECT a.id, a.author_id FROM answer a WHERE a.vote_up_count >= 40 AND\ - a.accepted = 1 AND\ - a.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (34) - - self.__process_badge(query, 34, Answer) - - def question_be_answered_after_60_days_and_be_voted_up_5(self): - """ - (35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0), - """ - query = "SELECT a.id, a.author_id FROM question q, answer a WHERE q.id = a.question_id AND\ - DATEDIFF(a.added_at, q.added_at) >= 60 AND\ - a.vote_up_count >= 5 AND \ - a.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (35) - - self.__process_badge(query, 35, Answer) - - def created_tag_be_used_in_question_50(self): - """ - (36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0); - """ - query = "SELECT t.id, t.created_by_id FROM tag t, auth_user u WHERE t.created_by_id = u.id AND \ - t. used_count >= 50 AND \ - t.id NOT IN \ - (SELECT object_id FROM award WHERE award.badge_id = %s)" % (36) - - self.__process_badge(query, 36, Tag) - - def __process_activities_badge(self, query, badge, content_object, update_auditted=True): - content_type = ContentType.objects.get_for_model(content_object) - - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - if update_auditted: - activity_ids = [] - badge = get_object_or_404(Badge, id=badge) - for row in rows: - activity_id = row[0] - user_id = row[1] - object_id = row[2] - - user = get_object_or_404(User, id=user_id) - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - - if update_auditted: - activity_ids.append(activity_id) - - if update_auditted: - self.update_activities_auditted(cursor, activity_ids) - finally: - cursor.close() - - def __process_badge(self, query, badge, content_object): - content_type = ContentType.objects.get_for_model(Answer) - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - badge = get_object_or_404(Badge, id=badge) - for row in rows: - object_id = row[0] - user_id = row[1] - - user = get_object_or_404(User, id=user_id) - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - finally: - cursor.close() diff --git a/forum/management/commands/once_award_badges.py b/forum/management/commands/once_award_badges.py deleted file mode 100644 index 8c91334..0000000 --- a/forum/management/commands/once_award_badges.py +++ /dev/null @@ -1,350 +0,0 @@ -#!/usr/bin/env python -#encoding:utf-8 -#------------------------------------------------------------------------------- -# Name: Award badges command -# Purpose: This is a command file croning in background process regularly to -# query database and award badges for user's special acitivities. -# -# Author: Mike, Sailing -# -# Created: 18/01/2009 -# Copyright: (c) Mike 2009 -# Licence: GPL V2 -#------------------------------------------------------------------------------- - -from datetime import datetime, date -from django.db import connection -from django.shortcuts import get_object_or_404 -from django.contrib.contenttypes.models import ContentType - -from forum.models import * -from forum.const import * -from base_command import BaseCommand -""" -(1, '炼狱法师', 3, '炼狱法师', '删除自己有3个以上赞成票的帖子', 1, 0), -(2, '压力白领', 3, '压力白领', '删除自己有3个以上反对票的帖子', 1, 0), -(3, '优秀回答', 3, '优秀回答', '回答好评10次以上', 1, 0), -(4, '优秀问题', 3, '优秀问题', '问题好评10次以上', 1, 0), -(5, '评论家', 3, '评论家', '评论10次以上', 0, 0), -(6, '流行问题', 3, '流行问题', '问题的浏览量超过1000人次', 1, 0), -(7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 0, 0), -(8, '清洁工', 3, '清洁工', '第一次撤销投票', 0, 0), -(9, '批评家', 3, '批评家', '第一次反对票', 0, 0), -(10, '小编', 3, '小编', '第一次编辑更新', 0, 0), -(11, '村长', 3, '村长', '第一次重新标签', 0, 0), -(12, '学者', 3, '学者', '第一次标记答案', 0, 0), -(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0), -(14, '支持者', 3, '支持者', '第一次赞成票', 0, 0), -(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0), -(16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 0, 0), -(17, '自学成才', 3, '自学成才', '回答自己的问题并且有3个以上赞成票', 1, 0), -(18, '最有价值回答', 1, '最有价值回答', '回答超过100次赞成票', 1, 0), -(19, '最有价值问题', 1, '最有价值问题', '问题超过100次赞成票', 1, 0), -(20, '万人迷', 1, '万人迷', '问题被100人以上收藏', 1, 0), -(21, '著名问题', 1, '著名问题', '问题的浏览量超过10000人次', 1, 0), -(22, 'alpha用户', 2, 'alpha用户', '内测期间的活跃用户', 0, 0), -(23, '极好回答', 2, '极好回答', '回答超过25次赞成票', 1, 0), -(24, '极好问题', 2, '极好问题', '问题超过25次赞成票', 1, 0), -(25, '受欢迎问题', 2, '受欢迎问题', '问题被25人以上收藏', 1, 0), -(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0), -(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0), -(28, '通才', 2, '通才', '在多个标签领域活跃', 0, 0), -(29, '专家', 2, '专家', '在一个标签领域活跃出众', 0, 0), -(30, '老鸟', 2, '老鸟', '活跃超过一年的用户', 0, 0), -(31, '最受关注问题', 2, '最受关注问题', '问题的浏览量超过2500人次', 1, 0), -(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0), -(33, 'beta用户', 2, 'beta用户', 'beta期间活跃参与', 0, 0), -(34, '导师', 2, '导师', '被指定为最佳答案并且赞成票40以上', 1, 0), -(35, '巫师', 2, '巫师', '在提问60天之后回答并且赞成票5次以上', 1, 0), -(36, '分类专家', 2, '分类专家', '创建的标签被50个以上问题使用', 1, 0); - - -TYPE_ACTIVITY_ASK_QUESTION=1 -TYPE_ACTIVITY_ANSWER=2 -TYPE_ACTIVITY_COMMENT_QUESTION=3 -TYPE_ACTIVITY_COMMENT_ANSWER=4 -TYPE_ACTIVITY_UPDATE_QUESTION=5 -TYPE_ACTIVITY_UPDATE_ANSWER=6 -TYPE_ACTIVITY_PRIZE=7 -TYPE_ACTIVITY_MARK_ANSWER=8 -TYPE_ACTIVITY_VOTE_UP=9 -TYPE_ACTIVITY_VOTE_DOWN=10 -TYPE_ACTIVITY_CANCEL_VOTE=11 -TYPE_ACTIVITY_DELETE_QUESTION=12 -TYPE_ACTIVITY_DELETE_ANSWER=13 -TYPE_ACTIVITY_MARK_OFFENSIVE=14 -TYPE_ACTIVITY_UPDATE_TAGS=15 -TYPE_ACTIVITY_FAVORITE=16 -TYPE_ACTIVITY_USER_FULL_UPDATED = 17 -""" - -BADGE_AWARD_TYPE_FIRST = { - TYPE_ACTIVITY_MARK_OFFENSIVE : 7, - TYPE_ACTIVITY_CANCEL_VOTE: 8, - TYPE_ACTIVITY_VOTE_DOWN : 9, - TYPE_ACTIVITY_UPDATE_QUESTION : 10, - TYPE_ACTIVITY_UPDATE_ANSWER : 10, - TYPE_ACTIVITY_UPDATE_TAGS : 11, - TYPE_ACTIVITY_MARK_ANSWER : 12, - TYPE_ACTIVITY_VOTE_UP : 14, - TYPE_ACTIVITY_USER_FULL_UPDATED: 16 - -} - -class Command(BaseCommand): - def handle_noargs(self, **options): - try: - try: - self.alpha_user() - self.beta_user() - self.first_type_award() - self.first_ask_be_voted() - self.first_answer_be_voted() - self.first_answer_be_voted_10() - self.vote_count_300() - self.edit_count_100() - self.comment_count_10() - except Exception, e: - print e - finally: - connection.close() - - def alpha_user(self): - """ - Before Jan 25, 2009(Chinese New Year Eve and enter into Beta for CNProg), every registered user - will be awarded the "Alpha" badge if he has any activities. - """ - alpha_end_date = date(2009, 1, 25) - if date.today() < alpha_end_date: - badge = get_object_or_404(Badge, id=22) - for user in User.objects.all(): - award = Award.objects.filter(user=user, badge=badge) - if award and not badge.multiple: - continue - activities = Activity.objects.filter(user=user) - if len(activities) > 0: - new_award = Award(user=user, badge=badge) - new_award.save() - - def beta_user(self): - """ - Before Feb 25, 2009, every registered user - will be awarded the "Beta" badge if he has any activities. - """ - beta_end_date = date(2009, 2, 25) - if date.today() < beta_end_date: - badge = get_object_or_404(Badge, id=33) - for user in User.objects.all(): - award = Award.objects.filter(user=user, badge=badge) - if award and not badge.multiple: - continue - activities = Activity.objects.filter(user=user) - if len(activities) > 0: - new_award = Award(user=user, badge=badge) - new_award.save() - - def first_type_award(self): - """ - This will award below badges for users first behaviors: - - (7, '巡逻兵', 3, '巡逻兵', '第一次标记垃圾帖子', 0, 0), - (8, '清洁工', 3, '清洁工', '第一次撤销投票', 0, 0), - (9, '批评家', 3, '批评家', '第一次反对票', 0, 0), - (10, '小编', 3, '小编', '第一次编辑更新', 0, 0), - (11, '村长', 3, '村长', '第一次重新标签', 0, 0), - (12, '学者', 3, '学者', '第一次标记答案', 0, 0), - (14, '支持者', 3, '支持者', '第一次赞成票', 0, 0), - (16, '自传作者', 3, '自传作者', '完整填写用户资料所有选项', 0, 0), - """ - activity_types = ','.join('%s' % item for item in BADGE_AWARD_TYPE_FIRST.keys()) - # ORDER BY user_id, activity_type - query = "SELECT id, user_id, activity_type, content_type_id, object_id FROM activity WHERE is_auditted = 0 AND activity_type IN (%s) ORDER BY user_id, activity_type" % activity_types - - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - # collect activity_id in current process - activity_ids = [] - last_user_id = 0 - last_activity_type = 0 - for row in rows: - activity_ids.append(row[0]) - user_id = row[1] - activity_type = row[2] - content_type_id = row[3] - object_id = row[4] - - # if the user and activity are same as the last, continue - if user_id == last_user_id and activity_type == last_activity_type: - continue; - - user = get_object_or_404(User, id=user_id) - badge = get_object_or_404(Badge, id=BADGE_AWARD_TYPE_FIRST[activity_type]) - content_type = get_object_or_404(ContentType, id=content_type_id) - - count = Award.objects.filter(user=user, badge=badge).count() - if count and not badge.multiple: - continue - else: - # new award - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - - # set the current user_id and activity_type to last - last_user_id = user_id - last_activity_type = activity_type - - # update processed rows to auditted - self.update_activities_auditted(cursor, activity_ids) - finally: - cursor.close() - - def first_ask_be_voted(self): - """ - For user asked question and got first upvote, we award him following badge: - - (13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0), - """ - query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM " \ - "activity act, question q WHERE act.activity_type = %s AND " \ - "act.object_id = q.id AND " \ - "act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 13) - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - badge = get_object_or_404(Badge, id=13) - content_type = ContentType.objects.get_for_model(Question) - awarded_users = [] - for row in rows: - user_id = row[0] - vote_up_count = row[1] - object_id = row[2] - if vote_up_count > 0 and user_id not in awarded_users: - user = get_object_or_404(User, id=user_id) - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - awarded_users.append(user_id) - finally: - cursor.close() - - def first_answer_be_voted(self): - """ - When user answerd questions and got first upvote, we award him following badge: - - (15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0), - """ - query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM " \ - "activity act, answer a WHERE act.activity_type = %s AND " \ - "act.object_id = a.id AND " \ - "act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 15) - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - awarded_users = [] - badge = get_object_or_404(Badge, id=15) - content_type = ContentType.objects.get_for_model(Answer) - for row in rows: - user_id = row[0] - vote_up_count = row[1] - object_id = row[2] - if vote_up_count > 0 and user_id not in awarded_users: - user = get_object_or_404(User, id=user_id) - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - awarded_users.append(user_id) - finally: - cursor.close() - - def first_answer_be_voted_10(self): - """ - (32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0) - """ - query = "SELECT act.user_id, act.object_id FROM " \ - "activity act, answer a WHERE act.object_id = a.id AND " \ - "act.activity_type = %s AND " \ - "a.vote_up_count >= 10 AND " \ - "act.user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 32) - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - awarded_users = [] - badge = get_object_or_404(Badge, id=32) - content_type = ContentType.objects.get_for_model(Answer) - for row in rows: - user_id = row[0] - if user_id not in awarded_users: - user = get_object_or_404(User, id=user_id) - object_id = row[1] - award = Award(user=user, badge=badge, content_type=content_type, object_id=object_id) - award.save() - awarded_users.append(user_id) - finally: - cursor.close() - - def vote_count_300(self): - """ - (26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0) - """ - query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \ - "activity_type = %s OR " \ - "activity_type = %s AND " \ - "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \ - "GROUP BY user_id HAVING vote_count >= 300" % (TYPE_ACTIVITY_VOTE_UP, TYPE_ACTIVITY_VOTE_DOWN, 26) - - self.__award_for_count_num(query, 26) - - def edit_count_100(self): - """ - (27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0) - """ - query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \ - "activity_type = %s OR " \ - "activity_type = %s AND " \ - "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \ - "GROUP BY user_id HAVING vote_count >= 100" % (TYPE_ACTIVITY_UPDATE_QUESTION, TYPE_ACTIVITY_UPDATE_ANSWER, 27) - - self.__award_for_count_num(query, 27) - - def comment_count_10(self): - """ - (5, '评论家', 3, '评论家', '评论10次以上', 0, 0), - """ - query = "SELECT count(*) vote_count, user_id FROM activity WHERE " \ - "activity_type = %s OR " \ - "activity_type = %s AND " \ - "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \ - "GROUP BY user_id HAVING vote_count >= 10" % (TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER, 5) - self.__award_for_count_num(query, 5) - - def __award_for_count_num(self, query, badge): - cursor = connection.cursor() - try: - cursor.execute(query) - rows = cursor.fetchall() - - awarded_users = [] - badge = get_object_or_404(Badge, id=badge) - for row in rows: - vote_count = row[0] - user_id = row[1] - - if user_id not in awarded_users: - user = get_object_or_404(User, id=user_id) - award = Award(user=user, badge=badge) - award.save() - awarded_users.append(user_id) - finally: - cursor.close() - -def main(): - pass - -if __name__ == '__main__': - main() diff --git a/forum/management/commands/sample_command.py b/forum/management/commands/sample_command.py deleted file mode 100644 index 55e6723..0000000 --- a/forum/management/commands/sample_command.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.core.management.base import NoArgsCommand -from forum.models import Comment - -class Command(NoArgsCommand): - def handle_noargs(self, **options): - objs = Comment.objects.all() - print objs \ No newline at end of file diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py deleted file mode 100644 index 26eb779..0000000 --- a/forum/management/commands/send_email_alerts.py +++ /dev/null @@ -1,192 +0,0 @@ -from django.core.management.base import NoArgsCommand -from django.db import connection -from django.db.models import Q, F -from forum.models import * -from forum import const -from django.core.mail import EmailMessage -from django.utils.translation import ugettext as _ -from django.utils.translation import ungettext -import datetime -from django.conf import settings -import logging -from forum.utils.odict import OrderedDict - -class Command(NoArgsCommand): - def handle_noargs(self,**options): - try: - try: - self.send_email_alerts() - except Exception, e: - print e - finally: - connection.close() - - def get_updated_questions_for_user(self,user): - q_sel = None - q_ask = None - q_ans = None - q_all = None - now = datetime.datetime.now() - Q_set1 = Question.objects.exclude( - last_activity_by=user, - ).exclude( - last_activity_at__lt=user.date_joined - ).filter( - Q(viewed__who=user,viewed__when__lt=F('last_activity_at')) | \ - ~Q(viewed__who=user) - ).exclude( - deleted=True - ).exclude( - closed=True - ) - - user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n') - for feed in user_feeds: - cutoff_time = now - EmailFeedSetting.DELTA_TABLE[feed.frequency] - if feed.reported_at == None or feed.reported_at <= cutoff_time: - Q_set = Q_set1.exclude(last_activity_at__gt=cutoff_time)#report these excluded later - feed.reported_at = now - feed.save()#may not actually report anything, depending on filters below - if feed.feed_type == 'q_sel': - q_sel = Q_set.filter(followed_by=user) - q_sel.cutoff_time = cutoff_time #store cutoff time per query set - elif feed.feed_type == 'q_ask': - q_ask = Q_set.filter(author=user) - q_ask.cutoff_time = cutoff_time - elif feed.feed_type == 'q_ans': - q_ans = Q_set.filter(answers__author=user) - q_ans.cutoff_time = cutoff_time - elif feed.feed_type == 'q_all': - if user.tag_filter_setting == 'ignored': - ignored_tags = Tag.objects.filter(user_selections__reason='bad',user_selections__user=user) - q_all = Q_set.exclude( tags__in=ignored_tags ) - else: - selected_tags = Tag.objects.filter(user_selections__reason='good',user_selections__user=user) - q_all = Q_set.filter( tags__in=selected_tags ) - q_all.cutoff_time = cutoff_time - #build list in this order - q_list = OrderedDict() - def extend_question_list(src, dst): - """src is a query set with questions - or an empty list - dst - is an ordered dictionary - """ - if src is None: - return #will not do anything if subscription of this type is not used - cutoff_time = src.cutoff_time - for q in src: - if q in dst: - if cutoff_time < dst[q]['cutoff_time']: - dst[q]['cutoff_time'] = cutoff_time - else: - #initialise a questions metadata dictionary to use for email reporting - dst[q] = {'cutoff_time':cutoff_time} - - extend_question_list(q_sel, q_list) - extend_question_list(q_ask, q_list) - extend_question_list(q_ans, q_list) - extend_question_list(q_all, q_list) - - ctype = ContentType.objects.get_for_model(Question) - EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT - for q, meta_data in q_list.items(): - #todo use Activity, but first start keeping more Activity records - #act = Activity.objects.filter(content_type=ctype, object_id=q.id) - #because currently activity is not fully recorded to through - #revision records to see what kind modifications were done on - #the questions and answers - try: - update_info = Activity.objects.get(content_type=ctype, - object_id=q.id, - activity_type=EMAIL_UPDATE_ACTIVITY) - emailed_at = update_info.active_at - except Activity.DoesNotExist: - update_info = Activity(user=user, content_object=q, activity_type=EMAIL_UPDATE_ACTIVITY) - emailed_at = datetime.datetime(1970,1,1)#long time ago - except Activity.MultipleObjectsReturned: - raise Exception('server error - multiple question email activities found per user-question pair') - - q_rev = QuestionRevision.objects.filter(question=q,\ - revised_at__lt=cutoff_time,\ - revised_at__gt=emailed_at) - q_rev = q_rev.exclude(author=user) - meta_data['q_rev'] = len(q_rev) - if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at: - meta_data['q_rev'] = 0 - meta_data['new_q'] = True - else: - meta_data['new_q'] = False - - new_ans = Answer.objects.filter(question=q,\ - added_at__lt=cutoff_time,\ - added_at__gt=emailed_at) - new_ans = new_ans.exclude(author=user) - meta_data['new_ans'] = len(new_ans) - ans_rev = AnswerRevision.objects.filter(answer__question=q,\ - revised_at__lt=cutoff_time,\ - revised_at__gt=emailed_at) - ans_rev = ans_rev.exclude(author=user) - meta_data['ans_rev'] = len(ans_rev) - if len(q_rev) == 0 and len(new_ans) == 0 and len(ans_rev) == 0: - meta_data['nothing_new'] = True - else: - meta_data['nothing_new'] = False - update_info.active_at = now - update_info.save() #save question email update activity - return q_list - - def __action_count(self,string,number,output): - if number > 0: - output.append(_(string) % {'num':number}) - - def send_email_alerts(self): - - #todo: move this to template - for user in User.objects.all(): - q_list = self.get_updated_questions_for_user(user) - num_q = 0 - num_moot = 0 - for meta_data in q_list.values(): - if meta_data['nothing_new'] == False: - num_q += 1 - else: - num_moot += 1 - if num_q > 0: - url_prefix = settings.APP_URL - subject = _('email update message subject') - print 'have %d updated questions for %s' % (num_q, user.username) - text = ungettext('%(name)s, this is an update message header for a question', - '%(name)s, this is an update message header for %(num)d questions',num_q) \ - % {'num':num_q, 'name':user.username} - - text += '' - if num_moot > 0: - text += '

' - text += ungettext('There is also one question which was recently '\ - +'updated but you might not have seen its latest version.', - 'There are also %(num)d more questions which were recently updated '\ - +'but you might not have seen their latest version.',num_moot) \ - % {'num':num_moot,} - text += _('Perhaps you could look up previously sent forum reminders in your mailbox.') - text += '

' - - link = url_prefix + user.get_profile_url() + '?sort=email_subscriptions' - text += _('go to %(link)s to change frequency of email updates or %(email)s administrator') \ - % {'link':link, 'email':settings.ADMINS[0][1]} - msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email]) - msg.content_subtype = 'html' - msg.send() diff --git a/forum/management/commands/subscribe_everyone.py b/forum/management/commands/subscribe_everyone.py deleted file mode 100644 index c79528f..0000000 --- a/forum/management/commands/subscribe_everyone.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.core.management.base import NoArgsCommand -from django.db import connection -from django.db.models import Q, F -from forum.models import * -from django.core.mail import EmailMessage -from django.utils.translation import ugettext as _ -from django.utils.translation import ungettext -import datetime -from django.conf import settings - -class Command(NoArgsCommand): - def handle_noargs(self,**options): - try: - try: - self.subscribe_everyone() - except Exception, e: - print e - finally: - connection.close() - - def subscribe_everyone(self): - - feed_type_info = EmailFeedSetting.FEED_TYPES - for user in User.objects.all(): - for feed_type in feed_type_info: - try: - feed_setting = EmailFeedSetting.objects.get(subscriber=user,feed_type = feed_type[0]) - except EmailFeedSetting.DoesNotExist: - feed_setting = EmailFeedSetting(subscriber=user,feed_type=feed_type[0]) - feed_setting.frequency = 'w' - feed_setting.reported_at = None - feed_setting.save() diff --git a/forum/middleware/__init__.py b/forum/middleware/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/forum/middleware/anon_user.py b/forum/middleware/anon_user.py deleted file mode 100644 index 866734d..0000000 --- a/forum/middleware/anon_user.py +++ /dev/null @@ -1,35 +0,0 @@ -from django.http import HttpResponseRedirect -from forum.utils.forms import get_next_url -from django.utils.translation import ugettext as _ -from forum.user_messages import create_message, get_and_delete_messages -from django.conf import settings -from django.core.urlresolvers import reverse -import logging - -class AnonymousMessageManager(object): - def __init__(self,request): - self.request = request - def create(self,message=''): - create_message(self.request,message) - def get_and_delete(self): - messages = get_and_delete_messages(self.request) - return messages - -def dummy_deepcopy(*arg): - """this is necessary to prevent deepcopy() on anonymous user object - that now contains reference to request, which cannot be deepcopied - """ - return None - -class ConnectToSessionMessagesMiddleware(object): - def process_request(self, request): - if not request.user.is_authenticated(): - request.user.__deepcopy__ = dummy_deepcopy #plug on deepcopy which may be called by django db "driver" - request.user.message_set = AnonymousMessageManager(request) #here request is linked to anon user - request.user.get_and_delete_messages = request.user.message_set.get_and_delete - - #also set the first greeting one time per session only - if 'greeting_set' not in request.session: - request.session['greeting_set'] = True - msg = _('First time here? Check out the FAQ!') % reverse('faq') - request.user.message_set.create(message=msg) diff --git a/forum/middleware/cancel.py b/forum/middleware/cancel.py deleted file mode 100644 index 15a4371..0000000 --- a/forum/middleware/cancel.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.http import HttpResponseRedirect -from forum.utils.forms import get_next_url -import logging -class CancelActionMiddleware(object): - def process_view(self, request, view_func, view_args, view_kwargs): - if 'cancel' in request.REQUEST: - #todo use session messages for the anonymous users - try: - msg = getattr(view_func,'CANCEL_MESSAGE') - except AttributeError: - msg = 'action canceled' - request.user.message_set.create(message=msg) - return HttpResponseRedirect(get_next_url(request)) - else: - return None diff --git a/forum/middleware/pagesize.py b/forum/middleware/pagesize.py deleted file mode 100644 index f6e6fcf..0000000 --- a/forum/middleware/pagesize.py +++ /dev/null @@ -1,33 +0,0 @@ -# used in questions -QUESTIONS_PAGE_SIZE = 10 -class QuestionsPageSizeMiddleware(object): - def process_request(self, request): - # Set flag to False by default. If it is equal to True, then need to be saved. - pagesize_changed = False - # get pagesize from session, if failed then get default value - user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE) - # set pagesize equal to logon user specified value in database - if request.user.is_authenticated() and request.user.questions_per_page > 0: - user_page_size = request.user.questions_per_page - - try: - # get new pagesize from UI selection - pagesize = int(request.GET.get('pagesize', user_page_size)) - if pagesize <> user_page_size: - pagesize_changed = True - - except ValueError: - pagesize = user_page_size - - # save this pagesize to user database - if pagesize_changed: - if request.user.is_authenticated(): - user = request.user - user.questions_per_page = pagesize - user.save() - # put pagesize into session - request.session["pagesize"] = pagesize - - def process_exception(self,request,exception): - import logging - logging.debug('have exception %s' % str(exception)) diff --git a/forum/models/__init__.py b/forum/models/__init__.py deleted file mode 100755 index 12a0239..0000000 --- a/forum/models/__init__.py +++ /dev/null @@ -1,343 +0,0 @@ -from question import Question ,QuestionRevision, QuestionView, AnonymousQuestion, FavoriteQuestion -from answer import Answer, AnonymousAnswer, AnswerRevision -from tag import Tag, MarkedTag -from meta import Vote, Comment, FlaggedItem -from user import Activity, AnonymousEmail, EmailFeedSetting, AuthKeyUserAssociation -from repute import Badge, Award, Repute - -from base import * - -# User extend properties -QUESTIONS_PER_PAGE_CHOICES = ( - (10, u'10'), - (30, u'30'), - (50, u'50'), -) - -def user_is_username_taken(cls,username): - try: - cls.objects.get(username=username) - return True - except cls.MultipleObjectsReturned: - return True - except cls.DoesNotExist: - return False - -def user_get_q_sel_email_feed_frequency(self): - #print 'looking for frequency for user %s' % self - try: - feed_setting = EmailFeedSetting.objects.get(subscriber=self,feed_type='q_sel') - except Exception, e: - #print 'have error %s' % e.message - raise e - #print 'have freq=%s' % feed_setting.frequency - return feed_setting.frequency - -User.add_to_class('is_approved', models.BooleanField(default=False)) -User.add_to_class('email_isvalid', models.BooleanField(default=False)) -User.add_to_class('email_key', models.CharField(max_length=32, null=True)) -User.add_to_class('reputation', models.PositiveIntegerField(default=1)) -User.add_to_class('gravatar', models.CharField(max_length=32)) - -#User.add_to_class('favorite_questions', -# models.ManyToManyField(Question, through=FavoriteQuestion, -# related_name='favorited_by')) - -#User.add_to_class('badges', models.ManyToManyField(Badge, through=Award, -# related_name='awarded_to')) -User.add_to_class('gold', models.SmallIntegerField(default=0)) -User.add_to_class('silver', models.SmallIntegerField(default=0)) -User.add_to_class('bronze', models.SmallIntegerField(default=0)) -User.add_to_class('questions_per_page', - models.SmallIntegerField(choices=QUESTIONS_PER_PAGE_CHOICES, default=10)) -User.add_to_class('last_seen', - models.DateTimeField(default=datetime.datetime.now)) -User.add_to_class('real_name', models.CharField(max_length=100, blank=True)) -User.add_to_class('website', models.URLField(max_length=200, blank=True)) -User.add_to_class('location', models.CharField(max_length=100, blank=True)) -User.add_to_class('date_of_birth', models.DateField(null=True, blank=True)) -User.add_to_class('about', models.TextField(blank=True)) -User.add_to_class('is_username_taken',classmethod(user_is_username_taken)) -User.add_to_class('get_q_sel_email_feed_frequency',user_get_q_sel_email_feed_frequency) -User.add_to_class('hide_ignored_questions', models.BooleanField(default=False)) -User.add_to_class('tag_filter_setting', - models.CharField( - max_length=16, - choices=TAG_EMAIL_FILTER_CHOICES, - default='ignored' - ) - ) - -# custom signal -tags_updated = django.dispatch.Signal(providing_args=["question"]) -edit_question_or_answer = django.dispatch.Signal(providing_args=["instance", "modified_by"]) -delete_post_or_answer = django.dispatch.Signal(providing_args=["instance", "deleted_by"]) -mark_offensive = django.dispatch.Signal(providing_args=["instance", "mark_by"]) -user_updated = django.dispatch.Signal(providing_args=["instance", "updated_by"]) -user_logged_in = django.dispatch.Signal(providing_args=["session"]) - - -def get_messages(self): - messages = [] - for m in self.message_set.all(): - messages.append(m.message) - return messages - -def delete_messages(self): - self.message_set.all().delete() - -def get_profile_url(self): - """Returns the URL for this User's profile.""" - return '%s%s/' % (reverse('user', args=[self.id]), slugify(self.username)) - -def get_profile_link(self): - profile_link = u'%s' % (self.get_profile_url(),self.username) - logging.debug('in get profile link %s' % profile_link) - return mark_safe(profile_link) - -User.add_to_class('get_profile_url', get_profile_url) -User.add_to_class('get_profile_link', get_profile_link) -User.add_to_class('get_messages', get_messages) -User.add_to_class('delete_messages', delete_messages) - -def calculate_gravatar_hash(instance, **kwargs): - """Calculates a User's gravatar hash from their email address.""" - if kwargs.get('raw', False): - return - instance.gravatar = hashlib.md5(instance.email).hexdigest() - -def record_ask_event(instance, created, **kwargs): - if created: - activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ASK_QUESTION) - activity.save() - -def record_answer_event(instance, created, **kwargs): - if created: - activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ANSWER) - activity.save() - -def record_comment_event(instance, created, **kwargs): - if created: - from django.contrib.contenttypes.models import ContentType - question_type = ContentType.objects.get_for_model(Question) - question_type_id = question_type.id - if (instance.content_type_id == question_type_id): - type = TYPE_ACTIVITY_COMMENT_QUESTION - else: - type = TYPE_ACTIVITY_COMMENT_ANSWER - activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=type) - activity.save() - -def record_revision_question_event(instance, created, **kwargs): - if created and instance.revision <> 1: - activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_QUESTION) - activity.save() - -def record_revision_answer_event(instance, created, **kwargs): - if created and instance.revision <> 1: - activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_ANSWER) - activity.save() - -def record_award_event(instance, created, **kwargs): - """ - After we awarded a badge to user, we need to record this activity and notify user. - We also recaculate awarded_count of this badge and user information. - """ - if created: - activity = Activity(user=instance.user, active_at=instance.awarded_at, content_object=instance, - activity_type=TYPE_ACTIVITY_PRIZE) - activity.save() - - instance.badge.awarded_count += 1 - instance.badge.save() - - if instance.badge.type == Badge.GOLD: - instance.user.gold += 1 - if instance.badge.type == Badge.SILVER: - instance.user.silver += 1 - if instance.badge.type == Badge.BRONZE: - instance.user.bronze += 1 - instance.user.save() - -def notify_award_message(instance, created, **kwargs): - """ - Notify users when they have been awarded badges by using Django message. - """ - if created: - user = instance.user - user.message_set.create(message=u"Congratulations, you have received a badge '%s'" % instance.badge.name) - -def record_answer_accepted(instance, created, **kwargs): - """ - when answer is accepted, we record this for question author - who accepted it. - """ - if not created and instance.accepted: - activity = Activity(user=instance.question.author, active_at=datetime.datetime.now(), \ - content_object=instance, activity_type=TYPE_ACTIVITY_MARK_ANSWER) - activity.save() - -def update_last_seen(instance, created, **kwargs): - """ - when user has activities, we update 'last_seen' time stamp for him - """ - user = instance.user - user.last_seen = datetime.datetime.now() - user.save() - -def record_vote(instance, created, **kwargs): - """ - when user have voted - """ - if created: - if instance.vote == 1: - vote_type = TYPE_ACTIVITY_VOTE_UP - else: - vote_type = TYPE_ACTIVITY_VOTE_DOWN - - activity = Activity(user=instance.user, active_at=instance.voted_at, content_object=instance, activity_type=vote_type) - activity.save() - -def record_cancel_vote(instance, **kwargs): - """ - when user canceled vote, the vote will be deleted. - """ - activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_CANCEL_VOTE) - activity.save() - -def record_delete_question(instance, delete_by, **kwargs): - """ - when user deleted the question - """ - if instance.__class__ == "Question": - activity_type = TYPE_ACTIVITY_DELETE_QUESTION - else: - activity_type = TYPE_ACTIVITY_DELETE_ANSWER - - activity = Activity(user=delete_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=activity_type) - activity.save() - -def record_mark_offensive(instance, mark_by, **kwargs): - activity = Activity(user=mark_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_MARK_OFFENSIVE) - activity.save() - -def record_update_tags(question, **kwargs): - """ - when user updated tags of the question - """ - activity = Activity(user=question.author, active_at=datetime.datetime.now(), content_object=question, activity_type=TYPE_ACTIVITY_UPDATE_TAGS) - activity.save() - -def record_favorite_question(instance, created, **kwargs): - """ - when user add the question in him favorite questions list. - """ - if created: - activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_FAVORITE) - activity.save() - -def record_user_full_updated(instance, **kwargs): - activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED) - activity.save() - -def post_stored_anonymous_content(sender,user,session_key,signal,*args,**kwargs): - aq_list = AnonymousQuestion.objects.filter(session_key = session_key) - aa_list = AnonymousAnswer.objects.filter(session_key = session_key) - import settings - if settings.EMAIL_VALIDATION == 'on':#add user to the record - for aq in aq_list: - aq.author = user - aq.save() - for aa in aa_list: - aa.author = user - aa.save() - #maybe add pending posts message? - else: #just publish the questions - for aq in aq_list: - aq.publish(user) - for aa in aa_list: - aa.publish(user) - -#signal for User modle save changes - -pre_save.connect(calculate_gravatar_hash, sender=User) -post_save.connect(record_ask_event, sender=Question) -post_save.connect(record_answer_event, sender=Answer) -post_save.connect(record_comment_event, sender=Comment) -post_save.connect(record_revision_question_event, sender=QuestionRevision) -post_save.connect(record_revision_answer_event, sender=AnswerRevision) -post_save.connect(record_award_event, sender=Award) -post_save.connect(notify_award_message, sender=Award) -post_save.connect(record_answer_accepted, sender=Answer) -post_save.connect(update_last_seen, sender=Activity) -post_save.connect(record_vote, sender=Vote) -post_delete.connect(record_cancel_vote, sender=Vote) -delete_post_or_answer.connect(record_delete_question, sender=Question) -delete_post_or_answer.connect(record_delete_question, sender=Answer) -mark_offensive.connect(record_mark_offensive, sender=Question) -mark_offensive.connect(record_mark_offensive, sender=Answer) -tags_updated.connect(record_update_tags, sender=Question) -post_save.connect(record_favorite_question, sender=FavoriteQuestion) -user_updated.connect(record_user_full_updated, sender=User) -user_logged_in.connect(post_stored_anonymous_content) - -Question = Question -QuestionRevision = QuestionRevision -QuestionView = QuestionView -FavoriteQuestion = FavoriteQuestion -AnonymousQuestion = AnonymousQuestion - -Answer = Answer -AnswerRevision = AnswerRevision -AnonymousAnswer = AnonymousAnswer - -Tag = Tag -Comment = Comment -Vote = Vote -FlaggedItem = FlaggedItem -MarkedTag = MarkedTag - -Badge = Badge -Award = Award -Repute = Repute - -Activity = Activity -EmailFeedSetting = EmailFeedSetting -AnonymousEmail = AnonymousEmail -AuthKeyUserAssociation = AuthKeyUserAssociation - -__all__ = [ - 'Question', - 'QuestionRevision', - 'QuestionView', - 'FavoriteQuestion', - 'AnonymousQuestion', - - 'Answer', - 'AnswerRevision', - 'AnonymousAnswer', - - 'Tag', - 'Comment', - 'Vote', - 'FlaggedItem', - 'MarkedTag', - - 'Badge', - 'Award', - 'Repute', - - 'Activity', - 'EmailFeedSetting', - 'AnonymousEmail', - 'AuthKeyUserAssociation', - - 'User' - ] - - -from forum.modules import get_modules_script_classes - -for k, v in get_modules_script_classes('models', models.Model).items(): - if not k in __all__: - __all__.append(k) - exec "%s = v" % k \ No newline at end of file diff --git a/forum/models/answer.py b/forum/models/answer.py deleted file mode 100755 index 14199de..0000000 --- a/forum/models/answer.py +++ /dev/null @@ -1,134 +0,0 @@ -from base import * - -from question import Question - -class AnswerManager(models.Manager): - @staticmethod - def create_new(cls, question=None, author=None, added_at=None, wiki=False, text='', email_notify=False): - answer = Answer( - question = question, - author = author, - added_at = added_at, - wiki = wiki, - html = text - ) - if answer.wiki: - answer.last_edited_by = answer.author - answer.last_edited_at = added_at - answer.wikified_at = added_at - - answer.save() - - #update question data - question.last_activity_at = added_at - question.last_activity_by = author - question.save() - Question.objects.update_answer_count(question) - - AnswerRevision.objects.create( - answer = answer, - revision = 1, - author = author, - revised_at = added_at, - summary = CONST['default_version'], - text = text - ) - - #set notification/delete - if email_notify: - if author not in question.followed_by.all(): - question.followed_by.add(author) - else: - #not sure if this is necessary. ajax should take care of this... - try: - question.followed_by.remove(author) - except: - pass - - #GET_ANSWERS_FROM_USER_QUESTIONS = u'SELECT answer.* FROM answer INNER JOIN question ON answer.question_id = question.id WHERE question.author_id =%s AND answer.author_id <> %s' - def get_answers_from_question(self, question, user=None): - """ - Retrieves visibile answers for the given question. Delete answers - are only visibile to the person who deleted them. - """ - - if user is None or not user.is_authenticated(): - return self.filter(question=question, deleted=False) - else: - return self.filter(models.Q(question=question), - models.Q(deleted=False) | models.Q(deleted_by=user)) - - #todo: I think this method is not being used anymore, I'll just comment it for now - #def get_answers_from_questions(self, user_id): - # """ - # Retrieves visibile answers for the given question. Which are not included own answers - # """ - # cursor = connection.cursor() - # cursor.execute(self.GET_ANSWERS_FROM_USER_QUESTIONS, [user_id, user_id]) - # return cursor.fetchall() - -class Answer(Content, DeletableContent): - question = models.ForeignKey('Question', related_name='answers') - accepted = models.BooleanField(default=False) - accepted_at = models.DateTimeField(null=True, blank=True) - - objects = AnswerManager() - - class Meta(Content.Meta): - db_table = u'answer' - - def get_user_vote(self, user): - if user.__class__.__name__ == "AnonymousUser": - return None - - votes = self.votes.filter(user=user) - if votes and votes.count() > 0: - return votes[0] - else: - return None - - def get_latest_revision(self): - return self.revisions.all()[0] - - def get_question_title(self): - return self.question.title - - def get_absolute_url(self): - return '%s%s#%s' % (reverse('question', args=[self.question.id]), django_urlquote(slugify(self.question.title)), self.id) - - def __unicode__(self): - return self.html - - -class AnswerRevision(ContentRevision): - """A revision of an Answer.""" - answer = models.ForeignKey('Answer', related_name='revisions') - - def get_absolute_url(self): - return reverse('answer_revisions', kwargs={'id':self.answer.id}) - - def get_question_title(self): - return self.answer.question.title - - class Meta(ContentRevision.Meta): - db_table = u'answer_revision' - ordering = ('-revision',) - - def save(self, **kwargs): - """Looks up the next available revision number if not set.""" - if not self.revision: - self.revision = AnswerRevision.objects.filter( - answer=self.answer).values_list('revision', - flat=True)[0] + 1 - super(AnswerRevision, self).save(**kwargs) - -class AnonymousAnswer(AnonymousContent): - question = models.ForeignKey('Question', related_name='anonymous_answers') - - def publish(self,user): - added_at = datetime.datetime.now() - #print user.id - AnswerManager.create_new(question=self.question,wiki=self.wiki, - added_at=added_at,text=self.text, - author=user) - self.delete() diff --git a/forum/models/base.py b/forum/models/base.py deleted file mode 100755 index 2c28a47..0000000 --- a/forum/models/base.py +++ /dev/null @@ -1,139 +0,0 @@ -import datetime -import hashlib -from urllib import quote_plus, urlencode -from django.db import models, IntegrityError, connection, transaction -from django.utils.http import urlquote as django_urlquote -from django.utils.html import strip_tags -from django.core.urlresolvers import reverse -from django.contrib.auth.models import User -from django.contrib.contenttypes import generic -from django.contrib.contenttypes.models import ContentType -from django.template.defaultfilters import slugify -from django.db.models.signals import post_delete, post_save, pre_save -from django.utils.translation import ugettext as _ -from django.utils.safestring import mark_safe -from django.contrib.sitemaps import ping_google -import django.dispatch -from django.conf import settings -import logging - -if settings.USE_SPHINX_SEARCH == True: - from djangosphinx.models import SphinxSearch - -from forum.const import * - -class MetaContent(models.Model): - """ - Base class for Vote, Comment and FlaggedItem - """ - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - user = models.ForeignKey(User, related_name='%(class)ss') - - class Meta: - abstract = True - app_label = 'forum' - - -class DeletableContent(models.Model): - deleted = models.BooleanField(default=False) - deleted_at = models.DateTimeField(null=True, blank=True) - deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_%(class)ss') - - class Meta: - abstract = True - app_label = 'forum' - - -class ContentRevision(models.Model): - """ - Base class for QuestionRevision and AnswerRevision - """ - revision = models.PositiveIntegerField() - author = models.ForeignKey(User, related_name='%(class)ss') - revised_at = models.DateTimeField() - summary = models.CharField(max_length=300, blank=True) - text = models.TextField() - - class Meta: - abstract = True - app_label = 'forum' - - -class AnonymousContent(models.Model): - """ - Base class for AnonymousQuestion and AnonymousAnswer - """ - session_key = models.CharField(max_length=40) #session id for anonymous questions - wiki = models.BooleanField(default=False) - added_at = models.DateTimeField(default=datetime.datetime.now) - ip_addr = models.IPAddressField(max_length=21) #allow high port numbers - author = models.ForeignKey(User,null=True) - text = models.TextField() - summary = models.CharField(max_length=180) - - class Meta: - abstract = True - app_label = 'forum' - - -from meta import Comment, Vote, FlaggedItem - -class Content(models.Model): - """ - Base class for Question and Answer - """ - author = models.ForeignKey(User, related_name='%(class)ss') - added_at = models.DateTimeField(default=datetime.datetime.now) - - wiki = models.BooleanField(default=False) - wikified_at = models.DateTimeField(null=True, blank=True) - - locked = models.BooleanField(default=False) - locked_by = models.ForeignKey(User, null=True, blank=True, related_name='locked_%(class)ss') - locked_at = models.DateTimeField(null=True, blank=True) - - score = models.IntegerField(default=0) - vote_up_count = models.IntegerField(default=0) - vote_down_count = models.IntegerField(default=0) - - comment_count = models.PositiveIntegerField(default=0) - offensive_flag_count = models.SmallIntegerField(default=0) - - last_edited_at = models.DateTimeField(null=True, blank=True) - last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss') - - html = models.TextField() - comments = generic.GenericRelation(Comment) - votes = generic.GenericRelation(Vote) - flagged_items = generic.GenericRelation(FlaggedItem) - - class Meta: - abstract = True - app_label = 'forum' - - def save(self,**kwargs): - super(Content,self).save(**kwargs) - try: - ping_google() - except Exception: - logging.debug('problem pinging google did you register you sitemap with google?') - - def get_object_comments(self): - comments = self.comments.all().order_by('id') - return comments - - def post_get_last_update_info(self): - when = self.added_at - who = self.author - if self.last_edited_at and self.last_edited_at > when: - when = self.last_edited_at - who = self.last_edited_by - comments = self.comments.all() - if len(comments) > 0: - for c in comments: - if c.added_at > when: - when = c.added_at - who = c.user - return when, who \ No newline at end of file diff --git a/forum/models/meta.py b/forum/models/meta.py deleted file mode 100755 index 3dfd3e8..0000000 --- a/forum/models/meta.py +++ /dev/null @@ -1,89 +0,0 @@ -from base import * - -class VoteManager(models.Manager): - def get_up_vote_count_from_user(self, user): - if user is not None: - return self.filter(user=user, vote=1).count() - else: - return 0 - - def get_down_vote_count_from_user(self, user): - if user is not None: - return self.filter(user=user, vote=-1).count() - else: - return 0 - - def get_votes_count_today_from_user(self, user): - if user is not None: - today = datetime.date.today() - return self.filter(user=user, voted_at__range=(today, today + datetime.timedelta(1))).count() - - else: - return 0 - - -class Vote(MetaContent): - VOTE_UP = +1 - VOTE_DOWN = -1 - VOTE_CHOICES = ( - (VOTE_UP, u'Up'), - (VOTE_DOWN, u'Down'), - ) - - vote = models.SmallIntegerField(choices=VOTE_CHOICES) - voted_at = models.DateTimeField(default=datetime.datetime.now) - - objects = VoteManager() - - class Meta(MetaContent.Meta): - unique_together = ('content_type', 'object_id', 'user') - db_table = u'vote' - - def __unicode__(self): - return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote) - - def is_upvote(self): - return self.vote == self.VOTE_UP - - def is_downvote(self): - return self.vote == self.VOTE_DOWN - - -class FlaggedItemManager(models.Manager): - def get_flagged_items_count_today(self, user): - if user is not None: - today = datetime.date.today() - return self.filter(user=user, flagged_at__range=(today, today + datetime.timedelta(1))).count() - else: - return 0 - -class FlaggedItem(MetaContent): - """A flag on a Question or Answer indicating offensive content.""" - flagged_at = models.DateTimeField(default=datetime.datetime.now) - - objects = FlaggedItemManager() - - class Meta(MetaContent.Meta): - unique_together = ('content_type', 'object_id', 'user') - db_table = u'flagged_item' - - def __unicode__(self): - return '[%s] flagged at %s' %(self.user, self.flagged_at) - -class Comment(MetaContent): - comment = models.CharField(max_length=300) - added_at = models.DateTimeField(default=datetime.datetime.now) - - class Meta(MetaContent.Meta): - ordering = ('-added_at',) - db_table = u'comment' - - def save(self,**kwargs): - super(Comment,self).save(**kwargs) - try: - ping_google() - except Exception: - logging.debug('problem pinging google did you register you sitemap with google?') - - def __unicode__(self): - return self.comment \ No newline at end of file diff --git a/forum/models/question.py b/forum/models/question.py deleted file mode 100755 index f916e65..0000000 --- a/forum/models/question.py +++ /dev/null @@ -1,336 +0,0 @@ -from base import * -from tag import Tag - -class QuestionManager(models.Manager): - @staticmethod - def create_new(cls, title=None,author=None,added_at=None, wiki=False,tagnames=None,summary=None, text=None): - question = Question( - title = title, - author = author, - added_at = added_at, - last_activity_at = added_at, - last_activity_by = author, - wiki = wiki, - tagnames = tagnames, - html = text, - summary = summary - ) - if question.wiki: - question.last_edited_by = question.author - question.last_edited_at = added_at - question.wikified_at = added_at - - question.save() - - # create the first revision - QuestionRevision.objects.create( - question = question, - revision = 1, - title = question.title, - author = author, - revised_at = added_at, - tagnames = question.tagnames, - summary = CONST['default_version'], - text = text - ) - return question - - def update_tags(self, question, tagnames, user): - """ - Updates Tag associations for a question to match the given - tagname string. - - Returns ``True`` if tag usage counts were updated as a result, - ``False`` otherwise. - """ - - current_tags = list(question.tags.all()) - current_tagnames = set(t.name for t in current_tags) - updated_tagnames = set(t for t in tagnames.split(' ') if t) - modified_tags = [] - - removed_tags = [t for t in current_tags - if t.name not in updated_tagnames] - if removed_tags: - modified_tags.extend(removed_tags) - question.tags.remove(*removed_tags) - - added_tagnames = updated_tagnames - current_tagnames - if added_tagnames: - added_tags = Tag.objects.get_or_create_multiple(added_tagnames, - user) - modified_tags.extend(added_tags) - question.tags.add(*added_tags) - - if modified_tags: - Tag.objects.update_use_counts(modified_tags) - return True - - return False - - def update_answer_count(self, question): - """ - Executes an UPDATE query to update denormalised data with the - number of answers the given question has. - """ - - # for some reasons, this Answer class failed to be imported, - # although we have imported all classes from models on top. - from answer import Answer - self.filter(id=question.id).update( - answer_count=Answer.objects.get_answers_from_question(question).filter(deleted=False).count()) - - def update_view_count(self, question): - """ - update counter+1 when user browse question page - """ - self.filter(id=question.id).update(view_count = question.view_count + 1) - - def update_favorite_count(self, question): - """ - update favourite_count for given question - """ - self.filter(id=question.id).update(favourite_count = FavoriteQuestion.objects.filter(question=question).count()) - - def get_similar_questions(self, question): - """ - Get 10 similar questions for given one. - This will search the same tag list for give question(by exactly same string) first. - Questions with the individual tags will be added to list if above questions are not full. - """ - #print datetime.datetime.now() - questions = list(self.filter(tagnames = question.tagnames, deleted=False).all()) - - tags_list = question.tags.all() - for tag in tags_list: - extend_questions = self.filter(tags__id = tag.id, deleted=False)[:50] - for item in extend_questions: - if item not in questions and len(questions) < 10: - questions.append(item) - - #print datetime.datetime.now() - return questions - -class Question(Content, DeletableContent): - title = models.CharField(max_length=300) - tags = models.ManyToManyField('Tag', related_name='questions') - answer_accepted = models.BooleanField(default=False) - closed = models.BooleanField(default=False) - closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions') - closed_at = models.DateTimeField(null=True, blank=True) - close_reason = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True) - followed_by = models.ManyToManyField(User, related_name='followed_questions') - - # Denormalised data - answer_count = models.PositiveIntegerField(default=0) - view_count = models.PositiveIntegerField(default=0) - favourite_count = models.PositiveIntegerField(default=0) - last_activity_at = models.DateTimeField(default=datetime.datetime.now) - last_activity_by = models.ForeignKey(User, related_name='last_active_in_questions') - tagnames = models.CharField(max_length=125) - summary = models.CharField(max_length=180) - - favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions') - - objects = QuestionManager() - - class Meta(Content.Meta): - db_table = u'question' - - def delete(self): - super(Question, self).delete() - try: - ping_google() - except Exception: - logging.debug('problem pinging google did you register you sitemap with google?') - - def save(self, **kwargs): - """ - Overridden to manually manage addition of tags when the object - is first saved. - - This is required as we're using ``tagnames`` as the sole means of - adding and editing tags. - """ - initial_addition = (self.id is None) - - super(Question, self).save(**kwargs) - - if initial_addition: - tags = Tag.objects.get_or_create_multiple(self.tagname_list(), - self.author) - self.tags.add(*tags) - Tag.objects.update_use_counts(tags) - - def tagname_list(self): - """Creates a list of Tag names from the ``tagnames`` attribute.""" - return [name for name in self.tagnames.split(u' ')] - - def tagname_meta_generator(self): - return u','.join([unicode(tag) for tag in self.tagname_list()]) - - def get_absolute_url(self): - return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title))) - - def has_favorite_by_user(self, user): - if not user.is_authenticated(): - return False - - return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0 - - def get_answer_count_by_user(self, user_id): - from answer import Answer - query_set = Answer.objects.filter(author__id=user_id) - return query_set.filter(question=self).count() - - def get_question_title(self): - if self.closed: - attr = CONST['closed'] - elif self.deleted: - attr = CONST['deleted'] - else: - attr = None - if attr is not None: - return u'%s %s' % (self.title, attr) - else: - return self.title - - def get_revision_url(self): - return reverse('question_revisions', args=[self.id]) - - def get_latest_revision(self): - return self.revisions.all()[0] - - def get_last_update_info(self): - when, who = self.post_get_last_update_info() - - answers = self.answers.all() - if len(answers) > 0: - for a in answers: - a_when, a_who = a.post_get_last_update_info() - if a_when > when: - when = a_when - who = a_who - - return when, who - - def get_update_summary(self,last_reported_at=None,recipient_email=''): - edited = False - if self.last_edited_at and self.last_edited_at > last_reported_at: - if self.last_edited_by.email != recipient_email: - edited = True - comments = [] - for comment in self.comments.all(): - if comment.added_at > last_reported_at and comment.user.email != recipient_email: - comments.append(comment) - new_answers = [] - answer_comments = [] - modified_answers = [] - commented_answers = [] - import sets - commented_answers = sets.Set([]) - for answer in self.answers.all(): - if (answer.added_at > last_reported_at and answer.author.email != recipient_email): - new_answers.append(answer) - if (answer.last_edited_at - and answer.last_edited_at > last_reported_at - and answer.last_edited_by.email != recipient_email): - modified_answers.append(answer) - for comment in answer.comments.all(): - if comment.added_at > last_reported_at and comment.user.email != recipient_email: - commented_answers.add(answer) - answer_comments.append(comment) - - #create the report - if edited or new_answers or modified_answers or answer_comments: - out = [] - if edited: - out.append(_('%(author)s modified the question') % {'author':self.last_edited_by.username}) - if new_answers: - names = sets.Set(map(lambda x: x.author.username,new_answers)) - people = ', '.join(names) - out.append(_('%(people)s posted %(new_answer_count)s new answers') \ - % {'new_answer_count':len(new_answers),'people':people}) - if comments: - names = sets.Set(map(lambda x: x.user.username,comments)) - people = ', '.join(names) - out.append(_('%(people)s commented the question') % {'people':people}) - if answer_comments: - names = sets.Set(map(lambda x: x.user.username,answer_comments)) - people = ', '.join(names) - if len(commented_answers) > 1: - out.append(_('%(people)s commented answers') % {'people':people}) - else: - out.append(_('%(people)s commented an answer') % {'people':people}) - url = settings.APP_URL + self.get_absolute_url() - retval = '%s:
\n' % (url,self.title) - out = map(lambda x: '
  • ' + x + '
  • ',out) - retval += '
    \n' - return retval - else: - return None - - def __unicode__(self): - return self.title - - -class QuestionView(models.Model): - question = models.ForeignKey(Question, related_name='viewed') - who = models.ForeignKey(User, related_name='question_views') - when = models.DateTimeField() - - class Meta: - app_label = 'forum' - -class FavoriteQuestion(models.Model): - """A favorite Question of a User.""" - question = models.ForeignKey(Question) - user = models.ForeignKey(User, related_name='user_favorite_questions') - added_at = models.DateTimeField(default=datetime.datetime.now) - - class Meta: - app_label = 'forum' - db_table = u'favorite_question' - def __unicode__(self): - return '[%s] favorited at %s' %(self.user, self.added_at) - -class QuestionRevision(ContentRevision): - """A revision of a Question.""" - question = models.ForeignKey(Question, related_name='revisions') - title = models.CharField(max_length=300) - tagnames = models.CharField(max_length=125) - - class Meta(ContentRevision.Meta): - db_table = u'question_revision' - ordering = ('-revision',) - - def get_question_title(self): - return self.question.title - - def get_absolute_url(self): - #print 'in QuestionRevision.get_absolute_url()' - return reverse('question_revisions', args=[self.question.id]) - - def save(self, **kwargs): - """Looks up the next available revision number.""" - if not self.revision: - self.revision = QuestionRevision.objects.filter( - question=self.question).values_list('revision', - flat=True)[0] + 1 - super(QuestionRevision, self).save(**kwargs) - - def __unicode__(self): - return u'revision %s of %s' % (self.revision, self.title) - -class AnonymousQuestion(AnonymousContent): - title = models.CharField(max_length=300) - tagnames = models.CharField(max_length=125) - - def publish(self,user): - added_at = datetime.datetime.now() - QuestionManager.create_new(title=self.title, author=user, added_at=added_at, - wiki=self.wiki, tagnames=self.tagnames, - summary=self.summary, text=self.text) - self.delete() - -from answer import Answer, AnswerManager diff --git a/forum/models/repute.py b/forum/models/repute.py deleted file mode 100755 index a47ce47..0000000 --- a/forum/models/repute.py +++ /dev/null @@ -1,109 +0,0 @@ -from base import * - -from django.utils.translation import ugettext as _ - -class Badge(models.Model): - """Awarded for notable actions performed on the site by Users.""" - GOLD = 1 - SILVER = 2 - BRONZE = 3 - TYPE_CHOICES = ( - (GOLD, _('gold')), - (SILVER, _('silver')), - (BRONZE, _('bronze')), - ) - - name = models.CharField(max_length=50) - type = models.SmallIntegerField(choices=TYPE_CHOICES) - slug = models.SlugField(max_length=50, blank=True) - description = models.CharField(max_length=300) - multiple = models.BooleanField(default=False) - # Denormalised data - awarded_count = models.PositiveIntegerField(default=0) - - awarded_to = models.ManyToManyField(User, through='Award', related_name='badges') - - class Meta: - app_label = 'forum' - db_table = u'badge' - ordering = ('name',) - unique_together = ('name', 'type') - - def __unicode__(self): - return u'%s: %s' % (self.get_type_display(), self.name) - - def save(self, **kwargs): - if not self.slug: - self.slug = self.name#slugify(self.name) - super(Badge, self).save(**kwargs) - - def get_absolute_url(self): - return '%s%s/' % (reverse('badge', args=[self.id]), self.slug) - -class AwardManager(models.Manager): - def get_recent_awards(self): - awards = super(AwardManager, self).extra( - select={'badge_id': 'badge.id', 'badge_name':'badge.name', - 'badge_description': 'badge.description', 'badge_type': 'badge.type', - 'user_id': 'auth_user.id', 'user_name': 'auth_user.username' - }, - tables=['award', 'badge', 'auth_user'], - order_by=['-awarded_at'], - where=['auth_user.id=award.user_id AND badge_id=badge.id'], - ).values('badge_id', 'badge_name', 'badge_description', 'badge_type', 'user_id', 'user_name') - return awards - -class Award(models.Model): - """The awarding of a Badge to a User.""" - user = models.ForeignKey(User, related_name='award_user') - badge = models.ForeignKey('Badge', related_name='award_badge') - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - awarded_at = models.DateTimeField(default=datetime.datetime.now) - notified = models.BooleanField(default=False) - - objects = AwardManager() - - def __unicode__(self): - return u'[%s] is awarded a badge [%s] at %s' % (self.user.username, self.badge.name, self.awarded_at) - - class Meta: - app_label = 'forum' - db_table = u'award' - -class ReputeManager(models.Manager): - def get_reputation_by_upvoted_today(self, user): - """ - For one user in one day, he can only earn rep till certain score (ep. +200) - by upvoted(also substracted from upvoted canceled). This is because we need - to prohibit gaming system by upvoting/cancel again and again. - """ - if user is not None: - today = datetime.date.today() - sums = self.filter(models.Q(reputation_type=1) | models.Q(reputation_type=-8), - user=user, reputed_at__range=(today, today + datetime.timedelta(1))). \ - agregate(models.Sum('positive'), models.Sum('negative')) - - return sums['positive__sum'] + sums['negative__sum'] - else: - return 0 - -class Repute(models.Model): - """The reputation histories for user""" - user = models.ForeignKey(User) - positive = models.SmallIntegerField(default=0) - negative = models.SmallIntegerField(default=0) - question = models.ForeignKey('Question') - reputed_at = models.DateTimeField(default=datetime.datetime.now) - reputation_type = models.SmallIntegerField(choices=TYPE_REPUTATION) - reputation = models.IntegerField(default=1) - - objects = ReputeManager() - - def __unicode__(self): - return u'[%s]\' reputation changed at %s' % (self.user.username, self.reputed_at) - - class Meta: - app_label = 'forum' - db_table = u'repute' diff --git a/forum/models/tag.py b/forum/models/tag.py deleted file mode 100755 index 28b9e57..0000000 --- a/forum/models/tag.py +++ /dev/null @@ -1,85 +0,0 @@ -from base import * - -from django.utils.translation import ugettext as _ - -class TagManager(models.Manager): - UPDATE_USED_COUNTS_QUERY = ( - 'UPDATE tag ' - 'SET used_count = (' - 'SELECT COUNT(*) FROM question_tags ' - 'INNER JOIN question ON question_id=question.id ' - 'WHERE tag_id = tag.id AND question.deleted=False' - ') ' - 'WHERE id IN (%s)') - - def get_valid_tags(self, page_size): - tags = self.all().filter(deleted=False).exclude(used_count=0).order_by("-id")[:page_size] - return tags - - def get_or_create_multiple(self, names, user): - """ - Fetches a list of Tags with the given names, creating any Tags - which don't exist when necesssary. - """ - tags = list(self.filter(name__in=names)) - #Set all these tag visible - for tag in tags: - if tag.deleted: - tag.deleted = False - tag.deleted_by = None - tag.deleted_at = None - tag.save() - - if len(tags) < len(names): - existing_names = set(tag.name for tag in tags) - new_names = [name for name in names if name not in existing_names] - tags.extend([self.create(name=name, created_by=user) - for name in new_names if self.filter(name=name).count() == 0 and len(name.strip()) > 0]) - - return tags - - def update_use_counts(self, tags): - """Updates the given Tags with their current use counts.""" - if not tags: - return - cursor = connection.cursor() - query = self.UPDATE_USED_COUNTS_QUERY % ','.join(['%s'] * len(tags)) - cursor.execute(query, [tag.id for tag in tags]) - transaction.commit_unless_managed() - - def get_tags_by_questions(self, questions): - question_ids = [] - for question in questions: - question_ids.append(question.id) - - question_ids_str = ','.join([str(id) for id in question_ids]) - related_tags = self.extra( - tables=['tag', 'question_tags'], - where=["tag.id = question_tags.tag_id AND question_tags.question_id IN (" + question_ids_str + ")"] - ).distinct() - - return related_tags - -class Tag(DeletableContent): - name = models.CharField(max_length=255, unique=True) - created_by = models.ForeignKey(User, related_name='created_tags') - # Denormalised data - used_count = models.PositiveIntegerField(default=0) - - objects = TagManager() - - class Meta(DeletableContent.Meta): - db_table = u'tag' - ordering = ('-used_count', 'name') - - def __unicode__(self): - return self.name - -class MarkedTag(models.Model): - TAG_MARK_REASONS = (('good',_('interesting')),('bad',_('ignored'))) - tag = models.ForeignKey('Tag', related_name='user_selections') - user = models.ForeignKey(User, related_name='tag_selections') - reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS) - - class Meta: - app_label = 'forum' \ No newline at end of file diff --git a/forum/models/user.py b/forum/models/user.py deleted file mode 100755 index 9502416..0000000 --- a/forum/models/user.py +++ /dev/null @@ -1,77 +0,0 @@ -from base import * - -from django.utils.translation import ugettext as _ - -class Activity(models.Model): - """ - We keep some history data for user activities - """ - user = models.ForeignKey(User) - activity_type = models.SmallIntegerField(choices=TYPE_ACTIVITY) - active_at = models.DateTimeField(default=datetime.datetime.now) - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - is_auditted = models.BooleanField(default=False) - - def __unicode__(self): - return u'[%s] was active at %s' % (self.user.username, self.active_at) - - class Meta: - app_label = 'forum' - db_table = u'activity' - -class EmailFeedSetting(models.Model): - DELTA_TABLE = { - 'w':datetime.timedelta(7), - 'd':datetime.timedelta(1), - 'n':datetime.timedelta(-1), - } - FEED_TYPES = ( - ('q_all',_('Entire forum')), - ('q_ask',_('Questions that I asked')), - ('q_ans',_('Questions that I answered')), - ('q_sel',_('Individually selected questions')), - ) - UPDATE_FREQUENCY = ( - ('w',_('Weekly')), - ('d',_('Daily')), - ('n',_('No email')), - ) - subscriber = models.ForeignKey(User) - feed_type = models.CharField(max_length=16,choices=FEED_TYPES) - frequency = models.CharField(max_length=8,choices=UPDATE_FREQUENCY,default='n') - added_at = models.DateTimeField(auto_now_add=True) - reported_at = models.DateTimeField(null=True) - - def save(self,*args,**kwargs): - type = self.feed_type - subscriber = self.subscriber - similar = self.__class__.objects.filter(feed_type=type,subscriber=subscriber).exclude(pk=self.id) - if len(similar) > 0: - raise IntegrityError('email feed setting already exists') - super(EmailFeedSetting,self).save(*args,**kwargs) - - class Meta: - app_label = 'forum' - -class AnonymousEmail(models.Model): - #validation key, if used - key = models.CharField(max_length=32) - email = models.EmailField(null=False,unique=True) - isvalid = models.BooleanField(default=False) - - class Meta: - app_label = 'forum' - - -class AuthKeyUserAssociation(models.Model): - key = models.CharField(max_length=256,null=False,unique=True) - provider = models.CharField(max_length=64) - user = models.ForeignKey(User) - added_at = models.DateTimeField(default=datetime.datetime.now) - - class Meta: - app_label = 'forum' - - \ No newline at end of file diff --git a/forum/modules.py b/forum/modules.py deleted file mode 100755 index 9c07233..0000000 --- a/forum/modules.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import types -import re - -from django.template import Template, TemplateDoesNotExist - -MODULES_PACKAGE = 'forum_modules' - -MODULES_FOLDER = os.path.join(os.path.dirname(__file__), '../' + MODULES_PACKAGE) - -MODULE_LIST = [ - __import__('forum_modules.%s' % f, globals(), locals(), ['forum_modules']) - for f in os.listdir(MODULES_FOLDER) - if os.path.isdir(os.path.join(MODULES_FOLDER, f)) and - os.path.exists(os.path.join(MODULES_FOLDER, "%s/__init__.py" % f)) and - not os.path.exists(os.path.join(MODULES_FOLDER, "%s/DISABLED" % f)) -] - -def get_modules_script(script_name): - all = [] - - for m in MODULE_LIST: - try: - all.append(__import__('%s.%s' % (m.__name__, script_name), globals(), locals(), [m.__name__])) - except Exception, e: - #print script_name + ":" + str(e) - pass - - return all - -def get_modules_script_classes(script_name, base_class): - scripts = get_modules_script(script_name) - all_classes = {} - - for script in scripts: - all_classes.update(dict([ - (n, c) for (n, c) in [(n, getattr(script, n)) for n in dir(script)] - if isinstance(c, (type, types.ClassType)) and issubclass(c, base_class) - ])) - - return all_classes - -def get_all_handlers(name): - handler_files = get_modules_script('handlers') - - return [ - h for h in [ - getattr(f, name) for f in handler_files - if hasattr(f, name) - ] - - if callable(h) - ] - -def get_handler(name, default): - all = get_all_handlers(name) - print(len(all)) - return len(all) and all[0] or default - -module_template_re = re.compile('^modules\/(\w+)\/(.*)$') - -def module_templates_loader(name, dirs=None): - result = module_template_re.search(name) - - if result is not None: - file_name = os.path.join(MODULES_FOLDER, result.group(1), 'templates', result.group(2)) - - if os.path.exists(file_name): - try: - f = open(file_name, 'r') - source = f.read() - f.close() - return (source, file_name) - except: - pass - - raise TemplateDoesNotExist, name - -module_templates_loader.is_usable = True \ No newline at end of file diff --git a/forum/sitemap.py b/forum/sitemap.py deleted file mode 100644 index c0c60b5..0000000 --- a/forum/sitemap.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.contrib.sitemaps import Sitemap -from forum.models import Question - -class QuestionsSitemap(Sitemap): - changefreq = 'daily' - priority = 0.5 - def items(self): - return Question.objects.exclude(deleted=True) - - def lastmod(self, obj): - return obj.last_activity_at - - def location(self, obj): - return obj.get_absolute_url() diff --git a/forum/skins/README b/forum/skins/README deleted file mode 100644 index 5565fa8..0000000 --- a/forum/skins/README +++ /dev/null @@ -1,22 +0,0 @@ -this directory contains available skins - -1) default - default skin with templates -2) common - this directory is to media directory common to all or many templates - -to create a new skin just create another directory under skins/ -and start populating it with the directory structure as in -default/templates - templates must be named the same way - -NO NEED TO CREATE ALL TEMPLATES/MEDIA FILES AT ONCE - -templates are resolved in the following way: -* check in skin named as in settings.OSQA_DEFAULT_SKIN -* then skin named 'default' - -media is resolved with one extra option -* settings.OSQA_DEFAULT_SKIN -* 'default' -* 'common' - -media does not have to be composed of files named the same way as in default skin -whatever media you link to from your templates - will be in operation diff --git a/forum/skins/__init__.py b/forum/skins/__init__.py deleted file mode 100644 index be6bd4f..0000000 --- a/forum/skins/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -from django.conf import settings -from django.template import loader -from django.template.loaders import filesystem -from django.http import HttpResponse -import os.path -import logging - -#module for skinning osqa -#at this point skin can be changed only in settings file -#via OSQA_DEFAULT_SKIN variable - -#note - Django template loaders use method django.utils._os.safe_join -#to work on unicode file paths -#here it is ignored because it is assumed that we won't use unicode paths - -def load_template_source(name, dirs=None): - try: - tname = os.path.join(settings.OSQA_DEFAULT_SKIN,'templates',name) - return filesystem.load_template_source(tname,dirs) - except: - tname = os.path.join('default','templates',name) - return filesystem.load_template_source(tname,dirs) -load_template_source.is_usable = True - -def find_media_source(url): - """returns url prefixed with the skin name - of the first skin that contains the file - directories are searched in this order: - settings.OSQA_DEFAULT_SKIN, then 'default', then 'commmon' - if file is not found - returns None - and logs an error message - """ - while url[0] == '/': url = url[1:] - d = os.path.dirname - n = os.path.normpath - j = os.path.join - f = os.path.isfile - skins = n(j(d(d(__file__)),'skins')) - try: - media = os.path.join(skins, settings.OSQA_DEFAULT_SKIN, url) - assert(f(media)) - use_skin = settings.OSQA_DEFAULT_SKIN - except: - try: - media = j(skins, 'default', url) - assert(f(media)) - use_skin = 'default' - except: - media = j(skins, 'common', url) - try: - assert(f(media)) - use_skin = 'common' - except: - logging.error('could not find media for %s' % url) - use_skin = '' - return None - return use_skin + '/' + url diff --git a/forum/skins/common/media/README b/forum/skins/common/media/README deleted file mode 100644 index 3376e75..0000000 --- a/forum/skins/common/media/README +++ /dev/null @@ -1 +0,0 @@ -directory for media common to all or many templates diff --git a/forum/skins/default/media/images/blue-up-arrow-h18px.png b/forum/skins/default/media/images/blue-up-arrow-h18px.png deleted file mode 100644 index e1f29e86334ce72d2d28989a133571d7bf53a94e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 593 zcmV-X0{6iqad+$V|KR(Q{q;Ok;ua!jjQtuI1z7)O( zySE1i5k-TnUMhU^!Fth&L`=(4hnCB&mew0>atrF^~@9muPo$nmJ5BNLwb>CS+ z;4aaxR`*WD1Hfmk^?b25_^vW#;gMP0a=;-lw8uKYF+TucXlk2wNsBS@}pFD ztaavBN$@-;DyO5Dqi0!d9a~=U7;O0Ayiuq>#Jyi<@Hb@35~1ra$v5dmgDzqB>^+=uOM7b5+>fY}+kwy1R`cV__*wFuQ!Bi@#VE~BJd f7UnWh{5Sjn&bP0xmAf5500000NkvXXu0mjfU!M$- diff --git a/forum/skins/default/media/images/box-arrow.gif b/forum/skins/default/media/images/box-arrow.gif deleted file mode 100644 index 89dcf5b3dd40fac0e6afb0b1a7ff899a059f923f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69 zcmZ?wbhEHbWM@!dXkcJ?_wL=lfBzJJvM@6+Ff!;c00Bsbfk~#Pf92`7{EJz*0#eqW WoE7iinDij`X5pe+YFj-S8LR>Nkr%B1 diff --git a/forum/skins/default/media/images/bullet_green.gif b/forum/skins/default/media/images/bullet_green.gif deleted file mode 100644 index fa530910f9dc11fadaa2314f72bd98f29df39daf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64 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 D3>(Ui diff --git a/forum/skins/default/media/images/close-small-dark.png b/forum/skins/default/media/images/close-small-dark.png deleted file mode 100644 index 280c1fc74e47c0e7d1c68d6f356eb22eeba7a2de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^d?3ui3?$#C89V|~1_3@Hu3NY7ShRS_jG43c?mKYe z;M6!dxb8-^+kP+MX_sAsp9}6ArM>V3CjzZ7^A^)I5Q~ t!yzC*Q0L$Zl?Eqn$0Lca5`Jx9W=NmTc;}pLNdZtBgQu&X%Q~loCIHsxKFr1QCT0q{1{MYeDE)e-c@Ne1ia=5ZCX&{{Hy&_tW!N_ZKfc zpObUM#pTWAs~3xk4w#ty`t$F>lBGXhy}DLgdpr1Q#zqRd1{MYe;g^zIfZEtgJbhi+Z*Z~+S_nO6;N1-r z;wE)e-c@Ne1ia=5Z4(qXDwR1Wb5`Fd-okU zaq{%lYd1c8`uyw9U!Xizkhgxu4WI-^NswRge+Xc>*St3pD5mS_;uunKD_NtRfsJRE z&YnFcvL4forc1XpAK{H{IrvG{>z#&4h|Ds+W&FE$GCZx(SSr0JY6i#_Pgg&ebxsLQ E08gA+X#fBK diff --git a/forum/skins/default/media/images/dash.gif b/forum/skins/default/media/images/dash.gif deleted file mode 100644 index d1ddc507fe00bd654fce38ac8552793aa18c9966..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44 wcmZ?wbhEHbWMN=rXkcLY|NsBAY10&cvM{hS{AbW%00NK<0~50k11p0y023w&(*OVf diff --git a/forum/skins/default/media/images/djangomade124x25_grey.gif b/forum/skins/default/media/images/djangomade124x25_grey.gif deleted file mode 100644 index d34bb311615b1378a672a828c7a7916490cd882b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2035 zcmcJOSyz(>0zk8Y5oHk(5d(s_FbFhAqNt4L16&YNCyID%iyA#v9i~-V)T#$7C{?Rq zJuXmNkX;Zk3t36XzAs-E$W8(YK|~TDELE}gFw-9~_w_#9r@MFGo{ViLN+D5@_t6k? zub_>}Y9`ZKyBS?Q+zuw^CB28p=9m6l=^h>P&(87W>M^fRs?m>(j#(W;9ErkUvGq!o zR>z=aV9@3qVhSZRzIguQM;cEA4PH>{`)!UPyVLdOr%&oW6O}KX^iRvR21>7B_K!bg zpuy#NEl_HdeI}XK;2M6dGg;OB7NH7sx`ycjiOOJXqcVp_-!Mh8P9}%M;d7*l9dn^o^Yc8JiXo6#2L{zfi^DzK#p>;|ITX6Se!BxS zS=nOw+`D&V4qvF$^jqyzo~TDG>y;|lVi{d1<;qn?yF=A))|stRQ2&y_<|)*2U7tjw zV~V8YUSW?!VYCi#Byx?(%9SZ)x_-xyo5JBc-5#D?H9GEn-bvP4>_a1?Mw^2xQ-LN+ zBe7ec(5U;2FS?oT(KkAyXb zH`<+SiGsov4vvg6M6xClb-?9rrO;i&BX+lk$mV$`rZ`gN>v8YfiAm6G<101ow4OKP zUbVqQ?BTjSuXPq%Yd5pISJ261cQQEjo#Yk@y{?1ASAq*s-`cubDGW-lki_O|%{D4etT9^j7JEC5N#je{GL^~hpbMnVVNY!b z@p%VHZ?SpC-cHTTm>h#mB$`;Qbq9D5VJ`EU_H44c4@Fu%*g{g$2m} zjre&46atBcB>!Fb`w0kg0fIg2-$QN?-a;-U9a~C|Sx_l#$$ zbyds`pGKe0LOZIh;hTXQH~7?2Jo0 zAKTtHp2*){xDdLxDX)5Bq$d9S)rRYTt~R1BZu8%arq9oL7S0X{cVZ83Md|CWuc5Ww zgHJrm4n{311;Egli>`(nMilUQIqb4)5Q?cl#}=HzL03S&F5J5ZvF3I&1iAmphxib7 z=~(%y)r?(&s;zbaOiB%VcyqB)a3LW*6`!N2T5$*vtPDAu4Lr&i{1t{hUIbJv$v&)4 zc!CfB!4I<5zFha<24-Hg2z@rDMTRf&8K%(xp|Jl;8yyb7(z29dO~7 z0?>d2d_u(#9&?g)BczhRg5UXUk{R}HU+hrKk846$t{)2uvfo5}`X_+FT_r3*q@K(Q zIFy3^Nem&SdwmdC?f@$3a69--AQ=DME>cj0|A&0oy86<nZyuyLVuwr{IGXQux+DRXY@2U6(<)cxduLt8LR@#Wa`O=WAre>^=26DJK^^h~Zenh_Qpc_eE|a>K3SC}>hGS%%baA>Rzm6~eB6s0c`oTN0US zfK?FULsI-Xr|IOSn-WhZ6RhFiUYWj6SlS#V&y{WdZMyPn->wo=`JS}ytYDdcZ9-8+ z#g^jc^%g~Q?0bcL=f~+^%9ggo{bjwMjFH13QK!~qEei?la)%F0L$*X*t*SoddGxEM zWy4mba{slN#|^%bl*nZdHaOy*)Xwd`S5&UbXN;^SSGFdf*{A-}K2y!otWP}=A9U0{ sv!XO(598i6?6_>^sSNjGbB$7Sdi(Nfq+XETwht`+l3E>&L_&7_7sn(m+5i9m diff --git a/forum/skins/default/media/images/dot-g.gif b/forum/skins/default/media/images/dot-g.gif deleted file mode 100644 index 5d6bb28e56377b0eeb80899222aa3290ec2a3a95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61 zcmZ?wbhEHb1;oomohA-cw8MruKF$f7>W?=Zo!hivofRLHNli}wd9fr@0yBS{oImf`r!T=CJ zObo<=KYvmfSa>QJq}1IQ{xNkh{QGMS5(Wq$!Uiw`?fv_wh=H9yhCxi_BLl18R|YAy zzYGlQ%?$tlTLT0TVFP~usbb(1@&ju6$nf>=e}=c;7#aR?|7H-C1iI?46+i&7;IWyL z;n$xU20l?+1~CPo=06M!Uw{_>X8zCc{xt`~yO&=Xm{>Lg1Q0F*xPh8m83e@j8ARki zGJO8U!0_!K1H&(%gWtd9WO)AQ6T^RoY6eEe8vp@>#en~UKxelz2uZ60@n?olzZn_6 z{|9LXI{!5n!^+`mIW?f>FASf4GBSJvI{OzR z1H&<(HAFtjse0v3qvG*Lj!k<6yW@2D$#+OV00*L7y zBZtO!W_$i{sO4^#Rs-O?>`EBV-VT&i$$;vm@)9CGk^eM*?-}6i0Jdne+|V2 zxHvw3_{Z?+(@RDM_T7w3%nJ!=1_6KoVp+N8l7OGV`-jpW1oz1C@m=Tm^ZxZW7V#J0 oz$F3z1Q6r@|Nj{%0RRC80Nya-9-e3d82|tP07*qoM6N<$g1t^w0{{R3 diff --git a/forum/skins/default/media/images/expander-arrow-hide.gif b/forum/skins/default/media/images/expander-arrow-hide.gif deleted file mode 100644 index feb6a6187c2742ea8e516244f139e7946ed757fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmZ?wbhEHb6k!l$Xl7tYOG_&#C^&ZP*n$NM9zTBE+}u2E+O#ug&iw!Xp8*?C{K>-1 zz`((v1Cj)p!N8&|aME-2UW?afcmGe&$YV~Jr(qS6`f6R+>scREmz$PdzB_la&4mZ% LT2lR!I2fz}g2F4- diff --git a/forum/skins/default/media/images/expander-arrow-show.gif b/forum/skins/default/media/images/expander-arrow-show.gif deleted file mode 100644 index 6825c56ee42f0184d66c0fe954d7fc4b6f05e850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135 zcmZ?wbhEHb6k!l$Xl7tYOG|5RZr;3k^RZ*c9zTA(V8Mcdf`WVZ?*0G&p8*?C{K>-1 zz`((v1Cj)p!N6i7aME-2(x+KmpRPH4k6ma{w6t6)bw%IW-N%f4X5Wr&{_cHgU%a-) Votr)GNqpOrH0{qn(_mt-1^|9hF$Dks diff --git a/forum/skins/default/media/images/favicon.gif b/forum/skins/default/media/images/favicon.gif deleted file mode 100644 index 910c26660ca2088729309bd9286403237c68f020..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3918 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 diff --git a/forum/skins/default/media/images/feed-icon-small.png b/forum/skins/default/media/images/feed-icon-small.png deleted file mode 100644 index b3c949d2244f2c0c81d65e74719af2a1b56d06a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 689 zcmV;i0#5yjP)(tky!*UETcH-TCU7SrqEjJM#?B`_A)!p7(kFf9-P@=@15kkTkGK zgFusyy#KECqZzRdBLb=P?$(kUP;>kYTDeG&{|a+iOiRbI6nbQ)j#7bOf>iF=C+|_py<&Fo1F5cC*iEM?zZGC{ejNg4LWYp=S$L6Qaby6y zp$+F`250{%tU{Lg$5*ROH}y!1UKJS4*xqd7P(Y3JQF?lrnf?yerr%&6yGXLG1ur*B z{$&R1@Oj)yl@%rY5rh?j(j10Yz_DBs`AKFU_QnB;)(aqQmGi&ieOS|21^NP9UMpa< zU&p!f6RZ6Owp^X!EXA=0SbN&h?CrQK%Q3(=YBqqHD^9ZUM0Hxt-6-KT;>lf@j?Z+v zHm(}`>85I&E<7e}oz?6UwjAogowzGO8kSN7+2`b^$Az9L{K5*ko87EV45LT-`_##3 z>d3AGh@>=mbg34|6}+-gT9N+6Dr@44VEl44O&{&|w=qpbzC#iWMKa?5)>tI+KLQK@ Xq0QFqn(9Yl00000NkvXXu0mjfZ8tBj>^LJ3~~S>i&IO88=qln{V-q zOM40!3-puuch|@DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5X*aCb)TzBu@{r~^}iVZzqfg(&L zL4Lvi8J=!8@B;EgJY5_^DsCku9AK6xWM-3k!OUU6z#qV1KKathOF(%BPgg&ebxsLQ E0Ke)mAOHXW diff --git a/forum/skins/default/media/images/indicator.gif b/forum/skins/default/media/images/indicator.gif deleted file mode 100644 index 1c72ebb554be018511ae972c3f2361dff02dce02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2545 zcma*pX;2es8VB%~zPr=ibVMCx-JQ^BhLDAsK)^**h(ZDp9YGuzZ%~j!}+w%FI;|aC7){7CdVvG)P{bng1y9Te*f}~*`1kQl$jwb z$tlW~rRS!X?#xfm_&6tTdp_`cjgYwbRFLNdoJCN$S-yhg`ZnC-yvedRSmOh%;Y`Gl6bY$Z-}#C=#F4%9!I1b zWQ~f+9P?;vhCxWwlwl=lrWG|7IYo;{jjmzJ5R9?f>n%-d@>kLINUc z4wM5dAO;kq<$}Dk{2-u0$I6@2N}&cUx9nmV1dYc8jfC}%=F9WCg^OQK9C6poh#2!A z3^EU*UFZvS^)?bu3T?J;@Ahb~%I?+@4!l5!*TjC}GIslNan-RCrrd~PdHYnNLJk+m&`$Y+NV(e>CCu%R#_8GqY4cv#j`#uRWdsg9DxWy(?oOvgCU}&@jy%c!H&-Q zqXJxajAtmQRoRa9V-RFXXh-bK*;Fum{BjpkYQGX~i@OZ^Dx0n&H}kvGKqQ?w(6iGXu_g08T|_hp#ZvFzIwKF*a=oMJ~3UGAjZ?g}GOxm44td zXoyYrU*I=y*vHv89hkYH(v5R#wc)BC3dZJKb3K)f>zaM3%JP(mpecViP0eKKYf3zy z->jx_mc?mCtPEvCQ?uppk?eLJt}_IR7giW%Jr)RyI!+E-voIs*lXI*z`GQc_&D#X( z{6G};HPYj6O|$lXxBJeDaweqa{4L=tOZCjTI^&UOxXg})LRG_cr^B9Rqt(i5ORbQX zq`_xCRsH>xEYY%&*Nyi#{S_JZNlTm#K56`RI%7^amom;*h90Si&g1CfaFV3D|a!`3Y-GKKbL*KSbl z>I96`TR@CqPJl(>QqB~RvK~-U)`e`l4LIqj+IU^~yyIe*|BRVB>4Bup%j{tLdKz4j zY^<8P8m~GRGz*yv0&-RJE+-keJ+%m3wNeopzsltWd->eWmBVwUr)pX` zK~CD<;~Z*Uy3W`3+MrEYxm5qYQ!z%YI;y7DTG`UVH0;@{M{!B&id_}3DBQ?zsotuR zEGLdRx25nLm%-wjlnEi;-aN_1S7???rO~WgA67jjr&(vRa3y$u#kqJbeKnw z{!T!1li9>M+sJ6AUe+*9d}2uGjhzd z|L1Rtp8uTGYyZoQ*`DS^m2dw-X{a)l+3m?ncvn^+O>)hdd3(hMtlhkRGns{<8c0I! zDDjpmwtj?@!6kA|iu3q+Ai;@JR+ zfk+ln&YFC{4bhK6IxVgLs4W%^8Lk`qzWU*L>yq0A3;l}{!wKZ!ue)C)SKI)9dl1hl zhIRLV@8E}rwvE{gX(}$f6x*k)_`*Ijt1=EU-Ls6-(phomeQBgtUs z5Xz~Cd*nE)Ac!0i4ep}Z1AugMB(&F?)#CU{Qc{Sp^vKsdL}vRB30H+Bbzrn`M##H3 z{W8dc_mDroEE+p8_}mnJtzZ4!RNe)zhB)Ds;S57nYSJxtek>^~&(7B+N5MPf2+2xx z5Dl&4X|c@f{Kd|z1r+N|$DmsoVp*3yOdxT^J^-VAk)Z@$4^XrPrFP-Co+MXZ+KJ(W z{JNYvraLLWA;&tRhIKOvhW|HC|L-dLvAUF(MG0(Nl?4tB{RzN7I(}Cb%hwN{crFC8 zji#aJElKvDFV+&VI1V?oUMA>*kto0^;3W8FQBSZ|{ z$v~TqE=(8DZa^i$^oht&h};P1N&wMXorKh*Z68gPV&ouy>%f36Oqkwemyeas$Qbz# zV?7Jy%o7KY6^I=P@eCji%W`o5sf(5hySYo9$l4e2`(hIV_?=H-#R6}0$WVA|*(K@3 z=5?@RlcLh(meW%A4)hGzcvEpm(_w?>zhL*i&s9$2>r zAtk{8Cia|+Y+V!uX9BtpXoF%lswuRKsM!pSs!?yhlCy!269K0|b M?FSZn2B>%I-}ej|s{jB1 diff --git a/forum/skins/default/media/images/logo.gif b/forum/skins/default/media/images/logo.gif deleted file mode 100644 index ab690de2a1c9679f225d80560cf5e06f3ed3cab0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2114 zcmb7<`#;kQ1INFc?}kmzHeo{yGuL*6N$J$gW^>CWm!Vv8cjzehrOw<6kC^+A;}XMS z9hWqvT#jUODI~OxD7lnMhwgPeub%(l`TX$y?frVaKMZ?2s{=tJfE6$U{MhR1YFJoU z4je8LiFS5&h(zLFDJkW6ypodA(yd#)QBgD+O_H5mT3RZVNZ!4BCvQ8_ z_=gUO#bT*c8W$IbL?S&rJmy@t@grT|{Qq zh0K_oTq=kM3b=(hHB}l|Sa{x!2he3@YU}FjC zB2wPg7;jqo?5x@bucWDJKv=WFQdv1#(Jmiiu3QehM=d1M%>Y4%J=mrPWvvHdlx41Y zW{_!hs0(#@wV*PUiDa7^E4ZQ3{n41+MvK%~K&xm6t$i^2870Ve4Dr-LN8G>8!a$)k z#3;u#TMRXp#cJ*{wMpP_nt9h$(PgvvlCQ>%z1`Gcc+knd#Ox>?ik#ISUP7 z#GoF#j`(()T+*;pki7QOd2ZU0?Y^JHaexWK{?0W{_Z}wUF4j{TvesPlwUA3#aZB+{ z7)YI}-H*93NW2`4MCuAPrZFhsV^1KID+PK(qmxx9HT5C{j_CnlC~n(<81SRAjmOZ zuX!fW#(kJC!;9E#B$#R1gk4Z3$`g2l&BG|F95wx6RDusfYIzZrf6-9!GW!ob- z5RpcTnp9Vz>-kOzC5~=XgNdh_RbUiRA=>DONAs;-F0M!f=HIj;uSn5mhkNdLM+7b5 zttN!evt6#TvEIC`GlR*a77ZMsw_@D)ox!xX7K_MBKlj;Xn&yVn*X$4(SGL98H(cy5 zf&^ht)zxu~uYy^YePFgdeCt_N^KETM`kCuam-B|;BBo=y&wza0g25i{{z1s9;c@Wp ze&a9Xi9#Ln)oD&b(J~Q9+94y}IMmm!fo9$8Q7O&LW-g-snULrAq*>Yf|&p0Y!q^tJn8k z?tt)jCuQEOXsK&=#eAh|voSsiUN2D@OH%{qg&)3si-LPzC+cf{8u&i1dX~zyBg*eu z-bm{Ad)$|uB+vu0aLRKWOl$|hrg5OXRto?t> zPs;`j#YI+Ta_ntCcl=0Gh^xqT($7(jnEs-ezc#2&^Ib?Ke5DdG))S zm~`)wK)`^@k;ex?RTinBr$R8jl4C5Hx|F5vo~7Fvlqbk2V~kOpuBSdP8*NKXa5^7XcD8 z4QWsdI1r7C`5UFWdm`=0ARYoS9W+*=jQTz@E6d4j+#8f)PaQ1c(kmPH2B$~@riysB z$$I-rbHGrePNSaPD|@pR$87%nr|^CQ@#pJ3qd^@(#WO=IiuPXGuTau6W^wK!GvRWYySSZdh?2JAdxm} z4@L^i%LZu%cDL5Y!_|r^6v_Ot5!AE>=`9+=W)GB#c ztC+B+x0S*yDC=ru#=O9JeRGiAsbOSn}iGDZgXt#=z(6UXyd@4U( z9p+K1+}PylDVYqeCpV~jZunedKO8Wcsk6P?$beXTjnyac40o+ME*)eE_+<1U&jvr7 z+Dy~YW2K+-em&vy#b^9N_x0_KjWC80YkmdO^^qoUe<5Hc8J!dr=&hPb4JX4f7B{LM z>bdE^oQoKI)chgd_$2z3TiqSyiUj&8t0wh@7R^~vNn3ykwMuQi;n{m$UugJo7o*wY z%44O6^@w_RU$I_(C>NM#?PUynb#!n{pa@KQ2Ee)H7 io>#?{QxAKS722~IPR}q^pN0&Mw&!{uAI1ZK^?v~_GK-J^ diff --git a/forum/skins/default/media/images/logo.png b/forum/skins/default/media/images/logo.png deleted file mode 100644 index 6a250e35b34cbe9113e3a62d17eba05d05c83888..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2081 zcmV++2;TRJP)00003b3#c}2nYz< z;ZNWI003-IOjJbx008gr?~jjw(EZ*psMAVX6$2C~zj0000MbVXQnLvm$dbZKvHAXI5>WdJcU zFEThUFgb%jHT(bo2Lee%K~!jg?OBPEqc{vThnq756B@|1A-n(ok1N~qO=!}S%xrb7 zs%AnXOV+av%Z4;Rgvg&Z;8pZLkpCJj0h!K4QJkm6@$+FUc8A-OQi6Xt%-^$d69qud zrxd9=oqguv19|t$ZM&498}Rn8vU-6$Am@8()7>#@-rKCLQb-rhd811lAoD5p>156A zaQ9oKkShLu{5?SC&%mNI{nR#%&ima)DWqNC#`giy7FByl+f(J+Bwkd-4HEuxPp6Gi zNSIuQ-vI>Yx~sL`VdQ_vKPShM-9{;-TM&@1CIbW`XK$8LCHH9fpT7JU80bnNT~y5d zO1ejDObukN7M4ufREgP(aGf_uIm3K-Pf>JD*4P@zxDXI3a7Hu0+wgWPQaf+h<(JZZ zU}PH*nX~?uEn`~*l+2O4o36`JlaaE9%_4i2x67|7C)fJeQQ#g!GhCw+_UcT9a+6)uG_ly+sOBy=u@=MQ8&dWkv+`CBBPl`GVBERwcyH z5Xd_~gxk}F0jV{)g`}F+q-I+RQ(ZlT>26s`7`lMzH+|#+c~FF(0%CWE)oruXT}M>4 znC`+{Sm=^_q2_NojwA1y?keBdp|y;|3$5@p;b*~4cZeSvNGLVgQU^5}_r)OH!Prc$ zGq;=ng4Ik08RR(W@ZnX-jx>+ByG=?etf*&OYHu`8i|G!ww(_ZiM=F0}WHMwvSAN4* zNT!9`SYV$xs%>UnYEFIf(_LC`J;vY=#f0?8p8j)>c@g9?{nHjgR9e^F9mXLO5&DipB* za$E!=3NWj48ecQqEF z^h|5j;;(@KlzpWQI{Pejwko_X<5n1y_QC6hMmtm?INrLqj`j8$SL(gng>9DnVBWWP@tLX2)6p(*jrgM=V0C^$Z#*eV-zMJ0l4e`w%+CuuVA44fw zXac%NR~MS1l?uP2j;ih{GBZ4-%8&+v`)D2l88UTG_K%^1LPqY^4E^m}D)j#XZ?0ibzk}2RDE|wMJc%MKJ>CmGMiea@KrJR%nT+qU74< zTzQ$d!t_qwImOWPM6{DU$%H>+`6pFolsWG@fWiNDIUQpDE-x3=HGL1iB92OuF=d2M zRq{{+HC^0xWl#9E9L^bm2@%e_4n*EtUP;e{6I$%kSOz>M+cwFhBvV(MjMRK)ew)Sy zp$Ps_(nFWd-}Q^?07Zg_rJ4<@9h9na@Kj4mfZgZ3dt}a>y}nvq19F53@)CYZaSxMY zJDL#Ai%P~CWa3bxJdc>a^BI&e(V!{`AL zgpYOR)bp+a5k};sPZF_6E#CQ|f!q>g;!r8vG7t|@L>=pg zmi0WuKtKY4u>&0}b+EK8y>fK}xMN^2NCsUm(j8SbO~%W?Q1aJD(stgQn}IYm)Az5s z@QXr_!NN+WQCMOT7?}K21M8e15b@4Y7xTln*hlzrHUleb5mhqilq&97xv2oqBe=+& za}|h3RByXb3?oEZ(tzpwjk|J59iA%@4GGC&{t2xU!@Uhk4vd&gerq0o&aFT~T5Mmw zMYLww>UJIV7ZBzp8k^$oP8y>jTswDJD}baok0pFnmG00000 LNkvXXu0mjfmiX8& diff --git a/forum/skins/default/media/images/logo1.png b/forum/skins/default/media/images/logo1.png deleted file mode 100644 index d79a627174b08ee90776540abad2e76f28909652..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2752 zcmcguX* z1E?4wgA2<ibF5B?oZ9u^18n1*~xFBuz3-<%yx3)#_ftUE+Qo`d)qPK67?2S(r z0zbj_1R*mtDSopsN*FIl+1W1i27nS38t4}z)g^qLp7y;lhYt7a0jSl3L8?S)fQbgp z9GIgd0|RA`d?7_d00faod_JKJpnwt1uSD7Z2a|-B1yhe(GKu=epgmLHL<<`k8h-xr z#Rdb>9oZ&!^VeQMo#r!{pg-pxO=%%wiP-5se;)6v3??meND?n)RA!O@$<(3FLWQ+$ zOH6FdOV()2Oid#y4ULJnFZpl4eYEx}KeR}+M$Gk5S zqnm}0W#xsXD4uMIn&y?8n~Sx|d}IA$=JVCuRjV$XJ}sknP^i=`V|K{Uo}IS~d2w;U zw>#2*{<@gaLWBV!hwNSpj+t{B4+|*Cyj*>2K%9^omNa`xrFm7gG6I0)*hvDZW~2n9%+MzzWk{Tzj9=GEY?tX{kpHp1&$#)S9m54a>eAI8%Q-XV);&;*9apqP&PXYp>>%+b;E;=0xznd$s;o zNiW9QI{j^mKNAYvs+E&f1KTijaz9V7?^FoLb3{g=Tb7$1e){vBP^z+Zns=jU$thc( zw2kd%$grJDyMNT!)Sct9dhWuKlacvPp`- z8Y8&LnwaoBc`{&GJVY{O#mCp`P@%=Q3Yaf}s2B6C79AD5YR#P~V>m6)bOTOOJli=W zPNp*HEQD667cH}?Hg{}+gdgp}93YjUmp*9c`gj8_aBZ0sW8avY zX6NiSFgF7CK79K0^heY)4c1V_P-sdc?>r6RHTL$J{dk^GMMm!9(tmz0dWka-lQA#W zXdf`;=ExOJv+V3vx`;W^wrWq(KyLp>!+{ofPxJF9|Ku2~4KPy`&%r!MfevTFv?hRH zP^Pv`=qS9h326iT7wKo$i=g2*B^lbLre~#DL(I(n28>2Gg^v4`z>bmBWVf432BE}! z=%dyMYS3f}wFCnuO`6FNZ&g-=WBwi8-KIYYS~6hF|43W|sCKWJaqiix73<%aT>M#5 z?iKC8)_XL&u;F5WRi;7`VW01Uz?7QJJz;?DfTU)e2~pZhZ!ORA0JzhpA(Hd7nVDJl ztq(E=8|M-c?lGfz@4u1lb$BMrC2Om_dxO4-tz2^b_1KuqlAiJtXpSQ6`8qPSH$8nC zMZpy}rL*@|27`gFMY^W63My8YCbaRwy~}3>~>!x8!nLwhyfOZXVGBycPfMA^MtwF)p}uJ zB~ORB*G&5!yTZ<$OqwMMHLF_PJ&jGd-SXLoYICY?CVF(&Vw#m#{b%s+m#mJxx&FG3 z8EpzW20O+=4wK)eCMQ3=(LXxwIZs6*uopv5ROAkrE?rPBaxA;pgO}{nULCe zHva>TDb#W^s+&*5L4WaxR#7-B1|!KkpC9{0e>FF=@ssguLF9d|wA!E~;qk9j!Nb{V z724{=IXkjH?b#LE~)Ia~*I(j^ z&q7!0`jgh#H!;;L(ylgBpXh9_2S(;HM+P(Zgj)SipDbK@^n^bC=|1xLztn?+(cTs; zL9LTzC`o)-7zuSAeKT~#fv@{a-vaYz1u)j9(QBzS8#fk8^g^SuEFbTf!OCZm@e1Hz zk~G1k6;|w?^B68VecJwAmXgBAYOPakiL>pz(w!`at=gC8Z#gHN?r?plOG7Gru6NLxkY;S=fF2z|YbO3%qJzr|R*`t+_ElUU&&^^{glpQP5mHpLzxP@1#e01HOQOj08Vo z)cfHL0^U{i&=SYTLGdn3&Ju3SY#4p@t=L7hVjDBl94p&Pms&GXe$dl$W59QduVdfz zK_DwVt5H0(psqg{TB3EPB_MT+v zLYBDN^U+I)`GZ+Th^mq2lakVw_C)=`4cD`4R&i(Ib*)VL&w?yA@5bAw@19`~{B3xY kse_>K@2>xA`@bf7AU)z?-rE%2I=lr1p}dH|I)5bN->?*N_5c6? diff --git a/forum/skins/default/media/images/logo2.png b/forum/skins/default/media/images/logo2.png deleted file mode 100644 index bd3cccd9f47793f86864cd068621ab07198b5ff0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2124 zcmcIm`&Uy}7Cw1j9(f?ogb*T6 zR7xF)f`B{(Do|8Luizj$s9*~MRt2>X1!+Z~1*!Hr|H7>K;heqp+UuPCt?ygs+owPh z9z-=}83O>QA;AHWSUia>UkH!w{6lRrED-njZSe!3sdpXe0oyJ}doah{1$l3>n$0jEa145Xm{l=`0 z1LOGW4g>)b$0!*Rr7zHbv%EOo9Z|$Fo71*7zJWCy1avV4C^u25yk)w+l|hG~+NP%M z5{YQYU@)jZ|6}ppWJ?dj(b2ICDyt7~YcEeqbnFp!&dzSWetl`j4p9%R#_ovkDqA); zH&^*-g-KjDYY(ZuwsyF`U!+y!<>j?5(BX=hvuhN^Uk??}&Q{n9Y4Zjg#C7RoPy$Wi z{*X1KD~4_Y4Z$7tC2Omw9FAC!5Acv66G_Q!o6uY7#pImab!WWHb~w?Z0Yl``%a$|q z+>?+r?Ts74s#CZ+-0m|}TfQ#NUh)?>(Z$J0GLxDv2Bn)2Z1H?F;I?WNsG~%EmS7Pjk|D)ZWt7A)huHmXOer^gBJH%1K9jp$`#$4x zb~w%Q?@pblQ{_46k=OZ}+xH(tNCYC#!ac#N_JOZWKf7U{DDkgy2`d$SnL*NS*Lyk0 z%meWH?Wzzz0i!T%m4v~F`SGnry4R#TIUJ1vJ3A0IipV;YRq&)YZGt}EW(eud{ zE;wK6z~y^1FP?Bu(p|Q0-uZ9VP{;H9U`&*-j-@vuhP{16BhsxE$`{EVKiAp{q~8uq zr@u2SsG*&O$?=ivqQiihvx^*$fSkYwVxu7!GvA=hX{$Q^|2i*Q5IBWivcFZ#_XbQb<4Md2}~BtK?7vNsOe@; z8A7rc8k5Y~=#YTZ36{>eteYjoWt1`AYnuXw~+sOqb zwxMU@^F4f%7!EBh=q1a|wAiZ_D+JOhUX!JJa2*$iS7#3pi1YLFdk4gKV7j*>o*xr) z>u|a52rtb9z` zL5qYJFB}IWKha&}+a4CAY57e4)62=pAG~t$p>#RjdtqsQ+_oJzW`~!f=cC-qY`D zk$bnEefjm5qa|4Mzj(KDJvR>pqy+7to)KGbH~EW!4A`pNaZ zoo-AVwbdl!!x09)Z|CpRy=ESskd{ID`jXDLfL?hW9X-=U$GpHyAgw3%zFZB{#O zNiG-P)g6G3eOSK97L?xGE4MfIYy#f`>zXaygC;%Ei~H&H6ZB;yzeOe+$gdv&7;t@C zrZ*)T@!lqtLa&6cr>4Y#2wypjY&gET2c|!nXb&Nw67mG0^=3cjK+>=HMrGJ-oxxOB?TeD9oE*q;kn@I-k&}bV{vSuh^`1%k6r<;IMd1E+ZG{w0g~MyWjA*d`_?1 z@A$la&+q&HfPsR8goTEOh-(y!jE#0PICFAzz_X{% zpFo2O9ZIyQ(W6L{DqYI7sne%Wqe>k@wW`&tShH%~%C)Q4uV7~+8cVjU*|TU7DOk(4 zt=qS7(BTJr4xw7TUm@^~T z%(=7Y&!9t#9!C>oFt6t5zwd>cgV;`7JySDAyxO3~?&AYen-@tu`Sa-0t6$H)z5Dm@NG7S| zk}d||0+o_zM{=bwNED(Iku7HVjkApih7e}UBq diff --git a/forum/skins/default/media/images/medala_on.gif b/forum/skins/default/media/images/medala_on.gif deleted file mode 100644 index a18f9e8562941254941a446efad3e6edcb651d9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 957 zcmV;u148^qNk%w1VJrb40K@E)v5}!; z41e42_PDkdcy;l$Dm3n3(BTJqC>oFt6n{%wd>cgW6KueptkMXxO3~?&AYen-@t5f($n3;DZoGDB*+&RA}La7-p#9h8%Y2;fElG zDB_4DmT2OMD5j|5iU_pm;)^iGDC3MY)@b96IOeG1jy(400+o_zM{=bwNED(Iku7Ha6Bh$gD&q69SR=%bKED(R$@R%+>`m}aW!rkr-_ z>8GHED(a{Mlxpg!sHUpws;su^>Z`EED(kGY)@tjmxaO+st^xGw>#x8DE9|hu7HjOW z$R?}ovdlK??6c5DEA6xbRBP=zwb*8>?Y7)@>+QGThAZy4+ZYo f#w+i<^ww+dz4+#<@4o!@>+in+2Q2WwApih7u&Gpl diff --git a/forum/skins/default/media/images/new.gif b/forum/skins/default/media/images/new.gif deleted file mode 100644 index 8a220b531225397b6a304918e4d96f6196ef40a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmZ?wbhEHblwuHIc*el+@5|9!VKPrU6JO0wzv{&J_sfTWzkfci3%c&b^ZDfVC#}&> zyOaNZ`}}-T?z6u1zh6H-?MZpollt+%s=r@9J?->=+L`dQ-S^kCd)M4KzTZCopv3i7 zg#7c#dEf6|d^NB3$Neksx6gmOcH+A&vz~S(UH9g@mudETVb^R-1c%-`NuBSmGx$*^t}v|N3{XpZ=QLxvghB=@852m{z+->`t|DZla{DoFCJX;;C#~TaW_r#|NsA29T^4|DE?#tJ3t3Sg5rdM{YC?W zNN`JQTYE>a2m^CyU;l)Olls+yCQqLcG;PM53A6e*r27K<7?(+e+V$BkQ0bc=>K)=6 z>S?AMvXf0cM9U_`CsbZ({cMkrfKVO*0bx^n7M2ip!4S?%Tu1x7I766NnV3TOd0ax> zT^02BokLcHZqTpCs*6-yL$WVW?v z$*r&`a5&o0$QRlWP#C1jBFZZwJ5}J(3P%A63#oz=VNXx?YB3g7+`6(-c+I>yOH7zf SWil{ucTQ5<#GoL+U=08@?DshU diff --git a/forum/skins/default/media/images/nophoto.png b/forum/skins/default/media/images/nophoto.png deleted file mode 100644 index 2daf0ffd4333c90aafd71479510144bcdcb16c79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 zcmV;p0!RIcP)FMR=<>BGs+}zyR+1b_A)zQ(>&CSip$;tWo`Nqb^+obycyPRT{LUB1#`*2@<8tPF=iD3b$&izilao_AJ$Uu| z?T7EI;9G2Ni9S*S|C71nPeS~@YXtLGZ#Xme_@@>8G%0p2sX6212og-Y1w$?e z!WtwvbPJl0Aa)A^G6(_^hxshQF(4>p2|9paHcPMx2&P29rJ}2$!H> zp6f%wU$+bD9?CDf;J*mCI1D_PzD=;|;mna;B%E*;B%w%FK=_dsy!3SVseTRsf;O0PA5l@7S3xZ$It;!i#Ky zUwupv47dxD@P=FMLIa$I+=l%s0_x#ZiV;DS09Qn^j9pByOm?A=ICBWn)?Lr=Eg7SN z03L<9;aJ866<{Oli{Qt&ARUsBlRXUURcV2;m^$aahm^dfY4!Hqk3O{)q1D z1TF3(2qBkcAppN3{)S!D3NGw#J)8~}C44zdYXvndi+CRUT0sljYWS7$P%CI+|Ayli em8wo4&)6FRqy5_K=O4cS0000${>eZ`v@813YY~Q2faPbmo5s9gt%|d4ho>o57Mp#$&^RgUuZ5eg+dZJYZnp<>ZnO zn8@79#>ir^py2~!6AQbMoJWI#lOrpaM#=_*i%myaxx_eX7A$CT;APg}>iKX$rJbGI pjAPFPVa3)-5*81xR0c3Hu?omAG~5VaYGz`Q2)lD?YqkS}H2_zIYl#2= diff --git a/forum/skins/default/media/images/openid/aol.gif b/forum/skins/default/media/images/openid/aol.gif deleted file mode 100644 index decc4f12362124c74e1e0b78ad4e5d132621ab23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2205 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 diff --git a/forum/skins/default/media/images/openid/google.gif b/forum/skins/default/media/images/openid/google.gif deleted file mode 100644 index 1b6cd07bd8b9f27175e0a03be3b5849e0f5479c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1596 zcmc(e`#aNn0DwQcU}GKMxn#>^B<6OWQKZt-cb3xBiE^HYQf=ZKSu)*APi@FdDnu7l zbE$~JN>R#|+lE{hiz(BRl~d+uOl9Xe=bt$55AUzjP!`6aB*XlLd;L`$MA0-=oh;_@%=DSKzTW5!kkg02oxN<-;QgzZXZ6@(M)5 zb-u1@<^vWqN`U%R3CtOJuojJt|Ec%yo>_yZ%MV%ajx`i>ysy4d0^mKeNIQ#t@2y*KMj}jE8i*m zl#eQZ7!1Pfn72wr)$QwY6gabm(O6$Lylw3Pd(s%KbU5crNh3{eeZxI4(dJKB1MUAN>n;QZCCkQs_tGtJY-^iC3ja3x9v_uTP?vFVW;}s># zx;OS=;!{FWer7!3y~sj6t|9~xWcTkC-QJ+z*` z{$kU`Oy-`7hp(oZDFCEubef~t-M)K#*_S^K7T>g7T^A0(oK7oIN_s0RehD8}s1*i- z0sK!m=+Xa`J^uB-PXLSoRAEU$)j~-M#?mcPT3yt{hn6u4gKCOf&J$L|DbuOJmz+s9 z2lJ2J?sjAok}A_-F35;rl&1P$i@IJDD5Bmxks6yO#s#L4K20(2&;kgjBXbWq$Y}&> zCc!g3Y<~;U$CQlDX2nU|3Dx218gg&b%2GehXilrp4#P1y;weqVUjQptQlB1c;VO7e z@*D^wqyiQ&MP@@Eiijj!C6&AUPa6q7&lm^MToqj2ny^P9>WX^Ttd-e`;&k}6HltTz=X|A>@zzv6@ z)2r$ZZK19Hq1s>pg(Wg*yF5bqcpgSu2*Z=3Y48rhsMseSGm6D#RWnKSz*rI2&e%)U zhJ)uMj-*j*Cq6a|SR^kuis=outMPl7vPf8@-OF`fK(;t_tEV6%zOcxe#-=20Mq7|L zi=0@wEQshFjSRBhL&)v46Z=EWNGr^Y7(cjs9|q}uirjP>UklMq_Cn}BpIZ=OxlIZN zrqgmZ9Daq-5mP(tkggoG%l1Mp5`!YX9P+{9a@vc{UA@ux9w!5<$J7Qsxz)kjp9U>O zdMGwqZ?ce!P4?kRO}wMe2<(jAw{y`J9zkIp$bd;9jpjy5e7h8h$r8hU6K*}g{&bHR zc4&^sGRyCwh1g@leXv&EK^8KfI43fLjtGZ4%_yBJq-Q6Ii74-1r$U?ItVA?Z^o7I@ z6Gx_VGVMkkya7VbaJCw^O!RGWg$&GOOC(&Bu>?}_7>IP{%ivHGBI}%WA6YI2+3M9H z%iJLj*4d~I--NgTJ(9t@qodNU?AaV`YHlKR%UVir5C+OujBse~Mp}pFlaUEl5;MVK zxnv+FK^_1to@fbJn^<{1g0s+?k E17=sO82|tP diff --git a/forum/skins/default/media/images/openid/livejournal.ico b/forum/skins/default/media/images/openid/livejournal.ico deleted file mode 100644 index f3d21ec5e8f629b77c77615982cef929802fbde4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5222 zcmdT{3s6+o89vBPQIq*$1QbbvAP7Q0Tpmk!l@)pHf>>S> z1vbL6JXf&Eq~nt$W+Y}?NhYbg%X2}TX`y3UlPS(H)68fPIsMMP%d)ZvOQtiO{(Js= z?m7Sef9JdZJ&(JD*bxy~wQ3b%;$cU~E2vFPBC#hV6@5-lg8iE%gba#Un|TxR-jjq} zb3h#KnTHdU;W5$jSK%T=Pj@H?K_Lo-P~nPOqSb0qGXv!dp_JW0@nc==!i$LGD~{u9 zt~8U?B2Fd~qvpC~M^KA`gqqWJF*i|=E@%ujnuad%Of!pb5`P(QC7kR#SP2OTzQ<#W zlv%8aIKD~feX!6nCX`OuQ922|4;{CsbQG#}pj5FEW=E(mRL;B7LWEq0KANYW^3Y=B z_y|vmH;?ldeDaRw*8J(~hC!qOw?4H%Oa?Y1JnqbNZuG{_4-W8zh5g(k>k33gQDw%FD{ne3XB@ z!rC7_g|Gdhw<&R;HMK*r`+|J;KQGI_{V?zIn&?P3mLE&uo!9m>GUrS3pvy(U5A^kP z_$(c0u8#D!b_R{U=43cu$bYTlSjYsNjhYF)s`QQZ*3Ky}xtxmjy4jX?u^{kLVeo`r zO$S;h4E5!2dRRN72QywCwpkgq;m=hECwm&HvGsd>T}g=BENAdX&yl^G;15ZD@oDXe za5~)ny+KtH;%e1SDcr|-+q7@ZKZGT0tS19Bm$;2T93LRj8^{4y675bB zwk%H%+bJ)|KhfTK`uexou|aVjGo#E;Z%!+~BizWLXGzMgwI!$9Yp#x{^ivH+c7UV2 ztG$yM@p8QPk{Hi9qZjA|_iy0IrBz^V2FDGCt7!c=X2YVB&%j+s%GRZq6}$VIQ&2P#@0_gE zNAUFwKQH_3h_#F3ZUXmN_F>UpAnQ~Ky-mq~NZp*1ER$dEt(TrWr;qctLx_#Sm^+j7oj?A#I7DC$ zaD!T6s6Sj3{L6HyM1HcisHVO0oT2v1d(D5PMI|R99BoZLz$4vBrg+7t)3*@)h!oupL+wwg_YH%9vj*4aIjHXba4{8xkuc);A<= z{dZS2HK=KK!_1Gt{0T^;r%|h@D@A zwEWI*^|gxqvzS+eyR}HSKjd>V18&q9+tQP_E(>?D2|U7;$hbAy$_UJGbI$ekhw(yN zQ(t@t+Lp`(@GUljJClQ+q->vynK|C(jk-g{A&xDnJEp9_2N%N}naK~`m>>4s;pgp< z9QJ=jEdleAH`nptjkB2FdOtgL+Y^|;w&WZ>d7<84e)0JS>Jtat2~yqPk^=D3P?xq0 z@f7|6Jern%&D$w>p*GAGyl#LeY+CZk`Lq2)w{GZkg^@2rdyw`F-&0YZ?HMmk^)y+7 zCvI74%WRnjCpgYpE3*5H!##ZipIx~q^<9GpuZi7A2hXs1Zk~!pO}{2J>4l}(OBYOw zFj0B(Bt6hCeb>`pT-SE@^z{x5U2Ln3-?S|8w?F!!Jf|8`_0G@Mi{w$ z=X|SDy7MOoto~1%!)>|A@LPpZ)J;^~NDC9o;+|ify5q^Z+~}r~bWFtv8#b;5N6F%T zh9Q2R{a&r|U)2@;IgyF6UTmI3tzX1!nST@^QP$V_qZVtm#9wTzwZCbi{LlWU{0Anp BEK2|Y diff --git a/forum/skins/default/media/images/openid/myopenid.ico b/forum/skins/default/media/images/openid/myopenid.ico deleted file mode 100644 index ceb06e6a3f0d88fb97cf10475a3062fb0edab33e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2862 zcmeHJJxc>Y5S@6ZrZbS)owhjA&;jnXfl*X745tmMB3MrBW$)n`RP3b417qd6J6bL?UM{+)q(3xlv0Ik%T7j-l59$8$m>#ard~jq(8yIciUu?j(!>?&WKIe?G5c$>` zV+r!H1WS-ha)=*H^!uZEl>O1BP8%xc=fconk~~4DvKCYWn4`b_pUnoZ788}%mc>uh z9HV;s)r}P~NWtqf_p5&HGjTJoZI|S8n)uf0l05g}rdhqaIBpnv^myAWbI*7E=&N3x z95xI+0zR;x-|08c&;6Ul#XdjZARV+no-wSN`};1(+>)AIisPc*P@H*_1Kd%ys#()H z>NUmL)tL6ccj9UxPF`{LG^Rc9JypwV>?^N0yvK~LBc9f{#^OA9dQUv#8Tz7oxfa(K u#=%<%_2}PpAb{bmUKcqz}))c5uC(7v?)v4a2P)ZNa- z@$&T2)z|&~{r~^}A^8LV00000EC2ui01yBW000GQ;3tk`X`bk)Wk@<6#nZYULKH{p zEx|?+kif!I0vIL|#ZMubBmjWH2OtmxIFVa~6JQ7!1CK!f5W#StOTv&C3=E8h2vI1s n+#cd5;2fT3B_0kF0v!+!GARoV78n&7dMN`JIW(4+BOw4gP{MS* diff --git a/forum/skins/default/media/images/openid/openid.gif b/forum/skins/default/media/images/openid/openid.gif deleted file mode 100644 index c718b0e6f37012db6c9c10d9d21c4dea0d0c01bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 740 zcmZ?wbhEHb^k$G`xXQrrKS$vIw-5i{JotZf!T-qt{~ulWe{RG7ST3!;kh({9A)7tlU&$%5*g$f^Ar># z6BXsynVh) zJ?osJf(s)D10z?npvQi179P(djPk7Va&pI%NfVlv<{V@&c*Q1S?C^%corz71;ll+1P9`Sd{~>qE3OQZcJ(5}z4)|O#`p@vJ zr9;Fsp~HjOs*vv^`}=;ISs7Cf1bMkUpV%Pi{6*$qgF{F5!;-XxTBi=%eG5gPtV^!wdin~r1kkVO&vN=8Ce+Xv z$*|MCqlY(ACp$%vPrNeV;U*4lo)c<`?yngdvl5)QWEV6rHbi?!)@MOEE;CkPT#L!!@77y7u K{UjJ!7_0#i2pVPp diff --git a/forum/skins/default/media/images/openid/technorati.ico b/forum/skins/default/media/images/openid/technorati.ico deleted file mode 100644 index fa1083c116527de7cdbf5897976aae8807fce878..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmeH}ze^lZ5XZl}d+sirdNzWcsg4x+2g0RLIAWPjuoD!tN}VeB7eq*vB1MXHX)Xi{ zAytZyMi86WScxK7SO|(gE|<@|cRuzut2sy&xMBC*%tj+A zE!c_l2H#`zaX;dYlru_mk^31KdcB@L9&W3#wIFp`YJOeP`OSr1{CK6O-`2Es@?E#T zy1MFK>-Ep~I=Vd7%e_s#J@}-Zvwh`X=4ClX_h=7BXW;)k1Ifb@+v7M5AZI7aYkiNm z$KjX;Qm=X2(~a>=Zn(6-IG8mv>sbkaBEroVrCFBdHr=3XM61uF&u!`5GI1u;Qf<+zMxU!sr1q{f@m!ic#&7x4 zjcDZqv{&NU85cGO2UiL7I^;$4kVpqJ@-E;pjlK(>l3v2Y;e5IS@q=)?(5+CX;*7LwCwnlxopJBahPURBFV+~&J eFF>coTp;}_7zqbJAQuX63TM^f{)_Klzq8-HK65Pq diff --git a/forum/skins/default/media/images/openid/twitter.png b/forum/skins/default/media/images/openid/twitter.png deleted file mode 100755 index 9a6552d18444ac98fdc776e6c58b794dd4452772..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3130 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 UY}!*r@&Et;07*qoM6N<$f<-Fwq5uE@ diff --git a/forum/skins/default/media/images/openid/verisign.ico b/forum/skins/default/media/images/openid/verisign.ico deleted file mode 100644 index 3953af931987b0e66c122b338dc352502564eafd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4710 zcmeHJc~n&A75@Q)fTGMB7?4e2SOip*O~H*}8$=cdnTIhNBRWh_BW_>?5imwU5pfq4 zQ4m>QjBTZ+CRIeErNk zREwwe2CX!zp{LmSu(HSiXS0Z~ELfW_hmFlL(pSOSItLB|b75<{0z+Ju!Pzbsp04@u z^IM5gez^!5o)68~JR~M1V)|=3XwNQ8?a>Ya%3;dK~By}6c*$o zzc7z#uYNYpl*u)SjcUZ3@pYK4t;Vd>gP50g5b0^P$e34y71<3~mHQrY z^v!hsAEG!C)5bMuezljdfeI&}&sTTWohhE|ksJA(uJTd-&Q zMO2ly;NXEa9IkGqoEFsAT)_K>+aNTx;izy9$B(q(h|rGX$9{>EKmIk&oIQ<;7cbz` z_Vf7oOgqlCbl~T$U*gkC?YPwb87^PGj4!TTMMqaVuHU?hTbV;iCum zZRbOL{qcZs;#f*}wrlz{`0xBe*(I;Sz zyL{rRJv~s#3{DZZtH%`9aNO9+=O$@yE9B}Ppw5xAUn^OeZyC|qoIL(nKmn&nYY>eL zKrf+{E*!VX7~r9ZuM^b@Gr+V$Li3f}Ym!#NDK|=*KfCmKlHM?d^N_SO`K0ZlR@aaD z`$@HgRh&}Pnx=3wq}{WbyQe^@gROXtjgE@>Qu-jEKP!rl1Z1YS(s35^4X=At_Fe%L7)Z2wJ zI=BcM$Zt(2XjtYnSb8HX6)sr~HNO7Fi=k7(q*OSR;1tv-=GQtZrfwBAkrlHYyo$=k zI88HxY21*dylU_ihyn*o`a+siMM#3?z2La9_bI5tty|5m@_$Kv=M-r`DWnsuDXI|SI(OnaFs5Rj zX)H<$bK-%v#3C6u8ZzR^Dh7HHqo*OR6YUU|4ygcb%!+EsW(iDpCu}sLU`Ao=$b{)2 zqYUx~O12syWYaUKC^j&d+|rIZmK*4)3nD=!V^Y|D)97J|C?PnK9W{j|5sikK_<-~j zB9Ma7re4g!anVfBnN3BRq6!uR)Iqc*BNYKUJ~~i(NLEqh;Ss1(xyk6vj3QL-oI(}E ztJRXtBFNMQ1%(&^QRrgWCG@7zAyK_e%IJBC60Uv0=A*yw|Kz_F$NuLuvWqkMvw2)i zo$zJE=5ZUFK~Q{S_xsb>KZ5B3WHsh5CkCG#~pZKK$?_l$V}GW#u_kRkqUX z`UyTd@da8=wc+%sYiMmfjdN#zfeRNd;rz$faN&FhZrr$v&dv^;YrTU@mu}(8l`dTS zyp!h7d$`$gpJq>*C%Yct?%liirkiHU``!4q`ysx0_@`GhR*Wg zL+$LnVne>U0!F8BBDJgQ#SO&zJnpsR{N}Sv)RGX5ladO5OX7h<2Rs-#nHmcwuE~3rz z2>~NUOyad;2ZtE}qZs8M)E9^dp|1)1sQ>G$Z=aRsiI#u(rfHU-9}N`$^h{weM0ms) zh?4E1IgP=fR~iiIb_PS5COyWGoN9OA+h%v^2+Yx zGJaHiGz3ONU|59!7au1(GXnz`A0HnV&|@H)n}q>L0s$9;ARnmIVdDT(f_z;3d|=N* zDLy_ze4rMf1_3@kMlc035Cr)7nOM2`_ymE1g8cmaK$@2aOo2_OfcXEPfdPgOHZw3Z X0PU5rU|_JTL0}LcBo2~?sfE!1%eOAT diff --git a/forum/skins/default/media/images/openid/wordpress.ico b/forum/skins/default/media/images/openid/wordpress.ico deleted file mode 100644 index 31b7d2c2b77c039342854190a90a8d8436992b47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmaKqJxT*n6op^J!coBi!TOa}allq&O3PWo1c^ULbO>qe21^@jt1Q7KOpyh+ge)Q1 zK|J4huRH_#zwbc3UEA;R9AO!H&d%roag-+O5 zO!N95T@?S*G}Sgw{mN!=VmhZ5Rzf4>LLtlrZUAWLgGPY+oVrG5xo^yW`xZU-Q@wk~@ zYxS@D)yH#t7kvCm!TtK*mFh-7(+TYB+*i5pa!nc|Jf3SU=XN{`fjrfux$lA7e}n0{ zlfCqFi>Z(M`wVVG>yKK1*9rZ1`iw}=W^iIUOLNU?<8e1$!1FrglCO_u)5YTUvK?eu yI~YIj#-~XLO;hd+o2#A2S^08*UB1qS`QCUE52vFxJ9}scm-~xFcCkL1j=lhFMR`a7 diff --git a/forum/skins/default/media/images/openid/yahoo.gif b/forum/skins/default/media/images/openid/yahoo.gif deleted file mode 100644 index 0f0eb8efe7eb64bfb49b71bcfed741c1193fae55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1510 zcmW+!eN5I>6h2Lvn6<^!)Xd5hDlfLZ?*XcrP9QW)@-4ktMwaM%)M8CbQ_0*l24$96 zFCxc~J~6$k=GUBkF2{?49T|aFsb(Ko&Z+fB)4rCSet7>lyXT(mKF@icXKLw`+wYh+ z8-~IXfYE>VhrW~BSNh&w=(_*{5C8)RfPw)q2!_Bg7y+YT0W5+gunbnfDmVa#;0PRp z6L1P1z$179&)@~TLI4N|fgmshfuPafpa@E!3@V^e6Ja9)AuxhOGcER$-0QkIY5^5?}#|%n$=&Pz;G-F(O9Af>;zw zVp*(+RdFB=#gRA`C*o8*h)3}xp2drJl>ib@0!d&AB0)t#6h%ptMMYHmf)Ke8NfPmj zhEWs@s6jQPhSi7~RSRlSEvaR-qE^*`I#fsMSe>X-^`IWrlX_M!>Qw`1Knp*qp;Bn<`OCEbSmdY9b-PCpKTi3^Piz?f8 zy?dyt^GwNvp40E_er`*8*@3T<(}!)EUr^Op+Wlj^>bA2Zu5HOanSSmqx^=>0X=Kzc=shR~H^k^D_Zi zm0opINA;Grd+-0WzzmB`9htoIiPY)gdyAhf=<2`k$K9pb0|sBWeR^%q^M`Ymzy0{v zAGS1YzH-Xo)hi!8cI)gxUElrt`{^%}>1j`mD86O+Bh%J=eAmCXEE%zRZiAWIIC00W zAKEkSsqYxqQb6nD8wb6-Eq;Dd#o_vaK4;Y0sB zlrb|aKY!qiCqsAY>3-`Dw8pcK>`aU~%LVGIDmHY4O%6#(r zGy7)b{WdzUcIZF3+Y{BVyg1;&!k_|&&Wb)U7@G{hd*@p61{K8lY zrQfzUZ=akxn9jU!Wo>@vjsXJ~W_|iavS?$;@p-quF|A^H-qD(SYOemduLbk@yBARv*JGzJSqW zdH4Uj&-?iX&Pnb)_vW6Q-0jh@w{~0$JK-|~h%skR?y5pa2$0O&vznEh|N+RO!h?sK@|HmRv z{h3y(TKyEJ2mNOMtn<{HAAUcKPwGpL&s#5zxz_#Zs$8wV{*2!`hmD)b^4H{i;qK%8 aqJF!3xj$$f?HydV+s)ZpZKm7Z3>&}3(53|d diff --git a/forum/skins/default/media/images/vote-accepted-on.png b/forum/skins/default/media/images/vote-accepted-on.png deleted file mode 100644 index 2026f3bcc50e2738bdb6c21f32ffb2a82d088e11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1124 zcmV-q1e^PbP)(98f962%urEyvrobTSI2iWDonJaRXmcCZ2&_7W|s$8;q zX78?p{;d3j=Jt6u zRf1NRn45~bKOeQloe<4k4F*a0^w988Pn>Cnf)+6fhvK8hS8!=&g-Tr5fO=!taU4$~ zOcn}~1dq~+P+Mn_{a3^epPXDNqV_QrDaOtjsGVmiri&cVy-8sMq#8b+xcl4la{1KX zd)90%K-Mw{%5_9>cd}5B8H|=?=ws;;*H`e>Y)`)g+x+z483yu`hh? z)vUt~N$7kH$t{g&Q6XMdNY^x24}P89!Jn~piFLVw3}%z-ZxONXwNtVCms$I=Hpt<1 z;>5`C2ui916R`wY2}KWfU9>D9Dg;Y<_4cY;b#?q^Z}exPXQRCee0Tq%=HACy;vCVa z)oQ5K>nMeJcUM{?j$?G%ZU0GpPJBRg?!=6hb@~7WeF-jmZ%z`A5yxGcdRvZYk@$u9 qnpoR$QRL8vDfll$;(wNZ1Q-D2C|}A%ZKM4F00002jDb`!&=tG_0s>$|K>*|`prJ6sL73(3+qcd@u04=FA87F=kXo2eKmZ_sFf2$; zPWA&zCIel<#Ldmk0CYVA$YsbuiEN3WpdiEV-@jQtefpFN6jJ#4^XDXHW@fmf00M{! z+3>`~M022FsXRP9Oq`sYV1r>6fM^&7@nIMgTp$C5g@r+ma0TLs@87?}%>)P_xCIFb z3Bo|lB^(?aU=1+CkRuHnMz)lXj}Igk4Pmg5nWK zgM9!HKul2A3d156+4UepK$wMv1;uh~hS${8fRioA43Jqsb)q0~fB<5G=1>+`+J?D) z%9JT^&HerTa5l0y4Aj-tf${>ww{PE&GbGq-fB*uAJJ7~2AO*0T3i2vCz-BNA)YjHA z05ccZaO6}4^z~N|8z6v~pcXs;rCV4KfV@~$RYfo!V1|GF`V}PzL1I7)9)r{X1Q0AA zT!9r*AO#=|po~*pU5(RlP?-Pt@dK;cg2@4U%(nbkq83~4GrM%MlNq) zt_Q^*$WcIgHIVxmBnA*bjL2RCmZUYn2r>s2cJMME1VFhHRs;jfeUu1=7iz%L6XYu( z0EK-K5dWAvcP;}!05PGJEj>WnAAr0L$}BL~0gGY=V7brm?%g}EuaFBtSO$Xz??)hR z2I3zuIe-8{v0&c3c_1f%lFyZoA3rjH3O+6_F0kui`2-depv(ty1ju)w_yQXE94J)^ z#Ltn<1PCBTY{dew=mzBvKWLT74YCM?K^B1kDEN?45GX8n0Pzwa{)%kQf&~j000M{+ zU%3+(7sm^vtby1Jh*f}C5Gn;S=spmi2jcxe{2E;^$d?NjE@S`*AVy+~WpV*P05LJp c7ytwq03Nl7Z}J%VEdT%j07*qoM6N<$f`!tbz5oCK diff --git a/forum/skins/default/media/images/vote-arrow-down-on.png b/forum/skins/default/media/images/vote-arrow-down-on.png deleted file mode 100644 index 048dbb44dcf2aa3669386737e4e34503659cfa70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 905 zcmV;419tq0P)-y5{XDqL?wtw8c7i~ zN0Q6^?9Pnu+qv8Oi^-+Pz_+tI^UZtT@2q2t0Un+PKF$My_TW0l0Sr+3C>}Z+0c92j zQ&9RPZchib4JRZRISTw*?j`s&D(yi!4W!bYK|2l~#3&Yl)q=eKB*_hofA~`;xN^ut zQH^pphu&R)Hdf>y>Qg&-^&xZ21q}p#FHqmiA?Xcc?0sNEuv}tToE&x%yyA;O9n_c& ztgi)$?=eay3oI<;;0F@w=OKY#QG@aB?kYGJj-3UDF8m+(%RAuS)fP`Uv|~x*NmL4j z!2}6hSuY1_FXH@Eno4SYa2fqafZMOBtL=P?a&g3-4|twf6~U}kNf0P6+^mhu1MQ&W zQ|)VwXZi;$cy;)KStHP5wXSdC?sR7rWK_$yj`F9K-3tj+pzGE&CT^qA=z+D=Rv$@J zbvtq)#Yq4@9@OYr{|tt^${b4@Tb$voWYw^jsXJl~1l){yZ6Z~mTapgVXlRrfvI@o5R%kNt_@+gec_sFS>sC)ftV7EML$Cz1 z{=+$y6i-HJNDispz>1H>a&r@96Rxcq37>Q;^OE=LI@u)mx5b(Kd2vsyAI4-kummT= zg6^eUr{s{$(8UZkHS&32F)wd(AU!Q7(Rdg%m8GwFfuZFFfcG!1F;4WvoH_`{s8d}AU+B-V@FC#${&~nKmaj< zELga3A;YgoU<-h@djJ(F zfE2(qfH25qFg7-fEDzJi!NCC%R{)s_G8-U(SfCczf+Ro+KtNAVkHN^u2xqW7e*BnW z&z?PC3($iL1VFy|@#BXrkhujQfWSWZ{rk5XND$^Ce1?O7tgI|UVqzj#J%|QjXJ=fy@M{1qdLp4}jidfk}eE+_`fx3{6f>#t=jHft;KiJOrSj0yY~UfM6D&CG|15)01!ZM3y{4xbLLD8!_w2!F~pGdzzl|Am>fU= z!Gj1S080fK85v~z06FP`06+k-pxX?ygxFk+ZUJ&W0Reyjg8Kl3VH&1PnSx) z)Ie%~{`?8YATeO(f|~^k4S)aw`v6o-fJ#FqCMIw$Jbn5!!8)eg7&Qmi00000xCZ&X`T>s1rrok967{t#$kYGS7Vd|fw?Kji~ z;lV5VHnRYeM`{4BF0c$^a34H4Y$j8XY%{~vP4Ur0f;38Hd%(7f1L*It^x#ox6Y^@F zBDnIA8Ir>UzFOH#7SIa-feR)47XkUfbW{ysEx$_Za+(2mrv@e0$jB+NG1p<%zK%|C zDhyl)$6NrHqq@G{IrJPRPyB_8o%g~qnsOblfcn? zud345g@qRO!2EE%0Z?uLjv-MxAZ&$ojSA9F#F=yV|e*{B8pP@ zPpy`qnVS0ErfIu&a2$lel&veGH2NtLOlegf9(x9-G9&7J^nDl1oLg=Hr16Fr(Oro+ zQbLGVpQ1pj;IRb_B#w0GLze=Va%%)w6bBhuOzm9OdN+s8=o$#_ccLp*OIu$G;h>rLx z;mgpUhOxf69+e^?1Ywq=jh2GNqFYu`xESK?pEsfZhXwuLEj*_r99^_vuKcEHdY&#l z0Wa8SHm?w7E{Z_H{N^6JFTqUk){$jh)SV7SR)<^84Pbk)5p-5xEIhKMBS92|x<@3= zZ)!HBX})$JOk*s=%QA0e+p{3c*vl0e=9sUD))!9#$+3Q`u!ebIIb1s(-e@F=*U1b% z9-vyObQ;pB6zoI_#Ud071$xZ|IC*EJ6cLci_@% diff --git a/forum/skins/default/media/images/vote-arrow-up.png b/forum/skins/default/media/images/vote-arrow-up.png deleted file mode 100644 index 6e9a51c7df2da30fd2e56359a93f4712077ee62d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 843 zcmV-R1GM~!P)Ze18CM!Al?Dub8&GoOqw)_0U&_j1|%mZ z3j?V-AXWlNa&mGq04*cZdym|9R2`JR?`}glckWT;thzab!KYu)chAIdN z2{HWr`xlHsmVhvfpOlou(AU?;;Ns$fQw<0U3k!q96hLNz%mxS`umwN?TMiBmxCT(X zz%UHx=;(lHFE1~+7_vH;K9D6Kvw*ZMNDV*$!7NY%c@N!iY!;y#j4TgxAjmABm>Nh7 zAb^;l8VIHqU?k#|$KnXEnE(OAf-H%y2t6WU0F?aD!Pc!?8Fud6iD4l?05Re7HZlf< zD?Z@u?ajc%#Do!S00G2;&E;unX$-o$x?py0ZZ5;*$&)b*1c~GFC9-({0mOnW3}J@j z3pQ+)=H=yK1UEncF%grAhy|b^LI(f=#DX0Dq!^ZylS5Px0R#}iRD>&trc9ZFHD1uo z0tg@`LIz>;HohQ2&zJxK#DXjV0<5g8D4IZp7&efdosDoMP(O0;g2Z7C0|+1%sG)yA zIS*DU-nemtK|@0WtN>JWV*^vCPQ{suK*a^n%pV{zfB=G7a0gg^Yk+0$lVq#(#)YQ~)1`j9~!(0t4szGKx0I>lA2$l~H18vm+Dfss78yF*}3LYLF zh6M{2fGtH24p`ms^XE@^(165%^kI-ZKmfrk*aj4E1sbd%ARqvC0Z0=pj6Z+=Ot?w| zS`LaokmG=6fn2{0Bn}Wjj4(qI5)wdFCb(AP=H>>wniTNm%NGV#&7yzfB V!E{DAJ$nEE002ovPDHLkV1i?NM1}wW diff --git a/forum/skins/default/media/images/vote-favorite-off.png b/forum/skins/default/media/images/vote-favorite-off.png deleted file mode 100644 index c1bef0745ea9acd1c405ac11e0d5555e8b12d7e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 930 zcmV;T16}-yP)Q zl~7{r#<-|Zx+tX^7v1(nLEMz+FA(Vu=&lr@i%_r>io5Ej3qgvws#2;kN-aKOFk(}p z#$w4mvd&mnLCfqGB`LW%tTQXT~$@pwWz4*(Z$7u`~3X;?Ck6f-uOMADC8`%H49ug9F8Y$ zw_8+IRf)E?w)=F~D6T0AgF(40thghvTO@bbp`oEcsi>%U%r*rBP;F6Pqt;fdRTLK& z>)!xC_VxAkhJ(#!6RoYS59m#UO~C*#0w5d#&H*ynH51s~l9G~3PA->Ap>jP%V%H7; z1$bs+Zcu>R9*^fGmE?+(-EJ4{?d|vr-^j>_mM?&1XlTeop!aHPYwM^Sb=B3?ZURv7 zN9E<^df;4gaBv`wkB@cT+uMthZf$OE#_0YhP1;0PS65oCtgL+9(a~Wg;GAGQS@Lv2 zkN}h`N1!eQU0hu3oSU1o(cP$Wa&nTu!eDWr*}!96BogVHo}P|wZ*Lo!n{BzQY=b5*FE0apfWSv{QAJ{HZLNQP zem;yw6#{1^;uGuZ>*=Yfskc2nJ!4n)Ad9ee={G;^@9!H;&ZqE2X`<2Sx8B~~uQ}N? z!#RA{$lSzt+5M1{!p76PmY3|<5RSAL&84NK2CzIy@&xf8fJSJCngW4N5yyPM&Jfr$uh-k@bUF=s0dG-KZhD`{`3D>TQ-Os; z#w#l;;f;+A00-HDHurrf6dIy?@=((>&<&onoKqxC$uC;-AG8mSL?SV4mQhBw zj*gB7W@ctSFDxuPr@!!0KgLYy`Z|>GFQSP5EPn+U0OR;~TRRy%rT_o{07*qoM6N<$ Ef@zSrumAu6 diff --git a/forum/skins/default/media/images/vote-favorite-on.png b/forum/skins/default/media/images/vote-favorite-on.png deleted file mode 100644 index 1f9c14ab0813a1aec1f66b12c3eebe7232be3d8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1023 zcmVZd<5{Le6mt|)_<`GX($dlRu2ZJkuE zjf4$Qewch0=TDhyPWI*W3&@@n;Mrh z;ON^;+o1J6x+lSyC4yAc5*r#_RRe6^%F}2A*z}DOqn}Ca7lL#(u})I%7x#^k&|B0; z`f()bM-h)+;pZ4u$ALJ}P;Wvb3dM-H#z&Yj5-&MXQ!CKC#TXEuPEEBSJ=cPnS)ej| z2r5#+g@;jQ$TU_*6Ij=36b6CwjWTT^%5_m~{H>S28)%4W9OsGaYMC6L=yK8ysOFtZ z$a|Cc`qnVdXsKFY-eyhS#>TZMyvv&Gk-Z`#?>^Zjhh+Uaj*dLD2Glrl0XhE%M&6JK zdqZ9sxMdI+<1Dr0Qu()0dB28}pC5!-B*l|clf(rIB=P3C6)a-E6moW+nx^tEqNfk1 zhaN6W(@j2{T4UmW|9SG(9X_!#|lMVmx<&Y38Ta_F{^dJ0jyZ z^KE3Yfqc<E7fl_u~mXc`B_ShF#sjOqSPbOw6(spucpG!yqP5!xrMP zXa--)`><8~qDbZjaUY(43Ik6LqKX$#+j`!7QB^cQueWs7N thq=s2qJz(mO1EpR@jr*ce;$7X7ywPEpB^Im6SDvS002ovPDHLkV1mKF-a7yQ diff --git a/forum/skins/default/media/jquery-openid/images/aol.gif b/forum/skins/default/media/jquery-openid/images/aol.gif deleted file mode 100644 index decc4f12362124c74e1e0b78ad4e5d132621ab23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2205 zcmV;O2x9j~Nk%w1VNn1b0QUd@0a~U0{{97Cr-7}~`~3at@%IK^rUhN5{r>*;`TQ|@ zxAXV<(c$m-`uz9${QUj?tjXaAU#9_Cqyt>0`uzP6Wve@Yx&8hA@b&ra^Y|liumW18 z16!pEV5rI5>-6~hXr0Mflf!YN%x>+Qkd8p6#`TXYZ_T}#Ooxt1~X|1!)YIhOpD5#NM*a<0W#j0a&CWZm>^{ zzyn;Rz}D!)*y=NTw$$VApTXTqiN5vt`#gcU#o6jVg1UmP(x}JZzt!kmmBs1t_qNaF zEOxXxf4M<~yV&LMwa?_c(&n4K+mpH2M25T;XRHups^01ID|NGbsn3_Y+VS@KWSYp* z;_ryE)EsK9fUMC>i@&bQ;tOD?Mu)vGc(qZE!4hSw$lL2DbFy2M#IVcb=I-{7w%6?P z_}%F8#@g%I=JCVW>A~0O1zM$Emc;;Aq|e~)=kN9^bhB5I!`tZcY@o~4Dwe zHhs4lW~<`t^hk)l_4)e+UZ(8x_}b_3h_Ter;O(~1GFN6(4WBES(L=`_W7sA;8&5u>hkx|;qKw=^yu*R z4rHnaUZ-7_#k9}l^!NJ*UZyBu2wvd-h_@b-M1#8yVW@Sa&Gh*C zz}DxCwAK`8te?W&k+|6D@b~`z|2%=Z24AP1z}wd3@G*F`*5vQL)#tg==7q1*{{H`_ z#^61Iy8r+GA^8LV00000EC2ui08s!P000R80RIUbNU)&6g9sBUT*$DY!-o+6Jy`H% zQ^boHGYUk|VhNoVyflg&nXrK{5cMRHfHRGxOOgqmlo8oERHm?$HPJbz#x1Z zpeoL(7W@hZxJ5+J9eE5BP*LH>O&${ zj5jX`S&`8IL!Cx*Fz7_k)nS8ApeE%1x(B4-jBvRPK#9X9Oc*K+HhF5Leg{%TGv{D8K;`L_xwpaHxaF z0b^+Mfl?X7amfU05OYC(Eiz<;2RbaUiytGQ0x5J^bziwedW^uQh}2wH>_T<*uvM9pjgf(kHL(TyFV3}K8NEHsip6(+=y z&mT8*M^FIdM4?9wB6I;j1ZWKZ^G^UCv;lw?B2a+P3?fKiKopBK>LNoIcyNRiBZxr* z3skJY1QoA5aVRDuT=9ep_zX!<2JM_N0V+YPFa`jiSn&@6Y-j*L7D^;UixL1NBE%5F zIz+$0D>L=cJ;YWUy}E(fIl&_o8nn81SpJFsxj2TRoOLkeItpmjn7WRMLXFdR_93ql-= z1sX|!ae@q8)L_8?$rNzmK!~tV!vO{eV8H9GyWWQlALOvc;zfv35CtA!F~I>nUE0WC6>_LJDwEf?Ad!6)ETg5hf{+1h8Trx)^{dte^urh{6TN9=*OL{Q)Z2o6xWB>${ z7E9g~a4RxB%)s5|;lj_{?8?N<+|JB}<)%Hfk6edRIx|)U-=MyYvG@3L2ePrxsR2Oqt zBxw2I!og0~3Z95SriB-Uh0Z(^<`&3W(C}!9Pi0zD;fb^77(DfzpVpq9FbC*K)e_f; zlH{V)#FA9q6d=I>^q-}!frYMtWr%^Hm7$51se!J6iIsuDpB2g>Fb%o+DVb@N$QsOa gjf_K#jI2zIfJz}6>YoYA12r&sy85}Sb4q9e0RGj5MF0Q* diff --git a/forum/skins/default/media/jquery-openid/images/blogger.ico b/forum/skins/default/media/jquery-openid/images/blogger.ico deleted file mode 100644 index 1b9730b01c3e60a396afa4193986b7ce800784a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3638 zcmeHKJ5Iwu5Ph~|?1U(aasn#_qUHo}jTDrKiXtUdlmp}lu2BjK4iLGb^Z_VRaDbGQ zV`g{OIJ=vVkdP%LkF;y=%$twL>zy$WAVijduPI(q;0nNaEbGS@D4BQ7Jci(whr)Rj z2q%0XEZ+#_Ct;QoHXnrD7mcRRG|JxzlR06vA#8Vq`Ijl@shxhCs9J>F=Pk_Z-FQz1P;kqy49I?9vmhesu(DDd2TIQ)X`OMtv zn36eGX(BoIuReV`=lQ(PMGs~LG0b10`Y_|q?3EjYCVKU(mu83%PtE7$VCeoT#ik(R zI_G=Ly}Z;TPEX~szaC%nFS05~vowSpGdW`wz5QNNiS763 z)A|{|X4mk|Pb``6HD(c4gZ06~PM`I2P38&B*lpoil+UKHq(V!B*N4IXtYRdaF@vLl zmV&|Rr42{^DojjF{P2k7k-;lA^VR%bjPq6nUi{3FY3ZQZzmogqF?nyszfZWEm-L2B z-JibT!wa5rZ$|dN(=9gsk6^s8>ePX{)JfmC{wZV@OTAD2$6>+F!Ka<9w$43N|KZD> zPKm$&mc^Jhy;?nm8U4s*&rmI|-^laso@xK@w* zQ%73r<~Q4ldN041`4(R&vsZcBa-Fqj;u&0Ae(<|~YnlAQHvQkZs|?d;eGo36IJ3*} zU)cm;w5gW3MwBEMr6!i7>ZSk*1|tIlOI-sCT?5My14AoA6Dv~#T>}#<1A{*+ltW+| qa`RI%(<+fQnCTiBhZq@InHT|;LNwGr6P5>RVDNPHb6Mw<&;$Sg?fAn0 diff --git a/forum/skins/default/media/jquery-openid/images/claimid.ico b/forum/skins/default/media/jquery-openid/images/claimid.ico deleted file mode 100644 index 2b80f49183c7c36fee4c4f9f0a82d4fd9950fcd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3638 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 diff --git a/forum/skins/default/media/jquery-openid/images/flickr.png b/forum/skins/default/media/jquery-openid/images/flickr.png deleted file mode 100644 index 142405a6e6a4d5739f00b18dd6ff5693f6db1109..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*VRoXegrjv*GO-%i}<$K)u`w*TgY2f{yOO759% zIVQj{S8?O+?FWuNikNpOhMmz%p*o8@@35=;(PrbQ5pQe$i2HdeZ*?nLqyz z*gx6rmBaFdf&I+MMb|f6OiX%kEqhthHhX5F*-XuQFM7Gz#J$x2c%k9W|0p|=FU=Ef zNL2hRo-L$jZzr9ZTC>}H~WqJD0<%)F#> zzDalYrg(pGEJF+otqe`9Obv7mOsotH{;W_AfoaIiPsvQH kMAl%YYh)Z^WMpMx1XK#qQ2$I=9;kuA)78&qol`;+0FfD;b^rhX diff --git a/forum/skins/default/media/jquery-openid/images/google.gif b/forum/skins/default/media/jquery-openid/images/google.gif deleted file mode 100644 index 1b6cd07bd8b9f27175e0a03be3b5849e0f5479c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1596 zcmc(e`#aNn0DwQcU}GKMxn#>^B<6OWQKZt-cb3xBiE^HYQf=ZKSu)*APi@FdDnu7l zbE$~JN>R#|+lE{hiz(BRl~d+uOl9Xe=bt$55AUzjP!`6aB*XlLd;L`$MA0-=oh;_@%=DSKzTW5!kkg02oxN<-;QgzZXZ6@(M)5 zb-u1@<^vWqN`U%R3CtOJuojJt|Ec%yo>_yZ%MV%ajx`i>ysy4d0^mKeNIQ#t@2y*KMj}jE8i*m zl#eQZ7!1Pfn72wr)$QwY6gabm(O6$Lylw3Pd(s%KbU5crNh3{eeZxI4(dJKB1MUAN>n;QZCCkQs_tGtJY-^iC3ja3x9v_uTP?vFVW;}s># zx;OS=;!{FWer7!3y~sj6t|9~xWcTkC-QJ+z*` z{$kU`Oy-`7hp(oZDFCEubef~t-M)K#*_S^K7T>g7T^A0(oK7oIN_s0RehD8}s1*i- z0sK!m=+Xa`J^uB-PXLSoRAEU$)j~-M#?mcPT3yt{hn6u4gKCOf&J$L|DbuOJmz+s9 z2lJ2J?sjAok}A_-F35;rl&1P$i@IJDD5Bmxks6yO#s#L4K20(2&;kgjBXbWq$Y}&> zCc!g3Y<~;U$CQlDX2nU|3Dx218gg&b%2GehXilrp4#P1y;weqVUjQptQlB1c;VO7e z@*D^wqyiQ&MP@@Eiijj!C6&AUPa6q7&lm^MToqj2ny^P9>WX^Ttd-e`;&k}6HltTz=X|A>@zzv6@ z)2r$ZZK19Hq1s>pg(Wg*yF5bqcpgSu2*Z=3Y48rhsMseSGm6D#RWnKSz*rI2&e%)U zhJ)uMj-*j*Cq6a|SR^kuis=outMPl7vPf8@-OF`fK(;t_tEV6%zOcxe#-=20Mq7|L zi=0@wEQshFjSRBhL&)v46Z=EWNGr^Y7(cjs9|q}uirjP>UklMq_Cn}BpIZ=OxlIZN zrqgmZ9Daq-5mP(tkggoG%l1Mp5`!YX9P+{9a@vc{UA@ux9w!5<$J7Qsxz)kjp9U>O zdMGwqZ?ce!P4?kRO}wMe2<(jAw{y`J9zkIp$bd;9jpjy5e7h8h$r8hU6K*}g{&bHR zc4&^sGRyCwh1g@leXv&EK^8KfI43fLjtGZ4%_yBJq-Q6Ii74-1r$U?ItVA?Z^o7I@ z6Gx_VGVMkkya7VbaJCw^O!RGWg$&GOOC(&Bu>?}_7>IP{%ivHGBI}%WA6YI2+3M9H z%iJLj*4d~I--NgTJ(9t@qodNU?AaV`YHlKR%UVir5C+OujBse~Mp}pFlaUEl5;MVK zxnv+FK^_1to@fbJn^<{1g0s+?k E17=sO82|tP diff --git a/forum/skins/default/media/jquery-openid/images/livejournal-1.png b/forum/skins/default/media/jquery-openid/images/livejournal-1.png deleted file mode 100644 index e643608186435818f547afa1dce4e2fdd739f7b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 713 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#Kf!x;TbdobJ8spE0RW=J?0&pKa{y{zXnp z*qkXmd$q)x1@jCg99bMCCYzoJo}PDpsbln(Mf;~G$S#s%WtDqvaECy|{p_~)B)({IQtT<3dh;gx6fZV2*R)4hETWrjdFTGIR0}oUy|+$@onIkZXUXME z70-kU3m^CP)=7+)#n*o>s#|x@^YNU}vtO$J_PDrDRPFS6W;-LbjE^TsP<7g+?mN56 zm}C4rjRM@Wm z@1eUhS$3_v{E~Zv?T%@}g66;3ZC%)H>RW&Ct3;oeIK%V9;)o-;;tm1}Bh+3LZ(+PL zp=R3ekGI!6;jTF~^?=%^+^tdnv!cbXX9?eCj%wJ?kP*E8x8j|{KY>X>wZt`|B)KRx zu_RSD1xPR$85mgV8d&HWScVuFS{a&HnHuOCm{=JY{8^zK0@IM2pOTqYiLAj)*T^`; c$jHjX2&fdIq5he$JWvCJr>mdKI;Vst02%)%`~Uy| diff --git a/forum/skins/default/media/jquery-openid/images/livejournal.ico b/forum/skins/default/media/jquery-openid/images/livejournal.ico deleted file mode 100644 index f3d21ec5e8f629b77c77615982cef929802fbde4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5222 zcmdT{3s6+o89vBPQIq*$1QbbvAP7Q0Tpmk!l@)pHf>>S> z1vbL6JXf&Eq~nt$W+Y}?NhYbg%X2}TX`y3UlPS(H)68fPIsMMP%d)ZvOQtiO{(Js= z?m7Sef9JdZJ&(JD*bxy~wQ3b%;$cU~E2vFPBC#hV6@5-lg8iE%gba#Un|TxR-jjq} zb3h#KnTHdU;W5$jSK%T=Pj@H?K_Lo-P~nPOqSb0qGXv!dp_JW0@nc==!i$LGD~{u9 zt~8U?B2Fd~qvpC~M^KA`gqqWJF*i|=E@%ujnuad%Of!pb5`P(QC7kR#SP2OTzQ<#W zlv%8aIKD~feX!6nCX`OuQ922|4;{CsbQG#}pj5FEW=E(mRL;B7LWEq0KANYW^3Y=B z_y|vmH;?ldeDaRw*8J(~hC!qOw?4H%Oa?Y1JnqbNZuG{_4-W8zh5g(k>k33gQDw%FD{ne3XB@ z!rC7_g|Gdhw<&R;HMK*r`+|J;KQGI_{V?zIn&?P3mLE&uo!9m>GUrS3pvy(U5A^kP z_$(c0u8#D!b_R{U=43cu$bYTlSjYsNjhYF)s`QQZ*3Ky}xtxmjy4jX?u^{kLVeo`r zO$S;h4E5!2dRRN72QywCwpkgq;m=hECwm&HvGsd>T}g=BENAdX&yl^G;15ZD@oDXe za5~)ny+KtH;%e1SDcr|-+q7@ZKZGT0tS19Bm$;2T93LRj8^{4y675bB zwk%H%+bJ)|KhfTK`uexou|aVjGo#E;Z%!+~BizWLXGzMgwI!$9Yp#x{^ivH+c7UV2 ztG$yM@p8QPk{Hi9qZjA|_iy0IrBz^V2FDGCt7!c=X2YVB&%j+s%GRZq6}$VIQ&2P#@0_gE zNAUFwKQH_3h_#F3ZUXmN_F>UpAnQ~Ky-mq~NZp*1ER$dEt(TrWr;qctLx_#Sm^+j7oj?A#I7DC$ zaD!T6s6Sj3{L6HyM1HcisHVO0oT2v1d(D5PMI|R99BoZLz$4vBrg+7t)3*@)h!oupL+wwg_YH%9vj*4aIjHXba4{8xkuc);A<= z{dZS2HK=KK!_1Gt{0T^;r%|h@D@A zwEWI*^|gxqvzS+eyR}HSKjd>V18&q9+tQP_E(>?D2|U7;$hbAy$_UJGbI$ekhw(yN zQ(t@t+Lp`(@GUljJClQ+q->vynK|C(jk-g{A&xDnJEp9_2N%N}naK~`m>>4s;pgp< z9QJ=jEdleAH`nptjkB2FdOtgL+Y^|;w&WZ>d7<84e)0JS>Jtat2~yqPk^=D3P?xq0 z@f7|6Jern%&D$w>p*GAGyl#LeY+CZk`Lq2)w{GZkg^@2rdyw`F-&0YZ?HMmk^)y+7 zCvI74%WRnjCpgYpE3*5H!##ZipIx~q^<9GpuZi7A2hXs1Zk~!pO}{2J>4l}(OBYOw zFj0B(Bt6hCeb>`pT-SE@^z{x5U2Ln3-?S|8w?F!!Jf|8`_0G@Mi{w$ z=X|SDy7MOoto~1%!)>|A@LPpZ)J;^~NDC9o;+|ify5q^Z+~}r~bWFtv8#b;5N6F%T zh9Q2R{a&r|U)2@;IgyF6UTmI3tzX1!nST@^QP$V_qZVtm#9wTzwZCbi{LlWU{0Anp BEK2|Y diff --git a/forum/skins/default/media/jquery-openid/images/myopenid-2.png b/forum/skins/default/media/jquery-openid/images/myopenid-2.png deleted file mode 100644 index f64fb8e81b1adfbdf56a27de64731491f9cb82d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 511 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#KA?T^vI!PA4ZU5HLs*?m4T~osf_a(WfS} zvm)v`SIO2h5hl-#3=Gb+7M(XRF!+<6knkWmA%Wwf`PRDfmtQUhpLjKMgGGYSl&}b! zwWmuyZqbuuV`Hl{v3$dJByFmt^UT=p<)yYQo%-{xeeGy$T*&Rq8zz20<$prqO>>R6 zE$12RG-|oJ88!xw#@LoR68=nUA^bgP7O;gK1jMIbk>J*@O-}%8c!i(EIWI z{rz}FN5!-nDf^l~AEq;E{tD!I@bFpcygPA6JI*)UIkoM-yj|S^p637m742qhFYP_hAF>%3ImO7yz6kU8N?5ex!R_zs z>o0dpe>}!^&mjdE692ya)mHQlOyXqlj0-XqdN%7fFaT9cTq8=7i&7IyQgu^+1OqUD zEOiYmbPX&+3=FLdO{`1}bPY_bfZ?@5IRvI5H$NpatrA&-nXZv>h>?+%i4jmKL__^E RVR@hi22WQ%mvv4FO#r_Lz6k&T diff --git a/forum/skins/default/media/jquery-openid/images/myopenid.ico b/forum/skins/default/media/jquery-openid/images/myopenid.ico deleted file mode 100644 index ceb06e6a3f0d88fb97cf10475a3062fb0edab33e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2862 zcmeHJJxc>Y5S@6ZrZbS)owhjA&;jnXfl*X745tmMB3MrBW$)n`RP3b417qd6J6bL?UM{+)q(3xlv0Ik%T7j-l59$8$m>#ard~jq(8yIciUu?j(!>?&WKIe?G5c$>` zV+r!H1WS-ha)=*H^!uZEl>O1BP8%xc=fconk~~4DvKCYWn4`b_pUnoZ788}%mc>uh z9HV;s)r}P~NWtqf_p5&HGjTJoZI|S8n)uf0l05g}rdhqaIBpnv^myAWbI*7E=&N3x z95xI+0zR;x-|08c&;6Ul#XdjZARV+no-wSN`};1(+>)AIisPc*P@H*_1Kd%ys#()H z>NUmL)tL6ccj9UxPF`{LG^Rc9JypwV>?^N0yvK~LBc9f{#^OA9dQUv#8Tz7oxfa(K u#=%<%_2}PpAb{bmUKcqz}))c5uC(7v?)v4a2P)ZNa- z@$&T2)z|&~{r~^}A^8LV00000EC2ui01yBW000GQ;3tk`X`bk)Wk@<6#nZYULKH{p zEx|?+kif!I0vIL|#ZMubBmjWH2OtmxIFVa~6JQ7!1CK!f5W#StOTv&C3=E8h2vI1s n+#cd5;2fT3B_0kF0v!+!GARoV78n&7dMN`JIW(4+BOw4gP{MS* diff --git a/forum/skins/default/media/jquery-openid/images/openid.gif b/forum/skins/default/media/jquery-openid/images/openid.gif deleted file mode 100644 index c718b0e6f37012db6c9c10d9d21c4dea0d0c01bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 740 zcmZ?wbhEHb^k$G`xXQrrKS$vIw-5i{JotZf!T-qt{~ulWe{RG7ST3!;kh({9A)7tlU&$%5*g$f^Ar># z6BXsynVh) zJ?osJf(s)D10z?npvQi179P(djPk7Va&pI%NfVlv<{V@&c*Q1S?C^%corz71;ll+1P9`Sd{~>qE3OQZcJ(5}z4)|O#`p@vJ zr9;Fsp~HjOs*vv^`}=;ISs7Cf1bMkUpV%Pi{6*$qgF{F5!;-XxTBi=%eG5gPtV^!wdin~r1kkVO&vN=8Ce+Xv z$*|MCqlY(ACp$%vPrNeV;U*4lo)c<`?yngdvl5)QWEV6rHbi?!)@MOEE;CkPT#L!!@77y7u K{UjJ!7_0#i2pVPp diff --git a/forum/skins/default/media/jquery-openid/images/openidico.png b/forum/skins/default/media/jquery-openid/images/openidico.png deleted file mode 100644 index ab622669dfd9a90d93d01eb3e371b7cafe6c655e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 654 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%3?x6Bmj*I0Fp32Dgt!8^n_%GkWH}&$@vzfy z1rWt>E_T&OqG&47xJU{SOk_34Y=jC7*0n{c5V6N|Jm8Y}^&-pOTo@1JE@fGk2Mm|U zk|4ie21aHU7FITPP98pf0dWZ#894<7C1n*|6AMc#7k5uz|L};|rUGc>Lt$+fQGx%PFW>%kX-!fgBRjqK{jeiYax&1X*6P`ZiOyxhY@aaR2pHCO>zir$)LCtXD8x_6F mSx4_%OzwSX@y%uX6P_|}hZ#5T25SNR#^CAd=d#Wzp$Py+&RzQe diff --git a/forum/skins/default/media/jquery-openid/images/openidico16.png b/forum/skins/default/media/jquery-openid/images/openidico16.png deleted file mode 100644 index ad718ac5a62bcc6e995e934064f095ead4b6e7c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 554 zcmV+_0@eMAP)&P@Tx$zK zg`~UL-C8ZQ2-|28!5~Wx5)m0L>Jb1(5jV;Nr?PiaL(OqwOY$%cI)+e zAGk59mne!(`M>};2%H0!rya0}IAG0BlH^dWR(m2M_f_=)@IgeLT5I34aqs`2{fRh^ s=d86?fHUW}g5FWL{!;FK`&|V13)hOgVr~+r0{{R307*qoM6N<$g5FK`NWB;egxu81uWJVQJd%?yFbuOKe63n-+pJq8^_inN|!<5KX zFN*sfuYBh^N#*37U5;*-g&BHG&qzF5KIPbyTdo@Gp3RZ!`IWi(>*ra1sXp?qirOVN z+Itk=U-XFkoPOfbN^#}~I=N0}kqkSk`viJ^ao?*q-!qH#kL$)M@5?;K9~EEDvaZD#)>=N%EREX+1lcxA4c zbH1=*x3k7Nr4-imOyRkvhk35~Crs+v$HZ_e=WoT`Y_=s6ikx`d{>Ip})TM+aN6+|d zsKDGyYt<-~H<*?|Py7&ZkT|u3=hh%dXrI`@B$d-ImSy<^r20u_tJy z{YrS?&d+&*_oKPcrceK*|8w1xcc@~H-P%ytZ}Ltj+A zE!c_l2H#`zaX;dYlru_mk^31KdcB@L9&W3#wIFp`YJOeP`OSr1{CK6O-`2Es@?E#T zy1MFK>-Ep~I=Vd7%e_s#J@}-Zvwh`X=4ClX_h=7BXW;)k1Ifb@+v7M5AZI7aYkiNm z$KjX;Qm=X2(~a>=Zn(6-IG8mv>sbkaBEroVrCFBdHr=3XM61uF&u!`5GI1u;Qf<+zMxU!sr1q{f@m!ic#&7x4 zjcDZqv{&NU85cGO2UiL7I^;$4kVpqJ@-E;pjlK(>l3v2Y;e5IS@q=)?(5+CX;*7LwCwnlxopJBahPURBFV+~&J eFF>coTp;}_7zqbJAQuX63TM^f{)_Klzq8-HK65Pq diff --git a/forum/skins/default/media/jquery-openid/images/verisign-2.png b/forum/skins/default/media/jquery-openid/images/verisign-2.png deleted file mode 100644 index c14670084ad7edd1b0e9d0795e6528cdef94476b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 859 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87?@f-T^vI!PEVa2>oGY|}cueE8LQ-r;?xW+qEnNYQEJ<;m0d)a9Q_@mBVkN|!>Qw5|?oEj@ zJHq?c^=`&1?qzR(mMiWxyVlEZV}5@A=jwBo|BFqWIFe>RcdoZ*x}TP)x54RF-iE~s z8DC#e@LbN^5O848Yiql$Ta`ELV`DH#n{(vi8smtFhy%ax$(8JV*Rc1K+L@U%85qvq z7pmEuXL6g%@aFaAyM}BT%H@tx|9dyM>Obn2cTOoZWK*|KKKZ)!@yE$)SOq+4T&ZVtR9A6KuU$Y6Q?$#Qaa}_p@ ziv*gC<@l8sFRJ+A!F1kJ==pE9CPrpHc5R{FIYm32n)aUJnmlO|N5i&BO52{sK0kbA zOM=7O&ft=;y9;$r`wVX1A7Ex4E?i21Paf zk!EFRxSVGEDCsc+!>?d^$k<~9c|4`!9(VT;faV{nLzlk55Tah2J(E1ez6oEP5T-aWN3KX2YP1Ks=A zYy(#2_0JYBF1~uJRbbBS84GlMPM>=wiOhxKu z#nY^gWqq5n3nWU#buPR-G_mk(7c;x?hvJ{?`$|fat4cU-KApNFrdB^?r^)|yoAa;r zUc8nrk(b}TNXJ>ox==$^@_Bx!qMqv0{kMOz|Izv_r~7BpAzFVdQ&MBb@03r5qo&W#< diff --git a/forum/skins/default/media/jquery-openid/images/verisign.ico b/forum/skins/default/media/jquery-openid/images/verisign.ico deleted file mode 100644 index 3953af931987b0e66c122b338dc352502564eafd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4710 zcmeHJc~n&A75@Q)fTGMB7?4e2SOip*O~H*}8$=cdnTIhNBRWh_BW_>?5imwU5pfq4 zQ4m>QjBTZ+CRIeErNk zREwwe2CX!zp{LmSu(HSiXS0Z~ELfW_hmFlL(pSOSItLB|b75<{0z+Ju!Pzbsp04@u z^IM5gez^!5o)68~JR~M1V)|=3XwNQ8?a>Ya%3;dK~By}6c*$o zzc7z#uYNYpl*u)SjcUZ3@pYK4t;Vd>gP50g5b0^P$e34y71<3~mHQrY z^v!hsAEG!C)5bMuezljdfeI&}&sTTWohhE|ksJA(uJTd-&Q zMO2ly;NXEa9IkGqoEFsAT)_K>+aNTx;izy9$B(q(h|rGX$9{>EKmIk&oIQ<;7cbz` z_Vf7oOgqlCbl~T$U*gkC?YPwb87^PGj4!TTMMqaVuHU?hTbV;iCum zZRbOL{qcZs;#f*}wrlz{`0xBe*(I;Sz zyL{rRJv~s#3{DZZtH%`9aNO9+=O$@yE9B}Ppw5xAUn^OeZyC|qoIL(nKmn&nYY>eL zKrf+{E*!VX7~r9ZuM^b@Gr+V$Li3f}Ym!#NDK|=*KfCmKlHM?d^N_SO`K0ZlR@aaD z`$@HgRh&}Pnx=3wq}{WbyQe^@gROXtjgE@>Qu-jEKP!rl1Z1YS(s35^4X=At_Fe%L7)Z2wJ zI=BcM$Zt(2XjtYnSb8HX6)sr~HNO7Fi=k7(q*OSR;1tv-=GQtZrfwBAkrlHYyo$=k zI88HxY21*dylU_ihyn*o`a+siMM#3?z2La9_bI5tty|5m@_$Kv=M-r`DWnsuDXI|SI(OnaFs5Rj zX)H<$bK-%v#3C6u8ZzR^Dh7HHqo*OR6YUU|4ygcb%!+EsW(iDpCu}sLU`Ao=$b{)2 zqYUx~O12syWYaUKC^j&d+|rIZmK*4)3nD=!V^Y|D)97J|C?PnK9W{j|5sikK_<-~j zB9Ma7re4g!anVfBnN3BRq6!uR)Iqc*BNYKUJ~~i(NLEqh;Ss1(xyk6vj3QL-oI(}E ztJRXtBFNMQ1%(&^QRrgWCG@7zAyK_e%IJBC60Uv0=A*yw|Kz_F$NuLuvWqkMvw2)i zo$zJE=5ZUFK~Q{S_xsb>KZ5B3WHsh5CkCG#~pZKK$?_l$V}GW#u_kRkqUX z`UyTd@da8=wc+%sYiMmfjdN#zfeRNd;rz$faN&FhZrr$v&dv^;YrTU@mu}(8l`dTS zyp!h7d$`$gpJq>*C%Yct?%liirkiHU``!4q`ysx0_@`GhR*Wg zL+$LnVne>U0!F8BBDJgQ#SO&zJnpsR{N}Sv)RGX5ladO5OX7h<2Rs-#nHmcwuE~3rz z2>~NUOyad;2ZtE}qZs8M)E9^dp|1)1sQ>G$Z=aRsiI#u(rfHU-9}N`$^h{weM0ms) zh?4E1IgP=fR~iiIb_PS5COyWGoN9OA+h%v^2+Yx zGJaHiGz3ONU|59!7au1(GXnz`A0HnV&|@H)n}q>L0s$9;ARnmIVdDT(f_z;3d|=N* zDLy_ze4rMf1_3@kMlc035Cr)7nOM2`_ymE1g8cmaK$@2aOo2_OfcXEPfdPgOHZw3Z X0PU5rU|_JTL0}LcBo2~?sfE!1%eOAT diff --git a/forum/skins/default/media/jquery-openid/images/vidoop.png b/forum/skins/default/media/jquery-openid/images/vidoop.png deleted file mode 100644 index 032c9e9897bb71bb0a603534bfac1a442be1cf20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#L+dT^vI!PM@7*>(3M@;Cgqe21^@jt1Q7KOpyh+ge)Q1 zK|J4huRH_#zwbc3UEA;R9AO!H&d%roag-+O5 zO!N95T@?S*G}Sgw{mN!=VmhZ5Rzf4>LLtlrZUAWLgGPY+oVrG5xo^yW`xZU-Q@wk~@ zYxS@D)yH#t7kvCm!TtK*mFh-7(+TYB+*i5pa!nc|Jf3SU=XN{`fjrfux$lA7e}n0{ zlfCqFi>Z(M`wVVG>yKK1*9rZ1`iw}=W^iIUOLNU?<8e1$!1FrglCO_u)5YTUvK?eu yI~YIj#-~XLO;hd+o2#A2S^08*UB1qS`QCUE52vFxJ9}scm-~xFcCkL1j=lhFMR`a7 diff --git a/forum/skins/default/media/jquery-openid/images/wordpress.png b/forum/skins/default/media/jquery-openid/images/wordpress.png deleted file mode 100644 index ee29f0cf1acf19c7dfe7407b582422511d8d20c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 566 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#QO{T^vI!POqJOFt^!3z;%8gR{`e|W&z#@ zTsh$k`!={g;#w5)pddwmoA!p_Mo&iVU?$Z7C%!+f+Dl}VQdLz&Yw`xl0Z#EMLLB^eIW!H4}F&{V=c{y`~F=GJ7WcP!sgnTVS9uyb*-2UJa zyX8gU^EHyJ5)F#0Z>a>7vTsvVNHXe-51kX5%U84V#``+8kTv3J@u{J|FE}JUSQ0Bg zlc#vvo$#l^NBfjkE2}kMVfyAM?Qu71W8A0etJe-(wf?BN$j{t_Xf0)0$=*^XiS;GhnchwTth?3-@)Wnih z-4r0fU}RumscT@NYhW2-U}$A%Vr6QeYhYq!VDM*!atKUAZhlH;S|zduGhHL&5F;Zi Z6CrIb?D>k<=p7w-06N?k+!11Z%BingssxX*~`Jx%e>NQL4U@#&si&Ry{X0d`1)-{ zg6ib$l60Y~mAI;tw^}Z8;o0SWTajTmc&LxG+tT3I%-z$;*=0U@n}Df z_WAbn_i93aS}k+@`~3Iy_*yJ-{r&yp+~-;?aeZ2la7u;o?eq2W_P3J0;iQSMZ9#_O-sRiQ;BHNT`1AO8Qj6r> z=!+x&Fkmx*3aAJ-s-85w)XV*n|rAH`~33k^Rb@1vYox} z>+;~*+x%&C>Lw4uMvz|_vc)vS@X=;7?8j0^uVyl!LrHg=Iz3>%W_GG_VoC(sJZv``HXa* zrIxkU(csd>*m+iriD#Si^7g{9%5+bN>E!JE{QaMVtz9y8td_W5GInuEg!AzAjBA~X zY@AsvasU7SA^8LV00000EC2ui08{`F000R80L>t9BSw)JIS9nHVe#jm!-o(fN}Ncs zqD6~fM)VmW02LY`Stc0KkV8WON`_FRxX7}l%ZU3P9D0C2ViSKjMS*eC!QC5NWc*24 z$ACo`hlu15G!rIFqD1JxyfmSQfQkeLyuEbT;aCwDIQ`|T5~at(emLt$WH9QCKO?Fj z!YZJpKo=h-$7uT!(ZdXCA3nU9VnV{d0N()k(Y5u#B%yvAamGe5)veXFd%|B&z}{E8T{37 zh=$XgAq(IDLK-DxqXs0h{KJhuWN1QBJY)EyRU!TiVM;~maN!RZP&~xT1YQjCP&*>v zG{z^SKvar9Z%BlLKM^>@P9t6rA<+h8P*4UH{%m1KMF#8;qhgZOW6=OR_%lH)|M;QC z8ZSfy%{eR3AQ2<}h+xkGOhf{J3Vrwkz(32laK<*D3lQa{dk%K=0FpwEPj!g6c z8PB|?!Vn>}!~`5T1t5_zE=)iG0UUIK4SoL5A(0aP5b%#W8tjnDD-wa@&pQ_U;|wMK zP_awA|9s&=3UeHwj6-G|f<{Y6;N(Ia64h{zIqvjAj2hSc^NKS(WVVJ5CDigyFgPgS zk0p~ZbHfV$&=8I(61-3X6MR?_!$S{5GXw`Ytg(h5N(#^hz#+8og#&*SW6=pXX^~7s zFkB+QLkzgEL@`eIumT%^WMK#(^!)R|8hsQ|gbd{TLyHi#R)~`zC)5;?9Um+JL^Gdc zPzgiQO?9dAYKu|J14=HfQCJs5ExCItCfU89hC~?OkX(YSVLmi;d zz!!K_6YW}g;8BGXI9aiX4Mdod4IRil;>SO66v75h2HbJ^?H7Hao9>T4MsJEFFH&Hw-a diff --git a/forum/skins/default/media/jquery-openid/jquery.openid.js b/forum/skins/default/media/jquery-openid/jquery.openid.js deleted file mode 100644 index 8d1cd20..0000000 --- a/forum/skins/default/media/jquery-openid/jquery.openid.js +++ /dev/null @@ -1,111 +0,0 @@ -//jQuery OpenID Plugin 1.1 Copyright 2009 Jarrett Vance http://jvance.com/pages/jQueryOpenIdPlugin.xhtml -$.fn.openid = function() { - var $this = $(this); - - //name input value - needed for name based OpenID - var $usr = $this.find('input[name=openid_username]'); - - //final url input value - var $id = $this.find('input[name=openid_url]'); - - //beginning and end of name OpenID url (name being the middle) - var $front = $this.find('p:has(input[name=openid_username])>span:eq(0)'); - var $end = $this.find('p:has(input[name=openid_username])>span:eq(1)'); - - //needed for special effects only - var $localfs = $this.find('fieldset:has(input[name=username])'); - var $usrfs = $this.find('fieldset:has(input[name=openid_username])'); - var $idfs = $this.find('fieldset:has(input[name=openid_url])'); - - var submitusr = function() { - if ($usr.val().length < 1) { - $usr.focus(); - return false; - } - $id.val($front.text() + $usr.val() + $end.text()); - return true; - }; - - var submitid = function() { - if ($id.val().length < 1) { - $id.focus(); - return false; - } - return true; - - }; - var local = function() { - var $li = $(this); - $('#openid_form .providers li').removeClass('highlight'); - $li.addClass('highlight'); - $usrfs.hide(); - $idfs.hide(); - $localfs.show(); - $this.unbind('submit').submit(submitid); - return false; - }; - - var direct = function() { - var $li = $(this); - $('#openid_form .providers li').removeClass('highlight'); - $li.addClass('highlight'); - $usrfs.fadeOut('slow'); - $localfs.fadeOut('slow'); - $idfs.fadeOut('slow'); - $id.val($this.find("li.highlight span").text()); - setTimeout(function(){$('#bsignin').click();},1000); - return false; - }; - - var openid = function() { - var $li = $(this); - $('#openid_form .providers li').removeClass('highlight'); - $li.addClass('highlight'); - $usrfs.hide(); - $localfs.hide(); - $idfs.show(); - $id.focus(); - $this.unbind('submit').submit(submitid); - return false; - }; - - var username = function() { - var $li = $(this); - $('#openid_form .providers li').removeClass('highlight'); - $li.addClass('highlight'); - $idfs.hide(); - $localfs.hide(); - $usrfs.show(); - $this.find('#enter_your_what').text($li.attr("title")); - $front.text($li.find("span").text().split("username")[0]); - $end.text("").text($li.find("span").text().split("username")[1]); - $id.focus(); - $this.unbind('submit').submit(submitusr); - return false; - }; - - $this.find('li.local').click(local); - $this.find('li.direct').click(direct); - $this.find('li.openid').click(openid); - $this.find('li.username').click(username); - $id.keypress(function(e) { - if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { - return submitid(); - } - }); - $usr.keypress(function(e) { - if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { - return submitusr(); - } - }); - $this.find('li span').hide(); - $this.find('li').css('line-height', 0).css('cursor', 'pointer'); - $usrfs.hide(); - $idfs.hide(); - $localfs.hide(); - $this.find('li:eq(0)').click(); - - return this; -}; -// submitting next=%2F&openid_username=&openid_url=http%3A%2F%2Fyahoo.com%2F -// submitting next=%2F&openid_username=&openid_url=http%3A%2F%2Fyahoo.com%2F diff --git a/forum/skins/default/media/jquery-openid/openid.css b/forum/skins/default/media/jquery-openid/openid.css deleted file mode 100644 index 1b7aaf8..0000000 --- a/forum/skins/default/media/jquery-openid/openid.css +++ /dev/null @@ -1,75 +0,0 @@ -fieldset { border-style:none; } -img {border-style:none;} - -.logo_box {display:inline-block;float:left;width:90px;height:40px;background:white;border:1px solid #dddddd;} -.openid_box img {margin-top:6px;} -.aol_box img {margin-top:6px;} -.yahoo_box img {margin-top:13px;} -.google_box img {margin-top:6px;} -.local_login_box img {margin-top:2px;margin-left:-3px;} - -form.openid ul{ margin:0;padding:0;text-align:center; list-style-type:none; display:block;} -form.openid ul li {float:left; padding:4px;display:inline-block;} -form.openid ul li div {display:inline-block;} -form.openid ul li span {padding:0 1em 0 3px} -form.openid ul li.first_tiny_li {clear:left;} -form.openid fieldset {clear:both;padding:10px 0px 0px 0px;} -form.openid div+fieldset {display:none} -form.openid label {display:block; font-weight:bold;} -input[name=openid_username] {width:8em} -input[name=openid_identifier] {width:18em} -form.openid ul li.highlight { -moz-border-radius:4px; -webkit-border-radius:4px; background-color: #FD6} -form.openid fieldset div { - -moz-border-radius:4px; - -webkit-border-radius:4px; - background: #DCDCDC; - padding:10px; - display:inline-block; - float:left; -} -form.openid p {margin-bottom:4px;} -form.openid fieldset div p {padding:0px;margin:0px;} -form.openid fieldset div p.login {padding:0px;margin:0 0 10px 0;} -form.openid label { - display:inline-block; - font-weight:normal; - width:6em; - text-align:right; -} -#local_login_fs div { - padding-bottom:4px; -} -#local_login_buttons { - text-align:center; - line-height:1.8em; - margin-top:3px; -} -/*form.openid input[type='submit'] {margin-left:1em;}*/ -#openid_username {background:#ffffa0;} -#openid_url {background:#ffffa0;} - -.openid_logo{color:#F7931E;padding:6px 0px 8px 28px; -background: url(images/openidico.png) no-repeat; -} - -#openid_login {float:left; width:30%; margin:2em 1em; text-align:center} -#openid_login div{margin-top:0.5em} - -form.openid ul.errorlist { - border: none; - list-style-position:inside; - list-style-type: disc; - margin-bottom:5px; -} -form.openid ul.errorlist li { - text-align: left; - margin: 5px; - float: none; - color:blue; -} -#openid_small_providers li { - margin-top:4px; -} -#openid_small_providers li.facebook { - margin-top:0px; -} diff --git a/forum/skins/default/media/js/com.cnprog.admin.js b/forum/skins/default/media/js/com.cnprog.admin.js deleted file mode 100644 index 39dff48..0000000 --- a/forum/skins/default/media/js/com.cnprog.admin.js +++ /dev/null @@ -1,13 +0,0 @@ -$(document).ready( function(){ - var options = { - success: function(a,b){$('.admin #action_status').html($.i18n._('changes saved'));}, - dataType:'json', - timeout:5000, - url: scriptUrl + $.i18n._('moderate-user/') + viewUserID + '/' - }; - var form = $('.admin #moderate_user_form').ajaxForm(options); - var box = $('.admin input#id_is_approved').click(function(){ - $('.admin #action_status').html($.i18n._('sending data...')); - form.ajaxSubmit(options); - }); -}); diff --git a/forum/skins/default/media/js/com.cnprog.editor.js b/forum/skins/default/media/js/com.cnprog.editor.js deleted file mode 100644 index 18cc516..0000000 --- a/forum/skins/default/media/js/com.cnprog.editor.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - jQuery TextAreaResizer plugin - Created on 17th January 2008 by Ryan O'Dell - Version 1.0.4 -*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('
    ').parent().append($('
    ').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i1){v=words.slice(0,words.length-1).join(options.multipleSeparator)+options.multipleSeparator+v;}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&¤tValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value){return[""];}var words=value.split(options.multipleSeparator);var result=[];$.each(words,function(i,value){if($.trim(value))result[i]=$.trim(value);});return result;}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.Autocompleter.Selection(input,previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else -$input.val("");}});}if(wasVisible)$.Autocompleter.Selection(input,input.value.length,input.value.length);};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"$1");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else -if(data[q]){return data[q];}else -if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("
    ").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("
      ").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.Autocompleter.Selection=function(field,start,end){if(field.createTextRange){var selRange=field.createTextRange();selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}else if(field.setSelectionRange){field.setSelectionRange(start,end);}else{if(field.selectionStart){field.selectionStart=start;field.selectionEnd=end;}}field.focus();};})(jQuery); -/* - * TypeWatch 2.0 - Original by Denny Ferrassoli / Refactored by Charles Christolini - * Copyright(c) 2007 Denny Ferrassoli - DennyDotNet.com - * Coprright(c) 2008 Charles Christolini - BinaryPie.com - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html -*/(function(jQuery){jQuery.fn.typeWatch=function(o){var options=jQuery.extend({wait:750,callback:function(){},highlight:true,captureLength:2},o);function checkElement(timer,override){var elTxt=jQuery(timer.el).val();if((elTxt.length>options.captureLength&&elTxt.toUpperCase()!=timer.text)||(override&&elTxt.length>options.captureLength)){timer.text=elTxt.toUpperCase();timer.cb(elTxt)}};function watchElement(elem){if(elem.type.toUpperCase()=="TEXT"||elem.nodeName.toUpperCase()=="TEXTAREA"){var timer={timer:null,text:jQuery(elem).val().toUpperCase(),cb:options.callback,el:elem,wait:options.wait};if(options.highlight){jQuery(elem).focus(function(){this.select()})}var startWatch=function(evt){var timerWait=timer.wait;var overrideBool=false;if(evt.keyCode==13&&this.type.toUpperCase()=="TEXT"){timerWait=1;overrideBool=true}var timerCallbackFx=function(){checkElement(timer,overrideBool)};clearTimeout(timer.timer);timer.timer=setTimeout(timerCallbackFx,timerWait)};jQuery(elem).keydown(startWatch)}};return this.each(function(index){watchElement(this)})}})(jQuery); -/* -Ajax upload -*/jQuery.extend({createUploadIframe:function(d,b){var a="jUploadFrame"+d;if(window.ActiveXObject){var c=document.createElement('