From 2869eaf8b9241fdb84edfab1fa0b3b264c92e2bc Mon Sep 17 00:00:00 2001 From: ketralnis Date: Mon, 3 May 2010 16:53:52 -0700 Subject: [PATCH] New features: * Activate negative-result caching for HardCache chain * begin migration to pylibmc: * Add pylibmc to the list of required packages in preparation for the replacement of the memcached library * Start using pylibmc for the rendercaches * Tweak the computation of the normalized hot page to be a bit faster when the precomputer is available, by relying on the precomputer's internal permacached structure. * Default to a SelfEmptyingCache for scripts run from `paster run'. Note that processes that run forever are still responsible for resetting their local-caches, but this can now be done with g.reset_caches() * threaded messaging patch part 1: backend changes only. This will allow migrate.py to be run to move new onto inbox and will start tracking message trees for users. * Specify some queries to run at most once per day * Refactored safemarkdown() and added soup testing Additions: * Added _byID_rel() * Made error messages more verbose for: 1. byID lookups of too-big thing_ids 2. memcache failures 3. Solr Nones * Award._all_awards() now sorts by date * Trophy.by_{account,award}() now cache properly * new feedback page with helpful links * Try to reduce the length of the query-queue by not adding known-long queries at all, rather than adding them and skipping them * whitespace clean up * simplify the 'why did my CC get denied' email checking. * added missing translation strings and users now get PMs when they are added as translators Bugfixes: * Fix a bug in unsaving * BeautifulSoup stopped hosting 3.0.7a, but 3.0.8 still uses the good parser * Better search error handling * Properly reset the cache-chains (incl. the hardcache; d'oh!) per-request * Fix an attribute error on listings where some items have author_ids and some don't * Bug when forcing recalculation of memoized functions * the subreddit creation and edit form aren't dealing with errors properly * buttons fix --- r2/Makefile | 4 +- r2/babel.cfg | 2 +- r2/example.ini | 4 +- r2/ez_setup/__init__.py | 10 +- r2/r2/__init__.py | 10 +- r2/r2/commands.py | 15 +- r2/r2/config/__init__.py | 10 +- r2/r2/config/admin_routes.py | 10 +- r2/r2/config/environment.py | 10 +- r2/r2/config/middleware.py | 2 +- r2/r2/config/rewrites.py | 10 +- r2/r2/config/routing.py | 12 +- r2/r2/config/templates.py | 10 +- r2/r2/config/utils.py | 10 +- r2/r2/controllers/__init__.py | 10 +- r2/r2/controllers/admin.py | 10 +- r2/r2/controllers/api.py | 143 +- r2/r2/controllers/awards.py | 10 +- r2/r2/controllers/buttons.py | 35 +- r2/r2/controllers/captcha.py | 10 +- r2/r2/controllers/embed.py | 10 +- r2/r2/controllers/error.py | 36 +- r2/r2/controllers/errors.py | 10 +- r2/r2/controllers/feedback.py | 17 +- r2/r2/controllers/front.py | 52 +- r2/r2/controllers/i18n.py | 27 +- r2/r2/controllers/listingcontroller.py | 91 +- r2/r2/controllers/mediaembed.py | 10 +- r2/r2/controllers/post.py | 12 +- r2/r2/controllers/promotecontroller.py | 10 +- r2/r2/controllers/reddit_base.py | 12 +- r2/r2/controllers/redirect.py | 10 +- r2/r2/controllers/template.py | 10 +- r2/r2/controllers/toolbar.py | 10 +- r2/r2/controllers/validator/__init__.py | 10 +- r2/r2/controllers/validator/validator.py | 22 +- r2/r2/i18n/__init__.py | 10 +- r2/r2/i18n/r2.pot | 1415 +++++++---- r2/r2/lib/__init__.py | 10 +- r2/r2/lib/amqp.py | 14 +- r2/r2/lib/app_globals.py | 38 +- r2/r2/lib/authorize/__init__.py | 10 +- r2/r2/lib/authorize/api.py | 10 +- r2/r2/lib/authorize/interaction.py | 10 +- r2/r2/lib/base.py | 10 +- r2/r2/lib/c/filters.c | 4 +- r2/r2/lib/c/recommendations/Database.cpp | 2 +- r2/r2/lib/c/recommendations/Database.h | 2 +- r2/r2/lib/c/recommendations/Dictionary.h | 2 +- r2/r2/lib/c/recommendations/ModsTable.cpp | 2 +- r2/r2/lib/c/recommendations/ModsTable.h | 2 +- r2/r2/lib/c/recommendations/Recommender.cpp | 2 +- r2/r2/lib/c/recommendations/Recommender.h | 2 +- r2/r2/lib/c/recommendations/SparseMatrix.h | 2 +- r2/r2/lib/c/recommendations/User.cpp | 2 +- r2/r2/lib/c/recommendations/User.h | 2 +- r2/r2/lib/c/recommendations/articles.cpp | 2 +- r2/r2/lib/c/recommendations/articles.h | 2 +- r2/r2/lib/c/recommendations/main.cpp | 2 +- .../c/recommendations/recommend_memcache.cpp | 2 +- .../c/recommendations/recommend_memcache.h | 2 +- r2/r2/lib/c/recommendations/recommender_py.h | 2 +- r2/r2/lib/c_markdown.py | 2 + r2/r2/lib/cache.py | 143 +- r2/r2/lib/captcha.py | 10 +- r2/r2/lib/comment_tree.py | 152 +- r2/r2/lib/contrib/gprof2dot.py | 2227 +++++++++++++++++ r2/r2/lib/contrib/markdown.py | 5 +- r2/r2/lib/contrib/memcache.py | 8 +- r2/r2/lib/contrib/nymph.py | 10 +- r2/r2/lib/count.py | 10 +- r2/r2/lib/cssfilter.py | 17 +- r2/r2/lib/db/__init__.py | 10 +- r2/r2/lib/db/alter_db.py | 10 +- r2/r2/lib/db/operators.py | 10 +- r2/r2/lib/db/queries.py | 103 +- r2/r2/lib/db/query_queue.py | 16 +- r2/r2/lib/db/sorts.py | 10 +- r2/r2/lib/db/stats.py | 10 +- r2/r2/lib/db/tdb_lite.py | 11 +- r2/r2/lib/db/tdb_sql.py | 39 +- r2/r2/lib/db/thing.py | 55 +- r2/r2/lib/db/userrel.py | 10 +- r2/r2/lib/emailer.py | 10 +- r2/r2/lib/filters.py | 124 +- r2/r2/lib/find_tz.py | 10 +- r2/r2/lib/hardcachebackend.py | 85 +- r2/r2/lib/helpers.py | 10 +- r2/r2/lib/html_source.py | 10 +- r2/r2/lib/jsonresponse.py | 10 +- r2/r2/lib/jsontemplates.py | 29 +- r2/r2/lib/lock.py | 10 +- r2/r2/lib/logger.py | 10 +- r2/r2/lib/manager/__init__.py | 10 +- r2/r2/lib/manager/db_manager.py | 10 +- r2/r2/lib/manager/tp_manager.py | 10 +- r2/r2/lib/media.py | 10 +- r2/r2/lib/memoize.py | 13 +- r2/r2/lib/menus.py | 10 +- r2/r2/lib/migrate.py | 81 +- r2/r2/lib/normalized_hot.py | 71 +- r2/r2/lib/organic.py | 24 +- r2/r2/lib/pages/__init__.py | 10 +- r2/r2/lib/pages/admin_pages.py | 11 +- r2/r2/lib/pages/graph.py | 10 +- r2/r2/lib/pages/pages.py | 60 +- r2/r2/lib/pages/things.py | 13 +- r2/r2/lib/promote.py | 12 +- r2/r2/lib/py_markdown.py | 59 + r2/r2/lib/queues.py | 10 +- r2/r2/lib/recommendation.py | 10 +- r2/r2/lib/rising.py | 10 +- r2/r2/lib/rpc.py | 10 +- r2/r2/lib/s3cp.py | 10 +- r2/r2/lib/scraper.py | 10 +- r2/r2/lib/services.py | 8 +- r2/r2/lib/set_reddit_pops.py | 10 +- r2/r2/lib/solrsearch.py | 45 +- r2/r2/lib/strings.py | 15 +- r2/r2/lib/sup.py | 10 +- r2/r2/lib/template_helpers.py | 14 +- r2/r2/lib/test_cache.py | 10 +- r2/r2/lib/test_wrapper.py | 10 +- r2/r2/lib/tracking.py | 10 +- r2/r2/lib/traffic.py | 10 +- r2/r2/lib/translation.py | 10 +- r2/r2/lib/utils/__init__.py | 10 +- r2/r2/lib/utils/cmd_utils.py | 10 +- r2/r2/lib/utils/utils.py | 37 +- r2/r2/lib/workqueue.py | 10 +- r2/r2/lib/wrapped.py | 20 +- r2/r2/models/__init__.py | 10 +- r2/r2/models/account.py | 75 +- r2/r2/models/admintools.py | 10 +- r2/r2/models/award.py | 66 +- r2/r2/models/bidding.py | 10 +- r2/r2/models/builder.py | 188 +- r2/r2/models/link.py | 135 +- r2/r2/models/listing.py | 16 +- r2/r2/models/mail_queue.py | 10 +- r2/r2/models/populatedb.py | 10 +- r2/r2/models/printable.py | 10 +- r2/r2/models/report.py | 10 +- r2/r2/models/subreddit.py | 11 +- r2/r2/models/types.py | 10 +- r2/r2/models/update_karmas.py | 10 +- r2/r2/models/vote.py | 17 +- r2/r2/public/static/alien-head.png | Bin 0 -> 322 bytes r2/r2/public/static/css/reddit-ie7-hax.css | 4 + r2/r2/public/static/css/reddit.css | 164 +- r2/r2/public/static/help.png | Bin 187 -> 206 bytes r2/r2/public/static/iphone/index.html | 2 +- r2/r2/public/static/js/jquery.reddit.js | 23 +- r2/r2/public/static/js/reddit.js | 70 +- r2/r2/public/static/js/sponsored.js | 2 +- r2/r2/public/static/kill.png | Bin 190 -> 216 bytes r2/r2/public/static/mail.png | Bin 184 -> 204 bytes r2/r2/public/static/mailgray.png | Bin 184 -> 208 bytes r2/r2/public/static/red-arrow.png | Bin 0 -> 804 bytes r2/r2/templates/__init__.py | 10 +- r2/r2/templates/admin/__init__.py | 10 +- r2/r2/templates/admin_rightbox.html | 10 +- r2/r2/templates/adminawardgive.html | 10 +- r2/r2/templates/adminawards.html | 10 +- r2/r2/templates/adminawardwinners.html | 10 +- r2/r2/templates/admintranslations.html | 45 +- r2/r2/templates/ads.html | 10 +- r2/r2/templates/appservicemonitor.html | 10 +- r2/r2/templates/autohandler | 2 +- r2/r2/templates/base.html | 10 +- r2/r2/templates/base.htmllite | 2 +- r2/r2/templates/base.mobile | 2 +- r2/r2/templates/base.wired | 2 +- r2/r2/templates/base.xml | 2 +- r2/r2/templates/bookmarklets.html | 10 +- r2/r2/templates/button.html | 10 +- r2/r2/templates/buttondemopanel.html | 10 +- r2/r2/templates/buttonembed.js | 2 +- r2/r2/templates/buttonlite.js | 2 +- r2/r2/templates/buttonnobody.html | 10 +- r2/r2/templates/buttontypes.html | 14 +- r2/r2/templates/captcha.html | 10 +- r2/r2/templates/clickgadget.html | 10 +- r2/r2/templates/cnameframe.html | 10 +- r2/r2/templates/comment.html | 10 +- r2/r2/templates/comment.htmllite | 2 +- r2/r2/templates/comment.mobile | 2 +- r2/r2/templates/comment.xml | 2 +- r2/r2/templates/comment_skeleton.html | 11 +- r2/r2/templates/commentspanel.html | 10 +- r2/r2/templates/createsubreddit.html | 17 +- r2/r2/templates/csserror.html | 10 +- r2/r2/templates/embed.html | 10 +- r2/r2/templates/errorpage.html | 10 +- r2/r2/templates/feedback.html | 10 +- r2/r2/templates/feedbackblurb.html | 69 + r2/r2/templates/frame.html | 10 +- r2/r2/templates/frametoolbar.html | 12 +- r2/r2/templates/gettextheader.html | 10 +- r2/r2/templates/headerbar.mobile | 2 +- r2/r2/templates/headerbar.xml | 2 +- r2/r2/templates/helppage.html | 10 +- r2/r2/templates/infobar.html | 10 +- r2/r2/templates/infobar.htmllite | 2 +- r2/r2/templates/infobar.mobile | 2 +- r2/r2/templates/infobar.wired | 2 +- r2/r2/templates/infobar.xml | 2 +- r2/r2/templates/innertoolbarframe.html | 10 +- r2/r2/templates/jquery.reddit.js | 2 +- r2/r2/templates/link.html | 18 +- r2/r2/templates/link.htmllite | 2 +- r2/r2/templates/link.mobile | 2 +- r2/r2/templates/link.wired | 2 +- r2/r2/templates/link.xml | 2 +- r2/r2/templates/linkinfobar.html | 10 +- r2/r2/templates/linkpromoteinfobar.html | 10 +- r2/r2/templates/listing.html | 10 +- r2/r2/templates/listing.htmllite | 2 +- r2/r2/templates/listing.mobile | 2 +- r2/r2/templates/listing.wired | 2 +- r2/r2/templates/listing.xml | 2 +- r2/r2/templates/login.html | 10 +- r2/r2/templates/login.mobile | 2 +- r2/r2/templates/loginformwide.html | 10 +- r2/r2/templates/mail_opt.email | 2 +- r2/r2/templates/mediaembed.html | 10 +- r2/r2/templates/mediaembedbody.html | 10 +- r2/r2/templates/menuarea.html | 10 +- r2/r2/templates/menuarea.htmllite | 2 +- r2/r2/templates/menuarea.mobile | 2 +- r2/r2/templates/menuarea.xml | 2 +- r2/r2/templates/message.html | 85 +- r2/r2/templates/message.xml | 2 +- r2/r2/templates/messagecompose.html | 10 +- r2/r2/templates/morechildren.html | 10 +- r2/r2/templates/morechildren.htmllite | 2 +- r2/r2/templates/morechildren.mobile | 2 +- r2/r2/templates/morechildren.xml | 2 +- r2/r2/templates/moremessages.html | 51 + r2/r2/templates/morerecursion.html | 10 +- r2/r2/templates/morerecursion.htmllite | 2 +- r2/r2/templates/morerecursion.mobile | 2 +- r2/r2/templates/morerecursion.xml | 2 +- r2/r2/templates/navbutton.html | 10 +- r2/r2/templates/navbutton.mobile | 2 +- r2/r2/templates/navmenu.html | 10 +- r2/r2/templates/navmenu.htmllite | 2 +- r2/r2/templates/navmenu.mobile | 2 +- r2/r2/templates/newlink.html | 11 +- r2/r2/templates/optout.html | 10 +- r2/r2/templates/organiclisting.html | 10 +- r2/r2/templates/over18.html | 10 +- r2/r2/templates/page_down.html | 10 +- r2/r2/templates/pagenamenav.html | 10 +- r2/r2/templates/pagenamenav.mobile | 2 +- r2/r2/templates/panestack.html | 10 +- r2/r2/templates/panestack.htmllite | 2 +- r2/r2/templates/panestack.mobile | 2 +- r2/r2/templates/panestack.wired | 2 +- r2/r2/templates/panestack.xml | 2 +- r2/r2/templates/password.html | 10 +- r2/r2/templates/passwordreset.email | 2 +- r2/r2/templates/paymentform.html | 10 +- r2/r2/templates/permalinkmessage.html | 10 +- r2/r2/templates/permalinkmessage.mobile | 2 +- r2/r2/templates/permalinkmessage.xml | 2 +- r2/r2/templates/prefdelete.html | 10 +- r2/r2/templates/prefoptions.html | 26 +- r2/r2/templates/prefupdate.html | 10 +- r2/r2/templates/printable.html | 13 +- r2/r2/templates/printable.htmllite | 2 +- r2/r2/templates/printable.mobile | 2 +- r2/r2/templates/printablebuttons.html | 28 +- r2/r2/templates/profilebar.html | 10 +- r2/r2/templates/profiling.html | 10 +- r2/r2/templates/promo_email.email | 4 +- r2/r2/templates/promote_graph.html | 10 +- r2/r2/templates/promotedlink.html | 10 +- r2/r2/templates/promotedtraffic.html | 10 +- r2/r2/templates/promotelinkform.html | 18 +- r2/r2/templates/reddit.html | 10 +- r2/r2/templates/reddit.htmllite | 2 +- r2/r2/templates/reddit.js | 2 +- r2/r2/templates/reddit.mobile | 2 +- r2/r2/templates/reddit.wired | 2 +- r2/r2/templates/reddit.xml | 2 +- r2/r2/templates/redditfooter.html | 10 +- r2/r2/templates/redditheader.html | 10 +- r2/r2/templates/redditheader.mobile | 2 +- r2/r2/templates/redditmin.html | 10 +- r2/r2/templates/reddittraffic.html | 10 +- r2/r2/templates/resetpassword.html | 10 +- r2/r2/templates/searchbar.html | 12 +- r2/r2/templates/searchbar.htmllite | 2 +- r2/r2/templates/searchbar.mobile | 2 +- r2/r2/templates/searchbar.xml | 2 +- r2/r2/templates/searchfail.html | 42 + r2/r2/templates/searchfail.htmllite | 0 r2/r2/templates/searchfail.mobile | 0 r2/r2/templates/searchfail.xml | 0 r2/r2/templates/searchform.html | 10 +- r2/r2/templates/selfserveblurb.html | 10 +- r2/r2/templates/selftext.html | 8 +- r2/r2/templates/share.email | 2 +- r2/r2/templates/sidebox.html | 10 +- r2/r2/templates/sidecontentbox.html | 10 +- r2/r2/templates/sponsorshipbox.html | 12 +- r2/r2/templates/starkcomment.html | 10 +- r2/r2/templates/subreddit.html | 10 +- r2/r2/templates/subreddit.mobile | 2 +- r2/r2/templates/subreddit.xml | 2 +- r2/r2/templates/subredditinfobar.html | 10 +- r2/r2/templates/subredditstylesheet.html | 10 +- r2/r2/templates/subreddittopbar.html | 10 +- r2/r2/templates/subscriptionbox.html | 10 +- r2/r2/templates/takedownpane.html | 10 +- r2/r2/templates/translatedstring.html | 10 +- r2/r2/templates/translation.html | 10 +- r2/r2/templates/translator_message.html | 47 + r2/r2/templates/trophycase.html | 24 +- r2/r2/templates/unfoundpage.html | 10 +- r2/r2/templates/unfoundpage.htmllite | 2 +- r2/r2/templates/unfoundpage.mobile | 2 +- r2/r2/templates/unfoundpage.xml | 2 +- r2/r2/templates/uploadedimage.html | 10 +- r2/r2/templates/userawards.html | 14 +- r2/r2/templates/userlist.html | 10 +- r2/r2/templates/usertableitem.html | 10 +- r2/r2/templates/usertext.html | 10 +- r2/r2/templates/utils.html | 10 +- r2/r2/templates/verifyemail.email | 2 +- r2/r2/templates/widgetdemopanel.html | 10 +- r2/r2/templates/wrappeduser.html | 10 +- r2/r2/tests/__init__.py | 10 +- r2/r2/tests/functional/__init__.py | 10 +- r2/r2/tests/test_models.py | 10 +- r2/r2/websetup.py | 10 +- r2/setup.py | 10 +- r2/supervise_watcher.py | 10 +- r2/translation.py | 10 +- 340 files changed, 6443 insertions(+), 2171 deletions(-) create mode 100644 r2/r2/lib/c_markdown.py create mode 100644 r2/r2/lib/contrib/gprof2dot.py create mode 100644 r2/r2/lib/py_markdown.py create mode 100644 r2/r2/public/static/alien-head.png create mode 100644 r2/r2/public/static/red-arrow.png create mode 100644 r2/r2/templates/feedbackblurb.html create mode 100644 r2/r2/templates/moremessages.html create mode 100644 r2/r2/templates/searchfail.html create mode 100644 r2/r2/templates/searchfail.htmllite create mode 100644 r2/r2/templates/searchfail.mobile create mode 100644 r2/r2/templates/searchfail.xml create mode 100644 r2/r2/templates/translator_message.html diff --git a/r2/Makefile b/r2/Makefile index 2a3219ab8..f744460e1 100644 --- a/r2/Makefile +++ b/r2/Makefile @@ -16,7 +16,7 @@ # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. # -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -94,4 +94,4 @@ md5: $(MD5S) rtl: $(RTLCSS) clean: - rm $(JSTARGETS) $(CSSTARGETS) $(MD5S) $(INIS) \ No newline at end of file + rm $(JSTARGETS) $(CSSTARGETS) $(MD5S) $(INIS) diff --git a/r2/babel.cfg b/r2/babel.cfg index 1f3bb8e92..961c3ead3 100644 --- a/r2/babel.cfg +++ b/r2/babel.cfg @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/example.ini b/r2/example.ini index b2cd67451..f7ad061a1 100644 --- a/r2/example.ini +++ b/r2/example.ini @@ -117,8 +117,6 @@ allowed_css_linked_domains = my.domain.com, my.otherdomain.com css_killswitch = False max_sr_images = 20 -show_awards = False - takedown_sr = _takedowns login_cookie = reddit_session domain = localhost @@ -139,6 +137,8 @@ profanity_wordlist = solr_url = solr_cache_time = 300 +markdown_backend = py + SECRET = abcdefghijklmnopqrstuvwxyz0123456789 MODSECRET = abcdefghijklmnopqrstuvwxyz0123456789 tracking_secret = abcdefghijklmnopqrstuvwxyz0123456789 diff --git a/r2/ez_setup/__init__.py b/r2/ez_setup/__init__.py index ef180d6c9..c8035d2bd 100644 --- a/r2/ez_setup/__init__.py +++ b/r2/ez_setup/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ #!python diff --git a/r2/r2/__init__.py b/r2/r2/__init__.py index 74b8665f4..fa85019b7 100644 --- a/r2/r2/__init__.py +++ b/r2/r2/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """r2 diff --git a/r2/r2/commands.py b/r2/r2/commands.py index 404fcdb01..21eea57e1 100644 --- a/r2/r2/commands.py +++ b/r2/r2/commands.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import paste.deploy.config @@ -34,7 +34,7 @@ from pylons.wsgiapp import PylonsApp import os, sys # # commands that will be available by running paste with this app -# +# class RunCommand(command.Command): max_args = 2 @@ -55,6 +55,7 @@ class RunCommand(command.Command): here_dir = os.getcwd() conf = appconfig(config_name, relative_to=here_dir) + conf.global_conf['running_as_script'] = True conf.update(dict(app_conf=conf.local_conf, global_conf=conf.global_conf)) paste.deploy.config.CONFIG.push_thread_config(conf) @@ -67,7 +68,7 @@ class RunCommand(command.Command): # Load the wsgi app first so that everything is initialized right wsgiapp = RegistryManager(PylonsApp()) test_app = paste.fixture.TestApp(wsgiapp) - + # Query the test app to setup the environment tresponse = test_app.get('/_test_vars') request_id = int(tresponse.body) diff --git a/r2/r2/config/__init__.py b/r2/r2/config/__init__.py index 3f52a4c72..95d168096 100644 --- a/r2/r2/config/__init__.py +++ b/r2/r2/config/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.cache import sgm diff --git a/r2/r2/config/admin_routes.py b/r2/r2/config/admin_routes.py index 99d6e361b..2a1f07ed1 100644 --- a/r2/r2/config/admin_routes.py +++ b/r2/r2/config/admin_routes.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ def add(mc): diff --git a/r2/r2/config/environment.py b/r2/r2/config/environment.py index 8c7620b55..47f321db7 100644 --- a/r2/r2/config/environment.py +++ b/r2/r2/config/environment.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import os diff --git a/r2/r2/config/middleware.py b/r2/r2/config/middleware.py index 4ac16a93e..a559b2c6d 100644 --- a/r2/r2/config/middleware.py +++ b/r2/r2/config/middleware.py @@ -16,7 +16,7 @@ # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. # -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """Pylons middleware initialization""" diff --git a/r2/r2/config/rewrites.py b/r2/r2/config/rewrites.py index d33318619..7e6dd728f 100644 --- a/r2/r2/config/rewrites.py +++ b/r2/r2/config/rewrites.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import re diff --git a/r2/r2/config/routing.py b/r2/r2/config/routing.py index 988a61fbd..3442aa5ca 100644 --- a/r2/r2/config/routing.py +++ b/r2/r2/config/routing.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ @@ -150,6 +150,8 @@ def make_map(global_conf={}, app_conf={}): requirements = dict(sort = 'top|controversial')) mc('/message/compose', controller='message', action='compose') + mc('/message/messages/:mid', controller='message', action='listing', + where = "messages") mc('/message/:where', controller='message', action='listing') mc('/:action', controller='front', diff --git a/r2/r2/config/templates.py b/r2/r2/config/templates.py index b04430042..d58fcf875 100644 --- a/r2/r2/config/templates.py +++ b/r2/r2/config/templates.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.manager import tp_manager diff --git a/r2/r2/config/utils.py b/r2/r2/config/utils.py index 8a943633f..e375886b2 100644 --- a/r2/r2/config/utils.py +++ b/r2/r2/config/utils.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ iters = (list, tuple, set) diff --git a/r2/r2/controllers/__init__.py b/r2/r2/controllers/__init__.py index 9bdaee522..bd02fd347 100644 --- a/r2/r2/controllers/__init__.py +++ b/r2/r2/controllers/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from listingcontroller import ListingController diff --git a/r2/r2/controllers/admin.py b/r2/r2/controllers/admin.py index fb8eaa8dc..694a621d8 100644 --- a/r2/r2/controllers/admin.py +++ b/r2/r2/controllers/admin.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.controllers.reddit_base import RedditController diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index 360218689..4942ae785 100644 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController, set_user_cookie @@ -31,7 +31,7 @@ from r2.models.subreddit import Default as DefaultSR from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified from r2.lib.utils import query_string, link_from_url, timefromnow -from r2.lib.utils import timeago +from r2.lib.utils import timeago, tup from r2.lib.pages import FriendList, ContributorList, ModList, \ BannedList, BoringPage, FormPage, CssError, UploadedImage, \ ClickGadget @@ -202,7 +202,8 @@ class ApiController(RedditController): l._commit() l.set_url_cache() - queries.queue_vote(c.user, l, True, ip) + queries.queue_vote(c.user, l, True, ip, + cheater = (errors.CHEATER, None) in c.errors) if save: r = l._save(c.user) queries.new_savehide(r) @@ -258,22 +259,33 @@ class ApiController(RedditController): @validatedForm(VRatelimit(rate_ip = True, prefix = 'login_', error = errors.WRONG_PASSWORD), user = VLogin(['user', 'passwd']), + username = VLength('user', max_length = 100), dest = VDestination(), rem = VBoolean('rem'), reason = VReason('reason')) - def POST_login(self, form, jquery, user, dest, rem, reason): + def POST_login(self, form, jquery, user, username, dest, rem, reason): if reason and reason[0] == 'redirect': dest = reason[1] hc_key = "login_attempts-%s" % request.ip - recent_attempts = g.hardcache.get(hc_key, 0) + # TODO: You-know-what (not mentioning it, just in case + # we accidentally release code with this comment in it) + # Cache lifetime for login_attmempts + la_expire_time = 3600 * 8 + + recent_attempts = g.hardcache.add(hc_key, 0, time=la_expire_time) + + fake_failure = False if recent_attempts >= 25: - raise NotImplementedError("need proper fail msg") - elif form.has_errors("passwd", errors.WRONG_PASSWORD): + g.log.error ("%s failed to login as %s (attempt #%d)" + % (request.ip, username, recent_attempts)) + fake_failure = True + + if fake_failure or form.has_errors("passwd", errors.WRONG_PASSWORD): VRatelimit.ratelimit(rate_ip = True, prefix = 'login_', seconds=1) - g.hardcache.set(hc_key, recent_attempts + 1, 3600 * 8) + g.hardcache.incr(hc_key, time = la_expire_time) else: self._login(form, user, dest, rem) @@ -635,7 +647,8 @@ class ApiController(RedditController): else: item, inbox_rel = Comment._new(c.user, link, parent_comment, comment, ip) - queries.queue_vote(c.user, item, True, ip) + queries.queue_vote(c.user, item, True, ip, + cheater = (errors.CHEATER, None) in c.errors) #update last modified set_last_modified(link, 'comments') @@ -653,6 +666,7 @@ class ApiController(RedditController): # insert the new comment jquery.insert_things(item) + # remove any null listings that may be present jquery("#noresults").hide() @@ -721,7 +735,7 @@ class ApiController(RedditController): if should_ratelimit: VRatelimit.ratelimit(rate_user=True, rate_ip = True, prefix = "rate_share_") - + @noresponse(VUser(), VModhash(), vote_type = VVotehash(('vh', 'id')), @@ -731,13 +745,21 @@ class ApiController(RedditController): def POST_vote(self, dir, thing, ip, vote_type): ip = request.ip user = c.user + store = True + if not thing or thing._deleted: return + if vote_type == "rejected": + g.log.error("POST_vote: rejected vote (%s) from '%s' on %s (%s)"% + (request.params.get('dir'), c.user.name, + thing._fullname, request.ip)) + store = False + # TODO: temporary hack until we migrate the rest of the vote data if thing._date < datetime(2009, 4, 17, 0, 0, 0, 0, g.tz): - g.log.debug("POST_vote: ignoring old vote on %s" % thing._fullname) - return + g.log.error("POST_vote: ignoring old vote on %s" % thing._fullname) + store = False # in a lock to prevent duplicate votes from people # double-clicking the arrows @@ -745,16 +767,18 @@ class ApiController(RedditController): dir = (True if dir > 0 else False if dir < 0 else None) + organic = vote_type == 'organic' - queries.queue_vote(user, thing, dir, ip, organic) + queries.queue_vote(user, thing, dir, ip, organic, store = store, + cheater = (errors.CHEATER, None) in c.errors) + if store: + #update relevant caches + if isinstance(thing, Link): + set_last_modified(c.user, 'liked') + set_last_modified(c.user, 'disliked') - #update relevant caches - if isinstance(thing, Link): - set_last_modified(c.user, 'liked') - set_last_modified(c.user, 'disliked') - - # flag search indexer that something has changed - changed(thing) + # flag search indexer that something has changed + changed(thing) @validatedForm(VUser(), VModhash(), @@ -967,12 +991,13 @@ class ApiController(RedditController): ip = ValidIP(), ad_type = VOneOf('ad', ('default', 'basic', 'custom')), ad_file = VLength('ad-location', max_length = 500), + sponsor_text =VLength('sponsorship-text', max_length = 500), sponsor_name =VLength('sponsorship-name', max_length = 500), sponsor_url = VLength('sponsorship-url', max_length = 500), css_on_cname = VBoolean("css_on_cname"), ) def POST_site_admin(self, form, jquery, name, ip, sr, ad_type, ad_file, - sponsor_url, sponsor_name, **kw): + sponsor_text, sponsor_url, sponsor_name, **kw): # the status button is outside the form -- have to reset by hand form.parent().set_html('.status', "") @@ -1004,6 +1029,7 @@ class ApiController(RedditController): elif (form.has_errors(None, errors.INVALID_OPTION) or form.has_errors('description', errors.TOO_LONG)): pass + #creating a new reddit elif not sr: #sending kw is ok because it was sanitized above @@ -1032,6 +1058,7 @@ class ApiController(RedditController): if ad_type != "custom": ad_file = Subreddit._defaults['ad_file'] sr.ad_file = ad_file + sr.sponsorship_text = sponsor_text or "" sr.sponsorship_url = sponsor_url or None sr.sponsorship_name = sponsor_name or None @@ -1053,7 +1080,10 @@ class ApiController(RedditController): changed(sr) form.parent().set_html('.status', _("saved")) - if redir: + # don't go any further until the form validates + if form.has_error(): + return + elif redir: form.redirect(redir) else: jquery.refresh() @@ -1107,6 +1137,32 @@ class ApiController(RedditController): if r: queries.new_savehide(r) + @noresponse(VUser(), + VModhash(), + thing = VByName('id', multiple = True)) + def POST_collapse_message(self, thing): + if not thing: + return + for t in tup(thing): + if hasattr(t, "to_id") and c.user._id == t.to_id: + t.to_collapse = True + elif hasattr(t, "author_id") and c.user._id == t.author_id: + t.author_collapse = True + t._commit() + + @noresponse(VUser(), + VModhash(), + thing = VByName('id', multiple = True)) + def POST_uncollapse_message(self, thing): + if not thing: + return + for t in tup(thing): + if hasattr(t, "to_id") and c.user._id == t.to_id: + t.to_collapse = False + elif hasattr(t, "author_id") and c.user._id == t.author_id: + t.author_collapse = False + t._commit() + @noresponse(VUser(), VModhash(), thing = VByName('id')) @@ -1115,8 +1171,7 @@ class ApiController(RedditController): return if hasattr(thing, "to_id") and c.user._id != thing.to_id: return - thing.new = True - thing._commit() + queries.set_unread(thing, True) @noresponse(VUser(), VModhash(), @@ -1125,10 +1180,7 @@ class ApiController(RedditController): if not thing: return if hasattr(thing, "to_id") and c.user._id != thing.to_id: return - thing.new = False - thing._commit() - - + queries.set_unread(thing, False) @noresponse(VUser(), VModhash(), @@ -1148,6 +1200,24 @@ class ApiController(RedditController): queries.new_savehide(r) + @validatedForm(VUser(), + parent = VByName('parent_id')) + def POST_moremessages(self, form, jquery, parent): + if not parent.can_view(): + return self.abort(403,'forbidden') + + builder = MessageBuilder(c.user, parent = parent, skip = False) + listing = Listing(builder).listing() + a = [] + for item in listing.things: + a.append(item) + for x in item.child.things: + a.append(x) + for item in a: + if hasattr(item, "child"): + item.child = None + jquery.things(parent._fullname).parent().replace_things(a, False, True) + @validatedForm(link = VByName('link_id'), sort = VMenu('where', CommentSortMenu), children = VCommentIDs('children'), @@ -1221,7 +1291,8 @@ class ApiController(RedditController): #vote up all of the links for link in links: queries.queue_vote(c.user, link, - action == 'like', request.ip) + action == 'like', request.ip, + cheater = (errors.CHEATER, None) in c.errors) elif action == 'save': link = max(links, key = lambda x: x._score) r = link._save(c.user) @@ -1285,7 +1356,7 @@ class ApiController(RedditController): jquery("body").captcha(get_iden()) @noresponse(VAdmin(), - tr = VTranslation("id"), + tr = VTranslation("lang"), user = nop('user')) def POST_deltranslator(self, tr, user): if tr: @@ -1398,8 +1469,8 @@ class ApiController(RedditController): else: cup_expiration = None - t = Trophy._new(recipient, award, description=description, - url=url, cup_expiration=cup_expiration) + t = Trophy._new(recipient, award, description=description, url=url, + cup_info=dict(expiration=cup_expiration)) form.set_html(".status", _('saved')) diff --git a/r2/r2/controllers/awards.py b/r2/r2/controllers/awards.py index b4f68aafa..9ce61dcce 100644 --- a/r2/r2/controllers/awards.py +++ b/r2/r2/controllers/awards.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import request, g diff --git a/r2/r2/controllers/buttons.py b/r2/r2/controllers/buttons.py index 9d43678eb..df99e0930 100644 --- a/r2/r2/controllers/buttons.py +++ b/r2/r2/controllers/buttons.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController @@ -41,6 +41,7 @@ class ButtonsController(RedditController): def get_wrapped_link(self, url, link = None, wrapper = None): try: + links = [] if link: links = [link] else: @@ -48,7 +49,7 @@ class ButtonsController(RedditController): try: links = tup(Link._by_url(url, sr)) except NotFound: - links = [] + pass if links: kw = {} @@ -80,10 +81,9 @@ class ButtonsController(RedditController): vote = VBoolean('vote', default=True), newwindow = VBoolean('newwindow'), width = VInt('width', 0, 800), - link = VByName('id')) - def GET_button_content(self, url, title, css, vote, newwindow, width, link): - - + l = VByName('id')) + def GET_button_content(self, url, title, css, vote, newwindow, width, l): + # no buttons on domain listings if isinstance(c.site, DomainSR): c.site = Default @@ -94,17 +94,20 @@ class ButtonsController(RedditController): css != 'http://www.wired.com/css/redditsocial.css'): css = None - if link: - url = link.url - title = link.title + if l: + url = l.url + title = l.title + kw = {} + if title: + kw = dict(title = title) wrapper = make_wrapper(Button if vote else ButtonNoBody, url = url, target = "_new" if newwindow else "_parent", - title = title, vote = vote, bgcolor = c.bgcolor, + vote = vote, bgcolor = c.bgcolor, width = width, css = css, - button = self.buttontype()) + button = self.buttontype(), **kw) - l = self.get_wrapped_link(url, link, wrapper) + l = self.get_wrapped_link(url, l, wrapper) res = l.render() c.response.content = spaceCompress(res) return c.response diff --git a/r2/r2/controllers/captcha.py b/r2/r2/controllers/captcha.py index a0a88b4c6..408e00ef1 100644 --- a/r2/r2/controllers/captcha.py +++ b/r2/r2/controllers/captcha.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController diff --git a/r2/r2/controllers/embed.py b/r2/r2/controllers/embed.py index 1fc4ec83e..6d0b4f8f4 100644 --- a/r2/r2/controllers/embed.py +++ b/r2/r2/controllers/embed.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController, proxyurl diff --git a/r2/r2/controllers/error.py b/r2/r2/controllers/error.py index 6a818330d..b155e4687 100644 --- a/r2/r2/controllers/error.py +++ b/r2/r2/controllers/error.py @@ -6,20 +6,21 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import os.path +from mako.filters import url_escape import paste.fileapp from pylons.middleware import error_document_template, media_path @@ -117,7 +118,12 @@ class ErrorController(RedditController): if 'usable_error_content' in request.environ: return request.environ['usable_error_content'] if c.site._spam and not c.user_is_admin: - message = (strings.banned_subreddit % dict(link = '/feedback')) + subject = ("the subreddit /r/%s has been incorrectly banned" % + c.site.name) + message = (strings.banned_subreddit % + dict(link = '/message/compose?to=%s&subject=%s' % + (g.admin_message_acct, + url_escape(subject)))) res = pages.RedditError(_('this reddit has been banned'), unsafe(safemarkdown(message))) @@ -125,6 +131,19 @@ class ErrorController(RedditController): else: return pages.Reddit404().render() + def send503(self): + c.response.status_code = 503 + if 'retry_after' in request.environ: + c.response.headers['Retry-After'] = request.environ['retry_after'] + else: + c.response.headers['Retry-After'] = 1 + + if 'usable_error_content' in request.environ: + return request.environ['usable_error_content'] + else: + c.response.content = toofast + return c.response + def GET_document(self): try: #no cookies on errors @@ -145,10 +164,7 @@ class ErrorController(RedditController): elif code == '500': return redditbroke % rand_strings.sadmessages elif code == '503': - c.response.status_code = 503 - c.response.headers['Retry-After'] = 1 - c.response.content = toofast - return c.response + return self.send503() elif code == '304': if request.GET.has_key('x-sup-id'): c.response.headers['x-sup-id'] = request.GET.get('x-sup-id') diff --git a/r2/r2/controllers/errors.py b/r2/r2/controllers/errors.py index 8791ae9bb..527a346e5 100644 --- a/r2/r2/controllers/errors.py +++ b/r2/r2/controllers/errors.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.utils import Storage, tup diff --git a/r2/r2/controllers/feedback.py b/r2/r2/controllers/feedback.py index 4fb11df17..4be78aefb 100644 --- a/r2/r2/controllers/feedback.py +++ b/r2/r2/controllers/feedback.py @@ -6,23 +6,23 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController from pylons import c, request from pylons.i18n import _ -from r2.lib.pages import FormPage, Feedback, Captcha, PaneStack, SelfServeBlurb +from r2.lib.pages import FormPage, Feedback, Captcha, PaneStack, SelfServeBlurb, FeedbackBlurb class FeedbackController(RedditController): @@ -32,13 +32,12 @@ class FeedbackController(RedditController): loginbox = False).render() def GET_feedback(self): - title = _("send reddit feedback") return FormPage('feedback', - content = Feedback(title=title, action='feedback'), + content = FeedbackBlurb(), loginbox = False).render() def GET_i18n(self): title = _("help translate reddit into your language") - return FormPage('help translate', + return FormPage(_('help translate'), content = Feedback(title=title, action='i18n'), loginbox = False).render() diff --git a/r2/r2/controllers/front.py b/r2/r2/controllers/front.py index 643d56c9f..212e69736 100644 --- a/r2/r2/controllers/front.py +++ b/r2/r2/controllers/front.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from validator import * @@ -31,16 +31,18 @@ from r2.lib.menus import * from r2.lib.utils import to36, sanitize_url, check_cheating, title_to_url from r2.lib.utils import query_string, UrlParser, link_from_url, link_duplicates from r2.lib.template_helpers import get_domain +from r2.lib.filters import unsafe from r2.lib.emailer import has_opted_out, Email from r2.lib.db.operators import desc from r2.lib.db import queries from r2.lib.strings import strings from r2.lib.solrsearch import RelatedSearchQuery, SubredditSearchQuery, LinkSearchQuery +from r2.lib.contrib.pysolr import SolrError from r2.lib import jsontemplates from r2.lib import sup import r2.lib.db.thing as thing from listingcontroller import ListingController -from pylons import c, request +from pylons import c, request, request, Response import random as rand import re @@ -228,7 +230,7 @@ class FrontController(RedditController): comment, context) listing = NestedListing(builder, num = num, parent_name = article._fullname) - + displayPane = PaneStack() # if permalink page, add that message first to the content @@ -238,11 +240,12 @@ class FrontController(RedditController): # insert reply box only for logged in user if c.user_is_loggedin and can_comment_link(article) and not is_api(): #no comment box for permalinks + display = not bool(comment) displayPane.append(UserText(item = article, creating = True, post_form = 'comment', - display = not bool(comment), + display = display, cloneable = True)) - + # finally add the comment listing displayPane.append(listing.listing()) @@ -469,12 +472,13 @@ class FrontController(RedditController): SearchSortMenu(default=sort)], search_params = dict(sort = sort, t = time), infotext = infotext).render() - + return res - + def _search(self, query_obj, num, after, reverse, count=0): """Helper function for interfacing with search. Basically a thin wrapper for SearchBuilder.""" + builder = SearchBuilder(query_obj, after = after, num = num, reverse = reverse, count = count, @@ -484,7 +488,31 @@ class FrontController(RedditController): # have to do it in two steps since total_num and timing are only # computed after fetch_more - res = listing.listing() + try: + res = listing.listing() + except SolrError, e: + errmsg = "SolrError: %r %r" % (e, query_obj) + + if (str(e) == 'None'): + # Production error logs only get non-None errors + g.log.debug(errmsg) + else: + g.log.error(errmsg) + + sf = SearchFail() + sb = SearchBar(prev_search = query_obj.q) + + us = unsafe(sb.render() + sf.render()) + + errpage = pages.RedditError(_('search failed'), us) + + c.response = Response() + c.response.status_code = 503 + request.environ['usable_error_content'] = errpage.render() + request.environ['retry_after'] = 60 + + abort(503) + timing = time_module.time() - builder.start_time return builder.total_num, timing, res diff --git a/r2/r2/controllers/i18n.py b/r2/r2/controllers/i18n.py index 26127fa45..6131cbc54 100644 --- a/r2/r2/controllers/i18n.py +++ b/r2/r2/controllers/i18n.py @@ -6,22 +6,23 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import request, g from reddit_base import RedditController -from r2.lib.pages import UnfoundPage, AdminTranslations, AdminPage +from r2.lib.pages import UnfoundPage, AdminTranslations, \ + AdminPage, Translator_Message from r2.lib.translation import Translator, TranslatorTemplate, get_translator from validator import * @@ -49,10 +50,18 @@ class I18nController(RedditController): lang = nop('lang'), a = VExistingUname('name')) def POST_adduser(self, lang, a): + from r2.lib.db import queries if a and Translator.exists(lang): tr = get_translator(locale = lang) tr.author.add(a.name) tr.save() + + # send the user a message + body = Translator_Message(lang, a).render("html") + subject = "Thanks for offering to help translate!" + m, inbox_rel = Message._new(c.user, a, subject, body, request.ip) + queries.new_message(m, inbox_rel) + return self.redirect("/admin/i18n") @@ -60,7 +69,8 @@ class I18nController(RedditController): VAdmin()) def GET_list(self): res = AdminPage(content = AdminTranslations(), - title = 'translate reddit').render() + title = 'translate reddit', + show_sidebar = False).render() return res @@ -85,7 +95,8 @@ class I18nController(RedditController): else: content = UnfoundPage() res = AdminPage(content = content, - title = 'translate reddit').render() + title = 'translate reddit', + show_sidebar = False).render() return res @validate(VTranslationEnabled(), diff --git a/r2/r2/controllers/listingcontroller.py b/r2/r2/controllers/listingcontroller.py index 1d9279fad..23ca47d31 100644 --- a/r2/r2/controllers/listingcontroller.py +++ b/r2/r2/controllers/listingcontroller.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController, base_listing @@ -39,10 +39,12 @@ from r2.lib.solrsearch import SearchQuery from r2.lib.utils import iters, check_cheating, timeago from r2.lib import sup from r2.lib.promote import PromoteSR +from r2.lib.contrib.pysolr import SolrError from admin import admin_profile_query from pylons.i18n import _ +from pylons import Response import random @@ -147,7 +149,29 @@ class ListingController(RedditController): if c.site.path == PromoteSR.path and not c.user_is_sponsor: abort(403, 'forbidden') listing = LinkListing(self.builder_obj, show_nums = self.show_nums) - return listing.listing() + try: + return listing.listing() + except SolrError, e: + errmsg = "SolrError: %r %r" % (e, self.builder_obj) + + if (str(e) == 'None'): + # Production error logs only get non-None errors + g.log.debug(errmsg) + else: + g.log.error(errmsg) + + sf = SearchFail() + + us = unsafe(sf.render()) + + errpage = pages.RedditError(_('search failed'), us) + + c.response = Response() + c.response.status_code = 503 + request.environ['usable_error_content'] = errpage.render() + request.environ['retry_after'] = 60 + + abort(503) def title(self): """Page """ @@ -229,7 +253,7 @@ class HotController(FixListing, ListingController): and not isinstance(c.site, FakeSubreddit) and self.after is None and self.count == 0): - return [l._fullname for l in get_hot(c.site)] + return get_hot(c.site, only_fullnames = True) else: return c.site.get_links('hot', 'all') @@ -483,8 +507,10 @@ class MessageController(ListingController): @property def menus(self): - if self.where in ('inbox', 'messages', 'comments', 'selfreply'): + if self.where in ('inbox', 'messages', 'comments', + 'selfreply', 'unread'): buttons = (NavButton(_("all"), "inbox"), + NavButton(_("unread"), "unread"), NavButton(plurals.messages, "messages"), NavButton(_("comment replies"), 'comments'), NavButton(_("post replies"), 'selfreply')) @@ -509,14 +535,36 @@ class MessageController(ListingController): w.permalink, w._fullname = p, f else: w = ListingController.builder_wrapper(thing) - - if c.user.pref_mark_messages_read and thing.new: - w.new = True - thing.new = False - thing._commit() return w + def builder(self): + if self.where == 'messages': + if self.message: + if self.message.first_message: + parent = Message._byID(self.message.first_message) + else: + parent = self.message + return MessageBuilder(c.user, parent = parent, + skip = False, + focal = self.message, + wrap = self.builder_wrapper, + num = self.num) + elif c.user.pref_threaded_messages: + skip = (c.render_style == "html") + return MessageBuilder(c.user, wrap = self.builder_wrapper, + skip = skip, + num = self.num, + after = self.after, + reverse = self.reverse) + return ListingController.builder(self) + + def listing(self): + if (self.where == 'messages' and + (c.user.pref_threaded_messages or self.message)): + return Listing(self.builder_obj).listing() + return ListingController.listing(self) + def query(self): if self.where == 'messages': q = queries.get_inbox_messages(c.user) @@ -524,24 +572,28 @@ class MessageController(ListingController): q = queries.get_inbox_comments(c.user) elif self.where == 'selfreply': q = queries.get_inbox_selfreply(c.user) - if self.where == 'inbox': + elif self.where == 'inbox': q = queries.get_inbox(c.user) + elif self.where == 'unread': + q = queries.get_unread_inbox(c.user) + elif self.where == 'sent': + q = queries.get_sent(c.user) + if self.where != 'sent': #reset the inbox if c.have_messages and self.mark != 'false': c.user.msgtime = False c.user._commit() - elif self.where == 'sent': - q = queries.get_sent(c.user) - return q @validate(VUser(), + message = VMessageID('mid'), mark = VOneOf('mark',('true','false'), default = 'true')) - def GET_listing(self, where, mark, **env): + def GET_listing(self, where, mark, message, **env): self.where = where self.mark = mark + self.message = message c.msg_location = where return ListingController.GET_listing(self, **env) @@ -627,7 +679,7 @@ class MyredditsController(ListingController): return stack @validate(VUser()) - def GET_listing(self, where, **env): + def GET_listing(self, where = 'inbox', **env): self.where = where return ListingController.GET_listing(self, **env) @@ -636,3 +688,4 @@ class CommentsController(ListingController): def query(self): return queries.get_all_comments() + diff --git a/r2/r2/controllers/mediaembed.py b/r2/r2/controllers/mediaembed.py index 83e80bf46..9cb4c5cf6 100644 --- a/r2/r2/controllers/mediaembed.py +++ b/r2/r2/controllers/mediaembed.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from validator import * diff --git a/r2/r2/controllers/post.py b/r2/r2/controllers/post.py index dcdcefe3a..5736b7631 100644 --- a/r2/r2/controllers/post.py +++ b/r2/r2/controllers/post.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.pages import * @@ -108,6 +108,8 @@ class PostController(ApiController): pref_label_nsfw = VBoolean('label_nsfw'), pref_show_promote = VBoolean('show_promote'), pref_mark_messages_read = VBoolean("mark_messages_read"), + pref_threaded_messages = VBoolean("threaded_messages"), + pref_collapse_read_messages = VBoolean("collapse_read_messages"), all_langs = nop('all-langs', default = 'all')) def POST_options(self, all_langs, pref_lang, **kw): #temporary. eventually we'll change pref_clickgadget to an diff --git a/r2/r2/controllers/promotecontroller.py b/r2/r2/controllers/promotecontroller.py index f25c08c89..31ff182cf 100644 --- a/r2/r2/controllers/promotecontroller.py +++ b/r2/r2/controllers/promotecontroller.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from validator import * diff --git a/r2/r2/controllers/reddit_base.py b/r2/r2/controllers/reddit_base.py index feece61a7..e291cbc45 100644 --- a/r2/r2/controllers/reddit_base.py +++ b/r2/r2/controllers/reddit_base.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import r2.lib.helpers as h @@ -463,7 +463,7 @@ class RedditController(BaseController): def pre(self): c.start_time = datetime.now(g.tz) - g.cache.caches = (LocalCache(),) + g.cache.caches[1:] + g.reset_caches() c.domain_prefix = request.environ.get("reddit-domain-prefix", g.domain_prefix) diff --git a/r2/r2/controllers/redirect.py b/r2/r2/controllers/redirect.py index f67090a92..51dbf0dd3 100644 --- a/r2/r2/controllers/redirect.py +++ b/r2/r2/controllers/redirect.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons.controllers.util import redirect_to diff --git a/r2/r2/controllers/template.py b/r2/r2/controllers/template.py index 67b0fce8e..c40243636 100644 --- a/r2/r2/controllers/template.py +++ b/r2/r2/controllers/template.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.base import * diff --git a/r2/r2/controllers/toolbar.py b/r2/r2/controllers/toolbar.py index 97ab9a13a..e76c8c4bd 100644 --- a/r2/r2/controllers/toolbar.py +++ b/r2/r2/controllers/toolbar.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from reddit_base import RedditController diff --git a/r2/r2/controllers/validator/__init__.py b/r2/r2/controllers/validator/__init__.py index 916603162..d3bf810b1 100644 --- a/r2/r2/controllers/validator/__init__.py +++ b/r2/r2/controllers/validator/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from validator import * diff --git a/r2/r2/controllers/validator/validator.py b/r2/r2/controllers/validator/validator.py index 89eb6dcba..519572bc1 100644 --- a/r2/r2/controllers/validator/validator.py +++ b/r2/r2/controllers/validator/validator.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import c, request, g @@ -308,6 +308,18 @@ class VCommentID(Validator): except (NotFound, ValueError): pass +class VMessageID(Validator): + def run(self, cid): + if cid: + try: + cid = int(cid, 36) + m = Message._byID(cid, True) + if not m.can_view(): + abort(403, 'forbidden') + return m + except (NotFound, ValueError): + pass + class VCount(Validator): def run(self, count): if count is None: diff --git a/r2/r2/i18n/__init__.py b/r2/r2/i18n/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/i18n/__init__.py +++ b/r2/r2/i18n/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/i18n/r2.pot b/r2/r2/i18n/r2.pot index 2b5621c7c..22e92c92c 100644 --- a/r2/r2/i18n/r2.pot +++ b/r2/r2/i18n/r2.pot @@ -1,14 +1,14 @@ # Translations template for r2. -# Copyright (C) 2009 ORGANIZATION +# Copyright (C) 2010 ORGANIZATION # This file is distributed under the same license as the r2 project. -# FIRST AUTHOR <EMAIL@ADDRESS>, 2009. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2010. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: r2 0.0.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2009-08-20 11:28-0700\n" +"POT-Creation-Date: 2010-01-25 14:44-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,108 +17,109 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.4\n" -#: r2/controllers/api.py:75 r2/controllers/listingcontroller.py:357 +#: r2/controllers/api.py:77 r2/controllers/listingcontroller.py:383 msgid "API" msgstr "" -#: r2/controllers/api.py:94 +#: r2/controllers/api.py:97 msgid "thanks for your message! you should hear back from us shortly." msgstr "" -#: r2/controllers/api.py:119 +#: r2/controllers/api.py:124 msgid "your message has been delivered" msgstr "" -#: r2/controllers/api.py:260 +#: r2/controllers/api.py:245 msgid "no title found" msgstr "" -#: r2/controllers/api.py:423 +#: r2/controllers/api.py:427 r2/controllers/promotecontroller.py:330 msgid "added" msgstr "" -#: r2/controllers/api.py:474 +#: r2/controllers/api.py:479 msgid "you should be getting a verification email shortly." msgstr "" -#: r2/controllers/api.py:476 +#: r2/controllers/api.py:481 msgid "your email has been updated" msgstr "" -#: r2/controllers/api.py:485 +#: r2/controllers/api.py:490 msgid "your email and password have been updated" msgstr "" -#: r2/controllers/api.py:488 +#: r2/controllers/api.py:493 msgid "your password has been updated" msgstr "" -#: r2/controllers/api.py:508 +#: r2/controllers/api.py:513 msgid "see? you don't really want to leave" msgstr "" -#: r2/controllers/api.py:646 +#: r2/controllers/api.py:665 msgid "replied" msgstr "" -#: r2/controllers/api.py:709 +#: r2/controllers/api.py:726 msgid "shared" msgstr "" -#: r2/controllers/api.py:712 +#: r2/controllers/api.py:729 msgid "your link has been shared." msgstr "" -#: r2/controllers/api.py:787 +#: r2/controllers/api.py:803 msgid "validation errors" msgstr "" -#: r2/controllers/api.py:808 r2/controllers/api.py:944 r2/controllers/api.py:1028 -#: r2/controllers/listingcontroller.py:251 r2/controllers/promotecontroller.py:311 +#: r2/controllers/api.py:824 r2/controllers/api.py:972 r2/controllers/api.py:1080 +#: r2/controllers/api.py:1433 r2/controllers/api.py:1471 +#: r2/controllers/listingcontroller.py:280 r2/controllers/promotecontroller.py:444 #: r2/lib/menus.py:49 r2/templates/frametoolbar.html:199 #: r2/templates/printablebuttons.html:122 msgid "saved" msgstr "" -#: r2/controllers/api.py:874 r2/lib/menus.py:148 +#: r2/controllers/api.py:894 r2/lib/menus.py:151 #: r2/templates/printablebuttons.html:36 r2/templates/subredditstylesheet.html:230 msgid "deleted" msgstr "" -#: r2/controllers/api.py:920 r2/templates/subredditstylesheet.html:189 +#: r2/controllers/api.py:945 r2/templates/subredditstylesheet.html:189 msgid "bad image name" msgstr "" -#: r2/controllers/api.py:927 r2/controllers/promotecontroller.py:304 +#: r2/controllers/api.py:952 r2/controllers/promotecontroller.py:437 msgid "bad image" msgstr "" -#: r2/controllers/api.py:931 +#: r2/controllers/api.py:956 #, python-format msgid "too many images (you only get %d)" msgstr "" -#: r2/controllers/api.py:1196 +#: r2/controllers/api.py:1309 msgid "an email will be sent to that account's address shortly" msgstr "" -#: r2/controllers/api.py:1380 +#: r2/controllers/api.py:1593 msgid "redirecting..." msgstr "" -#: r2/controllers/api.py:1383 +#: r2/controllers/api.py:1596 msgid "error (sorry)" msgstr "" -#: r2/controllers/buttons.py:176 +#: r2/controllers/buttons.py:177 msgid "reddit buttons" msgstr "" -#: r2/controllers/buttons.py:182 +#: r2/controllers/buttons.py:183 msgid "reddit widget" msgstr "" -#: r2/controllers/buttons.py:187 r2/lib/menus.py:93 +#: r2/controllers/buttons.py:188 r2/lib/menus.py:93 msgid "bookmarklets" msgstr "" @@ -127,20 +128,24 @@ msgid "edit this page" msgstr "" #: r2/controllers/embed.py:47 -msgid "read this first" +msgid "yes, it's okay!" msgstr "" -#: r2/controllers/embed.py:62 r2/lib/menus.py:87 r2/lib/pages/pages.py:281 -#: r2/templates/frametoolbar.html:103 r2/templates/frametoolbar.html:110 +#: r2/controllers/embed.py:48 +msgid "just read this first." +msgstr "" + +#: r2/controllers/embed.py:64 r2/lib/menus.py:87 r2/lib/pages/pages.py:328 +#: r2/templates/frametoolbar.html:110 msgid "help" msgstr "" -#: r2/controllers/error.py:110 +#: r2/controllers/error.py:112 #, python-format msgid "forbidden (%(domain)s)" msgstr "" -#: r2/controllers/error.py:121 +#: r2/controllers/error.py:128 msgid "this reddit has been banned" msgstr "" @@ -230,234 +235,253 @@ msgid "that number isn't in the right range (%(min)d to %(max)d)" msgstr "" #: r2/controllers/errors.py:50 -msgid "that link has already been submitted" +#, python-format +msgid "" +"your bid must be at least $%(min)d per day and no more than to $%(max)d in " +"total." msgstr "" #: r2/controllers/errors.py:51 -msgid "that reddit already exists" +msgid "that link has already been submitted" msgstr "" #: r2/controllers/errors.py:52 -msgid "that reddit doesn't exist" +msgid "that reddit already exists" msgstr "" #: r2/controllers/errors.py:53 -msgid "you aren't allowed to post there." +msgid "that reddit doesn't exist" msgstr "" #: r2/controllers/errors.py:54 -msgid "you must specify a reddit" +msgid "you aren't allowed to post there." msgstr "" #: r2/controllers/errors.py:55 -msgid "that name isn't going to work" +msgid "you must specify a reddit" msgstr "" #: r2/controllers/errors.py:56 +msgid "that name isn't going to work" +msgstr "" + +#: r2/controllers/errors.py:57 #, python-format msgid "you are trying to submit too fast. try again in %(time)s." msgstr "" -#: r2/controllers/errors.py:57 +#: r2/controllers/errors.py:58 msgid "your session has expired" msgstr "" -#: r2/controllers/errors.py:58 +#: r2/controllers/errors.py:59 msgid "you must accept the terms first" msgstr "" -#: r2/controllers/errors.py:63 +#: r2/controllers/errors.py:64 msgid "that option is not valid" msgstr "" -#: r2/controllers/errors.py:65 +#: r2/controllers/errors.py:66 #, python-format msgid "the following emails are invalid: %(emails)s" msgstr "" -#: r2/controllers/errors.py:66 +#: r2/controllers/errors.py:67 msgid "please enter at least one email address" msgstr "" -#: r2/controllers/errors.py:67 +#: r2/controllers/errors.py:68 #, python-format msgid "please only share to %(num)s emails at a time." msgstr "" -#: r2/controllers/errors.py:68 +#: r2/controllers/errors.py:69 msgid "please provide a date of the form mm/dd/yyyy" msgstr "" -#: r2/controllers/errors.py:69 -msgid "the dates need to be in order and not identical" -msgstr "" - #: r2/controllers/errors.py:70 -#, python-format -msgid "please enter a date at least %(day)s days in the future" +msgid "the dates need to be in order and not identical" msgstr "" #: r2/controllers/errors.py:71 #, python-format -msgid "please enter a date at least %(day)s days in the past" +msgid "please enter a date at least %(day)s days in the future" msgstr "" #: r2/controllers/errors.py:72 #, python-format -msgid "address problem: %(message)s" +msgid "please enter a date at least %(day)s days in the past" msgstr "" #: r2/controllers/errors.py:73 #, python-format -msgid "card problem: %(message)s" +msgid "address problem: %(message)s" msgstr "" #: r2/controllers/errors.py:74 #, python-format -msgid "this is too long (max: %(max_length)s)" +msgid "card problem: %(message)s" msgstr "" #: r2/controllers/errors.py:75 +#, python-format +msgid "this is too long (max: %(max_length)s)" +msgstr "" + +#: r2/controllers/errors.py:76 msgid "we need something here" msgstr "" -#: r2/controllers/feedback.py:30 -msgid "inquire about advertising on reddit" +#: r2/controllers/feedback.py:40 +msgid "help translate reddit into your language" msgstr "" -#: r2/controllers/feedback.py:37 -msgid "send reddit feedback" -msgstr "" - -#: r2/controllers/front.py:103 r2/templates/login.html:87 +#: r2/controllers/front.py:105 r2/templates/login.html:87 msgid "password" msgstr "" -#: r2/controllers/front.py:117 r2/controllers/front.py:133 +#: r2/controllers/front.py:119 r2/controllers/front.py:135 msgid "verify email" msgstr "" -#: r2/controllers/front.py:162 +#: r2/controllers/front.py:165 msgid "reset password" msgstr "" -#: r2/controllers/front.py:246 r2/controllers/listingcontroller.py:609 +#: r2/controllers/front.py:256 r2/controllers/listingcontroller.py:687 msgid "comments" msgstr "" -#: r2/controllers/front.py:276 r2/controllers/front.py:278 -#: r2/templates/createsubreddit.html:70 +#: r2/controllers/front.py:286 r2/controllers/front.py:288 +#: r2/templates/createsubreddit.html:76 msgid "create a reddit" msgstr "" -#: r2/controllers/front.py:307 +#: r2/controllers/front.py:317 msgid "your reddit has been created" msgstr "" -#: r2/controllers/front.py:346 r2/lib/menus.py:85 -msgid "stats" +#: r2/controllers/front.py:356 r2/lib/menus.py:138 +msgid "awards" msgstr "" -#: r2/controllers/front.py:376 r2/lib/menus.py:118 +#: r2/controllers/front.py:386 r2/lib/menus.py:118 msgid "related" msgstr "" -#: r2/controllers/front.py:394 +#: r2/controllers/front.py:404 msgid "other discussions" msgstr "" -#: r2/controllers/front.py:411 r2/controllers/front.py:458 +#: r2/controllers/front.py:423 r2/controllers/front.py:470 msgid "search results" msgstr "" -#: r2/controllers/front.py:555 +#: r2/controllers/front.py:507 r2/controllers/listingcontroller.py:167 +msgid "search failed" +msgstr "" + +#: r2/controllers/front.py:599 msgid "seen it" msgstr "" -#: r2/controllers/front.py:565 r2/lib/menus.py:86 +#: r2/controllers/front.py:609 r2/lib/menus.py:86 msgid "submit" msgstr "" -#: r2/controllers/front.py:578 r2/controllers/post.py:147 +#: r2/controllers/front.py:622 r2/controllers/post.py:163 msgid "opt out" msgstr "" -#: r2/controllers/front.py:578 r2/controllers/post.py:157 +#: r2/controllers/front.py:622 r2/controllers/post.py:173 msgid "welcome back" msgstr "" -#: r2/controllers/listingcontroller.py:262 r2/controllers/listingcontroller.py:330 +#: r2/controllers/listingcontroller.py:291 r2/controllers/listingcontroller.py:356 msgid "top scoring links" msgstr "" -#: r2/controllers/listingcontroller.py:272 +#: r2/controllers/listingcontroller.py:301 msgid "newest submissions" msgstr "" -#: r2/controllers/listingcontroller.py:332 +#: r2/controllers/listingcontroller.py:358 msgid "most controversial links" msgstr "" -#: r2/controllers/listingcontroller.py:339 +#: r2/controllers/listingcontroller.py:365 msgid "you're really bored now, eh?" msgstr "" -#: r2/controllers/listingcontroller.py:373 +#: r2/controllers/listingcontroller.py:399 msgid "recommended for you" msgstr "" -#: r2/controllers/listingcontroller.py:393 +#: r2/controllers/listingcontroller.py:419 #, python-format msgid "overview for %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:394 +#: r2/controllers/listingcontroller.py:420 #, python-format msgid "comments by %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:395 +#: r2/controllers/listingcontroller.py:421 #, python-format msgid "submitted by %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:396 +#: r2/controllers/listingcontroller.py:422 #, python-format msgid "liked by %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:397 +#: r2/controllers/listingcontroller.py:423 #, python-format msgid "disliked by %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:398 +#: r2/controllers/listingcontroller.py:424 #, python-format msgid "hidden by %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:399 +#: r2/controllers/listingcontroller.py:425 #, python-format msgid "profile for %(user)s" msgstr "" -#: r2/controllers/listingcontroller.py:483 r2/templates/redditheader.html:78 +#: r2/controllers/listingcontroller.py:512 r2/lib/menus.py:460 r2/lib/menus.py:510 +msgid "all" +msgstr "" + +#: r2/controllers/listingcontroller.py:513 r2/templates/printablebuttons.html:236 +msgid "unread" +msgstr "" + +#: r2/controllers/listingcontroller.py:515 +msgid "comment replies" +msgstr "" + +#: r2/controllers/listingcontroller.py:516 +msgid "post replies" +msgstr "" + +#: r2/controllers/listingcontroller.py:524 r2/templates/redditheader.html:80 msgid "messages" msgstr "" -#: r2/controllers/listingcontroller.py:493 -msgid "comment reply" -msgstr "" - -#: r2/controllers/listingcontroller.py:539 r2/templates/pagenamenav.html:33 +#: r2/controllers/listingcontroller.py:617 r2/templates/pagenamenav.html:33 msgid "reddits" msgstr "" -#: r2/controllers/listingcontroller.py:573 +#: r2/controllers/listingcontroller.py:651 msgid "reddits: " msgstr "" -#: r2/controllers/post.py:121 +#: r2/controllers/post.py:137 msgid "over 18?" msgstr "" @@ -465,15 +489,69 @@ msgstr "" msgid "promoted by you" msgstr "" -#: r2/controllers/promotecontroller.py:231 +#: r2/controllers/promotecontroller.py:251 msgid "that promoted link is already finished." msgstr "" -#: r2/controllers/promotecontroller.py:239 +#: r2/controllers/promotecontroller.py:259 msgid "too late to change the date." msgstr "" -#: r2/lib/cssfilter.py:253 +#: r2/controllers/promotecontroller.py:391 +msgid "that link is currently promoted. you can't update your bid now." +msgstr "" + +#: r2/controllers/promotecontroller.py:395 +msgid "" +"that promotion is already over, so updating your bid is kind of pointless, " +"don't you think?" +msgstr "" + +#: r2/controllers/promotecontroller.py:404 +msgid "failed to authenticate card. sorry." +msgstr "" + +#: r2/controllers/validator/validator.py:1154 +msgid "please provide a first name" +msgstr "" + +#: r2/controllers/validator/validator.py:1156 +msgid "please provide a last name" +msgstr "" + +#: r2/controllers/validator/validator.py:1158 +msgid "please provide an address" +msgstr "" + +#: r2/controllers/validator/validator.py:1160 +msgid "please provide your city" +msgstr "" + +#: r2/controllers/validator/validator.py:1162 +msgid "please provide your state" +msgstr "" + +#: r2/controllers/validator/validator.py:1164 +msgid "please provide your zip or post code" +msgstr "" + +#: r2/controllers/validator/validator.py:1167 +msgid "please pick a country" +msgstr "" + +#: r2/controllers/validator/validator.py:1191 +msgid "credit card numbers should be 13 to 16 digits" +msgstr "" + +#: r2/controllers/validator/validator.py:1194 +msgid "dates should be YYYY-MM" +msgstr "" + +#: r2/controllers/validator/validator.py:1196 +msgid "card verification codes should be 3 or 4 digits" +msgstr "" + +#: r2/lib/cssfilter.py:258 msgid "if you need backslashes, you're doing it wrong" msgstr "" @@ -493,11 +571,11 @@ msgstr "" msgid "most controversial" msgstr "" -#: r2/lib/menus.py:50 r2/lib/menus.py:65 +#: r2/lib/menus.py:50 r2/lib/menus.py:66 msgid "recommended" msgstr "" -#: r2/lib/menus.py:51 r2/lib/menus.py:151 r2/templates/printablebuttons.html:176 +#: r2/lib/menus.py:51 r2/templates/printablebuttons.html:173 msgid "promote" msgstr "" @@ -538,60 +616,62 @@ msgid "controversial" msgstr "" #: r2/lib/menus.py:64 +msgid "best" +msgstr "" + +#: r2/lib/menus.py:65 msgid "saved {toolbar}" msgstr "" -#: r2/lib/menus.py:66 +#: r2/lib/menus.py:67 msgid "rising" msgstr "" -#: r2/lib/menus.py:67 +#: r2/lib/menus.py:68 msgid "admin" msgstr "" -#: r2/lib/menus.py:70 r2/templates/widgetdemopanel.html:121 +#: r2/lib/menus.py:71 r2/templates/widgetdemopanel.html:121 msgid "this hour" msgstr "" -#: r2/lib/menus.py:71 r2/templates/userstats.html:38 -#: r2/templates/widgetdemopanel.html:122 +#: r2/lib/menus.py:72 r2/templates/widgetdemopanel.html:122 msgid "today" msgstr "" -#: r2/lib/menus.py:72 r2/templates/userstats.html:48 -#: r2/templates/widgetdemopanel.html:123 +#: r2/lib/menus.py:73 r2/templates/widgetdemopanel.html:123 msgid "this week" msgstr "" -#: r2/lib/menus.py:73 r2/templates/widgetdemopanel.html:124 +#: r2/lib/menus.py:74 r2/templates/widgetdemopanel.html:124 msgid "this month" msgstr "" -#: r2/lib/menus.py:74 +#: r2/lib/menus.py:75 msgid "this year" msgstr "" -#: r2/lib/menus.py:75 +#: r2/lib/menus.py:76 msgid "all time" msgstr "" -#: r2/lib/menus.py:78 +#: r2/lib/menus.py:79 msgid "spam" msgstr "" -#: r2/lib/menus.py:79 +#: r2/lib/menus.py:80 msgid "autobanned" msgstr "" -#: r2/lib/menus.py:82 +#: r2/lib/menus.py:83 msgid "turn admin on" msgstr "" -#: r2/lib/menus.py:83 +#: r2/lib/menus.py:84 msgid "turn admin off" msgstr "" -#: r2/lib/menus.py:84 r2/lib/pages/pages.py:429 r2/lib/pages/pages.py:438 +#: r2/lib/menus.py:85 r2/lib/pages/pages.py:476 r2/lib/pages/pages.py:487 msgid "preferences" msgstr "" @@ -599,7 +679,7 @@ msgstr "" msgid "the reddit blog" msgstr "" -#: r2/lib/menus.py:89 r2/templates/utils.html:388 +#: r2/lib/menus.py:89 r2/templates/utils.html:391 msgid "logout" msgstr "" @@ -632,7 +712,7 @@ msgid "store" msgstr "" #: r2/lib/menus.py:100 -msgid "advertise on reddit" +msgid "inquire about advertising" msgstr "" #: r2/lib/menus.py:101 @@ -693,8 +773,8 @@ msgstr "" msgid "shirt" msgstr "" -#: r2/lib/menus.py:122 r2/templates/printablebuttons.html:142 -msgid "traffic" +#: r2/lib/menus.py:122 +msgid "traffic stats" msgstr "" #: r2/lib/menus.py:125 @@ -705,127 +785,137 @@ msgstr "" msgid "about" msgstr "" -#: r2/lib/menus.py:127 r2/templates/printablebuttons.html:108 -#: r2/templates/printablebuttons.html:139 r2/templates/printablebuttons.html:204 -msgid "edit" +#: r2/lib/menus.py:127 +msgid "edit this reddit" msgstr "" -#: r2/lib/menus.py:128 r2/templates/printable.html:42 -#: r2/templates/printablebuttons.html:48 r2/templates/subredditinfobar.html:75 -msgid "banned" +#: r2/lib/menus.py:128 +msgid "edit moderators" msgstr "" -#: r2/lib/menus.py:129 r2/lib/pages/pages.py:1406 +#: r2/lib/menus.py:129 +msgid "edit contributors" +msgstr "" + +#: r2/lib/menus.py:130 r2/lib/menus.py:131 r2/lib/pages/pages.py:1602 msgid "ban users" msgstr "" -#: r2/lib/menus.py:131 +#: r2/lib/menus.py:133 msgid "popular" msgstr "" -#: r2/lib/menus.py:132 r2/templates/admintranslations.html:33 -#: r2/templates/createsubreddit.html:236 +#: r2/lib/menus.py:134 r2/templates/admintranslations.html:33 +#: r2/templates/createsubreddit.html:345 msgid "create" msgstr "" -#: r2/lib/menus.py:133 r2/lib/pages/pages.py:880 +#: r2/lib/menus.py:135 r2/lib/pages/pages.py:987 msgid "my reddits" msgstr "" -#: r2/lib/menus.py:135 -msgid "translate site" -msgstr "" - -#: r2/lib/menus.py:136 -msgid "promoted" -msgstr "" - #: r2/lib/menus.py:137 -msgid "reporters" -msgstr "" - -#: r2/lib/menus.py:138 r2admin/controllers/admin.py:67 -msgid "reports" +msgid "help translate" msgstr "" #: r2/lib/menus.py:139 -msgid "reported authors" +msgid "promoted" msgstr "" #: r2/lib/menus.py:140 +msgid "reporters" +msgstr "" + +#: r2/lib/menus.py:141 +msgid "reported links" +msgstr "" + +#: r2/lib/menus.py:142 +msgid "reported authors" +msgstr "" + +#: r2/lib/menus.py:143 msgid "info" msgstr "" -#: r2/lib/menus.py:141 r2/templates/printablebuttons.html:112 +#: r2/lib/menus.py:144 r2/templates/printablebuttons.html:112 #: r2/templates/sharelink.html:94 msgid "share" msgstr "" -#: r2/lib/menus.py:143 +#: r2/lib/menus.py:146 msgid "overview" msgstr "" -#: r2/lib/menus.py:144 +#: r2/lib/menus.py:147 msgid "submitted" msgstr "" -#: r2/lib/menus.py:145 +#: r2/lib/menus.py:148 msgid "liked" msgstr "" -#: r2/lib/menus.py:146 +#: r2/lib/menus.py:149 msgid "disliked" msgstr "" -#: r2/lib/menus.py:147 +#: r2/lib/menus.py:150 msgid "hidden {toolbar}" msgstr "" -#: r2/lib/menus.py:149 r2/templates/printablebuttons.html:31 +#: r2/lib/menus.py:152 r2/templates/printablebuttons.html:31 msgid "reported" msgstr "" -#: r2/lib/menus.py:152 -msgid "create promotion" -msgstr "" - -#: r2/lib/menus.py:153 -msgid "my promoted links" -msgstr "" - #: r2/lib/menus.py:154 -msgid "all promoted links" +msgid "self-serve advertising" msgstr "" #: r2/lib/menus.py:155 -msgid "unapproved" +msgid "create promotion" msgstr "" #: r2/lib/menus.py:156 -msgid "promo graph" +msgid "my promoted links" msgstr "" #: r2/lib/menus.py:157 -msgid "live" +msgid "all promoted links" msgstr "" #: r2/lib/menus.py:158 +msgid "unapproved" +msgstr "" + +#: r2/lib/menus.py:159 +msgid "analytics" +msgstr "" + +#: r2/lib/menus.py:160 +msgid "live" +msgstr "" + +#: r2/lib/menus.py:161 +msgid "unpaid" +msgstr "" + +#: r2/lib/menus.py:162 msgid "pending" msgstr "" -#: r2/lib/menus.py:381 +#: r2/lib/menus.py:163 +msgid "rejected" +msgstr "" + +#: r2/lib/menus.py:391 msgid "sorted by" msgstr "" -#: r2/lib/menus.py:442 +#: r2/lib/menus.py:455 msgid "kind" msgstr "" -#: r2/lib/menus.py:447 r2/lib/menus.py:497 -msgid "all" -msgstr "" - -#: r2/lib/menus.py:457 +#: r2/lib/menus.py:470 msgid "links from" msgstr "" @@ -851,7 +941,7 @@ msgstr "" #: r2/lib/strings.py:61 #, python-format -msgid "%(num)d %(persons)s" +msgid "<span class='number'>%(num)s</span> <span class='word'>%(persons)s</span>" msgstr "" #: r2/lib/strings.py:63 @@ -915,112 +1005,123 @@ msgstr "" msgid "you have been banned from posting to [%(title)s](%(url)s)." msgstr "" -#: r2/lib/strings.py:87 -msgid "you are a moderator" +#: r2/lib/strings.py:83 +#, python-format +msgid "" +"you have been added to the list of users able to see [traffic for the " +"sponsoted link \"%(title)s\"](%(traffic_url)s)." msgstr "" #: r2/lib/strings.py:88 -msgid "you are a contributor" +msgid "you are a moderator" msgstr "" #: r2/lib/strings.py:89 +msgid "you are a contributor" +msgstr "" + +#: r2/lib/strings.py:90 msgid "you've been banned" msgstr "" -#: r2/lib/strings.py:93 -msgid "you have not subscribed to any reddits." -msgstr "" - -#: r2/lib/strings.py:94 -msgid "below are the reddits you have subscribed to" +#: r2/lib/strings.py:91 +msgid "you can view traffic on a promoted link" msgstr "" #: r2/lib/strings.py:95 -msgid "below are the reddits that you have contributor access to." +msgid "you have not subscribed to any reddits." msgstr "" #: r2/lib/strings.py:96 +msgid "below are the reddits you have subscribed to" +msgstr "" + +#: r2/lib/strings.py:97 +msgid "below are the reddits that you have contributor access to." +msgstr "" + +#: r2/lib/strings.py:98 msgid "below are the reddits that you have moderator access to." msgstr "" -#: r2/lib/strings.py:99 +#: r2/lib/strings.py:101 msgid "" -"click the `add` or `remove` buttons to choose which reddits appear on your " -"front page." +"click the `+frontpage` or `-frontpage` buttons to choose which reddits appear" +" on your front page." msgstr "" -#: r2/lib/strings.py:101 +#: r2/lib/strings.py:103 #, python-format msgid "" "you're searching within the [%(reddit_name)s](%(reddit_link)s) reddit. you " "can also search within [all reddits](%(all_reddits_link)s)" msgstr "" -#: r2/lib/strings.py:105 +#: r2/lib/strings.py:107 #, python-format msgid "\"%(brokenurl)s\" is not a valid URL" msgstr "" -#: r2/lib/strings.py:106 +#: r2/lib/strings.py:108 #, python-format msgid "\"%(cssprop)s\" is not a valid CSS property" msgstr "" -#: r2/lib/strings.py:107 +#: r2/lib/strings.py:109 #, python-format msgid "\"%(cssvalue)s\" is not a valid value for CSS property \"%(cssprop)s\"" msgstr "" -#: r2/lib/strings.py:108 +#: r2/lib/strings.py:110 #, python-format msgid "too big. keep it under %(max_size)dkb" msgstr "" -#: r2/lib/strings.py:109 +#: r2/lib/strings.py:111 #, python-format msgid "syntax error: \"%(syntaxerror)s\"" msgstr "" -#: r2/lib/strings.py:110 +#: r2/lib/strings.py:112 msgid "@imports are not allowed" msgstr "" -#: r2/lib/strings.py:111 +#: r2/lib/strings.py:113 #, python-format msgid "invalid CSS property list \"%(proplist)s\"" msgstr "" -#: r2/lib/strings.py:112 +#: r2/lib/strings.py:114 #, python-format msgid "unknown CSS rule type \"%(ruletype)s\"" msgstr "" -#: r2/lib/strings.py:114 +#: r2/lib/strings.py:116 msgid "to anything interesting: news article, blog entry, video, picture..." msgstr "" -#: r2/lib/strings.py:115 +#: r2/lib/strings.py:117 #, python-format msgid "%(author)s comments on %(title)s" msgstr "" -#: r2/lib/strings.py:116 +#: r2/lib/strings.py:118 #, python-format msgid "%(title)s : %(site)s" msgstr "" -#: r2/lib/strings.py:117 +#: r2/lib/strings.py:119 #, python-format msgid "" "**this reddit has been banned**\n" "\n" "most likely this was done automatically by our spam filtering program. the " "program is still learning, and may even have some bugs, so if you feel the " -"ban was a mistake, please send a message to [feedback](%(link)s) and be sure " -"to include the exact name of the reddit." +"ban was a mistake, please send a message to [our site admins](%(link)s) and " +"be sure to include the **exact name of the reddit**." msgstr "" -#: r2/lib/strings.py:118 +#: r2/lib/strings.py:120 #, python-format msgid "" "\n" @@ -1031,344 +1132,418 @@ msgid "" " " msgstr "" -#: r2/lib/strings.py:125 +#: r2/lib/strings.py:127 msgid "" "You are submitting a link. The key to a successful submission is interesting " "content and a descriptive title." msgstr "" -#: r2/lib/strings.py:126 +#: r2/lib/strings.py:128 msgid "" "You are submitting a text-based post. Speak your mind. A title is required, " "but expanding further in the text field is not. Beginning your title with " "\"vote up if\" is violation of intergalactic law." msgstr "" -#: r2/lib/strings.py:127 +#: r2/lib/strings.py:129 msgid "" "You should consider using [reddit's free iphone " "app](http://itunes.com/apps/iredditfree)." msgstr "" -#: r2/lib/strings.py:128 +#: r2/lib/strings.py:130 msgid "we're going to need to verify your email address for you to proceed." msgstr "" -#: r2/lib/strings.py:129 +#: r2/lib/strings.py:131 msgid "your email address has been verfied" msgstr "" -#: r2/lib/strings.py:130 +#: r2/lib/strings.py:132 msgid "Verification failed. Please try that again" msgstr "" -#: r2/lib/strings.py:190 r2/lib/strings.py:195 r2/lib/template_helpers.py:140 +#: r2/lib/strings.py:133 +#, python-format +msgid "" +"Our search machines are under too much load to handle your request right now." +" :( Sorry for the inconvenience.\n" +"\n" +"[Try again](%(link)s) in a little bit -- but please don't mash reload; that " +"only makes the problem worse." +msgstr "" + +#: r2/lib/strings.py:193 r2/lib/strings.py:198 r2/lib/template_helpers.py:132 #: r2/templates/subredditstylesheet.html:264 msgid "comment" msgid_plural "comments" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:191 r2/templates/comment.htmllite:54 -#: r2/templates/linkinfobar.html:33 +#: r2/lib/strings.py:194 r2/templates/comment.htmllite:54 +#: r2/templates/linkinfobar.html:40 msgid "point" msgid_plural "points" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:194 +#: r2/lib/strings.py:197 msgid "link" msgid_plural "links" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:196 r2/lib/pages/pages.py:483 +#: r2/lib/strings.py:199 r2/lib/pages/pages.py:534 msgid "message" msgid_plural "messages" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:197 +#: r2/lib/strings.py:200 msgid "subreddit" msgid_plural "subreddits" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:200 r2/templates/subredditinfobar.html:43 +#: r2/lib/strings.py:203 +msgid "reader" +msgid_plural "readers" +msgstr[0] "" +msgstr[1] "" + +#: r2/lib/strings.py:204 msgid "subscriber" msgid_plural "subscribers" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:201 r2/templates/subreddit.html:80 +#: r2/lib/strings.py:205 r2/templates/subreddit.html:80 #: r2/templates/subreddit.html:81 msgid "contributor" msgid_plural "contributors" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:202 r2/templates/subreddit.html:74 +#: r2/lib/strings.py:206 r2/templates/subreddit.html:74 msgid "moderator" msgid_plural "moderators" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:205 +#: r2/lib/strings.py:209 msgid "milliseconds" msgid_plural "milliseconds" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:206 r2/lib/utils/utils.py:412 r2/templates/searchbar.html:42 +#: r2/lib/strings.py:210 r2/lib/utils/utils.py:411 r2/templates/searchbar.html:43 msgid "second" msgid_plural "seconds" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:207 r2/lib/utils/utils.py:411 +#: r2/lib/strings.py:211 r2/lib/utils/utils.py:410 msgid "minute" msgid_plural "minutes" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:208 r2/lib/utils/utils.py:410 +#: r2/lib/strings.py:212 r2/lib/utils/utils.py:409 msgid "hour" msgid_plural "hours" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:209 r2/lib/utils/utils.py:409 +#: r2/lib/strings.py:213 r2/lib/utils/utils.py:408 r2/templates/paymentform.html:46 +#: r2/templates/promotedlink.html:74 msgid "day" msgid_plural "days" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:210 r2/lib/utils/utils.py:408 +#: r2/lib/strings.py:214 r2/lib/utils/utils.py:407 msgid "month" msgid_plural "months" msgstr[0] "" msgstr[1] "" -#: r2/lib/strings.py:211 r2/lib/utils/utils.py:407 +#: r2/lib/strings.py:215 r2/lib/utils/utils.py:406 msgid "year" msgid_plural "years" msgstr[0] "" msgstr[1] "" -#: r2/lib/template_helpers.py:136 +#: r2/lib/template_helpers.py:128 msgid "comment {verb}" msgstr "" -#: r2/lib/pages/pages.py:55 +#: r2/lib/template_helpers.py:321 +msgid "friend" +msgstr "" + +#: r2/lib/template_helpers.py:328 +msgid "submitter" +msgstr "" + +#: r2/lib/template_helpers.py:342 +msgid "reddit admin, speaking officially" +msgstr "" + +#: r2/lib/pages/pages.py:58 #, python-format msgid "%d %b %Y" msgstr "" -#: r2/lib/pages/pages.py:148 +#: r2/lib/pages/pages.py:180 +msgid "moderators" +msgstr "" + +#: r2/lib/pages/pages.py:186 +msgid "admin box" +msgstr "" + +#: r2/lib/pages/pages.py:190 msgid "Submit a link" msgstr "" -#: r2/lib/pages/pages.py:155 +#: r2/lib/pages/pages.py:197 msgid "Create your own reddit" msgstr "" -#: r2/lib/pages/pages.py:273 +#: r2/lib/pages/pages.py:317 msgid "site links" msgstr "" -#: r2/lib/pages/pages.py:277 +#: r2/lib/pages/pages.py:321 msgid "FAQ" msgstr "" -#: r2/lib/pages/pages.py:279 +#: r2/lib/pages/pages.py:323 msgid "reddiquette" msgstr "" -#: r2/lib/pages/pages.py:290 +#: r2/lib/pages/pages.py:336 msgid "reddit tools" msgstr "" -#: r2/lib/pages/pages.py:297 +#: r2/lib/pages/pages.py:344 msgid "job board" msgstr "" -#: r2/lib/pages/pages.py:299 +#: r2/lib/pages/pages.py:346 msgid "about us" msgstr "" -#: r2/lib/pages/pages.py:315 +#: r2/lib/pages/pages.py:362 msgid "brothers" msgstr "" -#: r2/lib/pages/pages.py:327 +#: r2/lib/pages/pages.py:374 msgid "sisters" msgstr "" -#: r2/lib/pages/pages.py:531 +#: r2/lib/pages/pages.py:582 msgid "login or register" msgstr "" -#: r2/lib/pages/pages.py:597 r2/templates/comment.html:74 +#: r2/lib/pages/pages.py:614 +msgid "bummer" +msgstr "" + +#: r2/lib/pages/pages.py:626 +msgid "this page is no longer available due to a copyright claim." +msgstr "" + +#: r2/lib/pages/pages.py:670 r2/templates/comment.html:77 #: r2/templates/comment.htmllite:46 r2/templates/comment.xml:30 #: r2/templates/comment.xml:31 msgid "[deleted]" msgstr "" -#: r2/lib/pages/pages.py:682 r2/templates/createsubreddit.html:60 +#: r2/lib/pages/pages.py:755 r2/templates/createsubreddit.html:66 msgid "manage your reddit" msgstr "" -#: r2/lib/pages/pages.py:683 +#: r2/lib/pages/pages.py:756 #, python-format msgid "about %(site)s" msgstr "" -#: r2/lib/pages/pages.py:708 +#: r2/lib/pages/pages.py:782 msgid "search reddits" msgstr "" -#: r2/lib/pages/pages.py:830 +#: r2/lib/pages/pages.py:809 +msgid "your front page reddits" +msgstr "" + +#: r2/lib/pages/pages.py:872 r2/templates/organiclisting.html:60 +msgid "what's this?" +msgstr "" + +#: r2/lib/pages/pages.py:873 +msgid "trophy case" +msgstr "" + +#: r2/lib/pages/pages.py:935 msgid "page not found" msgstr "" -#: r2/lib/pages/pages.py:841 +#: r2/lib/pages/pages.py:946 msgid "you aren't allowed to do that." msgstr "" -#: r2/lib/pages/pages.py:979 +#: r2/lib/pages/pages.py:1089 msgid "try entering those letters again" msgstr "" -#: r2/lib/pages/pages.py:1029 +#: r2/lib/pages/pages.py:1141 msgid "previous search" msgstr "" -#: r2/lib/pages/pages.py:1049 +#: r2/lib/pages/pages.py:1171 #, python-format msgid "%(site_title)s via %(domain)s" msgstr "" -#: r2/lib/pages/pages.py:1290 +#: r2/lib/pages/pages.py:1450 msgid "This feature is currently unavailable. Sorry" msgstr "" -#: r2/lib/pages/pages.py:1357 +#: r2/lib/pages/pages.py:1553 msgid "add a friend" msgstr "" -#: r2/lib/pages/pages.py:1361 +#: r2/lib/pages/pages.py:1557 msgid "your friends" msgstr "" -#: r2/lib/pages/pages.py:1376 +#: r2/lib/pages/pages.py:1572 msgid "add contributor" msgstr "" -#: r2/lib/pages/pages.py:1380 +#: r2/lib/pages/pages.py:1576 #, python-format msgid "contributors to %(reddit)s" msgstr "" -#: r2/lib/pages/pages.py:1391 +#: r2/lib/pages/pages.py:1587 msgid "add moderator" msgstr "" -#: r2/lib/pages/pages.py:1395 +#: r2/lib/pages/pages.py:1591 #, python-format msgid "moderators to %(reddit)s" msgstr "" -#: r2/lib/pages/pages.py:1410 +#: r2/lib/pages/pages.py:1606 msgid "banned users" msgstr "" -#: r2/lib/utils/utils.py:425 +#: r2/lib/pages/pages.py:1623 +msgid "share traffic" +msgstr "" + +#: r2/lib/pages/pages.py:1627 +msgid "current viewers" +msgstr "" + +#: r2/lib/utils/utils.py:424 msgid "millisecond" msgid_plural "milliseconds" msgstr[0] "" msgstr[1] "" -#: r2/lib/utils/utils.py:436 r2/templates/comment.htmllite:46 +#: r2/lib/utils/utils.py:435 r2/templates/comment.htmllite:46 msgid "ago" msgstr "" -#: r2/models/builder.py:56 -msgid "friend" -msgstr "" - -#: r2/models/builder.py:63 -msgid "submitter" -msgstr "" - -#: r2/models/builder.py:77 -msgid "reddit admin, speaking officially" -msgstr "" - -#: r2/models/builder.py:137 +#: r2/models/builder.py:103 #, python-format msgid "moderator of /r/%(reddit)s, speaking officially" msgstr "" -#: r2/models/mail_queue.py:303 +#: r2/models/builder.py:151 +msgid "label_template" +msgstr "" + +#: r2/models/link.py:845 +msgid "comment reply" +msgstr "" + +#: r2/models/link.py:851 +msgid "post reply" +msgstr "" + +#: r2/models/mail_queue.py:306 #, python-format msgid "[reddit] %(user)s has shared a link with you" msgstr "" -#: r2/models/mail_queue.py:304 +#: r2/models/mail_queue.py:307 #, python-format msgid "[feedback] feedback from '%(user)s'" msgstr "" -#: r2/models/mail_queue.py:305 +#: r2/models/mail_queue.py:308 #, python-format msgid "[ad_inq] feedback from '%(user)s'" msgstr "" -#: r2/models/mail_queue.py:306 +#: r2/models/mail_queue.py:309 msgid "[reddit] email removal notice" msgstr "" -#: r2/models/mail_queue.py:307 +#: r2/models/mail_queue.py:310 msgid "[reddit] email addition notice" msgstr "" -#: r2/models/mail_queue.py:308 +#: r2/models/mail_queue.py:311 msgid "[reddit] reset your password" msgstr "" -#: r2/models/mail_queue.py:309 +#: r2/models/mail_queue.py:312 msgid "[reddit] verify your email address" msgstr "" -#: r2/models/mail_queue.py:310 +#: r2/models/mail_queue.py:313 msgid "[reddit] your bid has been accepted" msgstr "" -#: r2/models/mail_queue.py:311 +#: r2/models/mail_queue.py:314 msgid "[reddit] your promotion has been accepted" msgstr "" -#: r2/models/mail_queue.py:312 +#: r2/models/mail_queue.py:315 msgid "[reddit] your promotion has been rejected" msgstr "" -#: r2/models/mail_queue.py:313 +#: r2/models/mail_queue.py:316 msgid "[reddit] your promotion has been queued" msgstr "" -#: r2/models/mail_queue.py:314 +#: r2/models/mail_queue.py:317 msgid "[reddit] your promotion is now live" msgstr "" -#: r2/models/mail_queue.py:315 +#: r2/models/mail_queue.py:318 msgid "[reddit] your promotion has finished" msgstr "" -#: r2/models/subreddit.py:568 +#: r2/models/mail_queue.py:319 +msgid "[reddit] your promotion has been created" +msgstr "" + +#: r2/models/mail_queue.py:320 +#, python-format +msgid "[i18n] translation offer from '%(user)s'" +msgstr "" + +#: r2/models/subreddit.py:602 msgid "reddit.com: what's new online!" msgstr "" -#: r2/models/subreddit.py:616 +#: r2/models/subreddit.py:650 msgid "on reddit.com" msgstr "" @@ -1398,7 +1573,7 @@ msgid "" "the page header */" msgstr "" -#: r2/templates/base.htmllite:53 +#: r2/templates/base.htmllite:61 #, python-format msgid "links from %(site)s" msgstr "" @@ -1529,7 +1704,7 @@ msgstr "" msgid "specify a title" msgstr "" -#: r2/templates/buttondemopanel.html:98 r2/templates/prefoptions.html:101 +#: r2/templates/buttondemopanel.html:98 r2/templates/prefoptions.html:109 msgid "open links in a new window" msgstr "" @@ -1569,36 +1744,32 @@ msgstr "" msgid "type the letters from the image above" msgstr "" -#: r2/templates/clickgadget.html:26 -msgid "Recently viewed links" -msgstr "" - -#: r2/templates/clickgadget.html:33 +#: r2/templates/clickgadget.html:30 msgid "clear" msgstr "" -#: r2/templates/comment.html:70 +#: r2/templates/comment.html:71 msgid "deleted comment from" msgstr "" -#: r2/templates/comment.html:78 +#: r2/templates/comment.html:81 msgid "comment score below threshold" msgstr "" -#: r2/templates/comment.html:84 +#: r2/templates/comment.html:87 #, python-format msgid "%(timeago)s ago" msgstr "" -#: r2/templates/comment.html:96 +#: r2/templates/comment.html:99 r2/templates/message.html:50 msgid "+" msgstr "" -#: r2/templates/comment.html:96 +#: r2/templates/comment.html:99 r2/templates/message.html:50 msgid "-" msgstr "" -#: r2/templates/comment.html:99 +#: r2/templates/comment.html:102 msgid "child" msgid_plural "children" msgstr[0] "" @@ -1616,19 +1787,27 @@ msgstr "" msgid "This sidebar will not be shown automatically." msgstr "" -#: r2/templates/createsubreddit.html:68 +#: r2/templates/createsubreddit.html:74 msgid "that subreddit doesn't exist, but you can create it here." msgstr "" -#: r2/templates/createsubreddit.html:233 r2/templates/prefoptions.html:187 -#: r2/templates/promotelinkform.html:351 +#: r2/templates/createsubreddit.html:342 r2/templates/prefoptions.html:231 +#: r2/templates/promotelinkform.html:338 msgid "save options" msgstr "" +#: r2/templates/dart_ad.html:41 +msgid "reddit this ad" +msgstr "" + #: r2/templates/feedback.html:70 msgid "send" msgstr "" +#: r2/templates/feedbackblurb.html:67 +msgid "send reddit feedback" +msgstr "" + #: r2/templates/frametoolbar.html:56 msgid "caution: dorkbar detected" msgstr "" @@ -1657,6 +1836,10 @@ msgstr "" msgid "login / register" msgstr "" +#: r2/templates/frametoolbar.html:103 +msgid "new mail" +msgstr "" + #: r2/templates/frametoolbar.html:116 r2/templates/frametoolbar.html:117 msgid "visit this link without the toolbar" msgstr "" @@ -1699,31 +1882,43 @@ msgstr "" msgid "toggle the comments panel" msgstr "" -#: r2/templates/link.html:165 +#: r2/templates/link.html:69 +msgid "Adult content: Not Safe For Work" +msgstr "" + +#: r2/templates/link.html:70 +msgid "NSFW" +msgstr "" + +#: r2/templates/link.html:177 #, python-format msgid "submitted %(when)s ago by %(author)s to %(reddit)s" msgstr "" -#: r2/templates/link.html:167 +#: r2/templates/link.html:179 #, python-format msgid "submitted %(when)s ago by %(author)s" msgstr "" -#: r2/templates/linkinfobar.html:28 -msgid "toolbar link" +#: r2/templates/linkinfobar.html:34 +msgid "this post was submitted on" msgstr "" -#: r2/templates/linkinfobar.html:31 -msgid "submitted on" +#: r2/templates/linkinfobar.html:43 +msgid "like it" msgstr "" -#: r2/templates/linkinfobar.html:35 -msgid "up votes" -msgstr "" +#: r2/templates/linkinfobar.html:48 +msgid "up vote" +msgid_plural "up votes" +msgstr[0] "" +msgstr[1] "" -#: r2/templates/linkinfobar.html:37 -msgid "down votes" -msgstr "" +#: r2/templates/linkinfobar.html:54 +msgid "down vote" +msgid_plural "down votes" +msgstr[0] "" +msgstr[1] "" #: r2/templates/linkpromoteinfobar.html:31 msgid "promoted on" @@ -1810,22 +2005,34 @@ msgstr "" msgid "recover password" msgstr "" -#: r2/templates/message.html:43 r2/templates/message.xml:33 +#: r2/templates/message.html:56 r2/templates/message.xml:33 #, python-format msgid "from %(author)s sent %(when)s ago" msgstr "" -#: r2/templates/message.html:45 r2/templates/message.xml:35 +#: r2/templates/message.html:58 r2/templates/message.xml:35 #, python-format msgid "to %(dest)s sent %(when)s ago" msgstr "" -#: r2/templates/message.html:47 +#: r2/templates/message.html:60 #, python-format msgid "to %(dest)s from %(author)s sent %(when)s ago" msgstr "" -#: r2/templates/messagecompose.html:30 +#: r2/templates/message.html:90 +msgid "expand all" +msgstr "" + +#: r2/templates/message.html:93 +msgid "collapse all" +msgstr "" + +#: r2/templates/message.html:108 +msgid "show parent" +msgstr "" + +#: r2/templates/messagecompose.html:31 msgid "send a message" msgstr "" @@ -1839,6 +2046,10 @@ msgid_plural "replies" msgstr[0] "" msgstr[1] "" +#: r2/templates/moremessages.html:38 +msgid "[+] load the full conversation." +msgstr "" + #: r2/templates/morerecursion.html:29 msgid "continue this thread" msgstr "" @@ -1864,12 +2075,12 @@ msgid "Would you like the address %(email)s to no longer receive email from us?" msgstr "" #: r2/templates/optout.html:36 r2/templates/optout.html:52 -#: r2/templates/prefdelete.html:28 r2/templates/printablebuttons.html:293 +#: r2/templates/prefdelete.html:28 r2/templates/printablebuttons.html:306 msgid "yes" msgstr "" #: r2/templates/optout.html:39 r2/templates/optout.html:55 -#: r2/templates/prefdelete.html:28 r2/templates/printablebuttons.html:296 +#: r2/templates/prefdelete.html:28 r2/templates/printablebuttons.html:309 msgid "no" msgstr "" @@ -1883,35 +2094,31 @@ msgstr "" msgid "Allow '%(email)s' to receive email from us?" msgstr "" -#: r2/templates/organiclisting.html:60 -msgid "what's this?" +#: r2/templates/organiclisting.html:65 +#, python-format +msgid "Click %(here)s to close help." msgstr "" -#: r2/templates/organiclisting.html:66 +#: r2/templates/organiclisting.html:66 r2/templates/organiclisting.html:89 +msgid "here" +msgstr "" + +#: r2/templates/organiclisting.html:84 msgid "" "This area shows new and upcoming links. Vote on links here to help them " "become popular, and click the forwards and backwards buttons to view more. " msgstr "" -#: r2/templates/organiclisting.html:71 r2/templates/organiclisting.html:81 -msgid "here" -msgstr "" - -#: r2/templates/organiclisting.html:71 +#: r2/templates/organiclisting.html:89 msgid "This element has been disabled." msgstr "" -#: r2/templates/organiclisting.html:73 +#: r2/templates/organiclisting.html:91 #, python-format msgid "Click %(here)s to disable this feature." msgstr "" -#: r2/templates/organiclisting.html:80 -#, python-format -msgid "Click %(here)s to close help." -msgstr "" - -#: r2/templates/organiclisting.html:94 +#: r2/templates/organiclisting.html:105 msgid "" "The new link area will no longer appear for you. To re-enable it, visit your " "preferences." @@ -1937,6 +2144,108 @@ msgstr "" msgid "email me" msgstr "" +#: r2/templates/paymentform.html:33 +msgid "set up payment for this link" +msgstr "" + +#: r2/templates/paymentform.html:54 +#, python-format +msgid "Your current bid is $%(bid)s" +msgstr "" + +#: r2/templates/paymentform.html:57 +msgid "(total for the duration provided)" +msgstr "" + +#: r2/templates/paymentform.html:62 +msgid "Please pick your credit card:" +msgstr "" + +#: r2/templates/paymentform.html:64 +msgid "select..." +msgstr "" + +#: r2/templates/paymentform.html:70 +msgid "create a new one..." +msgstr "" + +#: r2/templates/paymentform.html:75 +msgid "please create a new payment profile" +msgstr "" + +#: r2/templates/paymentform.html:79 +msgid "" +"NOTE: your card will not be charged until the link has been queued for " +"promotion." +msgstr "" + +#: r2/templates/paymentform.html:125 +msgid "first name" +msgstr "" + +#: r2/templates/paymentform.html:126 +msgid "last name" +msgstr "" + +#: r2/templates/paymentform.html:127 +msgid "company" +msgstr "" + +#: r2/templates/paymentform.html:127 r2/templates/paymentform.html:133 +#: r2/templates/sharelink.html:36 r2/templates/sharelink.html:54 +#: r2/templates/sharelink.html:73 +msgid "(optional)" +msgstr "" + +#: r2/templates/paymentform.html:128 +msgid "address" +msgstr "" + +#: r2/templates/paymentform.html:129 +msgid "city" +msgstr "" + +#: r2/templates/paymentform.html:130 +msgid "state" +msgstr "" + +#: r2/templates/paymentform.html:131 +msgid "zip" +msgstr "" + +#: r2/templates/paymentform.html:133 +msgid "phone" +msgstr "" + +#: r2/templates/paymentform.html:134 +msgid "card number" +msgstr "" + +#: r2/templates/paymentform.html:134 +msgid "(14-17 digits)" +msgstr "" + +#: r2/templates/paymentform.html:135 +msgid "expiration date" +msgstr "" + +#: r2/templates/paymentform.html:136 +msgid "CCV" +msgstr "" + +#: r2/templates/paymentform.html:136 +msgid "(3 or 4 digits)" +msgstr "" + +#: r2/templates/paymentform.html:193 +msgid "authorize payment" +msgstr "" + +#: r2/templates/paymentform.html:196 r2/templates/printablebuttons.html:108 +#: r2/templates/printablebuttons.html:139 r2/templates/printablebuttons.html:206 +msgid "edit" +msgstr "" + #: r2/templates/permalinkmessage.html:24 msgid "you are viewing a single comment's thread." msgstr "" @@ -1953,150 +2262,194 @@ msgstr "" msgid "deleting..." msgstr "" -#: r2/templates/prefoptions.html:63 +#: r2/templates/prefoptions.html:71 msgid "your preferences have been updated" msgstr "" -#: r2/templates/prefoptions.html:81 +#: r2/templates/prefoptions.html:89 msgid "interface language" msgstr "" -#: r2/templates/prefoptions.html:85 +#: r2/templates/prefoptions.html:93 msgid "incomplete" msgstr "" -#: r2/templates/prefoptions.html:86 +#: r2/templates/prefoptions.html:94 msgid "volunteer to translate" msgstr "" -#: r2/templates/prefoptions.html:90 +#: r2/templates/prefoptions.html:98 msgid "content language" msgstr "" -#: r2/templates/prefoptions.html:97 +#: r2/templates/prefoptions.html:105 msgid "clicking options" msgstr "" -#: r2/templates/prefoptions.html:99 +#: r2/templates/prefoptions.html:107 msgid "display links with a reddit toolbar" msgstr "" -#: r2/templates/prefoptions.html:105 +#: r2/templates/prefoptions.html:113 msgid "media" msgstr "" -#: r2/templates/prefoptions.html:108 +#: r2/templates/prefoptions.html:116 msgid "show thumbnails next to links" msgstr "" -#: r2/templates/prefoptions.html:109 +#: r2/templates/prefoptions.html:117 msgid "don't show thumbnails next to links" msgstr "" -#: r2/templates/prefoptions.html:110 +#: r2/templates/prefoptions.html:118 msgid "show thumbnails based on that reddit's media preferences" msgstr "" -#: r2/templates/prefoptions.html:112 +#: r2/templates/prefoptions.html:120 msgid "to enable thumbnails, disable compressed link display" msgstr "" -#: r2/templates/prefoptions.html:118 +#: r2/templates/prefoptions.html:126 msgid "link options" msgstr "" -#: r2/templates/prefoptions.html:120 +#: r2/templates/prefoptions.html:128 msgid "show me new links on the front page" msgstr "" -#: r2/templates/prefoptions.html:121 +#: r2/templates/prefoptions.html:129 msgid "show me links I've recently viewed" msgstr "" -#: r2/templates/prefoptions.html:122 +#: r2/templates/prefoptions.html:130 msgid "compress the link display" msgstr "" -#: r2/templates/prefoptions.html:123 +#: r2/templates/prefoptions.html:131 msgid "don't show links after i've liked them" msgstr "" -#: r2/templates/prefoptions.html:124 +#: r2/templates/prefoptions.html:132 msgid "don't show links after i've disliked them" msgstr "" -#: r2/templates/prefoptions.html:127 +#: r2/templates/prefoptions.html:135 msgid "display" msgstr "" -#: r2/templates/prefoptions.html:128 +#: r2/templates/prefoptions.html:136 msgid "links at once" msgstr "" -#: r2/templates/prefoptions.html:129 +#: r2/templates/prefoptions.html:137 msgid "don't show me sites with a score less than" msgstr "" -#: r2/templates/prefoptions.html:130 +#: r2/templates/prefoptions.html:138 msgid "don't show me comments with a score less than" msgstr "" -#: r2/templates/prefoptions.html:131 +#: r2/templates/prefoptions.html:139 msgid "comments by default" msgstr "" -#: r2/templates/prefoptions.html:134 -#, python-format -msgid "display %(num)s links at once" -msgstr "" - #: r2/templates/prefoptions.html:142 #, python-format +msgid "display %(num)s links at once" +msgstr "" + +#: r2/templates/prefoptions.html:150 +#, python-format msgid "don't show me sites with a score less than %(num)s" msgstr "" -#: r2/templates/prefoptions.html:143 r2/templates/prefoptions.html:156 +#: r2/templates/prefoptions.html:151 r2/templates/prefoptions.html:164 msgid "(blank for none)" msgstr "" -#: r2/templates/prefoptions.html:148 +#: r2/templates/prefoptions.html:156 msgid "comment options" msgstr "" -#: r2/templates/prefoptions.html:155 +#: r2/templates/prefoptions.html:163 #, python-format msgid "don't show me comments with a score less than %(num)s" msgstr "" -#: r2/templates/prefoptions.html:164 +#: r2/templates/prefoptions.html:172 #, python-format msgid "display %(num)s comments by default" msgstr "" -#: r2/templates/prefoptions.html:170 r2/templates/widgetdemopanel.html:193 -msgid "display options" -msgstr "" - -#: r2/templates/prefoptions.html:172 -msgid "allow reddits to show me custom styles" -msgstr "" - -#: r2/templates/prefoptions.html:176 -msgid "privacy options" -msgstr "" - #: r2/templates/prefoptions.html:178 -msgid "make my votes public" +msgid "messaging options" msgstr "" #: r2/templates/prefoptions.html:180 +msgid "show message conversations in the inbox" +msgstr "" + +#: r2/templates/prefoptions.html:183 +msgid "(only applies when you go to the 'messages' panel)" +msgstr "" + +#: r2/templates/prefoptions.html:187 +msgid "collapse messages after I've read them" +msgstr "" + +#: r2/templates/prefoptions.html:190 +msgid "(otherwise, you'll have to collapse them yourself)" +msgstr "" + +#: r2/templates/prefoptions.html:194 +msgid "mark messages as read when I open my inbox" +msgstr "" + +#: r2/templates/prefoptions.html:197 +msgid "(otherwise, they will be marked as read when you click them)" +msgstr "" + +#: r2/templates/prefoptions.html:202 r2/templates/widgetdemopanel.html:193 +msgid "display options" +msgstr "" + +#: r2/templates/prefoptions.html:204 +msgid "allow reddits to show me custom styles" +msgstr "" + +#: r2/templates/prefoptions.html:207 +msgid "show promote tab on front page" +msgstr "" + +#: r2/templates/prefoptions.html:213 +msgid "content options" +msgstr "" + +#: r2/templates/prefoptions.html:215 msgid "i am over eighteen years old and willing to view adult content" msgstr "" -#: r2/templates/prefoptions.html:181 +#: r2/templates/prefoptions.html:216 msgid "required to view some reddits" msgstr "" +#: r2/templates/prefoptions.html:218 +msgid "make safe(r) for work." +msgstr "" + +#: r2/templates/prefoptions.html:220 +msgid "label posts that are not safe for work (NSFW)" +msgstr "" + +#: r2/templates/prefoptions.html:223 +msgid "privacy options" +msgstr "" + +#: r2/templates/prefoptions.html:225 +msgid "make my votes public" +msgstr "" + #: r2/templates/prefupdate.html:28 msgid "update your email or password" msgstr "" @@ -2129,19 +2482,24 @@ msgstr "" msgid "send verification email" msgstr "" +#: r2/templates/printable.html:42 r2/templates/printablebuttons.html:48 +#: r2/templates/subredditinfobar.html:86 +msgid "banned" +msgstr "" + #: r2/templates/printablebuttons.html:31 msgid "report" msgstr "" -#: r2/templates/printablebuttons.html:42 r2/templates/subredditinfobar.html:68 +#: r2/templates/printablebuttons.html:42 msgid "unban" msgstr "" -#: r2/templates/printablebuttons.html:43 r2/templates/subredditinfobar.html:69 +#: r2/templates/printablebuttons.html:43 r2/templates/subredditinfobar.html:78 msgid "unbanned" msgstr "" -#: r2/templates/printablebuttons.html:47 r2/templates/subredditinfobar.html:74 +#: r2/templates/printablebuttons.html:47 msgid "ban" msgstr "" @@ -2165,7 +2523,7 @@ msgstr "" msgid "distinguish this?" msgstr "" -#: r2/templates/printablebuttons.html:112 r2/templates/printablebuttons.html:164 +#: r2/templates/printablebuttons.html:112 r2/templates/printablebuttons.html:161 #: r2/templates/sharelink.html:98 msgid "cancel" msgstr "" @@ -2186,82 +2544,102 @@ msgstr "" msgid "hidden" msgstr "" -#: r2/templates/printablebuttons.html:146 +#: r2/templates/printablebuttons.html:143 msgid "unpromote" msgstr "" -#: r2/templates/printablebuttons.html:146 +#: r2/templates/printablebuttons.html:143 msgid "unpromoted" msgstr "" -#: r2/templates/printablebuttons.html:164 +#: r2/templates/printablebuttons.html:161 msgid "reject" msgstr "" -#: r2/templates/printablebuttons.html:172 +#: r2/templates/printablebuttons.html:169 msgid "accept" msgstr "" -#: r2/templates/printablebuttons.html:172 +#: r2/templates/printablebuttons.html:169 msgid "accepted" msgstr "" -#: r2/templates/printablebuttons.html:187 +#: r2/templates/printablebuttons.html:180 +msgid "traffic" +msgstr "" + +#: r2/templates/printablebuttons.html:189 r2/templates/printablebuttons.html:228 msgid "permalink" msgstr "" -#: r2/templates/printablebuttons.html:192 r2/templates/printablebuttons.html:199 +#: r2/templates/printablebuttons.html:194 r2/templates/printablebuttons.html:201 msgid "parent" msgstr "" -#: r2/templates/printablebuttons.html:212 r2/templates/printablebuttons.html:228 +#: r2/templates/printablebuttons.html:214 r2/templates/printablebuttons.html:240 msgid "reply {verb}" msgstr "" -#: r2/templates/printablebuttons.html:222 r2/templates/starkcomment.html:33 +#: r2/templates/printablebuttons.html:224 r2/templates/starkcomment.html:33 msgid "context" msgstr "" -#: r2/templates/printablebuttons.html:275 +#: r2/templates/printablebuttons.html:234 +msgid "mark unread" +msgstr "" + +#: r2/templates/printablebuttons.html:288 msgid "are you sure?" msgstr "" -#: r2/templates/printablebuttons.html:360 +#: r2/templates/printablebuttons.html:384 msgid "toggle" msgstr "" -#: r2/templates/profilebar.html:69 -msgid "karma:" +#: r2/templates/profilebar.html:54 +msgid "+ friends" msgstr "" -#: r2/templates/profilebar.html:72 -msgid "comment karma:" +#: r2/templates/profilebar.html:54 +msgid "- friends" msgstr "" -#: r2/templates/profilebar.html:76 -#, python-format -msgid "user for %(time)s" +#: r2/templates/profilebar.html:92 +msgid "link karma" msgstr "" -#: r2/templates/profilebar.html:81 r2/templates/usertableitem.html:46 +#: r2/templates/profilebar.html:97 +msgid "comment karma" +msgstr "" + +#: r2/templates/profilebar.html:104 r2/templates/usertableitem.html:46 msgid "send message" msgstr "" -#: r2/templates/profilebar.html:84 -msgid "add to friends" +#: r2/templates/profilebar.html:108 +#, python-format +msgid "redditor for %(time)s" msgstr "" -#: r2/templates/profilebar.html:84 -msgid "remove from friends" +#: r2/templates/promote_graph.html:162 +msgid "total promotion traffic" msgstr "" -#: r2/templates/promote_graph.html:76 +#: r2/templates/promote_graph.html:179 +msgid "historical site performance" +msgstr "" + +#: r2/templates/promote_graph.html:198 +msgid "top promoters this month" +msgstr "" + +#: r2/templates/promote_graph.html:239 msgid "promotions this month" msgstr "" #: r2/templates/promotedlink.html:35 #, python-format -msgid "to be promoted by %(author)s" +msgid "to be promoted on %(date)s by %(author)s" msgstr "" #: r2/templates/promotedlink.html:37 @@ -2269,90 +2647,102 @@ msgstr "" msgid "promoted %(when)s ago by %(author)s" msgstr "" -#: r2/templates/promotedlink.html:57 -msgid "unverified sponsored link" +#: r2/templates/promotedlink.html:58 +msgid "unpaid sponsored link" msgstr "" -#: r2/templates/promotedlink.html:59 +#: r2/templates/promotedlink.html:60 msgid "unapproved sponsored link" msgstr "" -#: r2/templates/promotedlink.html:61 -msgid "pending sponsored link" +#: r2/templates/promotedlink.html:62 +msgid "accepted sponsored link" msgstr "" -#: r2/templates/promotedlink.html:63 +#: r2/templates/promotedlink.html:64 msgid "rejected sponsored link" msgstr "" -#: r2/templates/promotedlink.html:65 -msgid "queued sponsored link" +#: r2/templates/promotedlink.html:66 +msgid "pending sponsored link" msgstr "" -#: r2/templates/promotedlink.html:67 r2/templates/promotedlink.html:72 +#: r2/templates/promotedlink.html:68 r2/templates/promotedlink.html:77 msgid "sponsored link" msgstr "" -#: r2/templates/promotedlink.html:69 +#: r2/templates/promotedlink.html:70 msgid "finished sponsored link" msgstr "" -#: r2/templates/promotelinkform.html:56 +#: r2/templates/promotedtraffic.html:43 +msgid "Promotion Traffic" +msgstr "" + +#: r2/templates/promotedtraffic.html:45 +msgid "(download as .csv)" +msgstr "" + +#: r2/templates/promotelinkform.html:58 msgid "create a promotion" msgstr "" -#: r2/templates/promotelinkform.html:56 +#: r2/templates/promotelinkform.html:58 msgid "edit promotion" msgstr "" -#: r2/templates/promotelinkform.html:70 +#: r2/templates/promotelinkform.html:72 msgid "NOTE:" msgstr "" -#: r2/templates/promotelinkform.html:72 -msgid "" -"you have not set up payment for this promotion. Please click \"set up " -"payment\" to authorize payment." -msgstr "" - -#: r2/templates/promotelinkform.html:75 +#: r2/templates/promotelinkform.html:78 msgid "" "once you set up payment, you will not be charged until the link is approved " "and scheduled for display" msgstr "" -#: r2/templates/promotelinkform.html:83 +#: r2/templates/promotelinkform.html:86 msgid "This promotion has been rejected. Please edit and resubmit." msgstr "" -#: r2/templates/promotelinkform.html:89 +#: r2/templates/promotelinkform.html:92 +msgid "" +"Your bid has been registered and your submission is awaiting review. We will" +" notify you by email of status updates." +msgstr "" + +#: r2/templates/promotelinkform.html:98 msgid "" "NOTE: changes to this promotion will result in its status being reverted to " "'unapproved'" msgstr "" -#: r2/templates/promotelinkform.html:95 +#: r2/templates/promotelinkform.html:104 msgid "This promotion is finished. Edits would be a little pointless." msgstr "" -#: r2/templates/promotelinkform.html:131 +#: r2/templates/promotelinkform.html:322 msgid "" "You'll be able to submit an image for the thumbnail once the promotion is " "submitted." msgstr "" -#: r2/templates/promotelinkform.html:354 -msgid "next ->" +#: r2/templates/promotelinkform.html:341 +msgid "agree" msgstr "" -#: r2/templates/promotelinkform.html:371 +#: r2/templates/promotelinkform.html:355 msgid "make this a freebie" msgstr "" -#: r2/templates/reddit.html:137 r2/templates/reddit.html:149 +#: r2/templates/reddit.html:135 r2/templates/reddit.html:147 msgid "close this window" msgstr "" +#: r2/templates/reddit.html:173 +msgid "Recently viewed links" +msgstr "" + #: r2/templates/redditfooter.html:39 #, python-format msgid "" @@ -2424,7 +2814,7 @@ msgstr "" msgid "cname" msgstr "" -#: r2/templates/searchbar.html:39 +#: r2/templates/searchbar.html:40 #, python-format msgid "about %(num)d results in %(second)s." msgstr "" @@ -2433,7 +2823,11 @@ msgstr "" msgid "search reddit" msgstr "" -#: r2/templates/share.email:31 +#: r2/templates/selfserveblurb.html:59 +msgid "inquire about advertising on reddit" +msgstr "" + +#: r2/templates/share.email:32 #, python-format msgid "There is currently %(num_comments)s on this link. You can view it here:" msgid_plural "There are currently %(num_comments)s on this link. You can view them here:" @@ -2448,11 +2842,6 @@ msgstr "" msgid "your name" msgstr "" -#: r2/templates/sharelink.html:36 r2/templates/sharelink.html:54 -#: r2/templates/sharelink.html:73 -msgid "(optional)" -msgstr "" - #: r2/templates/sharelink.html:51 msgid "your email" msgstr "" @@ -2474,27 +2863,35 @@ msgstr "" msgid "Your reddit headline shirt" msgstr "" -#: r2/templates/shirtpane.html:41 +#: r2/templates/shirtpane.html:52 msgid "Color" msgstr "" -#: r2/templates/shirtpane.html:48 +#: r2/templates/shirtpane.html:59 msgid "Size" msgstr "" -#: r2/templates/shirtpane.html:56 +#: r2/templates/shirtpane.html:67 msgid "Style" msgstr "" -#: r2/templates/shirtpane.html:63 +#: r2/templates/shirtpane.html:74 msgid "Qty:" msgstr "" -#: r2/templates/subreddit.html:59 r2/templates/subredditinfobar.html:47 +#: r2/templates/subreddit.html:59 r2/templates/subredditinfobar.html:71 #, python-format msgid "a community for %(time)s" msgstr "" +#: r2/templates/subreddit.html:64 +msgid "+ frontpage" +msgstr "" + +#: r2/templates/subreddit.html:64 +msgid "- frontpage" +msgstr "" + #: r2/templates/subreddit.html:84 r2/templates/subreddit.html:85 msgid "not contributor" msgstr "" @@ -2507,42 +2904,42 @@ msgstr "" msgid "over18" msgstr "" -#: r2/templates/subredditinfobar.html:36 -msgid "subscribe" +#: r2/templates/subredditinfobar.html:34 +msgid "leave" msgstr "" -#: r2/templates/subredditinfobar.html:36 -msgid "unsubscribe" -msgstr "" - -#: r2/templates/subredditinfobar.html:53 -#, python-format -msgid "you are a contributor of this reddit. (%(leave)s)" -msgstr "" - -#: r2/templates/subredditinfobar.html:54 -msgid "stop being a contributor?" -msgstr "" - -#: r2/templates/subredditinfobar.html:55 -msgid "you are no longer a contributor" -msgstr "" - -#: r2/templates/subredditinfobar.html:60 +#: r2/templates/subredditinfobar.html:47 #, python-format msgid "you are a moderator of this reddit. (%(leave)s)" msgstr "" -#: r2/templates/subredditinfobar.html:61 +#: r2/templates/subredditinfobar.html:48 msgid "stop being a moderator?" msgstr "" -#: r2/templates/subredditinfobar.html:62 +#: r2/templates/subredditinfobar.html:49 msgid "you are no longer a moderator" msgstr "" -#: r2/templates/subredditinfobar.html:88 -msgid "leave" +#: r2/templates/subredditinfobar.html:55 +#, python-format +msgid "you are a contributor of this reddit. (%(leave)s)" +msgstr "" + +#: r2/templates/subredditinfobar.html:56 +msgid "stop being a contributor?" +msgstr "" + +#: r2/templates/subredditinfobar.html:57 +msgid "you are no longer a contributor" +msgstr "" + +#: r2/templates/subredditinfobar.html:77 +msgid "unban this reddit" +msgstr "" + +#: r2/templates/subredditinfobar.html:85 +msgid "ban this reddit" msgstr "" #: r2/templates/subredditstylesheet.html:42 @@ -2612,26 +3009,52 @@ msgstr "" msgid "link with thumbnail" msgstr "" +#: r2/templates/trophycase.html:47 r2/templates/trophycase.html:67 +#: r2/templates/usertableitem.html:50 +msgid "remove" +msgstr "" + +#: r2/templates/trophycase.html:47 r2/templates/trophycase.html:67 +msgid "removed" +msgstr "" + +#: r2/templates/trophycase.html:74 +msgid "dust" +msgstr "" + +#: r2/templates/trophycase.html:107 +#, python-format +msgid "%d more" +msgstr "" + #: r2/templates/unfoundpage.html:25 msgid "the page you requested does not exist" msgstr "" -#: r2/templates/userlist.html:35 +#: r2/templates/userawards.html:39 +msgid "Ongoing awards, and their most recent winners:" +msgstr "" + +#: r2/templates/userawards.html:54 +msgid "won by" +msgstr "" + +#: r2/templates/userawards.html:57 +msgid "recently won by" +msgstr "" + +#: r2/templates/userawards.html:74 +msgid "for this" +msgstr "" + +#: r2/templates/userawards.html:83 +msgid "Special awards:" +msgstr "" + +#: r2/templates/userlist.html:37 msgid "add" msgstr "" -#: r2/templates/userstats.html:35 -msgid "biggest karma gainers" -msgstr "" - -#: r2/templates/userstats.html:58 r2/templates/widgetdemopanel.html:125 -msgid "all-time" -msgstr "" - -#: r2/templates/usertableitem.html:50 -msgid "remove" -msgstr "" - #: r2/templates/usertext.html:68 msgid "formatting help" msgstr "" @@ -2674,23 +3097,23 @@ msgstr "" msgid "some languages" msgstr "" -#: r2/templates/utils.html:266 +#: r2/templates/utils.html:267 msgid "uploading" msgstr "" -#: r2/templates/utils.html:268 +#: r2/templates/utils.html:269 msgid "upload" msgstr "" -#: r2/templates/utils.html:362 +#: r2/templates/utils.html:365 msgid "fetching title..." msgstr "" -#: r2/templates/utils.html:363 +#: r2/templates/utils.html:366 msgid "submitting..." msgstr "" -#: r2/templates/utils.html:364 +#: r2/templates/utils.html:367 msgid "loading..." msgstr "" @@ -2710,6 +3133,10 @@ msgstr "" msgid "which links do you want to display?" msgstr "" +#: r2/templates/widgetdemopanel.html:125 +msgid "all-time" +msgstr "" + #: r2/templates/widgetdemopanel.html:131 msgid "submitted by" msgstr "" @@ -2812,6 +3239,10 @@ msgstr "" msgid "add this into your HTML where you want the %(site)s links displayed" msgstr "" +#: r2admin/controllers/admin.py:67 +msgid "reports" +msgstr "" + #: r2admin/templates/switchuser.html:29 msgid "switch" msgstr "" diff --git a/r2/r2/lib/__init__.py b/r2/r2/lib/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/lib/__init__.py +++ b/r2/r2/lib/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/amqp.py b/r2/r2/lib/amqp.py index 6e961cd58..6c894422a 100644 --- a/r2/r2/lib/amqp.py +++ b/r2/r2/lib/amqp.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -174,9 +174,9 @@ def handle_items(queue, callback, ack = True, limit = 1, drain = False): time.sleep(1) continue + g.reset_caches() + items = [] - #reset the local cache - g.cache.caches = (LocalCache(),) + g.cache.caches[1:] while msg: items.append(msg) diff --git a/r2/r2/lib/app_globals.py b/r2/r2/lib/app_globals.py index 584f41cdd..104dc42a3 100644 --- a/r2/r2/lib/app_globals.py +++ b/r2/r2/lib/app_globals.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement @@ -24,6 +24,7 @@ from pylons import config import pytz, os, logging, sys, socket, re, subprocess from datetime import timedelta, datetime from r2.lib.cache import LocalCache, Memcache, HardCache, CacheChain +from r2.lib.cache import SelfEmptyingCache from r2.lib.db.stats import QueryStats from r2.lib.translation import get_active_langs from r2.lib.lock import make_lock_factory @@ -63,7 +64,6 @@ class Globals(object): 'enable_doquery', 'use_query_cache', 'write_query_queue', - 'show_awards', 'css_killswitch', 'db_create_tables', 'disallow_db_writes', @@ -77,6 +77,7 @@ class Globals(object): 'sponsors', 'monitored_servers', 'automatic_reddits', + 'skip_precompute_queries', 'agents', 'allowed_css_linked_domains'] @@ -119,12 +120,19 @@ class Globals(object): v = tuple(self.to_iter(v)) setattr(self, k, v) - # initialize caches + self.running_as_script = global_conf.get('running_as_script', False) + + self.skip_precompute_queries = set(self.skip_precompute_queries) + + # initialize caches. Any cache-chains built here must be added + # to reset_caches so that they can properly reset their local + # components mc = Memcache(self.memcaches, pickleProtocol = 1) self.memcache = mc self.cache = CacheChain((LocalCache(), mc)) self.permacache = Memcache(self.permacaches, pickleProtocol = 1) self.rendercache = Memcache(self.rendercaches, pickleProtocol = 1) + self.make_lock = make_lock_factory(mc) self.rec_cache = Memcache(self.rec_cache, pickleProtocol = 1) @@ -140,7 +148,10 @@ class Globals(object): self.dbm = self.load_db_params(global_conf) # can't do this until load_db_params() has been called - self.hardcache = CacheChain((LocalCache(), mc, HardCache(self))) + self.hardcache = CacheChain((LocalCache(), mc, HardCache(self)), + cache_negative_results = True) + + self.reset_caches() #make a query cache self.stats_collector = QueryStats() @@ -190,8 +201,6 @@ class Globals(object): else: self.log.setLevel(logging.WARNING) - if self.log_start: - self.log.error("reddit app started on %s" % datetime.now()) # set log level for pycountry which is chatty logging.getLogger('pycountry.db').setLevel(logging.CRITICAL) @@ -241,6 +250,15 @@ class Globals(object): self.log.info("Couldn't read source revision (%r)" % e) self.version = self.short_version = '(unknown)' + if self.log_start: + self.log.error("reddit app started %s at %s" % (self.short_version, datetime.now())) + + def reset_caches(self): + for ca in ('cache', 'hardcache'): + cache = getattr(self, ca) + new_cache = SelfEmptyingCache() if self.running_as_script else LocalCache() + cache.caches = (new_cache,) + cache.caches[1:] + @staticmethod def to_bool(x): return (x.lower() == 'true') if x else None diff --git a/r2/r2/lib/authorize/__init__.py b/r2/r2/lib/authorize/__init__.py index 87e88763e..34ded4caf 100644 --- a/r2/r2/lib/authorize/__init__.py +++ b/r2/r2/lib/authorize/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from interaction import * diff --git a/r2/r2/lib/authorize/api.py b/r2/r2/lib/authorize/api.py index 6b4a39434..b5447eb8b 100644 --- a/r2/r2/lib/authorize/api.py +++ b/r2/r2/lib/authorize/api.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ diff --git a/r2/r2/lib/authorize/interaction.py b/r2/r2/lib/authorize/interaction.py index b0feb6d5e..dd7eef124 100644 --- a/r2/r2/lib/authorize/interaction.py +++ b/r2/r2/lib/authorize/interaction.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from api import * diff --git a/r2/r2/lib/base.py b/r2/r2/lib/base.py index 039ad867f..c1d4da074 100644 --- a/r2/r2/lib/base.py +++ b/r2/r2/lib/base.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/c/filters.c b/r2/r2/lib/c/filters.c index ba8a5427e..b4b5456fe 100644 --- a/r2/r2/lib/c/filters.c +++ b/r2/r2/lib/c/filters.c @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ #include <Python.h> @@ -179,7 +179,7 @@ filters_websafe(PyObject * self, PyObject *args) buffer[ib++] = 'u'; buffer[ib++] = 'o'; buffer[ib++] = 't'; - buffer[ib] = ';'; + buffer[ib] = ';'; } else { buffer[ib] = input_buffer[ic]; diff --git a/r2/r2/lib/c/recommendations/Database.cpp b/r2/r2/lib/c/recommendations/Database.cpp index 839d590d6..965130bb1 100644 --- a/r2/r2/lib/c/recommendations/Database.cpp +++ b/r2/r2/lib/c/recommendations/Database.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/Database.h b/r2/r2/lib/c/recommendations/Database.h index 049e339af..512910c3e 100644 --- a/r2/r2/lib/c/recommendations/Database.h +++ b/r2/r2/lib/c/recommendations/Database.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/Dictionary.h b/r2/r2/lib/c/recommendations/Dictionary.h index 056b63b66..98d2dca3f 100644 --- a/r2/r2/lib/c/recommendations/Dictionary.h +++ b/r2/r2/lib/c/recommendations/Dictionary.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/ModsTable.cpp b/r2/r2/lib/c/recommendations/ModsTable.cpp index 3b01afde7..b0172f2a3 100644 --- a/r2/r2/lib/c/recommendations/ModsTable.cpp +++ b/r2/r2/lib/c/recommendations/ModsTable.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/ModsTable.h b/r2/r2/lib/c/recommendations/ModsTable.h index df0552d54..ac071292e 100644 --- a/r2/r2/lib/c/recommendations/ModsTable.h +++ b/r2/r2/lib/c/recommendations/ModsTable.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/Recommender.cpp b/r2/r2/lib/c/recommendations/Recommender.cpp index f26b6366c..4f13d21b0 100644 --- a/r2/r2/lib/c/recommendations/Recommender.cpp +++ b/r2/r2/lib/c/recommendations/Recommender.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/Recommender.h b/r2/r2/lib/c/recommendations/Recommender.h index d160ff322..2dc1c2216 100644 --- a/r2/r2/lib/c/recommendations/Recommender.h +++ b/r2/r2/lib/c/recommendations/Recommender.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/SparseMatrix.h b/r2/r2/lib/c/recommendations/SparseMatrix.h index 265139fd4..671cba1b9 100644 --- a/r2/r2/lib/c/recommendations/SparseMatrix.h +++ b/r2/r2/lib/c/recommendations/SparseMatrix.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/User.cpp b/r2/r2/lib/c/recommendations/User.cpp index 98e46a71d..b6f728198 100644 --- a/r2/r2/lib/c/recommendations/User.cpp +++ b/r2/r2/lib/c/recommendations/User.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/User.h b/r2/r2/lib/c/recommendations/User.h index c79dafb74..5d5217c12 100644 --- a/r2/r2/lib/c/recommendations/User.h +++ b/r2/r2/lib/c/recommendations/User.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/articles.cpp b/r2/r2/lib/c/recommendations/articles.cpp index 26a2f07eb..647697a82 100644 --- a/r2/r2/lib/c/recommendations/articles.cpp +++ b/r2/r2/lib/c/recommendations/articles.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/articles.h b/r2/r2/lib/c/recommendations/articles.h index 3501fa981..1ae7bbb1e 100644 --- a/r2/r2/lib/c/recommendations/articles.h +++ b/r2/r2/lib/c/recommendations/articles.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/main.cpp b/r2/r2/lib/c/recommendations/main.cpp index a1e416616..71c43e84b 100644 --- a/r2/r2/lib/c/recommendations/main.cpp +++ b/r2/r2/lib/c/recommendations/main.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/recommend_memcache.cpp b/r2/r2/lib/c/recommendations/recommend_memcache.cpp index d045680e2..db91bb7a3 100644 --- a/r2/r2/lib/c/recommendations/recommend_memcache.cpp +++ b/r2/r2/lib/c/recommendations/recommend_memcache.cpp @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/recommend_memcache.h b/r2/r2/lib/c/recommendations/recommend_memcache.h index 7a21de838..580fe9f20 100644 --- a/r2/r2/lib/c/recommendations/recommend_memcache.h +++ b/r2/r2/lib/c/recommendations/recommend_memcache.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c/recommendations/recommender_py.h b/r2/r2/lib/c/recommendations/recommender_py.h index 4c7fa10ba..8af7f1926 100644 --- a/r2/r2/lib/c/recommendations/recommender_py.h +++ b/r2/r2/lib/c/recommendations/recommender_py.h @@ -17,7 +17,7 @@ * The Original Developer is the Initial Developer. The Initial Developer of the * Original Code is CondeNet, Inc. * -* All portions of the code written by CondeNet are Copyright (c) 2006-2009 +* All portions of the code written by CondeNet are Copyright (c) 2006-2010 * CondeNet, Inc. All Rights Reserved. *******************************************************************************/ diff --git a/r2/r2/lib/c_markdown.py b/r2/r2/lib/c_markdown.py new file mode 100644 index 000000000..120e70de2 --- /dev/null +++ b/r2/r2/lib/c_markdown.py @@ -0,0 +1,2 @@ +def c_markdown(text, nofollow=False, target=None): + raise NotImplementedError() diff --git a/r2/r2/lib/cache.py b/r2/r2/lib/cache.py index 1e36925f6..a63d03f61 100644 --- a/r2/r2/lib/cache.py +++ b/r2/r2/lib/cache.py @@ -6,31 +6,33 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from threading import local -from utils import lstrips +from utils import lstrips, in_chunks from contrib import memcache from r2.lib.hardcachebackend import HardCacheBackend +class NoneResult(object): pass + class CacheUtils(object): - def incr_multi(self, keys, amt=1, prefix=''): + def incr_multi(self, keys, delta=1, time=0, prefix=''): for k in keys: try: - self.incr(prefix + k, amt) + self.incr(prefix + k, time=time, delta=delta) except ValueError: pass @@ -92,11 +94,34 @@ class HardCache(CacheUtils): return category, ids def set(self, key, val, time=0): + if val is NoneResult: + # NoneResult caching is for other parts of the chain + return + category, ids = self._split_key(key) - if time <= 0: - raise ValueError ("HardCache.set() *must* have an expiration time") self.backend.set(category, ids, val, time) + def simple_get_multi(self, keys): + results = {} + category_bundles = {} + for key in keys: + category, ids = self._split_key(key) + category_bundles.setdefault(category, []).append(ids) + + for category in category_bundles: + idses = category_bundles[category] + chunks = in_chunks(idses, size=50) + for chunk in chunks: + new_results = self.backend.get_multi(category, chunk) + results.update(new_results) + + return results + + def set_multi(self, keys, prefix='', time=0): + for k,v in keys.iteritems(): + if v is not NoneResult: + self.set(prefix+str(k), v, time=time) + def get(self, key, default=None): category, ids = self._split_key(key) r = self.backend.get(category, ids) @@ -104,9 +129,20 @@ class HardCache(CacheUtils): return r def delete(self, key, time=0): + # Potential optimization: When on a negative-result caching chain, + # shove NoneResult throughout the chain when a key is deleted. category, ids = self._split_key(key) self.backend.delete(category, ids) + def add(self, key, value, time=0): + category, ids = self._split_key(key) + return self.backend.add(category, ids, value, time=time) + + def incr(self, key, delta=1, time=0): + category, ids = self._split_key(key) + return self.backend.incr(category, ids, delta=delta, time=time) + + class LocalCache(dict, CacheUtils): def __init__(self, *a, **kw): return dict.__init__(self, *a, **kw) @@ -129,16 +165,17 @@ class LocalCache(dict, CacheUtils): return out def set(self, key, val, time = 0): + # time is ignored on localcache self._check_key(key) self[key] = val def set_multi(self, keys, prefix='', time=0): for k,v in keys.iteritems(): - self.set(prefix+str(k), v) + self.set(prefix+str(k), v, time=time) def add(self, key, val, time = 0): self._check_key(key) - self.setdefault(key, val) + return self.setdefault(key, val) def delete(self, key): if self.has_key(key): @@ -149,11 +186,11 @@ class LocalCache(dict, CacheUtils): if self.has_key(key): del self[key] - def incr(self, key, amt=1): + def incr(self, key, delta=1, time=0): if self.has_key(key): - self[key] = int(self[key]) + amt + self[key] = int(self[key]) + delta - def decr(self, key, amt=1): + def decr(self, key, amt=1): if self.has_key(key): self[key] = int(self[key]) - amt @@ -173,13 +210,15 @@ class LocalCache(dict, CacheUtils): self.clear() class CacheChain(CacheUtils, local): - def __init__(self, caches): + def __init__(self, caches, cache_negative_results=False): self.caches = caches + self.cache_negative_results = cache_negative_results def make_set_fn(fn_name): def fn(self, *a, **kw): for c in self.caches: - getattr(c, fn_name)(*a, **kw) + ret = getattr(c, fn_name)(*a, **kw) + return ret return fn set = make_set_fn('set') @@ -193,20 +232,60 @@ class CacheChain(CacheUtils, local): delete = make_set_fn('delete') delete_multi = make_set_fn('delete_multi') flush_all = make_set_fn('flush_all') + cache_negative_results = False + + def add(self, key, val, time=0): + authority = self.caches[-1] + added_val = authority.add(key, val, time=time) + for cache in self.caches[:-1]: + # Calling set() rather than add() to ensure that all caches are + # in sync and that de-syncs repair themselves + cache.set(key, added_val, time=time) + return added_val + + def accrue(self, key, time=0, delta=1): + auth_value = self.caches[-1].get(key) + + if auth_value is None: + self.caches[-1].set(key, 0, time) + auth_value = 0 + + try: + auth_value = int(auth_value) + except ValueError: + raise ValueError("Can't accrue %s; it's a %s (%r)" % + (key, auth_value.__class__.__name__, auth_value)) + + for c in self.caches: + c.set(key, auth_value, time=time) + + self.incr(key, time=time, delta=delta) def get(self, key, default = None, local = True): for c in self.caches: if not local and isinstance(c,LocalCache): continue - val = c.get(key, default) + + val = c.get(key) + if val is not None: #update other caches for d in self.caches: if c == d: - break; + break # so we don't set caches later in the chain d.set(key, val) - return val + + if self.cache_negative_results and val is NoneResult: + return None + else: + return val + #didn't find anything + + if self.cache_negative_results: + for c in self.caches: + c.set(key, NoneResult) + return default def simple_get_multi(self, keys): @@ -220,13 +299,32 @@ class CacheChain(CacheUtils, local): if r: for d in self.caches: if c == d: - break; + break # so we don't set caches later in the chain d.set_multi(r) r.update(out) out = r need = need - set(r.keys()) + + if need and self.cache_negative_results: + d = dict( (key,NoneResult) for key in need) + for c in self.caches: + c.set_multi(d) + + if self.cache_negative_results: + filtered_out = {} + for k,v in out.iteritems(): + if v is not NoneResult: + filtered_out[k] = v + out = filtered_out + return out + def debug(self, key): + print "Looking up [%r]" % key + for i, c in enumerate(self.caches): + print "[%d] %10s has value [%r]" % (i, c.__class__.__name__, + c.get(key)) + #smart get multi def sgm(cache, keys, miss_fn, prefix='', time=0): keys = set(keys) @@ -274,7 +372,7 @@ def test_cache(cache): # a cache that occasionally dumps itself to be used for long-running # processes class SelfEmptyingCache(LocalCache): - def __init__(self,max_size=100*1000): + def __init__(self, max_size=10*1000): self.max_size = max_size def maybe_reset(self): @@ -284,5 +382,6 @@ class SelfEmptyingCache(LocalCache): def set(self,key,val,time = 0): self.maybe_reset() return LocalCache.set(self,key,val,time) + def add(self,key,val): return self.set(key,val) diff --git a/r2/r2/lib/captcha.py b/r2/r2/lib/captcha.py index b7bfff448..94bc9f6a3 100644 --- a/r2/r2/lib/captcha.py +++ b/r2/r2/lib/captcha.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import random, string diff --git a/r2/r2/lib/comment_tree.py b/r2/r2/lib/comment_tree.py index eacaf18d4..5a701f977 100644 --- a/r2/r2/lib/comment_tree.py +++ b/r2/r2/lib/comment_tree.py @@ -6,24 +6,24 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement from pylons import g - -from r2.models import * +from itertools import chain +from utils import tup def comments_key(link_id): return 'comments_' + str(link_id) @@ -98,6 +98,7 @@ def link_comments(link_id): return r def load_link_comments(link_id): + from r2.models import Comment q = Comment._query(Comment.c.link_id == link_id, Comment.c._deleted == (True, False), Comment.c._spam == (True, False), @@ -135,3 +136,140 @@ def load_link_comments(link_id): num_children[cm_id] = num return cids, comment_tree, depth, num_children + +# message conversation functions +def messages_key(user_id): + return 'message_conversations_' + str(user_id) + +def messages_lock_key(user_id): + return 'message_conversations_lock_' + str(user_id) + +def add_message(message): + # add the message to the author's list and the recipient + with g.make_lock(messages_lock_key(message.author_id)): + add_message_nolock(message.author_id, message) + with g.make_lock(messages_lock_key(message.to_id)): + add_message_nolock(message.to_id, message) + +def add_message_nolock(user_id, message): + from r2.models import Account, Message + key = messages_key(user_id) + trees = g.permacache.get(key) + if not trees: + # no point computing it now. We'll do it when they go to + # their message page. + return + + # if it is a new root message, easy enough + if message.first_message is None: + trees.insert(0, (message._id, [])) + else: + tree_dict = dict(trees) + + # if the tree already has the first message, update the list + if message.first_message in tree_dict: + if message._id not in tree_dict[message.first_message]: + tree_dict[message.first_message].append(message._id) + tree_dict[message.first_message].sort() + # we have to regenerate the conversation :/ + else: + m = Message._query(Message.c.first_message == message.first_message, + data = True) + new_tree = compute_message_trees(m) + if new_tree: + trees.append(new_tree[0]) + trees.sort(key = tree_sort_fn, reverse = True) + + # done! + g.permacache.set(key, trees) + + +def conversation(user, parent): + from r2.models import Message + trees = dict(user_messages(user)) + + if parent._id in trees: + convo = trees[parent._id] + if convo: + m = Message._byID(convo[0], data = True) + if not convo or m.first_message == m.parent_id: + return [(parent._id, convo)] + + # if we get to this point, either we didn't find the conversation, + # or the first child of the result was not the actual first child. + # To the database! + m = Message._query(Message.c.first_message == parent._id, + data = True) + return compute_message_trees([parent] + list(m)) + +def user_messages(user): + key = messages_key(user._id) + trees = g.permacache.get(key) + if trees is None: + trees = user_messages_nocache(user) + g.permacache.set(key, trees) + return trees + +def user_messages_nocache(user): + """ + Just like user_messages, but avoiding the cache + """ + from r2.lib.db import queries + from r2.models import Message + + inbox = queries.get_inbox_messages(user) + if hasattr(inbox, 'prewrap_fn'): + inbox = [inbox.prewrap_fn(i) for i in inbox] + else: + inbox = list(inbox) + + sent = queries.get_sent(user) + if hasattr(sent, 'prewrap_fn'): + sent = [sent.prewrap_fn(i) for i in sent] + else: + sent = list(sent) + + m = {} + ids = [x for x in chain(inbox, sent) if not isinstance(x, Message)] + if ids: + m = Message._by_fullname(ids, return_dict = True, data = True) + + messages = [m.get(x, x) for x in chain(inbox, sent)] + + return compute_message_trees(messages) + +def compute_message_trees(messages): + from r2.models import Message + roots = set() + threads = {} + mdict = {} + messages = sorted(messages, key = lambda m: m._date, reverse = True) + + for m in messages: + if not m._loaded: + m._load() + mdict[m._id] = m + if m.first_message: + roots.add(m.first_message) + threads.setdefault(m.first_message, set()).add(m._id) + else: + roots.add(m._id) + + # load any top-level messages which are not in the original list + missing = [m for m in roots if m not in mdict] + if missing: + mdict.update(Message._byID(tup(missing), + return_dict = True, data = True)) + + # sort threads in chrono order + for k in threads: + threads[k] = list(sorted(threads[k])) + + tree = [(root, threads.get(root, [])) for root in roots] + tree.sort(key = tree_sort_fn, reverse = True) + + return tree + +def tree_sort_fn(tree): + root, threads = tree + return threads[-1] if threads else root diff --git a/r2/r2/lib/contrib/gprof2dot.py b/r2/r2/lib/contrib/gprof2dot.py new file mode 100644 index 000000000..55eb53ad8 --- /dev/null +++ b/r2/r2/lib/contrib/gprof2dot.py @@ -0,0 +1,2227 @@ +#!/usr/bin/env python +# +# Copyright 2008-2009 Jose Fonseca +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +"""Generate a dot graph from the output of several profilers.""" + +__author__ = "Jose Fonseca" + +__version__ = "1.0" + + +import sys +import math +import os.path +import re +import textwrap +import optparse +import xml.parsers.expat + + +try: + # Debugging helper module + import debug +except ImportError: + pass + + +def percentage(p): + return "%.02f%%" % (p*100.0,) + +def add(a, b): + return a + b + +def equal(a, b): + if a == b: + return a + else: + return None + +def fail(a, b): + assert False + + +tol = 2 ** -23 + +def ratio(numerator, denominator): + try: + ratio = float(numerator)/float(denominator) + except ZeroDivisionError: + # 0/0 is undefined, but 1.0 yields more useful results + return 1.0 + if ratio < 0.0: + if ratio < -tol: + sys.stderr.write('warning: negative ratio (%s/%s)\n' % (numerator, denominator)) + return 0.0 + if ratio > 1.0: + if ratio > 1.0 + tol: + sys.stderr.write('warning: ratio greater than one (%s/%s)\n' % (numerator, denominator)) + return 1.0 + return ratio + + +class UndefinedEvent(Exception): + """Raised when attempting to get an event which is undefined.""" + + def __init__(self, event): + Exception.__init__(self) + self.event = event + + def __str__(self): + return 'unspecified event %s' % self.event.name + + +class Event(object): + """Describe a kind of event, and its basic operations.""" + + def __init__(self, name, null, aggregator, formatter = str): + self.name = name + self._null = null + self._aggregator = aggregator + self._formatter = formatter + + def __eq__(self, other): + return self is other + + def __hash__(self): + return id(self) + + def null(self): + return self._null + + def aggregate(self, val1, val2): + """Aggregate two event values.""" + assert val1 is not None + assert val2 is not None + return self._aggregator(val1, val2) + + def format(self, val): + """Format an event value.""" + assert val is not None + return self._formatter(val) + + +MODULE = Event("Module", None, equal) +PROCESS = Event("Process", None, equal) + +CALLS = Event("Calls", 0, add) +SAMPLES = Event("Samples", 0, add) +SAMPLES2 = Event("Samples", 0, add) + +TIME = Event("Time", 0.0, add, lambda x: '(' + str(x) + ')') +TIME_RATIO = Event("Time ratio", 0.0, add, lambda x: '(' + percentage(x) + ')') +TOTAL_TIME = Event("Total time", 0.0, fail) +TOTAL_TIME_RATIO = Event("Total time ratio", 0.0, fail, percentage) + +CALL_RATIO = Event("Call ratio", 0.0, add, percentage) + +PRUNE_RATIO = Event("Prune ratio", 0.0, add, percentage) + + +class Object(object): + """Base class for all objects in profile which can store events.""" + + def __init__(self, events=None): + if events is None: + self.events = {} + else: + self.events = events + + def __hash__(self): + return id(self) + + def __eq__(self, other): + return self is other + + def __contains__(self, event): + return event in self.events + + def __getitem__(self, event): + try: + return self.events[event] + except KeyError: + raise UndefinedEvent(event) + + def __setitem__(self, event, value): + if value is None: + if event in self.events: + del self.events[event] + else: + self.events[event] = value + + +class Call(Object): + """A call between functions. + + There should be at most one call object for every pair of functions. + """ + + def __init__(self, callee_id): + Object.__init__(self) + self.callee_id = callee_id + + +class Function(Object): + """A function.""" + + def __init__(self, id, name): + Object.__init__(self) + self.id = id + self.name = name + self.calls = {} + self.cycle = None + + def add_call(self, call): + if call.callee_id in self.calls: + sys.stderr.write('warning: overwriting call from function %s to %s\n' % (str(self.id), str(call.callee_id))) + self.calls[call.callee_id] = call + + # TODO: write utility functions + + def __repr__(self): + return self.name + + +class Cycle(Object): + """A cycle made from recursive function calls.""" + + def __init__(self): + Object.__init__(self) + # XXX: Do cycles need an id? + self.functions = set() + + def add_function(self, function): + assert function not in self.functions + self.functions.add(function) + # XXX: Aggregate events? + if function.cycle is not None: + for other in function.cycle.functions: + if function not in self.functions: + self.add_function(other) + function.cycle = self + + +class Profile(Object): + """The whole profile.""" + + def __init__(self): + Object.__init__(self) + self.functions = {} + self.cycles = [] + + def add_function(self, function): + if function.id in self.functions: + sys.stderr.write('warning: overwriting function %s (id %s)\n' % (function.name, str(function.id))) + self.functions[function.id] = function + + def add_cycle(self, cycle): + self.cycles.append(cycle) + + def validate(self): + """Validate the edges.""" + + for function in self.functions.itervalues(): + for callee_id in function.calls.keys(): + assert function.calls[callee_id].callee_id == callee_id + if callee_id not in self.functions: + sys.stderr.write('warning: call to undefined function %s from function %s\n' % (str(callee_id), function.name)) + del function.calls[callee_id] + + def find_cycles(self): + """Find cycles using Tarjan's strongly connected components algorithm.""" + + # Apply the Tarjan's algorithm successively until all functions are visited + visited = set() + for function in self.functions.itervalues(): + if function not in visited: + self._tarjan(function, 0, [], {}, {}, visited) + cycles = [] + for function in self.functions.itervalues(): + if function.cycle is not None and function.cycle not in cycles: + cycles.append(function.cycle) + self.cycles = cycles + if 0: + for cycle in cycles: + sys.stderr.write("Cycle:\n") + for member in cycle.functions: + sys.stderr.write("\tFunction %s\n" % member.name) + + def _tarjan(self, function, order, stack, orders, lowlinks, visited): + """Tarjan's strongly connected components algorithm. + + See also: + - http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm + """ + + visited.add(function) + orders[function] = order + lowlinks[function] = order + order += 1 + pos = len(stack) + stack.append(function) + for call in function.calls.itervalues(): + callee = self.functions[call.callee_id] + # TODO: use a set to optimize lookup + if callee not in orders: + order = self._tarjan(callee, order, stack, orders, lowlinks, visited) + lowlinks[function] = min(lowlinks[function], lowlinks[callee]) + elif callee in stack: + lowlinks[function] = min(lowlinks[function], orders[callee]) + if lowlinks[function] == orders[function]: + # Strongly connected component found + members = stack[pos:] + del stack[pos:] + if len(members) > 1: + cycle = Cycle() + for member in members: + cycle.add_function(member) + return order + + def call_ratios(self, event): + # Aggregate for incoming calls + cycle_totals = {} + for cycle in self.cycles: + cycle_totals[cycle] = 0.0 + function_totals = {} + for function in self.functions.itervalues(): + function_totals[function] = 0.0 + for function in self.functions.itervalues(): + for call in function.calls.itervalues(): + if call.callee_id != function.id: + callee = self.functions[call.callee_id] + function_totals[callee] += call[event] + if callee.cycle is not None and callee.cycle is not function.cycle: + cycle_totals[callee.cycle] += call[event] + + # Compute the ratios + for function in self.functions.itervalues(): + for call in function.calls.itervalues(): + assert CALL_RATIO not in call + if call.callee_id != function.id: + callee = self.functions[call.callee_id] + if callee.cycle is not None and callee.cycle is not function.cycle: + total = cycle_totals[callee.cycle] + else: + total = function_totals[callee] + call[CALL_RATIO] = ratio(call[event], total) + + def integrate(self, outevent, inevent): + """Propagate function time ratio allong the function calls. + + Must be called after finding the cycles. + + See also: + - http://citeseer.ist.psu.edu/graham82gprof.html + """ + + # Sanity checking + assert outevent not in self + for function in self.functions.itervalues(): + assert outevent not in function + assert inevent in function + for call in function.calls.itervalues(): + assert outevent not in call + if call.callee_id != function.id: + assert CALL_RATIO in call + + # Aggregate the input for each cycle + for cycle in self.cycles: + total = inevent.null() + for function in self.functions.itervalues(): + total = inevent.aggregate(total, function[inevent]) + self[inevent] = total + + # Integrate along the edges + total = inevent.null() + for function in self.functions.itervalues(): + total = inevent.aggregate(total, function[inevent]) + self._integrate_function(function, outevent, inevent) + self[outevent] = total + + def _integrate_function(self, function, outevent, inevent): + if function.cycle is not None: + return self._integrate_cycle(function.cycle, outevent, inevent) + else: + if outevent not in function: + total = function[inevent] + for call in function.calls.itervalues(): + if call.callee_id != function.id: + total += self._integrate_call(call, outevent, inevent) + function[outevent] = total + return function[outevent] + + def _integrate_call(self, call, outevent, inevent): + assert outevent not in call + assert CALL_RATIO in call + callee = self.functions[call.callee_id] + subtotal = call[CALL_RATIO]*self._integrate_function(callee, outevent, inevent) + call[outevent] = subtotal + return subtotal + + def _integrate_cycle(self, cycle, outevent, inevent): + if outevent not in cycle: + + # Compute the outevent for the whole cycle + total = inevent.null() + for member in cycle.functions: + subtotal = member[inevent] + for call in member.calls.itervalues(): + callee = self.functions[call.callee_id] + if callee.cycle is not cycle: + subtotal += self._integrate_call(call, outevent, inevent) + total += subtotal + cycle[outevent] = total + + # Compute the time propagated to callers of this cycle + callees = {} + for function in self.functions.itervalues(): + if function.cycle is not cycle: + for call in function.calls.itervalues(): + callee = self.functions[call.callee_id] + if callee.cycle is cycle: + try: + callees[callee] += call[CALL_RATIO] + except KeyError: + callees[callee] = call[CALL_RATIO] + + for member in cycle.functions: + member[outevent] = outevent.null() + + for callee, call_ratio in callees.iteritems(): + ranks = {} + call_ratios = {} + partials = {} + self._rank_cycle_function(cycle, callee, 0, ranks) + self._call_ratios_cycle(cycle, callee, ranks, call_ratios, set()) + partial = self._integrate_cycle_function(cycle, callee, call_ratio, partials, ranks, call_ratios, outevent, inevent) + assert partial == max(partials.values()) + assert not total or abs(1.0 - partial/(call_ratio*total)) <= 0.001 + + return cycle[outevent] + + def _rank_cycle_function(self, cycle, function, rank, ranks): + if function not in ranks or ranks[function] > rank: + ranks[function] = rank + for call in function.calls.itervalues(): + if call.callee_id != function.id: + callee = self.functions[call.callee_id] + if callee.cycle is cycle: + self._rank_cycle_function(cycle, callee, rank + 1, ranks) + + def _call_ratios_cycle(self, cycle, function, ranks, call_ratios, visited): + if function not in visited: + visited.add(function) + for call in function.calls.itervalues(): + if call.callee_id != function.id: + callee = self.functions[call.callee_id] + if callee.cycle is cycle: + if ranks[callee] > ranks[function]: + call_ratios[callee] = call_ratios.get(callee, 0.0) + call[CALL_RATIO] + self._call_ratios_cycle(cycle, callee, ranks, call_ratios, visited) + + def _integrate_cycle_function(self, cycle, function, partial_ratio, partials, ranks, call_ratios, outevent, inevent): + if function not in partials: + partial = partial_ratio*function[inevent] + for call in function.calls.itervalues(): + if call.callee_id != function.id: + callee = self.functions[call.callee_id] + if callee.cycle is not cycle: + assert outevent in call + partial += partial_ratio*call[outevent] + else: + if ranks[callee] > ranks[function]: + callee_partial = self._integrate_cycle_function(cycle, callee, partial_ratio, partials, ranks, call_ratios, outevent, inevent) + call_ratio = ratio(call[CALL_RATIO], call_ratios[callee]) + call_partial = call_ratio*callee_partial + try: + call[outevent] += call_partial + except UndefinedEvent: + call[outevent] = call_partial + partial += call_partial + partials[function] = partial + try: + function[outevent] += partial + except UndefinedEvent: + function[outevent] = partial + return partials[function] + + def aggregate(self, event): + """Aggregate an event for the whole profile.""" + + total = event.null() + for function in self.functions.itervalues(): + try: + total = event.aggregate(total, function[event]) + except UndefinedEvent: + return + self[event] = total + + def ratio(self, outevent, inevent): + assert outevent not in self + assert inevent in self + for function in self.functions.itervalues(): + assert outevent not in function + assert inevent in function + function[outevent] = ratio(function[inevent], self[inevent]) + for call in function.calls.itervalues(): + assert outevent not in call + if inevent in call: + call[outevent] = ratio(call[inevent], self[inevent]) + self[outevent] = 1.0 + + def prune(self, node_thres, edge_thres): + """Prune the profile""" + + # compute the prune ratios + for function in self.functions.itervalues(): + try: + function[PRUNE_RATIO] = function[TOTAL_TIME_RATIO] + except UndefinedEvent: + pass + + for call in function.calls.itervalues(): + callee = self.functions[call.callee_id] + + if TOTAL_TIME_RATIO in call: + # handle exact cases first + call[PRUNE_RATIO] = call[TOTAL_TIME_RATIO] + else: + try: + # make a safe estimate + call[PRUNE_RATIO] = min(function[TOTAL_TIME_RATIO], callee[TOTAL_TIME_RATIO]) + except UndefinedEvent: + pass + + # prune the nodes + for function_id in self.functions.keys(): + function = self.functions[function_id] + try: + if function[PRUNE_RATIO] < node_thres: + del self.functions[function_id] + except UndefinedEvent: + pass + + # prune the egdes + for function in self.functions.itervalues(): + for callee_id in function.calls.keys(): + call = function.calls[callee_id] + try: + if callee_id not in self.functions or call[PRUNE_RATIO] < edge_thres: + del function.calls[callee_id] + except UndefinedEvent: + pass + + def dump(self): + for function in self.functions.itervalues(): + sys.stderr.write('Function %s:\n' % (function.name,)) + self._dump_events(function.events) + for call in function.calls.itervalues(): + callee = self.functions[call.callee_id] + sys.stderr.write(' Call %s:\n' % (callee.name,)) + self._dump_events(call.events) + for cycle in self.cycles: + sys.stderr.write('Cycle:\n') + self._dump_events(cycle.events) + for function in cycle.functions: + sys.stderr.write(' Function %s\n' % (function.name,)) + + def _dump_events(self, events): + for event, value in events.iteritems(): + sys.stderr.write(' %s: %s\n' % (event.name, event.format(value))) + + +class Struct: + """Masquerade a dictionary with a structure-like behavior.""" + + def __init__(self, attrs = None): + if attrs is None: + attrs = {} + self.__dict__['_attrs'] = attrs + + def __getattr__(self, name): + try: + return self._attrs[name] + except KeyError: + raise AttributeError(name) + + def __setattr__(self, name, value): + self._attrs[name] = value + + def __str__(self): + return str(self._attrs) + + def __repr__(self): + return repr(self._attrs) + + +class ParseError(Exception): + """Raised when parsing to signal mismatches.""" + + def __init__(self, msg, line): + self.msg = msg + # TODO: store more source line information + self.line = line + + def __str__(self): + return '%s: %r' % (self.msg, self.line) + + +class Parser: + """Parser interface.""" + + def __init__(self): + pass + + def parse(self): + raise NotImplementedError + + +class LineParser(Parser): + """Base class for parsers that read line-based formats.""" + + def __init__(self, file): + Parser.__init__(self) + self._file = file + self.__line = None + self.__eof = False + + def readline(self): + line = self._file.readline() + if not line: + self.__line = '' + self.__eof = True + self.__line = line.rstrip('\r\n') + + def lookahead(self): + assert self.__line is not None + return self.__line + + def consume(self): + assert self.__line is not None + line = self.__line + self.readline() + return line + + def eof(self): + assert self.__line is not None + return self.__eof + + +XML_ELEMENT_START, XML_ELEMENT_END, XML_CHARACTER_DATA, XML_EOF = range(4) + + +class XmlToken: + + def __init__(self, type, name_or_data, attrs = None, line = None, column = None): + assert type in (XML_ELEMENT_START, XML_ELEMENT_END, XML_CHARACTER_DATA, XML_EOF) + self.type = type + self.name_or_data = name_or_data + self.attrs = attrs + self.line = line + self.column = column + + def __str__(self): + if self.type == XML_ELEMENT_START: + return '<' + self.name_or_data + ' ...>' + if self.type == XML_ELEMENT_END: + return '</' + self.name_or_data + '>' + if self.type == XML_CHARACTER_DATA: + return self.name_or_data + if self.type == XML_EOF: + return 'end of file' + assert 0 + + +class XmlTokenizer: + """Expat based XML tokenizer.""" + + def __init__(self, fp, skip_ws = True): + self.fp = fp + self.tokens = [] + self.index = 0 + self.final = False + self.skip_ws = skip_ws + + self.character_pos = 0, 0 + self.character_data = '' + + self.parser = xml.parsers.expat.ParserCreate() + self.parser.StartElementHandler = self.handle_element_start + self.parser.EndElementHandler = self.handle_element_end + self.parser.CharacterDataHandler = self.handle_character_data + + def handle_element_start(self, name, attributes): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(XML_ELEMENT_START, name, attributes, line, column) + self.tokens.append(token) + + def handle_element_end(self, name): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(XML_ELEMENT_END, name, None, line, column) + self.tokens.append(token) + + def handle_character_data(self, data): + if not self.character_data: + self.character_pos = self.pos() + self.character_data += data + + def finish_character_data(self): + if self.character_data: + if not self.skip_ws or not self.character_data.isspace(): + line, column = self.character_pos + token = XmlToken(XML_CHARACTER_DATA, self.character_data, None, line, column) + self.tokens.append(token) + self.character_data = '' + + def next(self): + size = 16*1024 + while self.index >= len(self.tokens) and not self.final: + self.tokens = [] + self.index = 0 + data = self.fp.read(size) + self.final = len(data) < size + try: + self.parser.Parse(data, self.final) + except xml.parsers.expat.ExpatError, e: + #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS: + if e.code == 3: + pass + else: + raise e + if self.index >= len(self.tokens): + line, column = self.pos() + token = XmlToken(XML_EOF, None, None, line, column) + else: + token = self.tokens[self.index] + self.index += 1 + return token + + def pos(self): + return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber + + +class XmlTokenMismatch(Exception): + + def __init__(self, expected, found): + self.expected = expected + self.found = found + + def __str__(self): + return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) + + +class XmlParser(Parser): + """Base XML document parser.""" + + def __init__(self, fp): + Parser.__init__(self) + self.tokenizer = XmlTokenizer(fp) + self.consume() + + def consume(self): + self.token = self.tokenizer.next() + + def match_element_start(self, name): + return self.token.type == XML_ELEMENT_START and self.token.name_or_data == name + + def match_element_end(self, name): + return self.token.type == XML_ELEMENT_END and self.token.name_or_data == name + + def element_start(self, name): + while self.token.type == XML_CHARACTER_DATA: + self.consume() + if self.token.type != XML_ELEMENT_START: + raise XmlTokenMismatch(XmlToken(XML_ELEMENT_START, name), self.token) + if self.token.name_or_data != name: + raise XmlTokenMismatch(XmlToken(XML_ELEMENT_START, name), self.token) + attrs = self.token.attrs + self.consume() + return attrs + + def element_end(self, name): + while self.token.type == XML_CHARACTER_DATA: + self.consume() + if self.token.type != XML_ELEMENT_END: + raise XmlTokenMismatch(XmlToken(XML_ELEMENT_END, name), self.token) + if self.token.name_or_data != name: + raise XmlTokenMismatch(XmlToken(XML_ELEMENT_END, name), self.token) + self.consume() + + def character_data(self, strip = True): + data = '' + while self.token.type == XML_CHARACTER_DATA: + data += self.token.name_or_data + self.consume() + if strip: + data = data.strip() + return data + + +class GprofParser(Parser): + """Parser for GNU gprof output. + + See also: + - Chapter "Interpreting gprof's Output" from the GNU gprof manual + http://sourceware.org/binutils/docs-2.18/gprof/Call-Graph.html#Call-Graph + - File "cg_print.c" from the GNU gprof source code + http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/src/gprof/cg_print.c?rev=1.12&cvsroot=src + """ + + def __init__(self, fp): + Parser.__init__(self) + self.fp = fp + self.functions = {} + self.cycles = {} + + def readline(self): + line = self.fp.readline() + if not line: + sys.stderr.write('error: unexpected end of file\n') + sys.exit(1) + line = line.rstrip('\r\n') + return line + + _int_re = re.compile(r'^\d+$') + _float_re = re.compile(r'^\d+\.\d+$') + + def translate(self, mo): + """Extract a structure from a match object, while translating the types in the process.""" + attrs = {} + groupdict = mo.groupdict() + for name, value in groupdict.iteritems(): + if value is None: + value = None + elif self._int_re.match(value): + value = int(value) + elif self._float_re.match(value): + value = float(value) + attrs[name] = (value) + return Struct(attrs) + + _cg_header_re = re.compile( + # original gprof header + r'^\s+called/total\s+parents\s*$|' + + r'^index\s+%time\s+self\s+descendents\s+called\+self\s+name\s+index\s*$|' + + r'^\s+called/total\s+children\s*$|' + + # GNU gprof header + r'^index\s+%\s+time\s+self\s+children\s+called\s+name\s*$' + ) + + _cg_ignore_re = re.compile( + # spontaneous + r'^\s+<spontaneous>\s*$|' + # internal calls (such as "mcount") + r'^.*\((\d+)\)$' + ) + + _cg_primary_re = re.compile( + r'^\[(?P<index>\d+)\]?' + + r'\s+(?P<percentage_time>\d+\.\d+)' + + r'\s+(?P<self>\d+\.\d+)' + + r'\s+(?P<descendants>\d+\.\d+)' + + r'\s+(?:(?P<called>\d+)(?:\+(?P<called_self>\d+))?)?' + + r'\s+(?P<name>\S.*?)' + + r'(?:\s+<cycle\s(?P<cycle>\d+)>)?' + + r'\s\[(\d+)\]$' + ) + + _cg_parent_re = re.compile( + r'^\s+(?P<self>\d+\.\d+)?' + + r'\s+(?P<descendants>\d+\.\d+)?' + + r'\s+(?P<called>\d+)(?:/(?P<called_total>\d+))?' + + r'\s+(?P<name>\S.*?)' + + r'(?:\s+<cycle\s(?P<cycle>\d+)>)?' + + r'\s\[(?P<index>\d+)\]$' + ) + + _cg_child_re = _cg_parent_re + + _cg_cycle_header_re = re.compile( + r'^\[(?P<index>\d+)\]?' + + r'\s+(?P<percentage_time>\d+\.\d+)' + + r'\s+(?P<self>\d+\.\d+)' + + r'\s+(?P<descendants>\d+\.\d+)' + + r'\s+(?:(?P<called>\d+)(?:\+(?P<called_self>\d+))?)?' + + r'\s+<cycle\s(?P<cycle>\d+)\sas\sa\swhole>' + + r'\s\[(\d+)\]$' + ) + + _cg_cycle_member_re = re.compile( + r'^\s+(?P<self>\d+\.\d+)?' + + r'\s+(?P<descendants>\d+\.\d+)?' + + r'\s+(?P<called>\d+)(?:\+(?P<called_self>\d+))?' + + r'\s+(?P<name>\S.*?)' + + r'(?:\s+<cycle\s(?P<cycle>\d+)>)?' + + r'\s\[(?P<index>\d+)\]$' + ) + + _cg_sep_re = re.compile(r'^--+$') + + def parse_function_entry(self, lines): + parents = [] + children = [] + + while True: + if not lines: + sys.stderr.write('warning: unexpected end of entry\n') + line = lines.pop(0) + if line.startswith('['): + break + + # read function parent line + mo = self._cg_parent_re.match(line) + if not mo: + if self._cg_ignore_re.match(line): + continue + sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) + else: + parent = self.translate(mo) + parents.append(parent) + + # read primary line + mo = self._cg_primary_re.match(line) + if not mo: + sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) + return + else: + function = self.translate(mo) + + while lines: + line = lines.pop(0) + + # read function subroutine line + mo = self._cg_child_re.match(line) + if not mo: + if self._cg_ignore_re.match(line): + continue + sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) + else: + child = self.translate(mo) + children.append(child) + + function.parents = parents + function.children = children + + self.functions[function.index] = function + + def parse_cycle_entry(self, lines): + + # read cycle header line + line = lines[0] + mo = self._cg_cycle_header_re.match(line) + if not mo: + sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) + return + cycle = self.translate(mo) + + # read cycle member lines + cycle.functions = [] + for line in lines[1:]: + mo = self._cg_cycle_member_re.match(line) + if not mo: + sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) + continue + call = self.translate(mo) + cycle.functions.append(call) + + self.cycles[cycle.cycle] = cycle + + def parse_cg_entry(self, lines): + if lines[0].startswith("["): + self.parse_cycle_entry(lines) + else: + self.parse_function_entry(lines) + + def parse_cg(self): + """Parse the call graph.""" + + # skip call graph header + while not self._cg_header_re.match(self.readline()): + pass + line = self.readline() + while self._cg_header_re.match(line): + line = self.readline() + + # process call graph entries + entry_lines = [] + while line != '\014': # form feed + if line and not line.isspace(): + if self._cg_sep_re.match(line): + self.parse_cg_entry(entry_lines) + entry_lines = [] + else: + entry_lines.append(line) + line = self.readline() + + def parse(self): + self.parse_cg() + self.fp.close() + + profile = Profile() + profile[TIME] = 0.0 + + cycles = {} + for index in self.cycles.iterkeys(): + cycles[index] = Cycle() + + for entry in self.functions.itervalues(): + # populate the function + function = Function(entry.index, entry.name) + function[TIME] = entry.self + if entry.called is not None: + function[CALLS] = entry.called + if entry.called_self is not None: + call = Call(entry.index) + call[CALLS] = entry.called_self + function[CALLS] += entry.called_self + + # populate the function calls + for child in entry.children: + call = Call(child.index) + + assert child.called is not None + call[CALLS] = child.called + + if child.index not in self.functions: + # NOTE: functions that were never called but were discovered by gprof's + # static call graph analysis dont have a call graph entry so we need + # to add them here + missing = Function(child.index, child.name) + function[TIME] = 0.0 + function[CALLS] = 0 + profile.add_function(missing) + + function.add_call(call) + + profile.add_function(function) + + if entry.cycle is not None: + try: + cycle = cycles[entry.cycle] + except KeyError: + sys.stderr.write('warning: <cycle %u as a whole> entry missing\n' % entry.cycle) + cycle = Cycle() + cycles[entry.cycle] = cycle + cycle.add_function(function) + + profile[TIME] = profile[TIME] + function[TIME] + + for cycle in cycles.itervalues(): + profile.add_cycle(cycle) + + # Compute derived events + profile.validate() + profile.ratio(TIME_RATIO, TIME) + profile.call_ratios(CALLS) + profile.integrate(TOTAL_TIME, TIME) + profile.ratio(TOTAL_TIME_RATIO, TOTAL_TIME) + + return profile + + +class OprofileParser(LineParser): + """Parser for oprofile callgraph output. + + See also: + - http://oprofile.sourceforge.net/doc/opreport.html#opreport-callgraph + """ + + _fields_re = { + 'samples': r'(?P<samples>\d+)', + '%': r'(?P<percentage>\S+)', + 'linenr info': r'(?P<source>\(no location information\)|\S+:\d+)', + 'image name': r'(?P<image>\S+(?:\s\(tgid:[^)]*\))?)', + 'app name': r'(?P<application>\S+)', + 'symbol name': r'(?P<symbol>\(no symbols\)|.+?)', + } + + def __init__(self, infile): + LineParser.__init__(self, infile) + self.entries = {} + self.entry_re = None + + def add_entry(self, callers, function, callees): + try: + entry = self.entries[function.id] + except KeyError: + self.entries[function.id] = (callers, function, callees) + else: + callers_total, function_total, callees_total = entry + self.update_subentries_dict(callers_total, callers) + function_total.samples += function.samples + self.update_subentries_dict(callees_total, callees) + + def update_subentries_dict(self, totals, partials): + for partial in partials.itervalues(): + try: + total = totals[partial.id] + except KeyError: + totals[partial.id] = partial + else: + total.samples += partial.samples + + def parse(self): + # read lookahead + self.readline() + + self.parse_header() + while self.lookahead(): + self.parse_entry() + + profile = Profile() + + reverse_call_samples = {} + + # populate the profile + profile[SAMPLES] = 0 + for _callers, _function, _callees in self.entries.itervalues(): + function = Function(_function.id, _function.name) + function[SAMPLES] = _function.samples + profile.add_function(function) + profile[SAMPLES] += _function.samples + + if _function.application: + function[PROCESS] = os.path.basename(_function.application) + if _function.image: + function[MODULE] = os.path.basename(_function.image) + + total_callee_samples = 0 + for _callee in _callees.itervalues(): + total_callee_samples += _callee.samples + + for _callee in _callees.itervalues(): + if not _callee.self: + call = Call(_callee.id) + call[SAMPLES2] = _callee.samples + function.add_call(call) + + # compute derived data + profile.validate() + profile.find_cycles() + profile.ratio(TIME_RATIO, SAMPLES) + profile.call_ratios(SAMPLES2) + profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) + + return profile + + def parse_header(self): + while not self.match_header(): + self.consume() + line = self.lookahead() + fields = re.split(r'\s\s+', line) + entry_re = r'^\s*' + r'\s+'.join([self._fields_re[field] for field in fields]) + r'(?P<self>\s+\[self\])?$' + self.entry_re = re.compile(entry_re) + self.skip_separator() + + def parse_entry(self): + callers = self.parse_subentries() + if self.match_primary(): + function = self.parse_subentry() + if function is not None: + callees = self.parse_subentries() + self.add_entry(callers, function, callees) + self.skip_separator() + + def parse_subentries(self): + subentries = {} + while self.match_secondary(): + subentry = self.parse_subentry() + subentries[subentry.id] = subentry + return subentries + + def parse_subentry(self): + entry = Struct() + line = self.consume() + mo = self.entry_re.match(line) + if not mo: + raise ParseError('failed to parse', line) + fields = mo.groupdict() + entry.samples = int(fields.get('samples', 0)) + entry.percentage = float(fields.get('percentage', 0.0)) + if 'source' in fields and fields['source'] != '(no location information)': + source = fields['source'] + filename, lineno = source.split(':') + entry.filename = filename + entry.lineno = int(lineno) + else: + source = '' + entry.filename = None + entry.lineno = None + entry.image = fields.get('image', '') + entry.application = fields.get('application', '') + if 'symbol' in fields and fields['symbol'] != '(no symbols)': + entry.symbol = fields['symbol'] + else: + entry.symbol = '' + if entry.symbol.startswith('"') and entry.symbol.endswith('"'): + entry.symbol = entry.symbol[1:-1] + entry.id = ':'.join((entry.application, entry.image, source, entry.symbol)) + entry.self = fields.get('self', None) != None + if entry.self: + entry.id += ':self' + if entry.symbol: + entry.name = entry.symbol + else: + entry.name = entry.image + return entry + + def skip_separator(self): + while not self.match_separator(): + self.consume() + self.consume() + + def match_header(self): + line = self.lookahead() + return line.startswith('samples') + + def match_separator(self): + line = self.lookahead() + return line == '-'*len(line) + + def match_primary(self): + line = self.lookahead() + return not line[:1].isspace() + + def match_secondary(self): + line = self.lookahead() + return line[:1].isspace() + + +class SysprofParser(XmlParser): + + def __init__(self, stream): + XmlParser.__init__(self, stream) + + def parse(self): + objects = {} + nodes = {} + + self.element_start('profile') + while self.token.type == XML_ELEMENT_START: + if self.token.name_or_data == 'objects': + assert not objects + objects = self.parse_items('objects') + elif self.token.name_or_data == 'nodes': + assert not nodes + nodes = self.parse_items('nodes') + else: + self.parse_value(self.token.name_or_data) + self.element_end('profile') + + return self.build_profile(objects, nodes) + + def parse_items(self, name): + assert name[-1] == 's' + items = {} + self.element_start(name) + while self.token.type == XML_ELEMENT_START: + id, values = self.parse_item(name[:-1]) + assert id not in items + items[id] = values + self.element_end(name) + return items + + def parse_item(self, name): + attrs = self.element_start(name) + id = int(attrs['id']) + values = self.parse_values() + self.element_end(name) + return id, values + + def parse_values(self): + values = {} + while self.token.type == XML_ELEMENT_START: + name = self.token.name_or_data + value = self.parse_value(name) + assert name not in values + values[name] = value + return values + + def parse_value(self, tag): + self.element_start(tag) + value = self.character_data() + self.element_end(tag) + if value.isdigit(): + return int(value) + if value.startswith('"') and value.endswith('"'): + return value[1:-1] + return value + + def build_profile(self, objects, nodes): + profile = Profile() + + profile[SAMPLES] = 0 + for id, object in objects.iteritems(): + # Ignore fake objects (process names, modules, "Everything", "kernel", etc.) + if object['self'] == 0: + continue + + function = Function(id, object['name']) + function[SAMPLES] = object['self'] + profile.add_function(function) + profile[SAMPLES] += function[SAMPLES] + + for id, node in nodes.iteritems(): + # Ignore fake calls + if node['self'] == 0: + continue + + # Find a non-ignored parent + parent_id = node['parent'] + while parent_id != 0: + parent = nodes[parent_id] + caller_id = parent['object'] + if objects[caller_id]['self'] != 0: + break + parent_id = parent['parent'] + if parent_id == 0: + continue + + callee_id = node['object'] + + assert objects[caller_id]['self'] + assert objects[callee_id]['self'] + + function = profile.functions[caller_id] + + samples = node['self'] + try: + call = function.calls[callee_id] + except KeyError: + call = Call(callee_id) + call[SAMPLES2] = samples + function.add_call(call) + else: + call[SAMPLES2] += samples + + # Compute derived events + profile.validate() + profile.find_cycles() + profile.ratio(TIME_RATIO, SAMPLES) + profile.call_ratios(SAMPLES2) + profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) + + return profile + + +class SharkParser(LineParser): + """Parser for MacOSX Shark output. + + Author: tom@dbservice.com + """ + + def __init__(self, infile): + LineParser.__init__(self, infile) + self.stack = [] + self.entries = {} + + def add_entry(self, function): + try: + entry = self.entries[function.id] + except KeyError: + self.entries[function.id] = (function, { }) + else: + function_total, callees_total = entry + function_total.samples += function.samples + + def add_callee(self, function, callee): + func, callees = self.entries[function.id] + try: + entry = callees[callee.id] + except KeyError: + callees[callee.id] = callee + else: + entry.samples += callee.samples + + def parse(self): + self.readline() + self.readline() + self.readline() + self.readline() + + match = re.compile(r'(?P<prefix>[|+ ]*)(?P<samples>\d+), (?P<symbol>[^,]+), (?P<image>.*)') + + while self.lookahead(): + line = self.consume() + mo = match.match(line) + if not mo: + raise ParseError('failed to parse', line) + + fields = mo.groupdict() + prefix = len(fields.get('prefix', 0)) / 2 - 1 + + symbol = str(fields.get('symbol', 0)) + image = str(fields.get('image', 0)) + + entry = Struct() + entry.id = ':'.join([symbol, image]) + entry.samples = int(fields.get('samples', 0)) + + entry.name = symbol + entry.image = image + + # adjust the callstack + if prefix < len(self.stack): + del self.stack[prefix:] + + if prefix == len(self.stack): + self.stack.append(entry) + + # if the callstack has had an entry, it's this functions caller + if prefix > 0: + self.add_callee(self.stack[prefix - 1], entry) + + self.add_entry(entry) + + profile = Profile() + profile[SAMPLES] = 0 + for _function, _callees in self.entries.itervalues(): + function = Function(_function.id, _function.name) + function[SAMPLES] = _function.samples + profile.add_function(function) + profile[SAMPLES] += _function.samples + + if _function.image: + function[MODULE] = os.path.basename(_function.image) + + for _callee in _callees.itervalues(): + call = Call(_callee.id) + call[SAMPLES] = _callee.samples + function.add_call(call) + + # compute derived data + profile.validate() + profile.find_cycles() + profile.ratio(TIME_RATIO, SAMPLES) + profile.call_ratios(SAMPLES) + profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) + + return profile + + +class SleepyParser(Parser): + """Parser for GNU gprof output. + + See also: + - http://www.codersnotes.com/sleepy/ + - http://sleepygraph.sourceforge.net/ + """ + + def __init__(self, filename): + Parser.__init__(self) + + from zipfile import ZipFile + + self.database = ZipFile(filename) + + self.symbols = {} + self.calls = {} + + self.profile = Profile() + + _symbol_re = re.compile( + r'^(?P<id>\w+)' + + r'\s+"(?P<module>[^"]*)"' + + r'\s+"(?P<procname>[^"]*)"' + + r'\s+"(?P<sourcefile>[^"]*)"' + + r'\s+(?P<sourceline>\d+)$' + ) + + def parse_symbols(self): + lines = self.database.read('symbols.txt').splitlines() + for line in lines: + mo = self._symbol_re.match(line) + if mo: + symbol_id, module, procname, sourcefile, sourceline = mo.groups() + + function_id = ':'.join([module, procname]) + + try: + function = self.profile.functions[function_id] + except KeyError: + function = Function(function_id, procname) + function[SAMPLES] = 0 + self.profile.add_function(function) + + self.symbols[symbol_id] = function + + def parse_callstacks(self): + lines = self.database.read("callstacks.txt").splitlines() + for line in lines: + fields = line.split() + samples = int(fields[0]) + callstack = fields[1:] + + callstack = [self.symbols[symbol_id] for symbol_id in callstack] + + callee = callstack[0] + + callee[SAMPLES] += samples + self.profile[SAMPLES] += samples + + for caller in callstack[1:]: + try: + call = caller.calls[callee.id] + except KeyError: + call = Call(callee.id) + call[SAMPLES2] = samples + caller.add_call(call) + else: + call[SAMPLES2] += samples + + callee = caller + + def parse(self): + profile = self.profile + profile[SAMPLES] = 0 + + self.parse_symbols() + self.parse_callstacks() + + # Compute derived events + profile.validate() + profile.find_cycles() + profile.ratio(TIME_RATIO, SAMPLES) + profile.call_ratios(SAMPLES2) + profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) + + return profile + + +class AQtimeTable: + + def __init__(self, name, fields): + self.name = name + + self.fields = fields + self.field_column = {} + for column in range(len(fields)): + self.field_column[fields[column]] = column + self.rows = [] + + def __len__(self): + return len(self.rows) + + def __iter__(self): + for values, children in self.rows: + fields = {} + for name, value in zip(self.fields, values): + fields[name] = value + children = dict([(child.name, child) for child in children]) + yield fields, children + raise StopIteration + + def add_row(self, values, children=()): + self.rows.append((values, children)) + + +class AQtimeParser(XmlParser): + + def __init__(self, stream): + XmlParser.__init__(self, stream) + self.tables = {} + + def parse(self): + self.element_start('AQtime_Results') + self.parse_headers() + results = self.parse_results() + self.element_end('AQtime_Results') + return self.build_profile(results) + + def parse_headers(self): + self.element_start('HEADERS') + while self.token.type == XML_ELEMENT_START: + self.parse_table_header() + self.element_end('HEADERS') + + def parse_table_header(self): + attrs = self.element_start('TABLE_HEADER') + name = attrs['NAME'] + id = int(attrs['ID']) + field_types = [] + field_names = [] + while self.token.type == XML_ELEMENT_START: + field_type, field_name = self.parse_table_field() + field_types.append(field_type) + field_names.append(field_name) + self.element_end('TABLE_HEADER') + self.tables[id] = name, field_types, field_names + + def parse_table_field(self): + attrs = self.element_start('TABLE_FIELD') + type = attrs['TYPE'] + name = self.character_data() + self.element_end('TABLE_FIELD') + return type, name + + def parse_results(self): + self.element_start('RESULTS') + table = self.parse_data() + self.element_end('RESULTS') + return table + + def parse_data(self): + rows = [] + attrs = self.element_start('DATA') + table_id = int(attrs['TABLE_ID']) + table_name, field_types, field_names = self.tables[table_id] + table = AQtimeTable(table_name, field_names) + while self.token.type == XML_ELEMENT_START: + row, children = self.parse_row(field_types) + table.add_row(row, children) + self.element_end('DATA') + return table + + def parse_row(self, field_types): + row = [None]*len(field_types) + children = [] + self.element_start('ROW') + while self.token.type == XML_ELEMENT_START: + if self.token.name_or_data == 'FIELD': + field_id, field_value = self.parse_field(field_types) + row[field_id] = field_value + elif self.token.name_or_data == 'CHILDREN': + children = self.parse_children() + else: + raise XmlTokenMismatch("<FIELD ...> or <CHILDREN ...>", self.token) + self.element_end('ROW') + return row, children + + def parse_field(self, field_types): + attrs = self.element_start('FIELD') + id = int(attrs['ID']) + type = field_types[id] + value = self.character_data() + if type == 'Integer': + value = int(value) + elif type == 'Float': + value = float(value) + elif type == 'Address': + value = int(value) + elif type == 'String': + pass + else: + assert False + self.element_end('FIELD') + return id, value + + def parse_children(self): + children = [] + self.element_start('CHILDREN') + while self.token.type == XML_ELEMENT_START: + table = self.parse_data() + assert table.name not in children + children.append(table) + self.element_end('CHILDREN') + return children + + def build_profile(self, results): + assert results.name == 'Routines' + profile = Profile() + profile[TIME] = 0.0 + for fields, tables in results: + function = self.build_function(fields) + children = tables['Children'] + for fields, _ in children: + call = self.build_call(fields) + function.add_call(call) + profile.add_function(function) + profile[TIME] = profile[TIME] + function[TIME] + profile[TOTAL_TIME] = profile[TIME] + profile.ratio(TOTAL_TIME_RATIO, TOTAL_TIME) + return profile + + def build_function(self, fields): + function = Function(self.build_id(fields), self.build_name(fields)) + function[TIME] = fields['Time'] + function[TOTAL_TIME] = fields['Time with Children'] + #function[TIME_RATIO] = fields['% Time']/100.0 + #function[TOTAL_TIME_RATIO] = fields['% with Children']/100.0 + return function + + def build_call(self, fields): + call = Call(self.build_id(fields)) + call[TIME] = fields['Time'] + call[TOTAL_TIME] = fields['Time with Children'] + #call[TIME_RATIO] = fields['% Time']/100.0 + #call[TOTAL_TIME_RATIO] = fields['% with Children']/100.0 + return call + + def build_id(self, fields): + return ':'.join([fields['Module Name'], fields['Unit Name'], fields['Routine Name']]) + + def build_name(self, fields): + # TODO: use more fields + return fields['Routine Name'] + + +class PstatsParser: + """Parser python profiling statistics saved with te pstats module.""" + + def __init__(self, *filename): + import pstats + try: + self.stats = pstats.Stats(*filename) + except ValueError: + import hotshot.stats + self.stats = hotshot.stats.load(filename[0]) + self.profile = Profile() + self.function_ids = {} + + def get_function_name(self, (filename, line, name)): + module = os.path.splitext(filename)[0] + module = os.path.basename(module) + return "%s:%d:%s" % (module, line, name) + + def get_function(self, key): + try: + id = self.function_ids[key] + except KeyError: + id = len(self.function_ids) + name = self.get_function_name(key) + function = Function(id, name) + self.profile.functions[id] = function + self.function_ids[key] = id + else: + function = self.profile.functions[id] + return function + + def parse(self): + self.profile[TIME] = 0.0 + self.profile[TOTAL_TIME] = self.stats.total_tt + for fn, (cc, nc, tt, ct, callers) in self.stats.stats.iteritems(): + callee = self.get_function(fn) + callee[CALLS] = nc + callee[TOTAL_TIME] = ct + callee[TIME] = tt + self.profile[TIME] += tt + self.profile[TOTAL_TIME] = max(self.profile[TOTAL_TIME], ct) + for fn, value in callers.iteritems(): + caller = self.get_function(fn) + call = Call(callee.id) + if isinstance(value, tuple): + for i in xrange(0, len(value), 4): + nc, cc, tt, ct = value[i:i+4] + if CALLS in call: + call[CALLS] += cc + else: + call[CALLS] = cc + + if TOTAL_TIME in call: + call[TOTAL_TIME] += ct + else: + call[TOTAL_TIME] = ct + + else: + call[CALLS] = value + call[TOTAL_TIME] = ratio(value, nc)*ct + + caller.add_call(call) + #self.stats.print_stats() + #self.stats.print_callees() + + # Compute derived events + self.profile.validate() + self.profile.ratio(TIME_RATIO, TIME) + self.profile.ratio(TOTAL_TIME_RATIO, TOTAL_TIME) + + return self.profile + + +class Theme: + + def __init__(self, + bgcolor = (0.0, 0.0, 1.0), + mincolor = (0.0, 0.0, 0.0), + maxcolor = (0.0, 0.0, 1.0), + fontname = "Arial", + minfontsize = 10.0, + maxfontsize = 10.0, + minpenwidth = 0.5, + maxpenwidth = 4.0, + gamma = 2.2, + skew = 1.0): + self.bgcolor = bgcolor + self.mincolor = mincolor + self.maxcolor = maxcolor + self.fontname = fontname + self.minfontsize = minfontsize + self.maxfontsize = maxfontsize + self.minpenwidth = minpenwidth + self.maxpenwidth = maxpenwidth + self.gamma = gamma + self.skew = skew + + def graph_bgcolor(self): + return self.hsl_to_rgb(*self.bgcolor) + + def graph_fontname(self): + return self.fontname + + def graph_fontsize(self): + return self.minfontsize + + def node_bgcolor(self, weight): + return self.color(weight) + + def node_fgcolor(self, weight): + return self.graph_bgcolor() + + def node_fontsize(self, weight): + return self.fontsize(weight) + + def edge_color(self, weight): + return self.color(weight) + + def edge_fontsize(self, weight): + return self.fontsize(weight) + + def edge_penwidth(self, weight): + return max(weight*self.maxpenwidth, self.minpenwidth) + + def edge_arrowsize(self, weight): + return 0.5 * math.sqrt(self.edge_penwidth(weight)) + + def fontsize(self, weight): + return max(weight**2 * self.maxfontsize, self.minfontsize) + + def color(self, weight): + weight = min(max(weight, 0.0), 1.0) + + hmin, smin, lmin = self.mincolor + hmax, smax, lmax = self.maxcolor + + if self.skew < 0: + raise ValueError("Skew must be greater than 0") + elif self.skew == 1.0: + h = hmin + weight*(hmax - hmin) + s = smin + weight*(smax - smin) + l = lmin + weight*(lmax - lmin) + else: + base = self.skew + h = hmin + ((hmax-hmin)*(-1.0 + (base ** weight)) / (base - 1.0)) + s = smin + ((smax-smin)*(-1.0 + (base ** weight)) / (base - 1.0)) + l = lmin + ((lmax-lmin)*(-1.0 + (base ** weight)) / (base - 1.0)) + + return self.hsl_to_rgb(h, s, l) + + def hsl_to_rgb(self, h, s, l): + """Convert a color from HSL color-model to RGB. + + See also: + - http://www.w3.org/TR/css3-color/#hsl-color + """ + + h = h % 1.0 + s = min(max(s, 0.0), 1.0) + l = min(max(l, 0.0), 1.0) + + if l <= 0.5: + m2 = l*(s + 1.0) + else: + m2 = l + s - l*s + m1 = l*2.0 - m2 + r = self._hue_to_rgb(m1, m2, h + 1.0/3.0) + g = self._hue_to_rgb(m1, m2, h) + b = self._hue_to_rgb(m1, m2, h - 1.0/3.0) + + # Apply gamma correction + r **= self.gamma + g **= self.gamma + b **= self.gamma + + return (r, g, b) + + def _hue_to_rgb(self, m1, m2, h): + if h < 0.0: + h += 1.0 + elif h > 1.0: + h -= 1.0 + if h*6 < 1.0: + return m1 + (m2 - m1)*h*6.0 + elif h*2 < 1.0: + return m2 + elif h*3 < 2.0: + return m1 + (m2 - m1)*(2.0/3.0 - h)*6.0 + else: + return m1 + + +TEMPERATURE_COLORMAP = Theme( + mincolor = (2.0/3.0, 0.80, 0.25), # dark blue + maxcolor = (0.0, 1.0, 0.5), # satured red + gamma = 1.0 +) + +PINK_COLORMAP = Theme( + mincolor = (0.0, 1.0, 0.90), # pink + maxcolor = (0.0, 1.0, 0.5), # satured red +) + +GRAY_COLORMAP = Theme( + mincolor = (0.0, 0.0, 0.85), # light gray + maxcolor = (0.0, 0.0, 0.0), # black +) + +BW_COLORMAP = Theme( + minfontsize = 8.0, + maxfontsize = 24.0, + mincolor = (0.0, 0.0, 0.0), # black + maxcolor = (0.0, 0.0, 0.0), # black + minpenwidth = 0.1, + maxpenwidth = 8.0, +) + + +class DotWriter: + """Writer for the DOT language. + + See also: + - "The DOT Language" specification + http://www.graphviz.org/doc/info/lang.html + """ + + def __init__(self, fp): + self.fp = fp + + def graph(self, profile, theme): + self.begin_graph() + + fontname = theme.graph_fontname() + + self.attr('graph', fontname=fontname, ranksep=0.25, nodesep=0.125) + self.attr('node', fontname=fontname, shape="box", style="filled", fontcolor="white", width=0, height=0) + self.attr('edge', fontname=fontname) + + for function in profile.functions.itervalues(): + labels = [] + for event in PROCESS, MODULE: + if event in function.events: + label = event.format(function[event]) + labels.append(label) + labels.append(function.name) + for event in TOTAL_TIME_RATIO, TIME_RATIO, CALLS: + if event in function.events: + label = event.format(function[event]) + labels.append(label) + + try: + weight = function[PRUNE_RATIO] + except UndefinedEvent: + weight = 0.0 + + label = '\n'.join(labels) + self.node(function.id, + label = label, + color = self.color(theme.node_bgcolor(weight)), + fontcolor = self.color(theme.node_fgcolor(weight)), + fontsize = "%.2f" % theme.node_fontsize(weight), + ) + + for call in function.calls.itervalues(): + callee = profile.functions[call.callee_id] + + labels = [] + for event in TOTAL_TIME_RATIO, CALLS: + if event in call.events: + label = event.format(call[event]) + labels.append(label) + + try: + weight = call[PRUNE_RATIO] + except UndefinedEvent: + try: + weight = callee[PRUNE_RATIO] + except UndefinedEvent: + weight = 0.0 + + label = '\n'.join(labels) + + self.edge(function.id, call.callee_id, + label = label, + color = self.color(theme.edge_color(weight)), + fontcolor = self.color(theme.edge_color(weight)), + fontsize = "%.2f" % theme.edge_fontsize(weight), + penwidth = "%.2f" % theme.edge_penwidth(weight), + labeldistance = "%.2f" % theme.edge_penwidth(weight), + arrowsize = "%.2f" % theme.edge_arrowsize(weight), + ) + + self.end_graph() + + def begin_graph(self): + self.write('digraph {\n') + + def end_graph(self): + self.write('}\n') + + def attr(self, what, **attrs): + self.write("\t") + self.write(what) + self.attr_list(attrs) + self.write(";\n") + + def node(self, node, **attrs): + self.write("\t") + self.id(node) + self.attr_list(attrs) + self.write(";\n") + + def edge(self, src, dst, **attrs): + self.write("\t") + self.id(src) + self.write(" -> ") + self.id(dst) + self.attr_list(attrs) + self.write(";\n") + + def attr_list(self, attrs): + if not attrs: + return + self.write(' [') + first = True + for name, value in attrs.iteritems(): + if first: + first = False + else: + self.write(", ") + self.id(name) + self.write('=') + self.id(value) + self.write(']') + + def id(self, id): + if isinstance(id, (int, float)): + s = str(id) + elif isinstance(id, basestring): + if id.isalnum(): + s = id + else: + s = self.escape(id) + else: + raise TypeError + self.write(s) + + def color(self, (r, g, b)): + + def float2int(f): + if f <= 0.0: + return 0 + if f >= 1.0: + return 255 + return int(255.0*f + 0.5) + + return "#" + "".join(["%02x" % float2int(c) for c in (r, g, b)]) + + def escape(self, s): + s = s.encode('utf-8') + s = s.replace('\\', r'\\') + s = s.replace('\n', r'\n') + s = s.replace('\t', r'\t') + s = s.replace('"', r'\"') + return '"' + s + '"' + + def write(self, s): + self.fp.write(s) + + +class Main: + """Main program.""" + + themes = { + "color": TEMPERATURE_COLORMAP, + "pink": PINK_COLORMAP, + "gray": GRAY_COLORMAP, + "bw": BW_COLORMAP, + } + + def main(self): + """Main program.""" + + parser = optparse.OptionParser( + usage="\n\t%prog [options] [file] ...", + version="%%prog %s" % __version__) + parser.add_option( + '-o', '--output', metavar='FILE', + type="string", dest="output", + help="output filename [stdout]") + parser.add_option( + '-n', '--node-thres', metavar='PERCENTAGE', + type="float", dest="node_thres", default=0.5, + help="eliminate nodes below this threshold [default: %default]") + parser.add_option( + '-e', '--edge-thres', metavar='PERCENTAGE', + type="float", dest="edge_thres", default=0.1, + help="eliminate edges below this threshold [default: %default]") + parser.add_option( + '-f', '--format', + type="choice", choices=('prof', 'oprofile', 'sysprof', 'pstats', 'shark', 'sleepy', 'aqtime'), + dest="format", default="prof", + help="profile format: prof, oprofile, sysprof, shark, sleepy, aqtime, or pstats [default: %default]") + parser.add_option( + '-c', '--colormap', + type="choice", choices=('color', 'pink', 'gray', 'bw'), + dest="theme", default="color", + help="color map: color, pink, gray, or bw [default: %default]") + parser.add_option( + '-s', '--strip', + action="store_true", + dest="strip", default=False, + help="strip function parameters, template parameters, and const modifiers from demangled C++ function names") + parser.add_option( + '-w', '--wrap', + action="store_true", + dest="wrap", default=False, + help="wrap function names") + # add a new option to control skew of the colorization curve + parser.add_option( + '--skew', + type="float", dest="theme_skew", default=1.0, + help="skew the colorization curve. Values < 1.0 give more variety to lower percentages. Value > 1.0 give less variety to lower percentages") + (self.options, self.args) = parser.parse_args(sys.argv[1:]) + + if len(self.args) > 1 and self.options.format != 'pstats': + parser.error('incorrect number of arguments') + + try: + self.theme = self.themes[self.options.theme] + except KeyError: + parser.error('invalid colormap \'%s\'' % self.options.theme) + + # set skew on the theme now that it has been picked. + if self.options.theme_skew: + self.theme.skew = self.options.theme_skew + + if self.options.format == 'prof': + if not self.args: + fp = sys.stdin + else: + fp = open(self.args[0], 'rt') + parser = GprofParser(fp) + elif self.options.format == 'oprofile': + if not self.args: + fp = sys.stdin + else: + fp = open(self.args[0], 'rt') + parser = OprofileParser(fp) + elif self.options.format == 'sysprof': + if not self.args: + fp = sys.stdin + else: + fp = open(self.args[0], 'rt') + parser = SysprofParser(fp) + elif self.options.format == 'pstats': + if not self.args: + parser.error('at least a file must be specified for pstats input') + parser = PstatsParser(*self.args) + elif self.options.format == 'shark': + if not self.args: + fp = sys.stdin + else: + fp = open(self.args[0], 'rt') + parser = SharkParser(fp) + elif self.options.format == 'sleepy': + if len(self.args) != 1: + parser.error('exactly one file must be specified for sleepy input') + parser = SleepyParser(self.args[0]) + elif self.options.format == 'aqtime': + if not self.args: + fp = sys.stdin + else: + fp = open(self.args[0], 'rt') + parser = AQtimeParser(fp) + else: + parser.error('invalid format \'%s\'' % self.options.format) + + self.profile = parser.parse() + + if self.options.output is None: + self.output = sys.stdout + else: + self.output = open(self.options.output, 'wt') + + self.write_graph() + + _parenthesis_re = re.compile(r'\([^()]*\)') + _angles_re = re.compile(r'<[^<>]*>') + _const_re = re.compile(r'\s+const$') + + def strip_function_name(self, name): + """Remove extraneous information from C++ demangled function names.""" + + # Strip function parameters from name by recursively removing paired parenthesis + while True: + name, n = self._parenthesis_re.subn('', name) + if not n: + break + + # Strip const qualifier + name = self._const_re.sub('', name) + + # Strip template parameters from name by recursively removing paired angles + while True: + name, n = self._angles_re.subn('', name) + if not n: + break + + return name + + def wrap_function_name(self, name): + """Split the function name on multiple lines.""" + + if len(name) > 32: + ratio = 2.0/3.0 + height = max(int(len(name)/(1.0 - ratio) + 0.5), 1) + width = max(len(name)/height, 32) + # TODO: break lines in symbols + name = textwrap.fill(name, width, break_long_words=False) + + # Take away spaces + name = name.replace(", ", ",") + name = name.replace("> >", ">>") + name = name.replace("> >", ">>") # catch consecutive + + return name + + def compress_function_name(self, name): + """Compress function name according to the user preferences.""" + + if self.options.strip: + name = self.strip_function_name(name) + + if self.options.wrap: + name = self.wrap_function_name(name) + + # TODO: merge functions with same resulting name + + return name + + def write_graph(self): + dot = DotWriter(self.output) + profile = self.profile + profile.prune(self.options.node_thres/100.0, self.options.edge_thres/100.0) + + for function in profile.functions.itervalues(): + function.name = self.compress_function_name(function.name) + + dot.graph(profile, self.theme) + + +if __name__ == '__main__': + Main().main() diff --git a/r2/r2/lib/contrib/markdown.py b/r2/r2/lib/contrib/markdown.py index 789515a36..854ff0128 100644 --- a/r2/r2/lib/contrib/markdown.py +++ b/r2/r2/lib/contrib/markdown.py @@ -129,7 +129,7 @@ class _Markdown: [ ]{0,%d} <(hr) # start tag = $2 \b # word break - ([^<>])*? # + ([^<>])*? # /?> # the matching end tag [ \t]* (?=\n{2,}|\Z)# followed by a blank line or end of document @@ -264,6 +264,7 @@ class _Markdown: url = self.urls[link_id] url = url.replace("*", self.escapetable["*"]) url = url.replace("_", self.escapetable["_"]) + url = url.replace("[", self.escapetable["["]) res = '<a href="%s"' % htmlquote(url) if title: @@ -273,6 +274,7 @@ class _Markdown: res += ">%s</a>" % htmlquote(link_text) else: res = whole_match + return res def handler2(m): @@ -283,6 +285,7 @@ class _Markdown: url = url.replace("*", self.escapetable["*"]) url = url.replace("_", self.escapetable["_"]) + url = url.replace("[", self.escapetable["["]) res = '''<a href="%s"''' % htmlquote(url) if title: diff --git a/r2/r2/lib/contrib/memcache.py b/r2/r2/lib/contrib/memcache.py index 2c30141fd..abff3bcb1 100755 --- a/r2/r2/lib/contrib/memcache.py +++ b/r2/r2/lib/contrib/memcache.py @@ -256,6 +256,8 @@ class Client(local): # return server, key # serverhash = serverHashFunction(str(serverhash) + str(i)) + print ("Couldn't connect to any of the %d memcache servers" % + len(self.buckets)) return None, key def disconnect_all(self): @@ -355,7 +357,7 @@ class Client(local): return 0 return 1 - def incr(self, key, delta=1): + def incr(self, key, delta=1, time=0): """ Sends a command to the server to atomically increment the value for C{key} by C{delta}, or by 1 if C{delta} is unspecified. Returns None if C{key} doesn't @@ -379,8 +381,10 @@ class Client(local): @rtype: int """ return self._incrdecr("incr", key, delta) + # Note: cachechain throws away this return value, so it's almost + # pointless to return anything - def decr(self, key, delta=1): + def decr(self, key, delta=1, time=0): """ Like L{incr}, but decrements. Unlike L{incr}, underflow is checked and new values are capped at 0. If server value is 1, a decrement of 2 diff --git a/r2/r2/lib/contrib/nymph.py b/r2/r2/lib/contrib/nymph.py index 6a45de14b..b4341ad54 100644 --- a/r2/r2/lib/contrib/nymph.py +++ b/r2/r2/lib/contrib/nymph.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import re, sys, Image, os, hashlib, StringIO diff --git a/r2/r2/lib/count.py b/r2/r2/lib/count.py index 54dab5c3b..fd4412832 100644 --- a/r2/r2/lib/count.py +++ b/r2/r2/lib/count.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/cssfilter.py b/r2/r2/lib/cssfilter.py index 216311894..ac3102efd 100644 --- a/r2/r2/lib/cssfilter.py +++ b/r2/r2/lib/cssfilter.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement @@ -329,11 +329,14 @@ def find_preview_links(sr): from r2.lib.normalized_hot import get_hot # try to find a link to use, otherwise give up and return - links = get_hot(c.site) + links = get_hot(c.site, only_fullnames = True) if not links: sr = Subreddit._by_name(g.default_sr) if sr: - links = get_hot(sr) + links = get_hot(sr, only_fullnames = True) + + if links: + links = Link._by_fullname(links, data=True, return_dict=False) return links diff --git a/r2/r2/lib/db/__init__.py b/r2/r2/lib/db/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/lib/db/__init__.py +++ b/r2/r2/lib/db/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/db/alter_db.py b/r2/r2/lib/db/alter_db.py index 67b129055..58e9a3af1 100644 --- a/r2/r2/lib/db/alter_db.py +++ b/r2/r2/lib/db/alter_db.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import tdb_sql diff --git a/r2/r2/lib/db/operators.py b/r2/r2/lib/db/operators.py index f0ac795ba..3d62dd906 100644 --- a/r2/r2/lib/db/operators.py +++ b/r2/r2/lib/db/operators.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ class BooleanOp(object): diff --git a/r2/r2/lib/db/queries.py b/r2/r2/lib/db/queries.py index f28f5f742..c55dc6573 100644 --- a/r2/r2/lib/db/queries.py +++ b/r2/r2/lib/db/queries.py @@ -124,15 +124,13 @@ class CachedResults(object): def delete(self, items): """Deletes an item from the cached data.""" self.fetch() - did_change = False + fnames = set(self.filter(x)._fullname for x in tup(items)) - for item in tup(items): - t = self.make_item_tuple(item) - while t in self.data: - self.data.remove(t) - did_change = True - - if did_change: + data = filter(lambda x: x[0] not in fnames, + self.data) + + if data != self.data: + self.data = data query_cache.set(self.iden, self.data) def update(self): @@ -270,8 +268,8 @@ def get_submitted(user, sort, time): def get_overview(user, sort, time): return merge_results(get_comments(user, sort, time), get_submitted(user, sort, time)) - -def user_rel_query(rel, user, name): + +def user_rel_query(rel, user, name, filters = []): """General user relationship query.""" q = rel._query(rel.c._thing1_id == user._id, rel.c._t2_deleted == False, @@ -280,6 +278,8 @@ def user_rel_query(rel, user, name): eager_load = True, thing_data = not g.use_query_cache ) + if filters: + q._filter(*filters) return make_results(q, filter_thing2) @@ -301,13 +301,25 @@ inbox_message_rel = Inbox.rel(Account, Message) def get_inbox_messages(user): return user_rel_query(inbox_message_rel, user, 'inbox') +def get_unread_messages(user): + return user_rel_query(inbox_message_rel, user, 'inbox', + filters = [inbox_message_rel.c.new == True]) + inbox_comment_rel = Inbox.rel(Account, Comment) def get_inbox_comments(user): return user_rel_query(inbox_comment_rel, user, 'inbox') +def get_unread_comments(user): + return user_rel_query(inbox_comment_rel, user, 'inbox', + filters = [inbox_comment_rel.c.new == True]) + def get_inbox_selfreply(user): return user_rel_query(inbox_comment_rel, user, 'selfreply') +def get_unread_selfreply(user): + return user_rel_query(inbox_comment_rel, user, 'selfreply', + filters = [inbox_comment_rel.c.new == True]) + def get_inbox(user): return merge_results(get_inbox_comments(user), get_inbox_messages(user), @@ -319,6 +331,11 @@ def get_sent(user): sort = desc('_date')) return make_results(q) +def get_unread_inbox(user): + return merge_results(get_unread_comments(user), + get_unread_messages(user), + get_unread_selfreply(user)) + def add_queries(queries, insert_items = None, delete_items = None): """Adds multiple queries to the query queue. If insert_items or delete_items is specified, the query may not need to be recomputed at @@ -420,6 +437,8 @@ def new_comment(comment, inbox_rel): else: add_queries([get_inbox_selfreply(inbox_owner)], insert_items = inbox_rel) + set_unread(comment, True) + def new_subreddit(sr): @@ -451,14 +470,29 @@ def new_vote(vote): else: add_queries([get_liked(user)], delete_items = vote) add_queries([get_disliked(user)], delete_items = vote) - + def new_message(message, inbox_rel): + from r2.lib.comment_tree import add_message + from_user = Account._byID(message.author_id) to_user = Account._byID(message.to_id) add_queries([get_sent(from_user)], insert_items = message) add_queries([get_inbox_messages(to_user)], insert_items = inbox_rel) + add_message(message) + set_unread(message, True) + +def set_unread(message, unread): + for i in Inbox.set_unread(message, unread): + kw = dict(insert_items = i) if unread else dict(delete_items = i) + if i._name == 'selfreply': + add_queries([get_unread_selfreply(i._thing1)], **kw) + elif isinstance(message, Comment): + add_queries([get_unread_comments(i._thing1)], **kw) + else: + add_queries([get_unread_messages(i._thing1)], **kw) + def new_savehide(rel): user = rel._thing1 name = rel._name @@ -653,14 +687,19 @@ def run_new_comments(): # amqp.handle_items('newpage_q', _run_new_links, limit=100) -def queue_vote(user, thing, dir, ip, organic = False): - if g.amqp_host: - key = "registered_vote_%s_%s" % (user._id, thing._fullname) - g.cache.set(key, '1' if dir is True else '0' if dir is None else '-1') - amqp.add_item('register_vote_q', - pickle.dumps((user._id, thing._fullname, dir, ip, organic))) - else: - handle_vote(user, thing, dir, ip, organic) +def queue_vote(user, thing, dir, ip, organic = False, + cheater = False, store = True): + # set the vote in memcached so the UI gets updated immediately + key = "registered_vote_%s_%s" % (user._id, thing._fullname) + g.cache.set(key, '1' if dir is True else '0' if dir is None else '-1') + # queue the vote to be stored unless told not to + if store: + if g.amqp_host: + amqp.add_item('register_vote_q', + pickle.dumps((user._id, thing._fullname, + dir, ip, organic, cheater))) + else: + handle_vote(user, thing, dir, ip, organic) def get_likes(user, items): if not user or not items: @@ -688,15 +727,23 @@ def get_likes(user, items): return res -def handle_vote(user, thing, dir, ip, organic): +def handle_vote(user, thing, dir, ip, organic, cheater = False): from r2.lib.db import tdb_sql from sqlalchemy.exc import IntegrityError try: - v = Vote.vote(user, thing, dir, ip, organic) + v = Vote.vote(user, thing, dir, ip, organic, cheater = cheater) except (tdb_sql.CreationError, IntegrityError): g.log.error("duplicate vote for: %s" % str((user, thing, dir))) return + # keep track of upvotes in the hard cache by subreddit + sr_id = getattr(thing, "sr_id", None) + if (sr_id and dir > 0 and getattr(thing, "author_id", None) != user._id + and v.valid_thing): + now = datetime.now(g.tz).strftime("%Y/%m/%d") + g.hardcache.add("subreddit_vote-%s_%s_%s" % (now, sr_id, user._id), + sr_id, time = 86400 * 7) # 1 week for now + if isinstance(thing, Link): new_vote(v) if v.valid_thing: @@ -732,17 +779,21 @@ def process_votes(drain = False, limit = 100): uids = set() tids = set() for x in msgs: - uid, tid, dir, ip, organic = pickle.loads(x.body) - print (uid, tid, dir, ip, organic) + r = pickle.loads(x.body) + uid, tid, dir, ip, organic, cheater = r + + print (uid, tid, dir, ip, organic, cheater) + uids.add(uid) tids.add(tid) - to_do.append((uid, tid, dir, ip, organic)) + to_do.append((uid, tid, dir, ip, organic, cheater)) users = Account._byID(uids, data = True, return_dict = True) things = Thing._by_fullname(tids, data = True, return_dict = True) - for uid, tid, dir, ip, organic in to_do: - handle_vote(users[uid], things[tid], dir, ip, organic) + for uid, tid, dir, ip, organic, cheater in to_do: + handle_vote(users[uid], things[tid], dir, ip, organic, + cheater = cheater) amqp.handle_items('register_vote_q', _handle_votes, limit = limit, drain = drain) diff --git a/r2/r2/lib/db/query_queue.py b/r2/r2/lib/db/query_queue.py index 41af293ad..21406fc0a 100644 --- a/r2/r2/lib/db/query_queue.py +++ b/r2/r2/lib/db/query_queue.py @@ -12,6 +12,9 @@ TIMEOUT = 600 def add_query(cached_results): amqp.add_item('prec_links', pickle.dumps(cached_results, -1)) +def _skip_key(iden): + return 'skip_precompute_queries-%s' % iden + def run(): def callback(msgs, chan): for msg in msgs: # will be len==1 @@ -19,6 +22,11 @@ def run(): cr = pickle.loads(msg.body) iden = cr.query._iden() + if (iden in g.skip_precompute_queries + and g.hardcache.get(_skip_key(iden))): + print 'skipping known query', iden + continue + working_key = working_prefix + iden key = prefix + iden @@ -34,13 +42,17 @@ def run(): print 'skipping, someone else is working', working_key return - cr = pickle.loads(msg.body) - print 'working: ', iden, cr.query._rules, cr.query._sort start = datetime.now() try: cr.update() g.memcache.set(key, datetime.now()) + + if iden in g.skip_precompute_queries: + print 'setting to be skipped for 6 hours', iden + g.hardcache.set(_skip_key(iden), start, + 60*60*6) + finally: g.memcache.delete(working_key) diff --git a/r2/r2/lib/db/sorts.py b/r2/r2/lib/db/sorts.py index 655984bc0..498e63d9d 100644 --- a/r2/r2/lib/db/sorts.py +++ b/r2/r2/lib/db/sorts.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from math import log, sqrt diff --git a/r2/r2/lib/db/stats.py b/r2/r2/lib/db/stats.py index 73ef575ba..47fdb76de 100644 --- a/r2/r2/lib/db/stats.py +++ b/r2/r2/lib/db/stats.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ cache_key = 'popular_queries' diff --git a/r2/r2/lib/db/tdb_lite.py b/r2/r2/lib/db/tdb_lite.py index 3970d1158..a39f8f680 100644 --- a/r2/r2/lib/db/tdb_lite.py +++ b/r2/r2/lib/db/tdb_lite.py @@ -6,21 +6,22 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import sqlalchemy as sa +import cPickle as pickle class tdb_lite(object): def __init__(self, gc): diff --git a/r2/r2/lib/db/tdb_sql.py b/r2/r2/lib/db/tdb_sql.py index 85463b132..246b1ef13 100644 --- a/r2/r2/lib/db/tdb_sql.py +++ b/r2/r2/lib/db/tdb_sql.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from datetime import datetime @@ -307,12 +307,12 @@ def get_read_table(tables): load, avg_load, conns, avg_conns, max_conns = ip_loads[ip] #prune high-connection machines - if conns < .9 * max_conns: - max_load = max(load, avg_load) - total_load += max_load - have_loads.append((ip, max_load)) - else: - no_connections.append(ip) + #if conns < .9 * max_conns: + max_load = max(load, avg_load) + total_load += max_load + have_loads.append((ip, max_load)) + #else: + # no_connections.append(ip) if total_load: avg_load = total_load / max(len(have_loads), 1) @@ -390,6 +390,11 @@ def make_thing(type_id, ups, downs, date, deleted, spam, id=None): transactions.add_engine(t.bind) r = t.insert().execute(**params) new_id = r.last_inserted_ids()[0] + new_r = r.last_inserted_params() + for k, v in params.iteritems(): + if new_r[k] != v: + raise CreationError, ("There's shit in the plumbing. " + + "expected %s, got %s" % (params, new_r)) return new_id try: @@ -401,7 +406,7 @@ def make_thing(type_id, ups, downs, date, deleted, spam, id=None): raise # wrap the error to prevent db layer bleeding out raise CreationError, "Thing exists (%s)" % str(params) - + def set_thing_props(type_id, thing_id, **props): table = get_thing_table(type_id, action = 'write')[0] @@ -554,7 +559,12 @@ def get_data(table, thing_id): for row in r: val = db2py(row.value, row.kind) stor = res if single else res.setdefault(row.thing_id, storage()) + if single and row.thing_id != thing_id: + raise ValueError, ("tdb_sql.py: there's shit in the plumbing." + + " got %s, wanted %s" % (row.thing_id, + thing_id)) stor[row.key] = val + return res def set_thing_data(type_id, thing_id, **vals): @@ -583,6 +593,11 @@ def get_thing(type_id, thing_id): spam = row.spam) if single: res = stor + # check that we got what we asked for + if row.thing_id != thing_id: + raise ValueError, ("tdb_sql.py: there's shit in the plumbing." + + " got %s, wanted %s" % (row.thing_id, + thing_id)) else: res[row.thing_id] = stor return res diff --git a/r2/r2/lib/db/thing.py b/r2/r2/lib/db/thing.py index 184e4c289..adef809fc 100644 --- a/r2/r2/lib/db/thing.py +++ b/r2/r2/lib/db/thing.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ #TODO byID use Things? @@ -131,7 +131,13 @@ class DataThing(object): def _other_self(self): """Load from the cached version of myself. Skip the local cache.""" - return cache.get(self._cache_key(), local = False) + l = cache.get(self._cache_key(), local = False) + if l and l._id != self._id: + g.log.error("thing.py: Doppleganger on read: got %s for %s", + (l, self)) + cache.delete(self._cache_key()) + return + return l def _cache_myself(self): cache.set(self._cache_key(), self) @@ -270,8 +276,7 @@ class DataThing(object): prefix = thing_prefix(cls.__name__) if not all(x <= tdb.MAX_THING_ID for x in ids): - g.log.debug("Attempted to look up too-big thing_id?") - raise NotFound('thing_id greater than MAX_THING_ID') + raise NotFound('huge thing_id in %r' % ids) def items_db(ids): items = cls._get_item(cls._type_id, ids) @@ -283,9 +288,16 @@ class DataThing(object): bases = sgm(cache, ids, items_db, prefix) #check to see if we found everything we asked for - if any(i not in bases for i in ids): - missing = [i for i in ids if i not in bases] - raise NotFound, '%s %s' % (cls.__name__, missing) + for i in ids: + if i not in bases: + missing = [i for i in ids if i not in bases] + raise NotFound, '%s %s' % (cls.__name__, missing) + if bases[i] and bases[i]._id != i: + g.log.error("thing.py: Doppleganger on byID: %s got %s for %s" % + (cls.__name__, bases[i]._id, i)) + bases[i] = items_db([i]).values()[0] + bases[i]._cache_myself() + if data: need = [v for v in bases.itervalues() if not v._loaded] @@ -549,6 +561,27 @@ def Relation(type1, type2, denorm1 = None, denorm2 = None): _incr_data = staticmethod(tdb.incr_rel_data) _type_prefix = Relation._type_prefix + @classmethod + def _byID_rel(cls, ids, data=False, return_dict=True, extra_props=None, + eager_load=False, thing_data=False): + + ids, single = tup(ids, True) + + bases = cls._byID(ids, data=data, return_dict=True, + extra_props=extra_props) + + values = bases.values() + + if values and eager_load: + load_things(values, thing_data) + + if single: + return bases[ids[0]] + elif return_dict: + return bases + else: + return filter(None, (bases.get(i) for i in ids)) + def __init__(self, thing1, thing2, name, date = None, id = None, **attrs): DataThing.__init__(self) diff --git a/r2/r2/lib/db/userrel.py b/r2/r2/lib/db/userrel.py index f70de305e..ab211b86c 100644 --- a/r2/r2/lib/db/userrel.py +++ b/r2/r2/lib/db/userrel.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.memoize import memoize, clear_memo diff --git a/r2/r2/lib/emailer.py b/r2/r2/lib/emailer.py index dcb1016bd..284173e4e 100644 --- a/r2/r2/lib/emailer.py +++ b/r2/r2/lib/emailer.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from email.MIMEText import MIMEText diff --git a/r2/r2/lib/filters.py b/r2/r2/lib/filters.py index f86ee642e..808b681eb 100644 --- a/r2/r2/lib/filters.py +++ b/r2/r2/lib/filters.py @@ -6,19 +6,21 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ +from BeautifulSoup import BeautifulSoup + from pylons import c import cgi @@ -29,6 +31,8 @@ from wrapped import Templated, CacheStub SC_OFF = "<!-- SC_OFF -->" SC_ON = "<!-- SC_ON -->" +MD_START = '<div class="md">' +MD_END = '</div>' def python_websafe(text): @@ -118,59 +122,79 @@ def edit_comment_filter(text = ''): text = unicode(text) return url_escape(text) -#TODO is this fast? -r_url = re.compile('(?<![\(\[])(http://[^\s\'\"\]\)]+)') -jscript_url = re.compile('<a href="(?!http|ftp|mailto|/).*</a>', re.I | re.S) -img = re.compile('<img.*?>', re.I | re.S) -href_re = re.compile('<a href="([^"]+)"', re.I) -code_re = re.compile('<code>([^<]+)</code>') -a_re = re.compile('>([^<]+)</a>') -fix_url = re.compile('<(http://[^\s\'\"\]\)]+)>') +def markdown_souptest(text, nofollow=False, target=None, lang=None): + ok_tags = { + 'div': ('class'), + 'a': ('href', 'title', 'target', 'nofollow'), + } + + boring_tags = ( 'p', 'em', 'strong', 'br', 'ol', 'ul', 'hr', 'li', + 'pre', 'code', 'blockquote', + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', ) + + for bt in boring_tags: + ok_tags[bt] = () + + smd = safemarkdown (text, nofollow, target, lang) + soup = BeautifulSoup(smd) + + for tag in soup.findAll(): + if not tag.name in ok_tags: + raise ValueError("<%s> tag found in markdown!" % tag.name) + ok_attrs = ok_tags[tag.name] + for k,v in tag.attrs: + if not k in ok_attrs: + raise ValueError("<%s %s='%s'> attr found in markdown!" + % (tag.name, k,v)) + if tag.name == 'a' and k == 'href': + lv = v.lower() + if lv.startswith("http:"): + pass + elif lv.startswith("https:"): + pass + elif lv.startswith("ftp:"): + pass + elif lv.startswith("mailto:"): + pass + elif lv.startswith("/"): + pass + else: + raise ValueError("Link to '%s' found in markdown!" % v) + #TODO markdown should be looked up in batch? #@memoize('markdown') -def safemarkdown(text, nofollow=False, target=None): +def safemarkdown(text, nofollow=False, target=None, lang=None): + from r2.lib.c_markdown import c_markdown + from r2.lib.py_markdown import py_markdown + from pylons import g + from contrib.markdown import markdown + if c.user.pref_no_profanity: text = profanity_filter(text) - if text: - # increase escaping of &, < and > once - text = text.replace("&", "&").replace("<", "<").replace(">", ">") - #wrap urls in "<>" so that markdown will handle them as urls - text = r_url.sub(r'<\1>', text) - try: - text = markdown(text) - except RuntimeError: - text = "<p><em>Comment Broken</em></p>" - #remove images - text = img.sub('', text) - #wipe malicious javascript - text = jscript_url.sub('', text) - def href_handler(m): - url = m.group(1).replace('&', '&') - link = '<a href="%s"' % url - if target: - link += ' target="%s"' % target - elif c.cname: - link += ' target="_top"' + if not text: + return None - if nofollow: - link += ' rel="nofollow"' - return link - def code_handler(m): - l = m.group(1) - return '<code>%s</code>' % l.replace('&','&') - #unescape double escaping in links - def inner_a_handler(m): - l = m.group(1) - return '>%s</a>' % l.replace('&','&') - # remove the "&" escaping in urls - text = href_re.sub(href_handler, text) - text = code_re.sub(code_handler, text) - text = a_re.sub(inner_a_handler, text) - text = fix_url.sub(r'\1', text) - return SC_OFF + '<div class="md">' + text + '</div>' + SC_ON + if c.cname and not target: + target = "_top" + + if lang is None: + # TODO: lang should respect g.markdown_backend + lang = "py" + + try: + if lang == "c": + text = c_markdown(text, nofollow, target) + elif lang == "py": + text = py_markdown(text, nofollow, target) + else: + raise ValueError("weird lang") + except RuntimeError: + text = "<p><em>Comment Broken</em></p>" + + return SC_OFF + MD_START + text + MD_END + SC_ON def keep_space(text): diff --git a/r2/r2/lib/find_tz.py b/r2/r2/lib/find_tz.py index 86a970009..fe010b4ec 100644 --- a/r2/r2/lib/find_tz.py +++ b/r2/r2/lib/find_tz.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models.link import Link diff --git a/r2/r2/lib/hardcachebackend.py b/r2/r2/lib/hardcachebackend.py index 1c074d607..7fe70a3ba 100644 --- a/r2/r2/lib/hardcachebackend.py +++ b/r2/r2/lib/hardcachebackend.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -26,6 +26,11 @@ from datetime import datetime import sqlalchemy as sa from r2.lib.db.tdb_lite import tdb_lite +def expiration_from_time(time): + if time <= 0: + raise ValueError ("HardCache items *must* have an expiration time") + return datetime.now(g.tz) + timedelta(0, time) + class HardCacheBackend(object): def __init__(self, gc): self.tdb = tdb_lite(gc) @@ -50,10 +55,10 @@ class HardCacheBackend(object): self.delete(category, ids) # delete it if it already exists - expiration = datetime.now(g.tz) + timedelta(0, time) - value, kind = self.tdb.py2db(val, True) + expiration = expiration_from_time(time) + self.table.insert().execute( category=category, ids=ids, @@ -62,6 +67,53 @@ class HardCacheBackend(object): expiration=expiration ) + def add(self, category, ids, val, time=0): + expiration = expiration_from_time(time) + + value, kind = self.tdb.py2db(val, True) + + try: + rp = self.table.insert().execute( + category=category, + ids=ids, + value=value, + kind=kind, + expiration=expiration + ) + + return value + + except sa.exceptions.IntegrityError, e: + return self.get(category, ids) + + def incr(self, category, ids, time=0, delta=1): + expiration = expiration_from_time(time) + + rp = self.table.update(sa.and_(self.table.c.category==category, + self.table.c.ids==ids, + self.table.c.kind=='num'), + values = { + self.table.c.value: + sa.cast( + sa.cast(self.table.c.value, + sa.Integer) + delta, + sa.String), + self.table.c.expiration: expiration + } + ).execute() + if rp.rowcount == 1: + return self.get(category, ids) + elif rp.rowcount == 0: + existing_value = self.get(category, ids) + if existing_value is None: + raise ValueError("[%s][%s] can't be incr()ed -- it's not set" % + (category, ids)) + else: + raise ValueError("[%s][%s] has non-integer value %r" % + (category, ids, existing_value)) + else: + raise ValueError("Somehow %d rows got updated" % rp.rowcount) + def get(self, category, ids): s = sa.select([self.table.c.value, self.table.c.kind, @@ -77,6 +129,25 @@ class HardCacheBackend(object): else: return self.tdb.db2py(rows[0].value, rows[0].kind) + def get_multi(self, category, idses): + s = sa.select([self.table.c.ids, + self.table.c.value, + self.table.c.kind, + self.table.c.expiration], + sa.and_(self.table.c.category==category, + sa.or_(*[self.table.c.ids==ids + for ids in idses]))) + rows = s.execute().fetchall() + + results = {} + + for row in rows: + if row.expiration >= datetime.now(g.tz): + k = "%s-%s" % (category, row.ids) + results[k] = self.tdb.db2py(row.value, row.kind) + + return results + def delete(self, category, ids): self.table.delete( sa.and_(self.table.c.category==category, diff --git a/r2/r2/lib/helpers.py b/r2/r2/lib/helpers.py index 6eb17b195..6bd5d7bc4 100644 --- a/r2/r2/lib/helpers.py +++ b/r2/r2/lib/helpers.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ diff --git a/r2/r2/lib/html_source.py b/r2/r2/lib/html_source.py index cbbc506aa..396a6f7ba 100644 --- a/r2/r2/lib/html_source.py +++ b/r2/r2/lib/html_source.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from HTMLParser import HTMLParser diff --git a/r2/r2/lib/jsonresponse.py b/r2/r2/lib/jsonresponse.py index 5fcf12dff..95a500c15 100644 --- a/r2/r2/lib/jsonresponse.py +++ b/r2/r2/lib/jsonresponse.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.utils import tup diff --git a/r2/r2/lib/jsontemplates.py b/r2/r2/lib/jsontemplates.py index 86674c87b..161d475bd 100644 --- a/r2/r2/lib/jsontemplates.py +++ b/r2/r2/lib/jsontemplates.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from utils import to36, tup, iters @@ -178,11 +178,11 @@ class ThingJsonTemplate(JsonTemplate): return self.rendered_data(thing) else: return self.raw_data(thing) - + def render(self, thing = None, action = None, *a, **kw): return ObjectTemplate(dict(kind = self.kind(thing), data = self.data(thing))) - + class SubredditJsonTemplate(ThingJsonTemplate): _data_attrs_ = ThingJsonTemplate.data_attrs(subscribers = "score", title = "title", @@ -193,7 +193,15 @@ class SubredditJsonTemplate(ThingJsonTemplate): class AccountJsonTemplate(ThingJsonTemplate): _data_attrs_ = ThingJsonTemplate.data_attrs(name = "name", link_karma = "safe_karma", - comment_karma = "comment_karma") + comment_karma = "comment_karma", + has_mail = "has_mail") + + def thing_attr(self, thing, attr): + if attr == "has_mail": + if c.user_is_loggedin and thing._id == c.user._id: + return bool(c.have_messages) + return None + return ThingJsonTemplate.thing_attr(self, thing, attr) class LinkJsonTemplate(ThingJsonTemplate): _data_attrs_ = ThingJsonTemplate.data_attrs(ups = "upvotes", @@ -316,12 +324,15 @@ class MessageJsonTemplate(ThingJsonTemplate): _data_attrs_ = ThingJsonTemplate.data_attrs(new = "new", subject = "subject", body = "body", + replies = "child", body_html = "body_html", author = "author", dest = "dest", was_comment = "was_comment", context = "context", - created = "created") + created = "created", + parent_id = "parent_id", + first_message= "first_message") def thing_attr(self, thing, attr): if attr == "was_comment": diff --git a/r2/r2/lib/lock.py b/r2/r2/lib/lock.py index b2a175591..fd3ee8f8b 100644 --- a/r2/r2/lib/lock.py +++ b/r2/r2/lib/lock.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/logger.py b/r2/r2/lib/logger.py index e6a3b5e73..66e2471b1 100644 --- a/r2/r2/lib/logger.py +++ b/r2/r2/lib/logger.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement diff --git a/r2/r2/lib/manager/__init__.py b/r2/r2/lib/manager/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/lib/manager/__init__.py +++ b/r2/r2/lib/manager/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/manager/db_manager.py b/r2/r2/lib/manager/db_manager.py index 933350bd0..da808112d 100644 --- a/r2/r2/lib/manager/db_manager.py +++ b/r2/r2/lib/manager/db_manager.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import sqlalchemy as sa diff --git a/r2/r2/lib/manager/tp_manager.py b/r2/r2/lib/manager/tp_manager.py index 7c943f29c..898016782 100644 --- a/r2/r2/lib/manager/tp_manager.py +++ b/r2/r2/lib/manager/tp_manager.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import pylons, sha diff --git a/r2/r2/lib/media.py b/r2/r2/lib/media.py index 9cb589366..68a2c0ec1 100644 --- a/r2/r2/lib/media.py +++ b/r2/r2/lib/media.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/memoize.py b/r2/r2/lib/memoize.py index 3aaa99efc..00d96927d 100644 --- a/r2/r2/lib/memoize.py +++ b/r2/r2/lib/memoize.py @@ -6,23 +6,22 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.config import cache from r2.lib.filters import _force_utf8 - -class NoneResult(object): pass +from r2.lib.cache import NoneResult def memoize(iden, time = 0): def memoize_fn(fn): diff --git a/r2/r2/lib/menus.py b/r2/r2/lib/menus.py index c01dfc15f..6c313c756 100644 --- a/r2/r2/lib/menus.py +++ b/r2/r2/lib/menus.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from wrapped import CachedTemplate, Styled diff --git a/r2/r2/lib/migrate.py b/r2/r2/lib/migrate.py index 53a59b6f2..f5d39e5a9 100644 --- a/r2/r2/lib/migrate.py +++ b/r2/r2/lib/migrate.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ @@ -135,3 +135,74 @@ def subscribe_to_blog_and_annoucements(filename): print ("%d: subscribed %s to %s" % (i, account.name, sr.name)) else: print ("%d: didn't subscribe %s to %s" % (i, account.name, sr.name)) + + +def upgrade_messages(update_comments = True, update_messages = True, + update_trees = True): + from r2.lib.db import queries + from r2.lib import comment_tree, cache + from r2.models import Account + from pylons import g + accounts = set() + + def batch_fn(items): + g.reset_caches() + return items + + if update_messages or update_trees: + q = Message._query(Message.c.new == True, + sort = desc("_date"), + data = True) + for m in fetch_things2(q, batch_fn = batch_fn): + print m,m._date + if update_messages: + accounts = accounts | queries.set_unread(m, m.new) + else: + accounts.add(m.to_id) + if update_comments: + q = Comment._query(Comment.c.new == True, + sort = desc("_date")) + q._filter(Comment.c._id < 26152162676) + + for m in fetch_things2(q, batch_fn = batch_fn): + print m,m._date + queries.set_unread(m, True) + + print "Precomputing comment trees for %d accounts" % len(accounts) + + for i, a in enumerate(accounts): + if not isinstance(a, Account): + a = Account._byID(a) + print i, a + comment_tree.user_messages(a) + +def recompute_unread(min_date = None): + from r2.models import Inbox, Account, Comment, Message + from r2.lib.db import queries + + def load_accounts(inbox_rel): + accounts = set() + q = inbox_rel._query(eager_load = False, data = False, + sort = desc("_date")) + if min_date: + q._filter(inbox_rel.c._date > min_date) + + for i in fetch_things2(q): + accounts.add(i._thing1_id) + + return accounts + + accounts_m = load_accounts(Inbox.rel(Account, Message)) + for i, a in enumerate(accounts_m): + a = Account._byID(a) + print "%s / %s : %s" % (i, len(accounts_m), a) + queries.get_unread_messages(a).update() + queries.get_unread_comments(a).update() + queries.get_unread_selfreply(a).update() + + accounts = load_accounts(Inbox.rel(Account, Comment)) - accounts_m + for i, a in enumerate(accounts): + a = Account._byID(a) + print "%s / %s : %s" % (i, len(accounts), a) + queries.get_unread_comments(a).update() + queries.get_unread_selfreply(a).update() diff --git a/r2/r2/lib/normalized_hot.py b/r2/r2/lib/normalized_hot.py index 699107bf8..7160bb897 100644 --- a/r2/r2/lib/normalized_hot.py +++ b/r2/r2/lib/normalized_hot.py @@ -6,25 +6,26 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import Link, Subreddit from r2.lib.db.operators import desc, timeago +from r2.lib.db.sorts import epoch_seconds + from r2.lib import utils from r2.config import cache from r2.lib.memoize import memoize -from r2.lib.db.thing import Query from pylons import g @@ -33,6 +34,7 @@ import random expire_delta = timedelta(minutes = 2) TOP_CACHE = 1800 +max_items = 150 def access_key(sr): return sr.name + '_access' @@ -48,7 +50,7 @@ def expire_hot(sr): def cached_query(query, sr): """Returns the results from running query. The results are cached and only recomputed after 'expire_delta'""" - query._limit = 150 + query._limit = max_items query._write_cache = True iden = query._iden() @@ -75,40 +77,55 @@ def cached_query(query, sr): return res -def get_hot(sr): - """Get the hottest links for a subreddit. If g.use_query_cache is - True, it'll use the query cache, otherwise it'll use cached_query() - from above.""" +def get_hot(sr, only_fullnames = False): + """Get the (fullname, hotness, epoch_seconds) for the hottest + links in a subreddit. Use the query-cache to avoid some lookups + if we can.""" + from r2.lib.db.thing import Query + from r2.lib.db.queries import CachedResults + q = sr.get_links('hot', 'all') if isinstance(q, Query): - return cached_query(q, sr) - else: - return Link._by_fullname(list(q)[:150], return_dict = False) + links = cached_query(q, sr) + res = [(link._fullname, link._hot, epoch_seconds(link._date)) + for link in links] + elif isinstance(q, CachedResults): + # we're relying on an implementation detail of CachedResults + # here, where it's storing tuples that look exactly like the + # return-type we want, to make our sorting a bit cheaper + q.fetch() + res = list(q.data) -def only_recent(items): - return filter(lambda l: l._date > utils.timeago('%d day' % g.HOT_PAGE_AGE), - items) + age_limit = epoch_seconds(utils.timeago('%d days' % g.HOT_PAGE_AGE)) + return [(fname if only_fullnames else (fname, hot, date)) + for (fname, hot, date) in res + if date > age_limit] @memoize('normalize_hot', time = g.page_cache_time) def normalized_hot_cached(sr_ids): - """Fetches the hot lists for each subreddit, normalizes the scores, - and interleaves the results.""" + """Fetches the hot lists for each subreddit, normalizes the + scores, and interleaves the results.""" results = [] srs = Subreddit._byID(sr_ids, data = True, return_dict = False) for sr in srs: - items = only_recent(get_hot(sr)) + # items =:= (fname, hot, epoch_seconds), ordered desc('_hot') + items = get_hot(sr)[:max_items] if not items: continue - top_score = max(max(x._hot for x in items), 1) - if items: - results.extend((l, l._hot / top_score) for l in items) + # the hotness of the hottest item in this subreddit + top_score = max(items[0][1], 1) - results.sort(key = lambda x: (x[1], x[0]._hot), reverse = True) - return [l[0]._fullname for l in results] + results.extend((fname, hot/top_score, hot, date) + for (fname, hot, date) in items) + + # sort by (normalized_hot, hot, date) + results.sort(key = lambda x: x[1:], reverse = True) + + # and return the fullnames + return [l[0] for l in results] def normalized_hot(sr_ids): - sr_ids = list(sr_ids) - sr_ids.sort() + sr_ids = list(sorted(sr_ids)) return normalized_hot_cached(sr_ids) if sr_ids else () diff --git a/r2/r2/lib/organic.py b/r2/r2/lib/organic.py index 3e7139f17..c2e5f16e1 100644 --- a/r2/r2/lib/organic.py +++ b/r2/r2/lib/organic.py @@ -6,22 +6,22 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import * from r2.lib.memoize import memoize -from r2.lib.normalized_hot import get_hot, only_recent +from r2.lib.normalized_hot import get_hot from r2.lib import count from r2.lib.utils import UniqueIterator, timeago from r2.lib.promote import random_promoted @@ -99,13 +99,13 @@ def cached_organic_links(user_id, langs): #potentially add a up and coming link if random.choice((True, False)) and sr_ids: sr = Subreddit._byID(random.choice(sr_ids)) - items = only_recent(get_hot(sr)) - if items: - if len(items) == 1: - new_item = items[0] + fnames = get_hot(sr, True) + if fnames: + if len(fnames) == 1: + new_item = fnames[0] else: - new_item = random.choice(items[1:4]) - link_names.insert(0, new_item._fullname) + new_item = random.choice(fnames[1:4]) + link_names.insert(0, new_item) insert_promoted(link_names, sr_ids, user_id is not None) diff --git a/r2/r2/lib/pages/__init__.py b/r2/r2/lib/pages/__init__.py index f80fd6875..3c9c03d49 100644 --- a/r2/r2/lib/pages/__init__.py +++ b/r2/r2/lib/pages/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pages import * diff --git a/r2/r2/lib/pages/admin_pages.py b/r2/r2/lib/pages/admin_pages.py index 8e05bf987..14064da90 100644 --- a/r2/r2/lib/pages/admin_pages.py +++ b/r2/r2/lib/pages/admin_pages.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import c, g @@ -40,6 +40,7 @@ class AdminPage(Reddit): create_reddit_box = False submit_box = False extension_handling = False + show_sidebar = False def __init__(self, nav_menus = None, *a, **kw): #add admin options to the nav_menus diff --git a/r2/r2/lib/pages/graph.py b/r2/r2/lib/pages/graph.py index 376002bc1..31c2d665d 100644 --- a/r2/r2/lib/pages/graph.py +++ b/r2/r2/lib/pages/graph.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import math, datetime, locale diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index d1c82f5fe..f296e0223 100644 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.wrapped import Wrapped, Templated, NoTemplateFound, CachedTemplate @@ -35,7 +35,9 @@ from pylons.controllers.util import abort from r2.lib import promote from r2.lib.traffic import load_traffic, load_summary from r2.lib.captcha import get_iden -from r2.lib.filters import spaceCompress, _force_unicode, _force_utf8, unsafe, websafe +from r2.lib.contrib.markdown import markdown +from r2.lib.filters import spaceCompress, _force_unicode, _force_utf8 +from r2.lib.filters import unsafe, websafe, SC_ON, SC_OFF from r2.lib.menus import NavButton, NamedButton, NavMenu, PageNameNav, JsButton from r2.lib.menus import SubredditButton, SubredditMenu from r2.lib.menus import OffsiteButton, menu, JsNavMenu @@ -865,13 +867,14 @@ class ProfilePage(Reddit): if c.user_is_admin: from admin_pages import AdminSidebar rb.append(AdminSidebar(self.user)) - if g.show_awards: - tc = TrophyCase(self.user) - helplink = ( "/help/awards", _("what's this?") ) - scb = SideContentBox(title=_("trophy case"), - helplink=helplink, content=[tc], - extra_class="trophy-area") - rb.append(scb) + + tc = TrophyCase(self.user) + helplink = ( "/help/awards", _("what's this?") ) + scb = SideContentBox(title=_("trophy case"), + helplink=helplink, content=[tc], + extra_class="trophy-area") + rb.append(scb) + return rb class TrophyCase(Templated): @@ -893,7 +896,7 @@ class TrophyCase(Templated): self.trophies.append(trophy) award_ids_seen.append(trophy._thing2_id) - self.cup_date = user.should_show_cup() + self.cup_info = user.cup_info() Templated.__init__(self) class ProfileBar(Templated): @@ -1148,6 +1151,16 @@ class SearchBar(Templated): Templated.__init__(self, search_params = search_params) +class SearchFail(Templated): + """Search failure page.""" + def __init__(self, **kw): + md = SC_OFF + markdown(strings.search_failed % dict( + link="javascript:tryagain\(\)")) + SC_ON + + self.errmsg = md + + Templated.__init__(self) + class Frame(Templated): """Frameset for the FrameToolbar used when a user hits /tb/. The @@ -1294,6 +1307,7 @@ class Button(Wrapped): def __init__(self, link, **kw): Wrapped.__init__(self, link, **kw) if link is None: + self.title = "" self.add_props(c.user, [self]) @@ -1324,6 +1338,9 @@ class ButtonDemoPanel(Templated): class SelfServeBlurb(Templated): pass +class FeedbackBlurb(Templated): + pass + class Feedback(Templated): """The feedback and ad inquery form(s)""" def __init__(self, title, action): @@ -1360,6 +1377,14 @@ class Bookmarklets(Templated): Templated.__init__(self, buttons = buttons) +class Translator_Message(Templated): + def __init__(self, locale, user): + from r2.lib.translation import Translator + self.user = user + self.locale = locale + self.lang_name = Translator.get_name(self.locale) + self.en_name = Translator.get_en_name(self.locale) + Templated.__init__(self) class AdminTranslations(Templated): """The translator control interface, used for determining which @@ -1376,9 +1401,6 @@ class UserAwards(Templated): from r2.models import Award, Trophy Templated.__init__(self) - if not g.show_awards: - abort(404, "not found"); - self.regular_winners = [] self.manuals = [] self.invisibles = [] @@ -1734,7 +1756,7 @@ class LinkChild(object): self.expand = expand self.load = load or expand self.nofollow = nofollow - + def content(self): return '' @@ -2125,6 +2147,8 @@ class Promote_Graph(Templated): (total_sale, total_refund)), multiy = False) + # table is labeled as "last month" + history = self.now - datetime.timedelta(30) self.top_promoters = bidding.PromoteDates.top_promoters(history) else: self.money_graph = None diff --git a/r2/r2/lib/pages/things.py b/r2/r2/lib/pages/things.py index 5497de8ca..5d99751c5 100644 --- a/r2/r2/lib/pages/things.py +++ b/r2/r2/lib/pages/things.py @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.menus import Styled @@ -121,8 +121,7 @@ class CommentButtons(PrintableButtons): class MessageButtons(PrintableButtons): def __init__(self, thing, delete = False, report = True): was_comment = getattr(thing, 'was_comment', False) - permalink = thing.permalink if was_comment else "" - + permalink = thing.permalink PrintableButtons.__init__(self, "messagebuttons", thing, profilepage = c.profilepage, permalink = permalink, diff --git a/r2/r2/lib/promote.py b/r2/r2/lib/promote.py index 678b82997..e81eb944b 100644 --- a/r2/r2/lib/promote.py +++ b/r2/r2/lib/promote.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement @@ -190,7 +190,7 @@ def auth_paid_promo(thing, user, pay_id, bid): trans_id = authorize.auth_transaction(bid, user, pay_id, thing) thing.promote_bid = bid - if trans_id is not None: + if trans_id is not None and int(trans_id) != 0: # we won't reset to unseen if already approved and the payment went ok promotion_log(thing, "updated payment and/or bid: SUCCESS (id: %s)" % trans_id) diff --git a/r2/r2/lib/py_markdown.py b/r2/r2/lib/py_markdown.py new file mode 100644 index 000000000..312964736 --- /dev/null +++ b/r2/r2/lib/py_markdown.py @@ -0,0 +1,59 @@ +from contrib.markdown import markdown +import re + +r_url = re.compile('(?<![\(\[])(http://[^\s\'\"\]\)]+)') +jscript_url = re.compile('<a href="(?!http|ftp|mailto|/).*</a>', re.I | re.S) +img = re.compile('<img.*?>', re.I | re.S) +href_re = re.compile('<a href="([^"]+)"', re.I) +code_re = re.compile('<code>([^<]+)</code>') +a_re = re.compile('>([^<]+)</a>') +fix_url = re.compile('<(http://[^\s\'\"\]\)]+)>') + +def code_handler(m): + l = m.group(1) + return '<code>%s</code>' % l.replace('&','&') + +#unescape double escaping in links +def inner_a_handler(m): + l = m.group(1) + return '>%s</a>' % l.replace('&','&') + +def py_markdown(text, nofollow=False, target=None): + # increase escaping of &, < and > once + text = text.replace("&", "&").replace("<", "<").replace(">", ">") + + #wrap urls in "<>" so that markdown will handle them as urls + text = r_url.sub(r'<\1>', text) + + text = markdown(text) + + text = img.sub('', text) #remove images + # remove the "&" escaping in urls + text = code_re.sub(code_handler, text) + text = a_re.sub(inner_a_handler, text) + + #remove images + text = img.sub('', text) + + #wipe malicious javascript + text = jscript_url.sub('', text) + + # remove the "&" escaping in urls + def href_handler(m): + url = m.group(1).replace('&', '&') + link = '<a href="%s"' % url + + if target: + link += ' target="%s"' % target + + if nofollow: + link += ' rel="nofollow"' + + return link + + text = href_re.sub(href_handler, text) + text = code_re.sub(code_handler, text) + text = a_re.sub(inner_a_handler, text) + text = fix_url.sub(r'\1', text) + + return text diff --git a/r2/r2/lib/queues.py b/r2/r2/lib/queues.py index 68fe6f50f..1075316d0 100644 --- a/r2/r2/lib/queues.py +++ b/r2/r2/lib/queues.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ class QueueMap(object): diff --git a/r2/r2/lib/recommendation.py b/r2/r2/lib/recommendation.py index 06be7a334..e2b4e179c 100644 --- a/r2/r2/lib/recommendation.py +++ b/r2/r2/lib/recommendation.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import g, c diff --git a/r2/r2/lib/rising.py b/r2/r2/lib/rising.py index 3e1557f38..c9d4f8e29 100644 --- a/r2/r2/lib/rising.py +++ b/r2/r2/lib/rising.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import g, c diff --git a/r2/r2/lib/rpc.py b/r2/r2/lib/rpc.py index f66eef3ce..491850bb4 100644 --- a/r2/r2/lib/rpc.py +++ b/r2/r2/lib/rpc.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import socket, cPickle as pickle diff --git a/r2/r2/lib/s3cp.py b/r2/r2/lib/s3cp.py index 8a3aac6f8..5ed85b436 100644 --- a/r2/r2/lib/s3cp.py +++ b/r2/r2/lib/s3cp.py @@ -8,17 +8,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/scraper.py b/r2/r2/lib/scraper.py index aa07ffa15..78bc2740c 100644 --- a/r2/r2/lib/scraper.py +++ b/r2/r2/lib/scraper.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/services.py b/r2/r2/lib/services.py index 7476d3b39..ba5b210fd 100644 --- a/r2/r2/lib/services.py +++ b/r2/r2/lib/services.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# +# # All portions of the code written by CondeNet are Copyright (c) 2006-2008 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/set_reddit_pops.py b/r2/r2/lib/set_reddit_pops.py index 181f004f2..821f4c1ff 100644 --- a/r2/r2/lib/set_reddit_pops.py +++ b/r2/r2/lib/set_reddit_pops.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import Subreddit diff --git a/r2/r2/lib/solrsearch.py b/r2/r2/lib/solrsearch.py index 173bb57d1..b50cf2c62 100644 --- a/r2/r2/lib/solrsearch.py +++ b/r2/r2/lib/solrsearch.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ @@ -466,10 +466,32 @@ class SearchQuery(object): else: self.timerange = timerange + def __repr__(self): + attrs = [ "***q=%s***" % self.q ] + + if self.subreddits is not None: + attrs.append("srs=" + '+'.join([ "%d" % s + for s in self.subreddits ])) + + if self.authors is not None: + attrs.append("authors=" + '+'.join([ "%d" % s + for s in self.authors ])) + + if self.timerange is not None: + attrs.append("timerange=%s" % str(self.timerange)) + + if self.sort is not None: + attrs.append("sort=%r" % self.sort) + + return "<%s(%s)>" % (self.__class__.__name__, ", ".join(attrs)) + def run(self, after = None, num = 100, reverse = False): - if not self.q or not g.solr_url: + if not self.q: return pysolr.Results([],0) + if not g.solr_url: + raise SolrError("g.solr_url is not set") + # there are two parts to our query: what the user typed # (parsed with Solr's DisMax parser), and what we are adding # to it. The latter is called the "boost" (and is parsed using @@ -536,14 +558,9 @@ class SearchQuery(object): q,solr_params = self.solr_params(self.q,boost) - try: - search = self.run_search(q, self.sort, solr_params, - reverse, after, num) - return search - - except SolrError,e: - g.log.error(str(e)) - return pysolr.Results([],0) + search = self.run_search(q, self.sort, solr_params, + reverse, after, num) + return search @classmethod def run_search(cls, q, sort, solr_params, reverse, after, num): diff --git a/r2/r2/lib/strings.py b/r2/r2/lib/strings.py index d17a48a9d..f3d11907d 100644 --- a/r2/r2/lib/strings.py +++ b/r2/r2/lib/strings.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ @@ -58,7 +58,7 @@ string_dict = dict( float_label = _("%(num)5.3f %(thing)s"), # this is for Japanese which treats people counds differently - person_label = _('<span class="number">%(num)s</span> <span class="word">%(persons)s</span>'), + person_label = _("<span class='number'>%(num)s</span> <span class='word'>%(persons)s</span>"), firsttext = _("reddit is a source for what's new and popular online. vote on links that you like or dislike and help decide what's popular, or submit your own!"), @@ -116,7 +116,7 @@ string_dict = dict( submit_box_text = _('to anything interesting: news article, blog entry, video, picture...'), permalink_title = _("%(author)s comments on %(title)s"), link_info_title = _("%(title)s : %(site)s"), - banned_subreddit = _("""**this reddit has been banned**\n\nmost likely this was done automatically by our spam filtering program. the program is still learning, and may even have some bugs, so if you feel the ban was a mistake, please send a message to [feedback](%(link)s) and be sure to include the exact name of the reddit."""), + banned_subreddit = _("""**this reddit has been banned**\n\nmost likely this was done automatically by our spam filtering program. the program is still learning, and may even have some bugs, so if you feel the ban was a mistake, please send a message to [our site admins](%(link)s) and be sure to include the **exact name of the reddit**."""), comments_panel_text = _(""" The following is a sample of what Reddit users had to say about this page. The full discussion is available [here](%(fd_link)s); you can @@ -130,6 +130,7 @@ string_dict = dict( verify_email = _("we're going to need to verify your email address for you to proceed."), email_verified = _("your email address has been verfied"), email_verify_failed = _("Verification failed. Please try that again"), + search_failed = _("Our search machines are under too much load to handle your request right now. :( Sorry for the inconvenience.\n\n[Try again](%(link)s) in a little bit -- but please don't mash reload; that only makes the problem worse.") ) class StringHandler(object): diff --git a/r2/r2/lib/sup.py b/r2/r2/lib/sup.py index cec8020e9..0ef07b2d6 100644 --- a/r2/r2/lib/sup.py +++ b/r2/r2/lib/sup.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/template_helpers.py b/r2/r2/lib/template_helpers.py index 4c9cf9e1a..8a035b30c 100644 --- a/r2/r2/lib/template_helpers.py +++ b/r2/r2/lib/template_helpers.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import * @@ -342,8 +342,8 @@ def add_attr(attrs, code, label=None, link=None): label = _('reddit admin, speaking officially') if not link: link = '/help/faq#Whomadereddit' - elif code == 'trophy': - img = (static('award.png'), '!', 11, 8) + elif code.startswith ('trophy:'): + img = (code[7:], '!', 11, 8) priority = 99 cssclass = 'recent-trophywinner' if not label: diff --git a/r2/r2/lib/test_cache.py b/r2/r2/lib/test_cache.py index 07d6103c8..5547d21bf 100644 --- a/r2/r2/lib/test_cache.py +++ b/r2/r2/lib/test_cache.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from cache import * diff --git a/r2/r2/lib/test_wrapper.py b/r2/r2/lib/test_wrapper.py index bca1cf454..0f196197e 100644 --- a/r2/r2/lib/test_wrapper.py +++ b/r2/r2/lib/test_wrapper.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from utils import Wrapped, storify diff --git a/r2/r2/lib/tracking.py b/r2/r2/lib/tracking.py index 02de1b006..71bd8220c 100644 --- a/r2/r2/lib/tracking.py +++ b/r2/r2/lib/tracking.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from base64 import standard_b64decode as b64dec, \ diff --git a/r2/r2/lib/traffic.py b/r2/r2/lib/traffic.py index 46efd296f..816a213ac 100644 --- a/r2/r2/lib/traffic.py +++ b/r2/r2/lib/traffic.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from httplib import HTTPConnection diff --git a/r2/r2/lib/translation.py b/r2/r2/lib/translation.py index 204534159..8a20356db 100644 --- a/r2/r2/lib/translation.py +++ b/r2/r2/lib/translation.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement diff --git a/r2/r2/lib/utils/__init__.py b/r2/r2/lib/utils/__init__.py index 747197565..9f909a4f3 100644 --- a/r2/r2/lib/utils/__init__.py +++ b/r2/r2/lib/utils/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from utils import * diff --git a/r2/r2/lib/utils/cmd_utils.py b/r2/r2/lib/utils/cmd_utils.py index c9640b332..13926d304 100644 --- a/r2/r2/lib/utils/cmd_utils.py +++ b/r2/r2/lib/utils/cmd_utils.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ """ diff --git a/r2/r2/lib/utils/utils.py b/r2/r2/lib/utils/utils.py index 176bdca50..92f8c22f9 100644 --- a/r2/r2/lib/utils/utils.py +++ b/r2/r2/lib/utils/utils.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from urllib import unquote_plus, urlopen @@ -862,18 +862,6 @@ def fetch_things2(query, chunk_size = 100, batch_fn = None, chunks = False): query._after(after) items = list(query) -def set_emptying_cache(): - """ - The default thread-local cache is a regular dictionary, which - isn't designed for long-running processes. This sets the - thread-local cache to be a SelfEmptyingCache, which naively - empties itself out every N requests - """ - from pylons import g - from r2.lib.cache import SelfEmptyingCache - g.cache.caches = [SelfEmptyingCache(),] + list(g.cache.caches[1:]) - - def fix_if_broken(thing, delete = True): from r2.models import Link, Comment @@ -897,7 +885,7 @@ def fix_if_broken(thing, delete = True): if not delete: raise # it still broke. We should delete it - print "%s is missing %r, deleting" % (thing._fullname, a) + print "%s is missing %r, deleting" % (thing._fullname, attr) thing._deleted = True thing._commit() break @@ -1146,3 +1134,16 @@ def to_csv(table): return x return u"\n".join(u','.join(quote_commas(y) for y in x) for x in table) + +def in_chunks(it, size=25): + chunk = [] + it = iter(it) + try: + while True: + chunk.append(it.next()) + if len(chunk) >= size: + yield chunk + chunk = [] + except StopIteration: + if chunk: + yield chunk diff --git a/r2/r2/lib/workqueue.py b/r2/r2/lib/workqueue.py index 68dc2654d..1fa2ed7de 100644 --- a/r2/r2/lib/workqueue.py +++ b/r2/r2/lib/workqueue.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/lib/wrapped.py b/r2/r2/lib/wrapped.py index 1683c2f51..e574aba0f 100644 --- a/r2/r2/lib/wrapped.py +++ b/r2/r2/lib/wrapped.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from itertools import chain @@ -169,7 +169,7 @@ class Templated(object): # fetch template template = self.template(style) if template: - # store the global render style (since child templates + # store the global render style (since child templates) render_style = c.render_style c.render_style = style # are we doing a partial render? @@ -293,7 +293,7 @@ class Templated(object): g.rendercache.set_multi(dict((k, v) for k, (v, kw) in updates.values() if k in to_cache)) - + # edge case: this may be the primary tempalte and cachable if isinstance(res, CacheStub): res = updates[res.name][1][0] @@ -374,7 +374,7 @@ class CachedTemplate(Templated): if (k not in self.cache_ignore and not k.startswith('_'))) def cache_key(self, attr, style, *a): - from pylons import c + from pylons import c, g # if template debugging is on, there will be no hash and we # can make the caching process-local. @@ -385,8 +385,8 @@ class CachedTemplate(Templated): # a menu is just a set of links, so we best cache against # them. keys = [c.user_is_loggedin, c.user_is_admin, c.domain_prefix, - c.render_style, c.cname, c.lang, c.site.path, - template_hash] + style, c.cname, c.lang, c.site.path, + template_hash, g.markdown_backend] keys = [make_cachable(x, *a) for x in keys] # add all parameters sent into __init__, using their current value diff --git a/r2/r2/models/__init__.py b/r2/r2/models/__init__.py index fb605121f..fdf8db877 100644 --- a/r2/r2/models/__init__.py +++ b/r2/r2/models/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from account import * diff --git a/r2/r2/models/account.py b/r2/r2/models/account.py index ba4c5062d..d11b626bf 100644 --- a/r2/r2/models/account.py +++ b/r2/r2/models/account.py @@ -6,24 +6,25 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.db.thing import Thing, Relation, NotFound from r2.lib.db.operators import lower from r2.lib.db.userrel import UserRel from r2.lib.memoize import memoize -from r2.lib.utils import modhash, valid_hash, randstr +from r2.lib.utils import modhash, valid_hash, randstr, timefromnow +from r2.lib.cache import sgm from pylons import g import time, sha @@ -58,11 +59,12 @@ class Account(Thing): pref_label_nsfw = True, pref_show_stylesheets = True, pref_mark_messages_read = True, + pref_threaded_messages = True, + pref_collapse_read_messages = False, reported = 0, report_made = 0, report_correct = 0, report_ignored = 0, - cup_date = None, spammer = 0, sort_options = {}, has_subscribed = False, @@ -263,34 +265,53 @@ class Account(Thing): share_emails = share['emails'] for e in emails: share_emails[e] = share_emails.get(e, 0) +1 - + share['recent'] = emails self.share = share - def extend_cup(self, new_expiration): - if self.cup_date and self.cup_date > new_expiration: + def set_cup(self, cup_info): + from r2.lib.template_helpers import static + + if cup_info is None: return - self.cup_date = new_expiration - self._commit() + + if cup_info.get("expiration", None) is None: + return + + cup_info.setdefault("label_template", + "%(user)s recently won a trophy! click here to see it.") + + cup_info.setdefault("img_url", static('award.png')) + + existing_info = self.cup_info() + + if (existing_info and + existing_info["expiration"] > cup_info["expiration"]): + # The existing award has a later expiration, + # so it trumps the new one as far as cups go + return + + td = cup_info["expiration"] - timefromnow("0 seconds") + + cache_lifetime = td.seconds + + if cache_lifetime <= 0: + g.log.error("Adding a cup that's already expired?") + else: + g.hardcache.set("cup_info-%d" % self._id, cup_info, cache_lifetime) + def remove_cup(self): - if not self.cup_date: - return - self.cup_date = None - self._commit() + g.hardcache.delete("cup_info-%d" % self._id) - def should_show_cup(self): - # FIX ME. - # this is being called inside builder (Bad #1) in the - # listing loop. On machines that are not allowed to write to - # the db, this generates an exception (Bad #2) on every - # listing page with users with cups. - return False # temporarily disable cups - if self.cup_date and self.cup_date < datetime.now(g.tz): - self.cup_date = None - self._commit() - return self.cup_date + def cup_info(self): + return g.hardcache.get("cup_info-%d" % self._id) + + @classmethod + def cup_info_multi(cls, ids): + ids = [ int(i) for i in ids ] + return sgm(g.hardcache, ids, miss_fn=None, prefix="cup_info-") class FakeAccount(Account): _nodb = True diff --git a/r2/r2/models/admintools.py b/r2/r2/models/admintools.py index 0feb3dda4..32c98ab3a 100644 --- a/r2/r2/models/admintools.py +++ b/r2/r2/models/admintools.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.utils import tup diff --git a/r2/r2/models/award.py b/r2/r2/models/award.py index ee5bafeee..4447fe31c 100644 --- a/r2/r2/models/award.py +++ b/r2/r2/models/award.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# +# # All portions of the code written by CondeNet are Copyright (c) 2006-2008 # CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -25,6 +25,7 @@ from r2.lib.db.operators import desc, lower from r2.lib.memoize import memoize from r2.models import Account from pylons import c, g, request +from r2.lib.db.operators import asc class Award (Thing): _defaults = dict( @@ -34,12 +35,15 @@ class Award (Thing): @classmethod @memoize('award.all_awards') def _all_awards_cache(cls): - return [ a._id for a in Award._query(limit=100) ] + return [ a._id for a in Award._query(sort=asc('_date'), limit=100) ] @classmethod def _all_awards(cls, _update=False): all = Award._all_awards_cache(_update=_update) - return Award._byID(all, data=True).values() + # Can't just return Award._byID() results because + # the ordering will be lost + d = Award._byID(all, data=True) + return [ d[id] for id in all ] @classmethod def _new(cls, codename, title, awardtype, imgurl): @@ -62,7 +66,7 @@ class Award (Thing): raise NotFound, 'Award %s' % codename @classmethod - def give_if_needed(cls, codename, user, cup_expiration=None): + def give_if_needed(cls, codename, user, cup_info=None): """Give an award to a user, unless they already have it. Returns silently (except for g.log.debug) if the award doesn't exist""" @@ -80,7 +84,7 @@ class Award (Thing): g.log.debug("%s already has %s" % (user, codename)) return - Trophy._new(user, award, cup_expiration=cup_expiration) + Trophy._new(user, award, cup_info=cup_info) g.log.debug("Gave %s to %s" % (codename, user)) @classmethod @@ -115,7 +119,7 @@ class Award (Thing): class Trophy(Relation(Account, Award)): @classmethod def _new(cls, recipient, award, description = None, - url = None, cup_expiration = None): + url = None, cup_info = None): # The "name" column of the relation can't be a constant or else a # given account would not be allowed to win a given award more than @@ -133,29 +137,39 @@ class Trophy(Relation(Account, Award)): if url: t.url = url - if cup_expiration: - recipient.extend_cup(cup_expiration) + if cup_info: + recipient.set_cup(cup_info) t._commit() Trophy.by_account(recipient, _update=True) Trophy.by_award(award, _update=True) @classmethod - @memoize('trophy.by_account') - def by_account(cls, account): + @memoize('trophy.by_account2') + def by_account_cache(cls, account): q = Trophy._query(Trophy.c._thing1_id == account._id, - eager_load = True, thing_data = True, - data = True, - sort = desc('_date')) - q._limit = 50 - return list(q) - - @classmethod - @memoize('trophy.by_award') - def by_award(cls, award): - q = Trophy._query(Trophy.c._thing2_id == award._id, - eager_load = True, thing_data = True, - data = True, sort = desc('_date')) q._limit = 500 - return list(q) + return [ t._id for t in q ] + + @classmethod + def by_account(cls, account, _update=False): + rel_ids = cls.by_account_cache(account, _update=_update) + trophies = Trophy._byID_rel(rel_ids, data=True, eager_load=True, + thing_data=True, return_dict = False) + return trophies + + @classmethod + @memoize('trophy.by_award2') + def by_award_cache(cls, award): + q = Trophy._query(Trophy.c._thing2_id == award._id, + sort = desc('_date')) + q._limit = 500 + return [ t._id for t in q ] + + @classmethod + def by_award(cls, award, _update=False): + rel_ids = cls.by_award_cache(award, _update=_update) + trophies = Trophy._byID_rel(rel_ids, data=True, eager_load=True, + thing_data=True, return_dict = False) + return trophies diff --git a/r2/r2/models/bidding.py b/r2/r2/models/bidding.py index 0498c47c6..e5d974a71 100644 --- a/r2/r2/models/bidding.py +++ b/r2/r2/models/bidding.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from sqlalchemy import Column, String, DateTime, Date, Float, Integer, \ diff --git a/r2/r2/models/builder.py b/r2/r2/models/builder.py index 69dbf8432..4b701b768 100644 --- a/r2/r2/models/builder.py +++ b/r2/r2/models/builder.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from account import * @@ -34,7 +34,7 @@ from r2.lib.wrapped import Wrapped from r2.lib import utils from r2.lib.db import operators from r2.lib.cache import sgm -from r2.lib.comment_tree import link_comments +from r2.lib.comment_tree import link_comments, user_messages, conversation, tree_sort_fn from copy import deepcopy, copy import time @@ -64,12 +64,15 @@ class Builder(object): #TODO pull the author stuff into add_props for links and #comments and messages? - try: - aids = set(l.author_id for l in items) - except AttributeError: - aids = None + aids = set(l.author_id for l in items if hasattr(l, 'author_id')) + + if aids: + authors = Account._byID(aids, True) if aids else {} + cup_infos = Account.cup_info_multi(aids) + else: + authors = {} + cup_infos = {} - authors = Account._byID(aids, True) if aids else {} # srids = set(l.sr_id for l in items if hasattr(l, "sr_id")) subreddits = Subreddit.load_subreddits(items) @@ -127,10 +130,10 @@ class Builder(object): try: w.author = authors.get(item.author_id) if user and item.author_id in user.friends: - # deprecated old way: - w.friend = True - # new way: - add_attr(w.attribs, 'F') + # deprecated old way: + w.friend = True + # new way: + add_attr(w.attribs, 'F') except AttributeError: pass @@ -143,12 +146,13 @@ class Builder(object): getattr(item, "author_id", None) in mods): add_attr(w.attribs, 'M', label=modlabel, link=modlink) - if (g.show_awards and w.author - and w.author.should_show_cup()): - add_attr(w.attribs, 'trophy', label= - _("%(user)s recently won a trophy! click here to see it.") - % {'user':w.author.name}, - link = "/user/%s" % w.author.name) + if w.author and w.author._id in cup_infos and not c.profilepage: + cup_info = cup_infos[w.author._id] + label = _(cup_info["label_template"]) % \ + {'user':w.author.name} + add_attr(w.attribs, 'trophy:' + cup_info["img_url"], + label=label, + link = "/user/%s" % w.author.name) if hasattr(item, "sr_id"): w.subreddit = subreddits[item.sr_id] @@ -159,12 +163,14 @@ class Builder(object): compute_votes(w, item) w.score = w.upvotes - w.downvotes + if w.likes: base_score = w.score - 1 elif w.likes is None: base_score = w.score else: base_score = w.score + 1 + # store the set of available scores based on the vote # for ease of i18n when there is a label w.voting_score = [(base_score + x - 1) for x in range(3)] @@ -240,6 +246,9 @@ class QueryBuilder(Builder): self.prewrap_fn = query.prewrap_fn #self.prewrap_fn = kw.get('prewrap_fn') + def __repr__(self): + return "<%s(%r)>" % (self.__class__.__name__, self.query) + def item_iter(self, a): """Iterates over the items returned by get_items""" for i in a[0]: @@ -438,6 +447,18 @@ class SearchBuilder(QueryBuilder): return done, new_items +def empty_listing(*things): + parent_name = None + for t in things: + try: + parent_name = t.parent_name + break + except AttributeError: + continue + l = Listing(None, None, parent_name = parent_name) + l.things = list(things) + return Wrapped(l) + class CommentBuilder(Builder): def __init__(self, link, sort, comment = None, context = None, load_more=True, continue_this_thread=True, @@ -472,18 +493,6 @@ class CommentBuilder(Builder): else: comments = () - def empty_listing(*things): - parent_name = None - for t in things: - try: - parent_name = t.parent_name - break - except AttributeError: - continue - l = Listing(None, None, parent_name = parent_name) - l.things = list(things) - return Wrapped(l) - comment_dict = dict((cm._id, cm) for cm in comments) #convert tree into objects @@ -531,7 +540,7 @@ class CommentBuilder(Builder): def sort_candidates(): candidates.sort(key = self.sort_key, reverse = self.rev_sort) - + #find the comments num_have = 0 sort_candidates() @@ -558,7 +567,7 @@ class CommentBuilder(Builder): wrapped = self.wrap_items(items) cids = dict((cm._id, cm) for cm in wrapped) - + final = [] #make tree @@ -623,7 +632,7 @@ class CommentBuilder(Builder): #add more children if comment_tree.has_key(to_add._id): candidates.extend(comment_tree[to_add._id]) - + if direct_child: mc2.children.append(to_add) @@ -631,6 +640,113 @@ class CommentBuilder(Builder): return final +class MessageBuilder(Builder): + def __init__(self, user, parent = None, focal = None, + skip = True, **kw): + self.user = user + self.num = kw.pop('num', None) + self.focal = focal + self.parent = parent + self.skip = skip + + self.after = kw.pop('after', None) + self.reverse = kw.pop('reverse', None) + + Builder.__init__(self, **kw) + + def item_iter(self, a): + for i in a[0]: + yield i + if hasattr(i, 'child'): + for j in i.child.things: + yield j + + def get_items(self): + if self.parent: + tree = conversation(self.user, self.parent) + else: + tree = user_messages(self.user) + + prev = next = None + if not self.parent: + if self.num is not None: + if self.after: + if self.reverse: + tree = filter( + lambda x: tree_sort_fn(x) >= self.after._id, tree) + next = self.after._id + if len(tree) > self.num: + prev = tree[-(self.num+1)][0] + tree = tree[-self.num:] + else: + prev = self.after._id + tree = filter( + lambda x: tree_sort_fn(x) < self.after._id, tree) + if len(tree) > self.num: + tree = tree[:self.num] + next = tree[-1][0] + + # generate the set of ids to look up and look them up + message_ids = [] + for root, thread in tree: + message_ids.append(root) + message_ids.extend(thread) + if prev: + message_ids.append(prev) + + messages = Message._byID(message_ids, data = True, return_dict = False) + wrapped = dict((m._id, m) for m in self.wrap_items(messages)) + + if prev: + prev = wrapped[prev] + if next: + next = wrapped[next] + + final = [] + for parent, children in tree: + parent = wrapped[parent] + if children: + # if no parent is specified, check if any of the messages are + # uncollapsed, and truncate the thread + children = [wrapped[child] for child in children] + parent.child = empty_listing() + # if the parent is new, uncollapsed, or focal we don't + # want it to become a moremessages wrapper. + if (self.skip and + not self.parent and not parent.new and parent.is_collapsed + and not (self.focal and self.focal._id == parent._id)): + for i, child in enumerate(children): + if (child.new or not child.is_collapsed or + (self.focal and self.focal._id == child._id)): + break + else: + i = -1 + parent = Wrapped(MoreMessages(parent, empty_listing())) + children = children[i:] + + parent.child.parent_name = parent._fullname + parent.child.things = [] + + for child in children: + child.is_child = True + if self.focal and child._id == self.focal._id: + # focal message is never collapsed + child.collapsed = False + child.focal = True + else: + child.collapsed = child.is_collapsed + parent.child.things.append(child) + parent.is_parent = True + # the parent might be the focal message on a permalink page + if self.focal and parent._id == self.focal._id: + parent.collapsed = False + parent.focal = True + else: + parent.collapsed = parent.is_collapsed + final.append(parent) + + return (final, prev, next, len(final), len(final)) + def make_wrapper(parent_wrapper = Wrapped, **params): def wrapper_fn(thing): w = parent_wrapper(thing) diff --git a/r2/r2/models/link.py b/r2/r2/models/link.py index 945a02101..ff94b8457 100644 --- a/r2/r2/models/link.py +++ b/r2/r2/models/link.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.db.thing import Thing, Relation, NotFound, MultiRelation, \ @@ -356,7 +356,7 @@ class Link(Thing, Printable): item.different_sr = (isinstance(site, FakeSubreddit) or site.name != item.subreddit.name) - if user_is_loggedin and item.author._id == user._id: + if user_is_loggedin and item.author_id == user._id: item.nofollow = False elif item.score <= 1 or item._spam or item.author._spam: item.nofollow = True @@ -504,9 +504,6 @@ class Comment(Thing, Printable): to = Account._byID(link.author_id) name = 'selfreply' - if to: - c.new = True - c._commit() inbox_rel = None @@ -539,7 +536,7 @@ class Comment(Thing, Printable): @staticmethod def wrapped_cache_key(wrapped, style): s = Printable.wrapped_cache_key(wrapped, style) - s.extend([wrapped.body, wrapped.new]) + s.extend([wrapped.body]) return s def make_permalink(self, link, sr=None, context=None, anchor=False): @@ -668,6 +665,50 @@ class StarkComment(Comment): the reddit toolbar""" _nodb = True +class MoreMessages(Printable): + cachable = False + display = "" + new = False + was_comment = False + is_collapsed = True + + def __init__(self, parent, child): + self.parent = parent + self.child = child + + @staticmethod + def wrapped_cache_key(item, style): + return False + + @property + def _fullname(self): + return self.parent._fullname + + @property + def _id36(self): + return self.parent._id36 + + @property + def subject(self): + return self.parent.subject + + @property + def childlisting(self): + return self.child + + @property + def to(self): + return self.parent.to + + @property + def author(self): + return self.parent.author + + @property + def recipient(self): + return self.parent.recipient + + class MoreComments(Printable): cachable = False display = "" @@ -702,13 +743,14 @@ class MoreRecursion(MoreComments): class MoreChildren(MoreComments): pass - + class Message(Thing, Printable): _defaults = dict(reported = 0, was_comment = False, parent_id = None, - new = False, first_message = None) + new = False, first_message = None, + to_collapse = None, author_collapse = None) _data_int_props = Thing._data_int_props + ('reported', ) cache_ignore = set(["to"]).union(Printable.cache_ignore) - + @classmethod def _new(cls, author, to, subject, body, ip, parent = None): m = Message(subject = subject, @@ -723,7 +765,7 @@ class Message(Thing, Printable): m.first_message = parent.first_message else: m.first_message = parent._id - + m.to_id = to._id m._commit() @@ -737,12 +779,22 @@ class Message(Thing, Printable): return (m, inbox_rel) + @property + def permalink(self): + return "/message/messages/%s" % self._id36 + + def can_view(self): + return (c.user_is_loggedin and + (c.user_is_admin or + c.user._id in (self.author_id, self.to_id))) + @classmethod def add_props(cls, user, wrapped): + from r2.lib.db import queries #TODO global-ish functions that shouldn't be here? #reset msgtime after this request msgtime = c.have_messages - + #load the "to" field if required to_ids = set(w.to_id for w in wrapped) tos = Account._byID(to_ids, True) if to_ids else {} @@ -755,21 +807,39 @@ class Message(Thing, Printable): if l.parent_id and l.was_comment), data = True, return_dict = True) + # load the inbox relations for the messages to determine new-ness + inbox = Inbox._fast_query(c.user, + [item.lookups[0] for item in wrapped], + ['inbox', 'selfreply']) + + # we don't care about the username or the rel name + inbox = dict((m._fullname, v) + for (u, m, n), v in inbox.iteritems() if v) + for item in wrapped: item.to = tos[item.to_id] item.recipient = (item.to_id == c.user._id) - # TODO: can be removed (holdover from when there was no new attr) - if msgtime and item._date >= msgtime: - item.new = True + # don't mark non-recipient messages as new if not item.recipient: item.new = False + # new-ness is stored on the relation + elif item._fullname in inbox: + item.new = getattr(inbox[item._fullname], "new", False) + if item.new and c.user.pref_mark_messages_read: + queries.set_unread(inbox[item._fullname]._thing2, False) + else: + item.new = False + + item.score_fmt = Score.none item.message_style = "" if item.was_comment: link = links[item.link_id] sr = subreddits[link.sr_id] + item.to_collapse = False + item.author_collapse = False item.link_title = link.title item.link_permalink = link.make_permalink(sr) if item.parent_id: @@ -784,13 +854,22 @@ class Message(Thing, Printable): if c.user.pref_no_profanity: item.subject = profanity_filter(item.subject) + item.is_collapsed = None + if not item.new: + if item.recipient: + item.is_collapsed = item.to_collapse + if item.author_id == c.user._id: + item.is_collapsed = item.author_collapse + if c.user.pref_collapse_read_messages: + item.is_collapsed = (item.is_collapsed is not False) + # Run this last Printable.add_props(user, wrapped) @staticmethod def wrapped_cache_key(wrapped, style): s = Printable.wrapped_cache_key(wrapped, style) - s.extend([c.msg_location, wrapped.new]) + s.extend([c.msg_location, wrapped.new, wrapped.collapsed]) return s @@ -803,9 +882,13 @@ class Click(Relation(Account, Link)): pass class Inbox(MultiRelation('inbox', Relation(Account, Comment), Relation(Account, Message))): + + _defaults = dict(new = False) + @classmethod def _add(cls, to, obj, *a, **kw): i = Inbox(to, obj, *a, **kw) + i.new = True i._commit() if not to._loaded: @@ -817,3 +900,17 @@ class Inbox(MultiRelation('inbox', to._commit() return i + + @classmethod + def set_unread(cls, thing, unread): + inbox_rel = cls.rel(Account, thing.__class__) + inbox = inbox_rel._query(inbox_rel.c._thing2_id == thing._id, + eager_load = True) + res = [] + for i in inbox: + if i: + i.new = unread + i._commit() + res.append(i) + return res + diff --git a/r2/r2/models/listing.py b/r2/r2/models/listing.py index 64854290e..a4b22abaf 100644 --- a/r2/r2/models/listing.py +++ b/r2/r2/models/listing.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from account import * @@ -57,8 +57,10 @@ class Listing(object): from r2.lib.template_helpers import replace_render builder_items = self.builder.get_items(*a, **kw) for item in self.builder.item_iter(builder_items): - # rewrite the render method - item.render = replace_render(self, item, item.render) + # rewrite the render method + if not hasattr(item, "render_replaced"): + item.render = replace_render(self, item, item.render) + item.render_replaced = True return builder_items def listing(self): diff --git a/r2/r2/models/mail_queue.py b/r2/r2/models/mail_queue.py index 606656b90..da91ba967 100644 --- a/r2/r2/models/mail_queue.py +++ b/r2/r2/models/mail_queue.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ############################################################################## import sha, datetime diff --git a/r2/r2/models/populatedb.py b/r2/r2/models/populatedb.py index ef04ec09c..75dca34a3 100644 --- a/r2/r2/models/populatedb.py +++ b/r2/r2/models/populatedb.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import * diff --git a/r2/r2/models/printable.py b/r2/r2/models/printable.py index 722b21fa5..b053180bc 100644 --- a/r2/r2/models/printable.py +++ b/r2/r2/models/printable.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from pylons import c, request diff --git a/r2/r2/models/report.py b/r2/r2/models/report.py index 3a75d920a..ac796c323 100644 --- a/r2/r2/models/report.py +++ b/r2/r2/models/report.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.db.thing import Thing, Relation, MultiRelation, thing_prefix diff --git a/r2/r2/models/subreddit.py b/r2/r2/models/subreddit.py index 111e2ae9e..ebd69fc84 100644 --- a/r2/r2/models/subreddit.py +++ b/r2/r2/models/subreddit.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from __future__ import with_statement @@ -59,6 +59,7 @@ class Subreddit(Thing, Printable): domain = None, over_18 = False, mod_actions = 0, + sponsorship_text = "this reddit is sponsored by", sponsorship_url = None, sponsorship_img = None, sponsorship_name = None, diff --git a/r2/r2/models/types.py b/r2/r2/models/types.py index f4040ed5d..1c1c0821a 100644 --- a/r2/r2/models/types.py +++ b/r2/r2/models/types.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.db.thing import Thing, Relation, Vote diff --git a/r2/r2/models/update_karmas.py b/r2/r2/models/update_karmas.py index 048aec9bb..9ae498f69 100644 --- a/r2/r2/models/update_karmas.py +++ b/r2/r2/models/update_karmas.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.models import Link, Account, Subreddit diff --git a/r2/r2/models/vote.py b/r2/r2/models/vote.py index 96528323b..4f9189a44 100644 --- a/r2/r2/models/vote.py +++ b/r2/r2/models/vote.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from r2.lib.db.thing import MultiRelation, Relation, thing_prefix, cache @@ -50,7 +50,7 @@ class Vote(MultiRelation('vote', @classmethod - def vote(cls, sub, obj, dir, ip, organic = False): + def vote(cls, sub, obj, dir, ip, organic = False, cheater = False): from admintools import valid_user, valid_thing, update_score from r2.lib.count import incr_counts @@ -78,7 +78,7 @@ class Vote(MultiRelation('vote', #these still need to be recalculated old_valid_thing = v.valid_thing - v.valid_thing = (valid_thing(v, karma) + v.valid_thing = (valid_thing(v, karma, cheater = cheater) and v.valid_thing) v.valid_user = (v.valid_user and v.valid_thing @@ -91,7 +91,8 @@ class Vote(MultiRelation('vote', v.author_id = obj.author_id v.sr_id = sr._id v.ip = ip - old_valid_thing = v.valid_thing = (valid_thing(v, karma)) + old_valid_thing = v.valid_thing = \ + valid_thing(v, karma, cheater = cheater) v.valid_user = (v.valid_thing and valid_user(v, sr, karma) and not is_self_link) if organic: diff --git a/r2/r2/public/static/alien-head.png b/r2/r2/public/static/alien-head.png new file mode 100644 index 0000000000000000000000000000000000000000..468557ae35288878368b6632cf388d2fd25e7fcf GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^+(691!3HGtEm%8%6k~CayA#8@b22Z19JVBHcNd2L zAh=-f^2tCE&H|6fVxTr*5N2eUHAey{$X?><>&kwMkyT7gYnA)^6+odwo-U3d5|>*i zoaJIn6lt5EpYiGJA=8KlOv_Hl-iV0M^1gP>OwZwLmv;ek*rcE-ty6-^j`@k5I^WTj zW5?ZVC|Mc4eBNifxqN?4EC~&o9On5^|8A61>)DIvmpa<6Wr+EHaA|zVH^t7#Z7s)J zubc7AjZy61k#{fkdyVt4<Td@8XEv#tG<bxlM`tn^%wNYS@lA|DW;<VX^{d&8GP@UV zx%=jH&F(v%A;*~<J|9@|*QlS}+pm3f{xnG@^Y&UNuemkFq7VF?4cr%NP3$}X^bLcj LtDnm{r-UW|s6%)W literal 0 HcmV?d00001 diff --git a/r2/r2/public/static/css/reddit-ie7-hax.css b/r2/r2/public/static/css/reddit-ie7-hax.css index 676c7b0c8..3228db245 100644 --- a/r2/r2/public/static/css/reddit-ie7-hax.css +++ b/r2/r2/public/static/css/reddit-ie7-hax.css @@ -10,3 +10,7 @@ .award-square .award-name { font-size:18px; } + +.message .midcol { + width: 15px; +} diff --git a/r2/r2/public/static/css/reddit.css b/r2/r2/public/static/css/reddit.css index f5abf7877..ac7fd2b64 100644 --- a/r2/r2/public/static/css/reddit.css +++ b/r2/r2/public/static/css/reddit.css @@ -99,6 +99,9 @@ label.disabled { color: gray; } .flat-list form {display: inline; } .flat-list .selected a { color: orangered; } +.link .flat-list { display: block; padding-bottom: 1px; } +.link.compressed .flat-list { display: inline-block; } + ul.flat-vert {text-align: left;} .flat-vert .separator { margin: 0 } @@ -580,6 +583,11 @@ ul.flat-vert {text-align: left;} .link.promotedlink.finished { background-color: #DDD; } #promo-form + form #img-preview-container { display: none; } +.rejection-form textarea { + width: 40em; + height: 10em; +} + .promoted-list { font-size: larger; } .promoted-list .unpromote-button { display: inline } .promoted-list .unpromote-button a { color: gray; } @@ -840,6 +848,13 @@ textarea.gray { color: gray; } .morecomments a:hover { text-decoration: underline} .morecomments .gray {font-weight: normal; color: gray} +.expand-btn { + font-size: smaller; + margin: 0px 5px; + margin-top: 4px; + display: inline-block; +} + .message { margin: 10px 10px 20px 5px; padding-left: 5px; @@ -847,7 +862,40 @@ textarea.gray { color: gray; } padding:7px; } -.message.new { +.message.focal > .entry .md { + background-color: #FFFFCC; +} + +.message .collapsed .head { + color: #888888; + font-style: italic; +} + + +.message.message-parent .tagline, +.message.message-reply .tagline { + color: #485; +} + +.message.message-parent > .entry .noncollapsed, +.message.message-reply > .entry .noncollapsed { + color: #485; +} + +.message.recipient > .entry .noncollapsed { + color: black; +} + +.message.message-reply.recipient > .entry .head, +.message.message-parent.recipient > .entry .head { + color: black; + font-weight: bold; +} + +.message.new > .entry .head { + color:orangered; font-weight: bold; +} +.message.new > .entry{ background-color:#F7F7F7; border:1px solid #E9E9E9; padding: 6px; @@ -858,6 +906,59 @@ textarea.gray { color: gray; } } +.message .child .message, +.message .child .usertext { + margin-top: 10px; + margin-left: 12px; +} + +.message .expand { + display: none; +} + +.message .entry { + margin-left: 0px; +} + +.message.message-parent .expand { + display: inline; +} + +/* threaded message styles: remove padding */ +.message.message-parent .child, +.message.message-reply .child { + margin: 0; + padding: 0; +} + +.message.message-parent .child .message, +.message.message-reply .child .message + { + margin: 0; + padding: 0; +} + +.message.message-parent .subject { + margin-bottom: 10px; +} + +.message.message-parent .message .subject { + display: none; +} + +.message.message-reply .subject { + display:none; +} + +.message.message-reply .entry, +.message.message-parent .entry { + margin-left: 10px; + padding-left: 10px; + padding-bottom: 10px; + border-left: 2px dashed #E7E7E7; +} + + .message .buttons, .message .md { margin-left: 15px; } .message .entry .parent { @@ -865,6 +966,16 @@ textarea.gray { color: gray; } max-width: 60em; margin: 3px 10px; } + +.message .subject .correspondent { + background-color:#EFF7FF; + border:1px solid #336699; + color:#336699; + display:inline-block; + margin-right:10px; + padding:2px 5px; +} + .message .subject .title { font-weight: normal; font-style: italic; @@ -886,9 +997,7 @@ textarea.gray { color: gray; } margin-left: 2px; } -.message .child { margin-left: 15px; } -.message.new .head {color:orangered; font-weight: bold; } .message .subject { font-weight: bold; font-size: larger; } .clippy img { @@ -1192,6 +1301,17 @@ textarea.gray { color: gray; } margin-bottom: 10px; } +.searchfail { + color: #c00000; + font-size: larger; + line-height: 2em; +} + +.searchfail a { + color: red; + text-decoration: underline; +} + /* login, register */ @@ -1522,6 +1642,22 @@ textarea.gray { color: gray; } list-style-image:url(/static/red-arrow.png); } + +.feedback.instructions dl { + margin-left: 20px; +} + +.feedback.instructions dt { + margin-top: 10px; +} + +.feedback.instructions dd { + background: transparent none no-repeat scroll bottom left; + background-image: url(/static/red-arrow.png); + padding-left: 35px; +} + + .button-demo a.view-code, .button-demo a.hide-code { float: right; margin-bottom: 1em; } .button-demo a.hide-code { display: none; } @@ -1816,9 +1952,16 @@ form input[type=radio] {margin: 2px .5em 0 0; } .over18 button { margin: 0 10px 0 10px; padding: 5px} -.link.over18 acronym { - color: red; - font-weight: bold; +.entry .buttons li.nsfw-stamp { + border: 1px solid #ff7777 !important; + padding: 0 4px; + background-color: white; +} + +.nsfw-stamp acronym { + border: none; + color: black; + text-decoration: none; } .reported { background-color: #f6e69f } @@ -2696,6 +2839,15 @@ table.award-table { display: inline; } +.cup-info-box { + border: dashed #eeaa33 2px; + padding: 5px; +} + +.cup-info-box tt { + background-color: #f5f5aa; +} + /* Datepicker ----------------------------------*/ .datepicker { diff --git a/r2/r2/public/static/help.png b/r2/r2/public/static/help.png index 19558da9eee601c29fac3d45c215324dbd02f3c2..bcde64e54fbbc9a462b2189bbb61e2627e665775 100644 GIT binary patch delta 117 zcmV-*0E+*+0nP!C7zqdh0000c&fsy8AxvRRNkl<Zc-mt;c<>+tUcdsxc6N5Sqz@fB z#DdIESq5dyi9$64E)ADJW;4N6AnQYS2c|{Hs+lk~p&7=6UmA-FxOYe}g9Q>Sc)}C_ XX%Q5Q$APX300000NkvXXu0mjfwje2z delta 98 zcmX@dxSMf;1Sb<S0|UdAL-V&zRP^!V4DbnYO<wx{;K76c|Njr05mE${RPl6i4B@z* z%)!f>cp_?Ri(+>sr}Hr`1>Qrx4tKV)DDf?Ae8rGpD-b{5X9_1!J%gvKpUXO@geCwH C7b714 diff --git a/r2/r2/public/static/iphone/index.html b/r2/r2/public/static/iphone/index.html index 7053cd00e..4c0aa869a 100644 --- a/r2/r2/public/static/iphone/index.html +++ b/r2/r2/public/static/iphone/index.html @@ -145,7 +145,7 @@ h2 { <script src="random.js" language="javascript" type="text/javascript"> </script> </head><body> -<div id="nav"><span style="font-weight: bold; color: white;">»</span> <a href="http://reddit.com/">back to reddit.com</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="http://getsatisfaction.com/reddit/products/reddit_ireddit">give us feedback</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="#buzz">bask in the buzz</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="http://apple.reddit.com/">visit apple.reddit</a>  <span style="font-weight: bold; color: white;">|</span>  <span><a href="http://reddit.com/store">wear your reddit pride</a></span></div> +<div id="nav"><span style="font-weight: bold; color: white;">»</span> <a href="http://reddit.com/">back to reddit.com</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="http://getsatisfaction.com/reddit/products/reddit_ireddit">give us feedback</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="#buzz">bask in the buzz</a>  <span style="font-weight: bold; color: white;">|</span>  <a href="http://apple.reddit.com/">visit apple.reddit</a>  <span style="font-weight: bold; color: white;">|</span>  <span><a href="http://reddit.com/store">wear your reddit pride</a></span></div> <div id="main"> <div id="right"> diff --git a/r2/r2/public/static/js/jquery.reddit.js b/r2/r2/public/static/js/jquery.reddit.js index 2c63ad956..8f1b1fe24 100644 --- a/r2/r2/public/static/js/jquery.reddit.js +++ b/r2/r2/public/static/js/jquery.reddit.js @@ -240,7 +240,7 @@ rate_limit = function() { }() -$.fn.vote = function(vh, callback) { +$.fn.vote = function(vh, callback, event) { /* for vote to work, $(this) should be the clicked arrow */ if($(this).hasClass("arrow")) { var dir = ( $(this).hasClass(up_cls) ? 1 : @@ -272,9 +272,10 @@ $.fn.vote = function(vh, callback) { entry.addClass('unvoted') .removeClass('likes dislikes'); }); - - $.request("vote", {id: things.filter(":first").thing_id(), - dir : dir, vh : vh}); + var thing_id = things.filter(":first").thing_id(); + /* IE6 hack */ + vh += event ? "" : ("-" + thing_id); + $.request("vote", {id: thing_id, dir : dir, vh : vh}); } /* execute any callbacks passed in. */ if(callback) @@ -420,11 +421,19 @@ $.fn.replace_things = function(things, keep_children, reveal, stubs) { var existing = $(self).things(data.id); if(stubs) existing = existing.filter(".stub"); + if(existing.length == 0) { + var parent = $.things(data.parent); + if (parent.length) { + existing = $("<div></div>"); + parent.find(".child:first").append(existing); + } + } existing.after($.unsafe(data.content)); var new_thing = existing.next(); - new_thing.find(".midcol").css("width", midcol).end() - .find(".rank").css("width", midcol); - + if($.defined(midcol)) { + new_thing.find(".midcol").css("width", midcol).end() + .find(".rank").css("width", midcol); + } if(keep_children) { /* show the new thing */ new_thing.show() diff --git a/r2/r2/public/static/js/reddit.js b/r2/r2/public/static/js/reddit.js index 11146e98b..2cc4d3777 100644 --- a/r2/r2/public/static/js/reddit.js +++ b/r2/r2/public/static/js/reddit.js @@ -380,18 +380,63 @@ function helpoff(elem) { $(elem).parents(".usertext-edit:first").children(".markhelp:first").hide(); }; +function show_all_messages(elem) { + var m = $(elem).parents(".message"); + var ids = []; + m.find(".entry .collapsed").hide().end() + .find(".noncollapsed, .midcol:first").filter(":hidden") + .each(function() { + var t = $(this).show().thing_id(); + if(ids.indexOf(t) == -1) { + ids.push(t); + } + }); + if(ids.length) { + $.request("uncollapse_message", {"id": ids.join(',')}); + } + return false; +} + +function hide_all_messages(elem) { + var m = $(elem).parents(".message"); + var ids = []; + m.find(".entry .collapsed").show().end() + .find(".noncollapsed, .midcol:first").filter(":visible") + .each(function() { + var t = $(this).hide().thing_id(); + if(ids.indexOf(t) == -1) { + ids.push(t); + } + }); + if(ids.length) { + $.request("collapse_message", {"id": ids.join(',')}); + } + return false; +} + function hidecomment(elem) { - $(elem).thing().hide() - .find(".noncollapsed:first, .midcol:first, .child:first").hide().end() + var t = $(elem).thing(); + t.hide() + .find(".noncollapsed:first, .midcol:first").hide().end() .show().find(".entry:first .collapsed").show(); + if(t.hasClass("message")) { + $.request("collapse_message", {"id": $(t).thing_id()}); + } else { + t.find(".child:first").hide(); + } return false; }; function showcomment(elem) { - var comment = $(elem).thing(); - comment.find(".entry:first .collapsed").hide().end() - .find(".noncollapsed:first, .midcol:first, .child:first").show().end() + var t = $(elem).thing(); + t.find(".entry:first .collapsed").hide().end() + .find(".noncollapsed:first, .midcol:first").show().end() .show(); + if(t.hasClass("message")) { + $.request("uncollapse_message", {"id": $(t).thing_id()}); + } else { + t.find(".child:first").show(); + } return false; }; @@ -404,6 +449,12 @@ function morechildren(form, link_id, children, depth) { return false; }; +function moremessages(elem) { + $(elem).html(reddit.status_msg.loading).css("color", "red"); + $.request("moremessages", {parent_id: $(elem).thing_id()}); + return false; +} + /* stylesheet and CSS stuff */ function update_reddit_count(site) { @@ -1129,7 +1180,7 @@ function check_some_langs(elem) { function fetch_parent(elem, parent_permalink, parent_id) { $(elem).css("color", "red").html(reddit.status_msg.loading); var thing = $(elem).thing(); - var parentdiv = thing.find(".body .parent"); + var parentdiv = thing.find(".uncollapsed .parent"); if (parentdiv.length == 0) { var parent = ''; $.getJSON(parent_permalink, function(response) { @@ -1144,9 +1195,10 @@ function fetch_parent(elem, parent_permalink, parent_id) { }); if(parent) { /* make a parent div for the contents of the fetch */ - thing.find(".body .md").before('<div class="parent rounded">' + - $.unsafe(parent) + - '</div>'); + thing.find(".noncollapsed .md") + .before('<div class="parent rounded">' + + $.unsafe(parent) + + '</div>'); } $(elem).parent("li").andSelf().remove(); }); diff --git a/r2/r2/public/static/js/sponsored.js b/r2/r2/public/static/js/sponsored.js index 4e7729f7e..8e9be4c00 100644 --- a/r2/r2/public/static/js/sponsored.js +++ b/r2/r2/public/static/js/sponsored.js @@ -61,4 +61,4 @@ function attach_calendar(where, min_date_src, max_date_src, callback) { }).click(function() { $(this).siblings(".datepicker.inuse").addClass("active"); }); -} \ No newline at end of file +} diff --git a/r2/r2/public/static/kill.png b/r2/r2/public/static/kill.png index ab602af979c5aae4321581cb73e4039158fbbc94..ef7cb6513d6d41be49c70c2aae1bd2641a1e6ffa 100644 GIT binary patch delta 127 zcmV-_0D%9#0oVbM7zqdh0000c&fsy8AxvvlNkl<Zc-mt;c<>+tUcdsxc6N5Sqz@fB z!~|ibEJK%ri$GP(i9%5XWCKM|R3IxtmPSzlSA;B$t^y*B<|ZaIX-qdUp-E#p9N`x< h02g6_1Ph)p1pu=MA){*E4e$T}002ovPDHLkV1nloDnbAN delta 101 zcmcb?xQ}sy1Sb<S0|UdAL-V&zRP+ht4DbnYO<wx{;K76c|Njr05mE${RQGgo4B@z* z%)!f>cp_?Ri(=+fF6U!isyvZi4tH1=I@V0E@Q_=<$KdmvU-x2jJqJ(=gQu&X%Q~lo FCIE^+Bv}9e diff --git a/r2/r2/public/static/mail.png b/r2/r2/public/static/mail.png index 11d09a11881c3f803af09c851e5b2bf9b09100b8..745b8ef081f4aee68f3667fdec9ed9c02156715a 100644 GIT binary patch delta 188 zcmdnNc!qI;L_G%+0|Ud8%E{}16mzkYX9x!e$L)vy4}e_G0*}aI1_o|n5N2eUHAey{ zC{yAZQ4*Y=R#Ki=l*-_klAn~S;FejGTAp8&U98|7Y{Itb@&cebcTX3`5Q)plKjhCj z*feeAU~0+YVBa5P(3xVO$LqlrFt>3fW2jiDX{mJEGqadgw<RXnwuH*4-D<l&J@>@E j9Azbz+Y=7YwqRjk@dy_D^s8<I&`btTS3j3^P6<r_t!_OM delta 168 zcmX@ZxPx(mL_HHT0|SFt>6<Jd#ggvm>&U=x?Zy@V2qPe0vcxr_Bsf2<q&%@GmBBG3 zKPgqgGdD3kH7GSPrLyp3str&PXMj(L>wi~<|D_E7|NpO(Je>>_H1%|G4B@z*oWQ`i zE_Ah&#FVhLK?xTkwk9z)PrIh1@bK!k2FK#YXH0C0TSHe1Nh}FlJBuNVn<4rypQdx9 Rd<oD522WQ%mvv4FO#ngSIc)#{ diff --git a/r2/r2/public/static/mailgray.png b/r2/r2/public/static/mailgray.png index 91675e670345b4ea7f57c5e605d53ad87678f679..8d319052f10b5c71c9bbd66331708daa030ca0c7 100644 GIT binary patch delta 192 zcmdnNc!6<(L_G%+0|Ud8%E{}16mzkYX9x!e$L)vy4}e_G0*}aI1_o|n5N2eUHAey{ zC{yAZQ4*Y=R#Ki=l*-_klAn~S;FejGTAp8&U98|7Y{Itb@&cebZ%-G;5Q)plH{7`r z8Up@vGPY!Ku<sAzILQ#+?#;Z3i7mx-hSY@=%fOKPyGprzr8JsiO=Fnkm}Wc*xOyTj nfvH0$#I$bdiM|vC%`yi0tp2C=nR71#&1LX(^>bP0l+XkKVn{t2 delta 168 zcmcb>xPx(mL_HHT0|SFt>6<Jd#ggvm>&U=x?Zy@V2qPe0vcxr_Bsf2<q&%@GmBBG3 zKPgqgGdD3kH7GSPrLyp3str&PXMj(L>*mdyFJHd=|NsB1=T7wi1x-C&978y+Cnqp4 zt_xi)B{3yzZBW96h^<MC&C{+aDLlNot--Ol@fj1F;?~gBLJ~{D*3M!G<7SBd%ctoa SDPICKfx*+&&t;ucLK6T-qC9^9 diff --git a/r2/r2/public/static/red-arrow.png b/r2/r2/public/static/red-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..9eba80903e1844d448d124eddecb2de631691c79 GIT binary patch literal 804 zcmV+<1Ka$GP)<h;3K|Lk000e1NJLTq0015U000jN1^@s6^SXbW00009a7bBm000XU z000XU0RWnu7ytkQ)=5M`R5%f}RnJRQQ562pee-5?G*QY(En6sw7LiLyiKsS33)51h zh+Kptl?i6HXc5)UKcE&7QDG4nMA)K5p#%kns}M6%Guo&~jn12SKkn_^r>|g?(3%dM z_wJAL?sv|2&pD4=>EK_4l!sIbuon`@Da->&0R@6B6ins9P=F#@0U^MP28I4wm54x) zgE!~Tz8=4S@200@0SO>WdeCRPVkM~dg6!l1=0A*qJa>gxX$vOLwT4+Yux?^4<mk#g zCvjl7t-T>RHHD20P4j!YI<Mwe?YiYbdBS4{*bxmcS+(df{g@oXz~Opj&d)&^OaO07 zZMjAvrjoe@7=SoRhj|Z`Y(vGl*vO94XJR5J_Z`5LGpb@l4ZZ|CF^cC0k23HqU>NHL z*8XX55`nV{!gXMKgq*rsReibpc5!W8kAnKHI3EJ>t@THN3cjHA>TghvNJnLw2#3Rn z4-L}WmXmEG*RPFQbF=k=bIJAT@!1c2$jn=4K3OHx5ROCuD~|Er-lA8HP5oa62KtPo zTcB?y;3qSvtDIsW0y8@T>-`W0Pqj9GdfeYf3>#X-Hls_n;eZyC2yZDz`Gwe>(j$jD z^<DorU|k=Mlj7V7q3GE0&y_uw+VU%_UMg_*E0uX*#g|8%)lN#nsHm`aU+m~DYd&!U zhG|LeWJ|S23@jy_gasrLemM!AucwavqU48}mBkrDP*w_FZZ5XBwmjR}(a{wx-a0Nh zN+Dg}G-#g`pP9zT2TvwLi&j(_6y=1>X1CU!bX-5uvoU@55f*2@PUY{dd0O3l<>BW2 z`-UY$>83)Q;ks$)<`HBxr8s;Ox^XNm>J1)q9U!`_+L2()Vfl{feS_@;w}hm$;_(-a zEmI|RH4|0sF+}nT_%IjTLwq3pqevHWxkoR9{Q^%n`s18`1h!?t{WgPec_{>6G7}D$ ixJ_z`bzSo)U48=WP!qUlA2II$0000<MNUMnLSTZHcxuo9 literal 0 HcmV?d00001 diff --git a/r2/r2/templates/__init__.py b/r2/r2/templates/__init__.py index 8f4571a72..f7cf60c7d 100644 --- a/r2/r2/templates/__init__.py +++ b/r2/r2/templates/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/admin/__init__.py b/r2/r2/templates/admin/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/templates/admin/__init__.py +++ b/r2/r2/templates/admin/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/admin_rightbox.html b/r2/r2/templates/admin_rightbox.html index fb953b8f5..8e690c363 100644 --- a/r2/r2/templates/admin_rightbox.html +++ b/r2/r2/templates/admin_rightbox.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/adminawardgive.html b/r2/r2/templates/adminawardgive.html index 0e12b7f57..7c9c3c059 100644 --- a/r2/r2/templates/adminawardgive.html +++ b/r2/r2/templates/adminawardgive.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/adminawards.html b/r2/r2/templates/adminawards.html index 15407b32c..b7f1c73ca 100644 --- a/r2/r2/templates/adminawards.html +++ b/r2/r2/templates/adminawards.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/adminawardwinners.html b/r2/r2/templates/adminawardwinners.html index 348b97a82..5902c9738 100644 --- a/r2/r2/templates/adminawardwinners.html +++ b/r2/r2/templates/adminawardwinners.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/admintranslations.html b/r2/r2/templates/admintranslations.html index 8ab0899d4..7b5f933a8 100644 --- a/r2/r2/templates/admintranslations.html +++ b/r2/r2/templates/admintranslations.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -41,7 +41,7 @@ <p> <table style="margin-left: 10px; white-space: nowrap" class="pretty-form infotable"> - %for t in thing.translations: + %for t in sorted(thing.translations): <% name = Translator.get_name(t) en_name = Translator.get_en_name(t) @@ -84,28 +84,29 @@ <td class="little"> ${"%d%%" % int(100*frac)} </td> - <td> - <span class="little oldbylink"><b>authors: </b> + <td class="little oldbylink"> + <span class="little oldbylink"> + <a class="bylink" + href="javascript:void(0)" + onclick="$(this).hide(); $('#add_authors_${t}').show(); return false;"> + [add author]</a> + </span> + <div style="display:inline"> + <form id="add_authors_${t}" style="float:left;display:none" + method="post" action="/admin/i18n/adduser/${t}"> + <input style="margin: 0px; width 100px" type="text" name="name" + class="txt little"/> + <button class="btn little" type="submit"> + ${_("add authors")} + </button> + </form> + </div> %if authors: %for a in authors: ${ynbutton(a, "removed", "deltranslator", hidden_data = dict(lang=t, user=a))} %endfor %endif - <a class="bylink" - href="javascript:void(0)" - onclick="$(this).hide(); $('#add_authors_${t}').show(); return false;"> - [add author]</a> - </span> - </td> - <td> - <form id="add_authors_${t}" style="display:none" - method="post" action="/admin/i18n/adduser/${t}"> - <input style="margin: 0px" type="text" name="name" - class="txt little"/> - <button class="btn little" type="submit">${_("add authors")} - </button> - </form> </td> </tr> %endfor diff --git a/r2/r2/templates/ads.html b/r2/r2/templates/ads.html index 31bc4629e..28d3651e3 100644 --- a/r2/r2/templates/ads.html +++ b/r2/r2/templates/ads.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/appservicemonitor.html b/r2/r2/templates/appservicemonitor.html index 4159e7738..53d9666f1 100644 --- a/r2/r2/templates/appservicemonitor.html +++ b/r2/r2/templates/appservicemonitor.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/autohandler b/r2/r2/templates/autohandler index a704fd427..118ce733c 100644 --- a/r2/r2/templates/autohandler +++ b/r2/r2/templates/autohandler @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/base.html b/r2/r2/templates/base.html index b2304bfc8..b8c955bc1 100644 --- a/r2/r2/templates/base.html +++ b/r2/r2/templates/base.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/base.htmllite b/r2/r2/templates/base.htmllite index 6212b327c..33f3453c3 100644 --- a/r2/r2/templates/base.htmllite +++ b/r2/r2/templates/base.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="utils.html" import="optionalstyle"/> diff --git a/r2/r2/templates/base.mobile b/r2/r2/templates/base.mobile index 5f26928b0..1a7ee94cc 100644 --- a/r2/r2/templates/base.mobile +++ b/r2/r2/templates/base.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/base.wired b/r2/r2/templates/base.wired index b2a8d3468..9895f7685 100644 --- a/r2/r2/templates/base.wired +++ b/r2/r2/templates/base.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/base.xml b/r2/r2/templates/base.xml index cb5ee00f0..8422b2df3 100644 --- a/r2/r2/templates/base.xml +++ b/r2/r2/templates/base.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/bookmarklets.html b/r2/r2/templates/bookmarklets.html index 06d127ef3..8e4dbbd7d 100644 --- a/r2/r2/templates/bookmarklets.html +++ b/r2/r2/templates/bookmarklets.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/button.html b/r2/r2/templates/button.html index 1bbe3bf4d..639bd0307 100644 --- a/r2/r2/templates/button.html +++ b/r2/r2/templates/button.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/buttondemopanel.html b/r2/r2/templates/buttondemopanel.html index 175916403..57cc7a21f 100644 --- a/r2/r2/templates/buttondemopanel.html +++ b/r2/r2/templates/buttondemopanel.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/buttonembed.js b/r2/r2/templates/buttonembed.js index 07086d009..489c633f1 100644 --- a/r2/r2/templates/buttonembed.js +++ b/r2/r2/templates/buttonembed.js @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/buttonlite.js b/r2/r2/templates/buttonlite.js index b18bc794c..a2050c081 100644 --- a/r2/r2/templates/buttonlite.js +++ b/r2/r2/templates/buttonlite.js @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/buttonnobody.html b/r2/r2/templates/buttonnobody.html index 3852f3a2d..2ca983aba 100644 --- a/r2/r2/templates/buttonnobody.html +++ b/r2/r2/templates/buttonnobody.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/buttontypes.html b/r2/r2/templates/buttontypes.html index 99345be6d..162ce520c 100644 --- a/r2/r2/templates/buttontypes.html +++ b/r2/r2/templates/buttontypes.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! @@ -231,7 +231,7 @@ <a class="arrow up${'mod' if dir==1 else ''}" id="up_${fullname}" %if c.user_is_loggedin and thing._fullname: - href="#" onclick="$(this).vote('', set_score); return false; " + href="#" onclick="$(this).vote('', set_score, event); return false;" %else: href="${submitlink}" target="_new" %endif @@ -244,7 +244,7 @@ </a> <a class="arrow down${'mod' if dir==-1 else ''}" id="down_${fullname}" %if c.user_is_loggedin and thing._fullname: - href="#" onclick="$(this).vote('', set_score); return false;" + href="#" onclick="$(this).vote('', set_score, event); return false;" %else: href="${submitlink}" target="_new" %endif diff --git a/r2/r2/templates/captcha.html b/r2/r2/templates/captcha.html index 4b400ff94..7c9794681 100644 --- a/r2/r2/templates/captcha.html +++ b/r2/r2/templates/captcha.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/clickgadget.html b/r2/r2/templates/clickgadget.html index 416a7d155..ee06c245f 100644 --- a/r2/r2/templates/clickgadget.html +++ b/r2/r2/templates/clickgadget.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="printablebuttons.html" import="simple_button" /> diff --git a/r2/r2/templates/cnameframe.html b/r2/r2/templates/cnameframe.html index e1cc199be..c30891f51 100644 --- a/r2/r2/templates/cnameframe.html +++ b/r2/r2/templates/cnameframe.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/comment.html b/r2/r2/templates/comment.html index 99e29b621..8aaf3c7da 100644 --- a/r2/r2/templates/comment.html +++ b/r2/r2/templates/comment.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/comment.htmllite b/r2/r2/templates/comment.htmllite index ab98ce76d..5ae4f0e8d 100644 --- a/r2/r2/templates/comment.htmllite +++ b/r2/r2/templates/comment.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/comment.mobile b/r2/r2/templates/comment.mobile index c1051bfac..fdb47d4d0 100644 --- a/r2/r2/templates/comment.mobile +++ b/r2/r2/templates/comment.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/comment.xml b/r2/r2/templates/comment.xml index 5d29cb58e..0299e8850 100644 --- a/r2/r2/templates/comment.xml +++ b/r2/r2/templates/comment.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/comment_skeleton.html b/r2/r2/templates/comment_skeleton.html index 250cc652a..eebf5c388 100644 --- a/r2/r2/templates/comment_skeleton.html +++ b/r2/r2/templates/comment_skeleton.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -43,6 +43,7 @@ ${self.tagline(True)} <%def name="entry()"> <% collapse = thing.collapsed %> + <div class="collapsed" ${(not collapse and "style='display:none'" or "")}> ${self.collapsed()} </div> diff --git a/r2/r2/templates/commentspanel.html b/r2/r2/templates/commentspanel.html index 2ae78946b..8b3de0f7b 100644 --- a/r2/r2/templates/commentspanel.html +++ b/r2/r2/templates/commentspanel.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/createsubreddit.html b/r2/r2/templates/createsubreddit.html index 2cd5f8b54..f911d64be 100644 --- a/r2/r2/templates/createsubreddit.html +++ b/r2/r2/templates/createsubreddit.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -287,7 +287,12 @@ function update_title(elem) { <%utils:line_field title="${_('sponsorship')}"> <ul class="upload"> <li> - <input type="text" name="sponsorship-name" + <input type="text" name="sponsorship-text" + value="${thing.site.sponsorship_text}" + /> + </li> + <li> + <input type="text" name="sponsorship-name" %if thing.site.sponsorship_name: value="${thing.site.sponsorship_name}" %else: diff --git a/r2/r2/templates/csserror.html b/r2/r2/templates/csserror.html index 98ef92408..a76e14443 100644 --- a/r2/r2/templates/csserror.html +++ b/r2/r2/templates/csserror.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <% error = thing.error %> diff --git a/r2/r2/templates/embed.html b/r2/r2/templates/embed.html index d7a4dfb38..88f469502 100644 --- a/r2/r2/templates/embed.html +++ b/r2/r2/templates/embed.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/errorpage.html b/r2/r2/templates/errorpage.html index 36b95b6eb..fd34ca24b 100644 --- a/r2/r2/templates/errorpage.html +++ b/r2/r2/templates/errorpage.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/feedback.html b/r2/r2/templates/feedback.html index 6adb8dc11..cabb291b6 100644 --- a/r2/r2/templates/feedback.html +++ b/r2/r2/templates/feedback.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/feedbackblurb.html b/r2/r2/templates/feedbackblurb.html new file mode 100644 index 000000000..5d10e0cfe --- /dev/null +++ b/r2/r2/templates/feedbackblurb.html @@ -0,0 +1,69 @@ +## The contents of this file are subject to the Common Public Attribution +## License Version 1.0. (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License at +## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public +## License Version 1.1, but Sections 14 and 15 have been added to cover use of +## software over a computer network and provide for limited attribution for the +## Original Developer. In addition, Exhibit A has been modified to be consistent +## with Exhibit B. +## +## Software distributed under the License is distributed on an "AS IS" basis, +## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +## the specific language governing rights and limitations under the License. +## +## The Original Code is Reddit. +## +## The Original Developer is the Initial Developer. The Initial Developer of +## the Original Code is CondeNet, Inc. +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 +## CondeNet, Inc. All Rights Reserved. +################################################################################ +<%! + from r2.lib.pages import Feedback + import random + %> + +<div class="feedback instructions"> + <h1>Request Help</h1> + + <p> + reddit is a community, and as such there are a lot of outlets to get help for what ails you. + </p> + + <dl> + <dt>Are your submissions not showing up? Subreddit marked as spam? Is the spam filter acting up?</dt> + <dd> + <a href="/message/compose?to=${g.admin_message_acct}">Send a private message to an admin.</a> (We really do want to help) + </dd> + <dt>Got a feature request?</dt> + <dd><a href="/r/ideasfortheadmins">Post it to our development community so the admins can see it</a>.</dd> + <dt>Got a bug report?</dt> + <dd><a href="http://code.reddit.com/">reddit is open source and you can submit a ticket (or even a patch!)</a></dd> + <dt>Are you a new moderator? Having trouble staying out of the fray? Need advice?</dt> + <dd><a href="/r/modhelp">There's a reddit for that</a>.</dd> + <dt>Want to advertise but don't know how?</dt> + <dd><a href="/ad_inq">The instructions are here</a>.</dd> + <dt>General questions? Need help?</dt> + <dd><a href="/r/help">There's a reddit for that, too</a>.</dd> + <dt>Crazy, or just feel like ranting at us?</dt> + <% r = random.randint(0,2) %> + %if r == 0: + <dd><a href="/r/null">Here is a soothing place to get your aggressions out</a>.</dd> + %elif r == 1: + <dd><a href="/important" onclick="return false">Just click here until you feel better (like a stress ball)</a>.</dd> + %elif r == 2: + <dd><a href="about:blank" target="_blank">There are always other options</a>.</dd> + %endif + </dl> +<p> + Or, if none of these solve your problem, + <a href="#" onclick="$('#feedback-form').slideDown(function(){$(this).find('input[type=text]:first').focus();}); return false;"> + send a message to our feedback. + </a> +</p> + + <div id="feedback-form" style="display:none"> + ${Feedback(title=_("send reddit feedback"), action = "feedback")} + </div> +</div> diff --git a/r2/r2/templates/frame.html b/r2/r2/templates/frame.html index fc3403123..9d54d252c 100644 --- a/r2/r2/templates/frame.html +++ b/r2/r2/templates/frame.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <% diff --git a/r2/r2/templates/frametoolbar.html b/r2/r2/templates/frametoolbar.html index ef9213cdf..255e9972c 100644 --- a/r2/r2/templates/frametoolbar.html +++ b/r2/r2/templates/frametoolbar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! @@ -173,7 +173,7 @@ title="${_('vote %(direction)s') % dict(direction=direction)}" %if thing.user_is_loggedin: href="javascript:void(0);" - onclick="$(this).vote('${thing.votehash}')" + onclick="$(this).vote('${thing.votehash}', null, event)" %else: href="${thing.loginurl}" target="_top" diff --git a/r2/r2/templates/gettextheader.html b/r2/r2/templates/gettextheader.html index 6adeaaf8f..6b6beed6c 100644 --- a/r2/r2/templates/gettextheader.html +++ b/r2/r2/templates/gettextheader.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/headerbar.mobile b/r2/r2/templates/headerbar.mobile index 4ec96f061..f555afeef 100644 --- a/r2/r2/templates/headerbar.mobile +++ b/r2/r2/templates/headerbar.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/headerbar.xml b/r2/r2/templates/headerbar.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/headerbar.xml +++ b/r2/r2/templates/headerbar.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/helppage.html b/r2/r2/templates/helppage.html index b16ef765a..99977e20c 100644 --- a/r2/r2/templates/helppage.html +++ b/r2/r2/templates/helppage.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/infobar.html b/r2/r2/templates/infobar.html index d2bc67494..f2a69ef95 100644 --- a/r2/r2/templates/infobar.html +++ b/r2/r2/templates/infobar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/infobar.htmllite b/r2/r2/templates/infobar.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/infobar.htmllite +++ b/r2/r2/templates/infobar.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/infobar.mobile b/r2/r2/templates/infobar.mobile index afd7d0880..41730fd4e 100644 --- a/r2/r2/templates/infobar.mobile +++ b/r2/r2/templates/infobar.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/infobar.wired b/r2/r2/templates/infobar.wired index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/infobar.wired +++ b/r2/r2/templates/infobar.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/infobar.xml b/r2/r2/templates/infobar.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/infobar.xml +++ b/r2/r2/templates/infobar.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/innertoolbarframe.html b/r2/r2/templates/innertoolbarframe.html index 90e2fd8ec..a7a806e74 100644 --- a/r2/r2/templates/innertoolbarframe.html +++ b/r2/r2/templates/innertoolbarframe.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/jquery.reddit.js b/r2/r2/templates/jquery.reddit.js index 45de66620..9730f512f 100644 --- a/r2/r2/templates/jquery.reddit.js +++ b/r2/r2/templates/jquery.reddit.js @@ -10,4 +10,4 @@ jQuery.log = function(message) { console.debug(message); else alert(message); -}; \ No newline at end of file +}; diff --git a/r2/r2/templates/link.html b/r2/r2/templates/link.html index 6e9829ed5..da1e37fc0 100644 --- a/r2/r2/templates/link.html +++ b/r2/r2/templates/link.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -65,8 +65,10 @@ <%def name="bottom_buttons()"> <ul class="flat-list buttons"> %if thing.nsfw: - <li> - <acronym title="Not Safe for Work">NSFW</acronym> + <li class="rounded nsfw-stamp"> + <acronym title="${_('Adult content: Not Safe For Work')}"> + ${_("NSFW")} + </acronym> </li> %endif ${self.buttons()} @@ -156,7 +158,7 @@ ${parent.thing_css_class(what)} ${"over18" if thing.over_18 else ""} <div class="score dislikes">•</div> %else: ${self.score(thing, thing.likes, tag='div')} - %endif + %endif ${self.arrow(thing, 0, thing.likes == False)} </div> ${self.thumbnail()} diff --git a/r2/r2/templates/link.htmllite b/r2/r2/templates/link.htmllite index 0722e4021..a64d40caa 100644 --- a/r2/r2/templates/link.htmllite +++ b/r2/r2/templates/link.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="utils.html" import="optionalstyle"/> diff --git a/r2/r2/templates/link.mobile b/r2/r2/templates/link.mobile index c0e3c1bd5..981e41a70 100644 --- a/r2/r2/templates/link.mobile +++ b/r2/r2/templates/link.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/link.wired b/r2/r2/templates/link.wired index 70a2c7ef4..82871cae6 100644 --- a/r2/r2/templates/link.wired +++ b/r2/r2/templates/link.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/link.xml b/r2/r2/templates/link.xml index a89988660..9721f88f0 100644 --- a/r2/r2/templates/link.xml +++ b/r2/r2/templates/link.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/linkinfobar.html b/r2/r2/templates/linkinfobar.html index d7972d1ef..4959f793a 100644 --- a/r2/r2/templates/linkinfobar.html +++ b/r2/r2/templates/linkinfobar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/linkpromoteinfobar.html b/r2/r2/templates/linkpromoteinfobar.html index 2a2b80a61..b645a68d9 100644 --- a/r2/r2/templates/linkpromoteinfobar.html +++ b/r2/r2/templates/linkpromoteinfobar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/listing.html b/r2/r2/templates/listing.html index 26d321a98..95359d51e 100644 --- a/r2/r2/templates/listing.html +++ b/r2/r2/templates/listing.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/listing.htmllite b/r2/r2/templates/listing.htmllite index 13697f9cc..949211684 100644 --- a/r2/r2/templates/listing.htmllite +++ b/r2/r2/templates/listing.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/listing.mobile b/r2/r2/templates/listing.mobile index b5fbda605..14eb743cb 100644 --- a/r2/r2/templates/listing.mobile +++ b/r2/r2/templates/listing.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/listing.wired b/r2/r2/templates/listing.wired index b5a499084..6e2c31a64 100644 --- a/r2/r2/templates/listing.wired +++ b/r2/r2/templates/listing.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/listing.xml b/r2/r2/templates/listing.xml index 8728d0505..dd522284f 100644 --- a/r2/r2/templates/listing.xml +++ b/r2/r2/templates/listing.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ %for a in thing.things: diff --git a/r2/r2/templates/login.html b/r2/r2/templates/login.html index 0a281de97..8faae8512 100644 --- a/r2/r2/templates/login.html +++ b/r2/r2/templates/login.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/login.mobile b/r2/r2/templates/login.mobile index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/login.mobile +++ b/r2/r2/templates/login.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/loginformwide.html b/r2/r2/templates/loginformwide.html index 9e268a6a2..d6a469e07 100644 --- a/r2/r2/templates/loginformwide.html +++ b/r2/r2/templates/loginformwide.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/mail_opt.email b/r2/r2/templates/mail_opt.email index 6679ffd66..1f79045d0 100644 --- a/r2/r2/templates/mail_opt.email +++ b/r2/r2/templates/mail_opt.email @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ %if thing.leave: diff --git a/r2/r2/templates/mediaembed.html b/r2/r2/templates/mediaembed.html index a2fd40292..8d0aeed52 100644 --- a/r2/r2/templates/mediaembed.html +++ b/r2/r2/templates/mediaembed.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/mediaembedbody.html b/r2/r2/templates/mediaembedbody.html index 5c2c73e77..51554a8c9 100644 --- a/r2/r2/templates/mediaembedbody.html +++ b/r2/r2/templates/mediaembedbody.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> diff --git a/r2/r2/templates/menuarea.html b/r2/r2/templates/menuarea.html index 53d742234..08e8e2ca3 100644 --- a/r2/r2/templates/menuarea.html +++ b/r2/r2/templates/menuarea.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/menuarea.htmllite b/r2/r2/templates/menuarea.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/menuarea.htmllite +++ b/r2/r2/templates/menuarea.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/menuarea.mobile b/r2/r2/templates/menuarea.mobile index afd7d0880..41730fd4e 100644 --- a/r2/r2/templates/menuarea.mobile +++ b/r2/r2/templates/menuarea.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/menuarea.xml b/r2/r2/templates/menuarea.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/menuarea.xml +++ b/r2/r2/templates/menuarea.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/message.html b/r2/r2/templates/message.html index 13e5a40cf..ab9d14c25 100644 --- a/r2/r2/templates/message.html +++ b/r2/r2/templates/message.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -31,23 +31,33 @@ <%def name="midcol(cls='')"> %if thing.was_comment and not thing._spam: ${parent.midcol(display=True, cls = cls)} + %else: + <div class="midcol" style='display:none'></div> %endif </%def> <%def name="thing_css_class(what)" buffered="True"> -${parent.thing_css_class(what)} ${"new" if thing.new else ""} ${"was-comment" if thing.was_comment else ""} ${"recipient" if thing.recipient else ""} +${parent.thing_css_class(what)} ${"new" if thing.new else ""} ${"was-comment" if thing.was_comment else ""} ${"recipient" if thing.recipient else ""} ${"message-reply" if getattr(thing, "is_child", False) else ""} ${"message-parent" if getattr(thing, "is_parent", False) else ""} ${"focal" if getattr(thing, "focal", False) else ""} </%def> <%def name="tagline(collapse=False)"> + <a href="#" class="expand" + %if collapse: + onclick="return showcomment(this)"> + %else: + onclick="return hidecomment(this)"> + %endif + [${_("+") if collapse else _("-")}]  + </a> <span class="head"> <% taglinetext = '' - if c.msg_location == "sent" or not c.msg_location: - taglinetext = _("to %(dest)s sent %(when)s ago") - elif c.msg_location == "admin" and c.user_is_admin: - taglinetext = _("to %(dest)s from %(author)s sent %(when)s ago") - else: + if thing.to_id == c.user._id: taglinetext = _("from %(author)s sent %(when)s ago") + elif thing.author_id == c.user._id: + taglinetext = _("to %(dest)s sent %(when)s ago") + else: + taglinetext = _("to %(dest)s from %(author)s sent %(when)s ago") taglinetext = taglinetext.replace(' ', ' ') author = WrappedUser(thing.author, thing.attribs, thing).render() @@ -59,26 +69,46 @@ ${parent.thing_css_class(what)} ${"new" if thing.new else ""} ${"was-comment" if %if c.user_is_admin: ${self.admintagline()} %endif - </p> +</%def> + +<%def name="subject()"> <p class="subject"> + %if getattr(thing, "is_parent", False): + <span class="correspondent rounded"> + <% + corr = thing.author if thing.recipient else thing.to + %> + ${WrappedUser(corr)} + </span> + %endif ${thing.subject} %if thing.was_comment: <a href="${thing.link_permalink}" class="title">${thing.link_title}</a> - %if hasattr(thing, "parent"): - </p> + %elif getattr(thing, "is_parent", False): + <br/> + <a class="expand-btn" href="#" onclick="return show_all_messages(this)"> + ${_("expand all")} + </a> + <a class="expand-btn" href="#" onclick="return hide_all_messages(this)"> + ${_("collapse all")} + </a> + %endif + </p> +</%def> + +<%def name="ParentDiv()"> +${self.subject()} +</%def> + +<%def name="commentBody()"> + %if thing.was_comment and hasattr(thing, "parent"): <p> <a href="#" class="parent-link" onclick="return fetch_parent(this, '${thing.parent_permalink}/.json', '${thing.parent}')"> ${_("show parent")} </a> - %endif - %endif -</%def> - -<%def name="ParentDiv()"> -</%def> - -<%def name="commentBody()"> + </p> + %endif ${unsafe(safemarkdown(thing.body))} </%def> @@ -87,14 +117,5 @@ ${unsafe(safemarkdown(thing.body))} </%def> <%def name="entry()"> -<div class="uncollapsed ${thing.message_style}"> - <p class="tagline"> - ${self.tagline()} - </p> - <div class="body">${self.commentBody()} - </div> - <ul class="flat-list buttons" ${(collapse and "style='display:none'" or '')}> - ${self.buttons()} - </ul> -</div> + ${parent.entry()} </%def> diff --git a/r2/r2/templates/message.xml b/r2/r2/templates/message.xml index 9eb4d0dec..920be6446 100644 --- a/r2/r2/templates/message.xml +++ b/r2/r2/templates/message.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/messagecompose.html b/r2/r2/templates/messagecompose.html index 72f414bb4..846f5cf74 100644 --- a/r2/r2/templates/messagecompose.html +++ b/r2/r2/templates/messagecompose.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morechildren.html b/r2/r2/templates/morechildren.html index 71d582a20..a1b78c3e5 100644 --- a/r2/r2/templates/morechildren.html +++ b/r2/r2/templates/morechildren.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morechildren.htmllite b/r2/r2/templates/morechildren.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/morechildren.htmllite +++ b/r2/r2/templates/morechildren.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morechildren.mobile b/r2/r2/templates/morechildren.mobile index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/morechildren.mobile +++ b/r2/r2/templates/morechildren.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morechildren.xml b/r2/r2/templates/morechildren.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/morechildren.xml +++ b/r2/r2/templates/morechildren.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/moremessages.html b/r2/r2/templates/moremessages.html new file mode 100644 index 000000000..d627ba41c --- /dev/null +++ b/r2/r2/templates/moremessages.html @@ -0,0 +1,51 @@ +## The contents of this file are subject to the Common Public Attribution +## License Version 1.0. (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License at +## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public +## License Version 1.1, but Sections 14 and 15 have been added to cover use of +## software over a computer network and provide for limited attribution for the +## Original Developer. In addition, Exhibit A has been modified to be consistent +## with Exhibit B. +## +## Software distributed under the License is distributed on an "AS IS" basis, +## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +## the specific language governing rights and limitations under the License. +## +## The Original Code is Reddit. +## +## The Original Developer is the Initial Developer. The Initial Developer of +## the Original Code is CondeNet, Inc. +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 +## CondeNet, Inc. All Rights Reserved. +################################################################################ + +<%inherit file="message.html"/> + +<%def name="thing_css_class(what)" buffered="True"> +message ${parent.thing_css_class(what)} message-parent +</%def> + +<%def name="commentBody()"> +</%def> + +<%def name="tagline(collapse=False)"> +<span class="head"> + <a style="font-size: smaller; font-weight: bold" + id="more_${thing._fullname}" href="javascript:void()" + onclick="return moremessages(this)" + > + ${_("[+] load the full conversation.")} + </a> +</span> +</%def> + +<%def name="arrows()"> +</%def> + +<%def name="buttons()"> +</%def> + +<%def name="midcol(cls = '')"> +</%def> + diff --git a/r2/r2/templates/morerecursion.html b/r2/r2/templates/morerecursion.html index 754ae32a0..d390667b0 100644 --- a/r2/r2/templates/morerecursion.html +++ b/r2/r2/templates/morerecursion.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morerecursion.htmllite b/r2/r2/templates/morerecursion.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/morerecursion.htmllite +++ b/r2/r2/templates/morerecursion.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morerecursion.mobile b/r2/r2/templates/morerecursion.mobile index afd7d0880..41730fd4e 100644 --- a/r2/r2/templates/morerecursion.mobile +++ b/r2/r2/templates/morerecursion.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/morerecursion.xml b/r2/r2/templates/morerecursion.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/morerecursion.xml +++ b/r2/r2/templates/morerecursion.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/navbutton.html b/r2/r2/templates/navbutton.html index 266212a3c..8c5cbb957 100644 --- a/r2/r2/templates/navbutton.html +++ b/r2/r2/templates/navbutton.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/navbutton.mobile b/r2/r2/templates/navbutton.mobile index 6f7acefec..cd3af7e0d 100644 --- a/r2/r2/templates/navbutton.mobile +++ b/r2/r2/templates/navbutton.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/navmenu.html b/r2/r2/templates/navmenu.html index effb589e2..9b5525858 100644 --- a/r2/r2/templates/navmenu.html +++ b/r2/r2/templates/navmenu.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/navmenu.htmllite b/r2/r2/templates/navmenu.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/navmenu.htmllite +++ b/r2/r2/templates/navmenu.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/navmenu.mobile b/r2/r2/templates/navmenu.mobile index fa543a804..80d3c8c11 100644 --- a/r2/r2/templates/navmenu.mobile +++ b/r2/r2/templates/navmenu.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/newlink.html b/r2/r2/templates/newlink.html index c0ed709a2..7ced7f68b 100644 --- a/r2/r2/templates/newlink.html +++ b/r2/r2/templates/newlink.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -69,6 +69,7 @@ ${thing.formtabs_menu} <div class="spacer"> <%utils:round_field title="${_('text')}", description="${_('(optional)')}" id="text-field"> <input name="kind" value="self" type="hidden"/> + ${UserText(None, have_form = False, creating = True)} </%utils:round_field> </div> diff --git a/r2/r2/templates/optout.html b/r2/r2/templates/optout.html index 17b888383..2ff4cc4da 100644 --- a/r2/r2/templates/optout.html +++ b/r2/r2/templates/optout.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of the ## Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ############################################################################### <div class="opt-form"> diff --git a/r2/r2/templates/organiclisting.html b/r2/r2/templates/organiclisting.html index fcaf69e1f..90579bb1f 100644 --- a/r2/r2/templates/organiclisting.html +++ b/r2/r2/templates/organiclisting.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/over18.html b/r2/r2/templates/over18.html index 714a4c488..bf7db753d 100644 --- a/r2/r2/templates/over18.html +++ b/r2/r2/templates/over18.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/page_down.html b/r2/r2/templates/page_down.html index f31452dbe..cdbd4707e 100644 --- a/r2/r2/templates/page_down.html +++ b/r2/r2/templates/page_down.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/pagenamenav.html b/r2/r2/templates/pagenamenav.html index 8e4ad4239..29876c190 100644 --- a/r2/r2/templates/pagenamenav.html +++ b/r2/r2/templates/pagenamenav.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/pagenamenav.mobile b/r2/r2/templates/pagenamenav.mobile index 11c74af1c..184d3f7d9 100644 --- a/r2/r2/templates/pagenamenav.mobile +++ b/r2/r2/templates/pagenamenav.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/panestack.html b/r2/r2/templates/panestack.html index 12edc278c..a0cbf7335 100644 --- a/r2/r2/templates/panestack.html +++ b/r2/r2/templates/panestack.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/panestack.htmllite b/r2/r2/templates/panestack.htmllite index e5ebbad69..9673a0860 100644 --- a/r2/r2/templates/panestack.htmllite +++ b/r2/r2/templates/panestack.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/panestack.mobile b/r2/r2/templates/panestack.mobile index e5ebbad69..9673a0860 100644 --- a/r2/r2/templates/panestack.mobile +++ b/r2/r2/templates/panestack.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/panestack.wired b/r2/r2/templates/panestack.wired index a167859c6..18c73729b 100644 --- a/r2/r2/templates/panestack.wired +++ b/r2/r2/templates/panestack.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/panestack.xml b/r2/r2/templates/panestack.xml index e5ebbad69..9673a0860 100644 --- a/r2/r2/templates/panestack.xml +++ b/r2/r2/templates/panestack.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/password.html b/r2/r2/templates/password.html index 653563426..6977978bc 100644 --- a/r2/r2/templates/password.html +++ b/r2/r2/templates/password.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/passwordreset.email b/r2/r2/templates/passwordreset.email index b5b5a9d48..44c901b05 100644 --- a/r2/r2/templates/passwordreset.email +++ b/r2/r2/templates/passwordreset.email @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/paymentform.html b/r2/r2/templates/paymentform.html index 92d232bd4..91ee0efbe 100644 --- a/r2/r2/templates/paymentform.html +++ b/r2/r2/templates/paymentform.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/permalinkmessage.html b/r2/r2/templates/permalinkmessage.html index 44d42aa23..8cc1821c5 100644 --- a/r2/r2/templates/permalinkmessage.html +++ b/r2/r2/templates/permalinkmessage.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/permalinkmessage.mobile b/r2/r2/templates/permalinkmessage.mobile index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/permalinkmessage.mobile +++ b/r2/r2/templates/permalinkmessage.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/permalinkmessage.xml b/r2/r2/templates/permalinkmessage.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/permalinkmessage.xml +++ b/r2/r2/templates/permalinkmessage.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/prefdelete.html b/r2/r2/templates/prefdelete.html index 5d41d8ffc..7f7581694 100644 --- a/r2/r2/templates/prefdelete.html +++ b/r2/r2/templates/prefdelete.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/prefoptions.html b/r2/r2/templates/prefoptions.html index 5d1370f7d..ca059d445 100644 --- a/r2/r2/templates/prefoptions.html +++ b/r2/r2/templates/prefoptions.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! @@ -91,7 +91,7 @@ ${language_tool(allow_blank = False, show_regions = True, default_lang = c.user.pref_lang)} <span class="little gray hover">(*) ${_("incomplete")} - ${plain_link(_("volunteer to translate"), "/feedback")}</span> + ${plain_link(_("volunteer to translate"), "/i18n")}</span> </td> </tr> <tr> @@ -177,6 +177,20 @@ <tr> <th>${_("messaging options")}</th> <td class="prefright"> + ${checkbox(_("show message conversations in the inbox"), \ + "threaded_messages")} + <span class="little gray"> + ${_("(only applies when you go to the 'messages' panel)")} + </span> + <br/> + %if c.user.pref_threaded_messages: + ${checkbox(_("collapse messages after I've read them"), \ + "collapse_read_messages")} + <span class="little gray"> + ${_("(otherwise, you'll have to collapse them yourself)")} + </span> + <br/> + %endif ${checkbox(_("mark messages as read when I open my inbox"), \ "mark_messages_read")} <span class="little gray"> diff --git a/r2/r2/templates/prefupdate.html b/r2/r2/templates/prefupdate.html index a00b48b7c..2f6a281af 100644 --- a/r2/r2/templates/prefupdate.html +++ b/r2/r2/templates/prefupdate.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/printable.html b/r2/r2/templates/printable.html index c490836cc..d56571812 100644 --- a/r2/r2/templates/printable.html +++ b/r2/r2/templates/printable.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -112,6 +112,7 @@ thing id-${what._fullname} <%def name="Child(display=True)"> <div class="child" ${(not display and "style='display:none'" or "")}> + ${thing.childlisting} </div> </%def> @@ -124,7 +125,7 @@ thing id-${what._fullname} %> <div class="arrow ${_class}" %if c.user_is_loggedin: - onclick="$(this).vote('${thing.votehash}')" + onclick="$(this).vote('${thing.votehash}', null, event)" %else: onclick="showcover(true, 'vote_${fullname}')" %endif diff --git a/r2/r2/templates/printable.htmllite b/r2/r2/templates/printable.htmllite index 26c4a3ca2..61ed2b9f6 100644 --- a/r2/r2/templates/printable.htmllite +++ b/r2/r2/templates/printable.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="utils.html" import="optionalstyle"/> diff --git a/r2/r2/templates/printable.mobile b/r2/r2/templates/printable.mobile index 8885aa224..6bdc952bc 100644 --- a/r2/r2/templates/printable.mobile +++ b/r2/r2/templates/printable.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/printablebuttons.html b/r2/r2/templates/printablebuttons.html index 50b5c585c..d2db806e1 100644 --- a/r2/r2/templates/printablebuttons.html +++ b/r2/r2/templates/printablebuttons.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="utils.html" import="plain_link" /> @@ -223,19 +223,23 @@ <li> ${self.bylink_button(_("context"), thing.permalink + "?context=3")} </li> + %else: + <li class="first"> + ${self.bylink_button(_("permalink"), thing.permalink)} + </li> %endif - ${self.banbuttons()} %if thing.recipient: - <li class="unread"> + ${self.banbuttons()} + <li class="unread"> ${self.state_button("unread", _("mark unread"), \ "return change_state(this, 'unread_message', unread_thing, true);", \ _("unread"))} - </li> - %endif - %if thing.can_reply: - <li> - ${self.simple_button(_("reply {verb}"), "reply")} </li> + %if thing.can_reply: + <li> + ${self.simple_button(_("reply {verb}"), "reply")} + </li> + %endif %endif </%def> diff --git a/r2/r2/templates/profilebar.html b/r2/r2/templates/profilebar.html index 7133077e7..2155e03ce 100644 --- a/r2/r2/templates/profilebar.html +++ b/r2/r2/templates/profilebar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/profiling.html b/r2/r2/templates/profiling.html index 1a2a886d4..4f672373f 100644 --- a/r2/r2/templates/profiling.html +++ b/r2/r2/templates/profiling.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/promo_email.email b/r2/r2/templates/promo_email.email index 2f761059d..1195afe7e 100644 --- a/r2/r2/templates/promo_email.email +++ b/r2/r2/templates/promo_email.email @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! @@ -115,4 +115,4 @@ The Reddit Team selfservicepromotion@reddit.com _____ -http://www.reddit.com/help/selfservicepromotion \ No newline at end of file +http://www.reddit.com/help/selfservicepromotion diff --git a/r2/r2/templates/promote_graph.html b/r2/r2/templates/promote_graph.html index a640c5e6d..09b3c9c54 100644 --- a/r2/r2/templates/promote_graph.html +++ b/r2/r2/templates/promote_graph.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/promotedlink.html b/r2/r2/templates/promotedlink.html index 7e7e3d3b6..b95cd8311 100644 --- a/r2/r2/templates/promotedlink.html +++ b/r2/r2/templates/promotedlink.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/promotedtraffic.html b/r2/r2/templates/promotedtraffic.html index e2bcc6413..e9ce98d9e 100644 --- a/r2/r2/templates/promotedtraffic.html +++ b/r2/r2/templates/promotedtraffic.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/promotelinkform.html b/r2/r2/templates/promotelinkform.html index e5eb936bf..85ac4bf29 100644 --- a/r2/r2/templates/promotelinkform.html +++ b/r2/r2/templates/promotelinkform.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! @@ -24,6 +24,7 @@ from r2.lib.media import thumbnail_url from r2.lib.template_helpers import static from r2.lib.promote import STATUS + from r2.models import Account %> <%namespace file="utils.html" import="error_field, checkbox, plain_link, image_upload" /> @@ -403,8 +404,13 @@ %endif <form id="promotion-history" method="post" action="/post/promote_note" - onsubmit="return post_form(this, 'promote_note')"> + onsubmit="post_form(this, 'promote_note'); $('#promote_note').val('');return false;"> <%utils:line_field title="${_('promotion history')}"> + <div style="font-size:smaller; margin-bottom: 10px;"> + To check with <a href="https://account.authorize.net/"> + authorize.net</a>, use CustomerID + <b>t${Account._type_id}_${to36(thing.link.author_id)}</b> when searching by batch. + </div> <input type="hidden" name="link" value="${thing.link._fullname}"/> <label for="promote_note">add note:</label> <input id="promote_note" name="note" value="" type="text" size="40" /> diff --git a/r2/r2/templates/reddit.html b/r2/r2/templates/reddit.html index 52fc86aba..50b0f4b1b 100644 --- a/r2/r2/templates/reddit.html +++ b/r2/r2/templates/reddit.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/reddit.htmllite b/r2/r2/templates/reddit.htmllite index 55ce38545..c21bade24 100644 --- a/r2/r2/templates/reddit.htmllite +++ b/r2/r2/templates/reddit.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/reddit.js b/r2/r2/templates/reddit.js index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/reddit.js +++ b/r2/r2/templates/reddit.js @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/reddit.mobile b/r2/r2/templates/reddit.mobile index 429f3419f..020f9788e 100644 --- a/r2/r2/templates/reddit.mobile +++ b/r2/r2/templates/reddit.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/reddit.wired b/r2/r2/templates/reddit.wired index 2a23cda28..09bb58ca9 100644 --- a/r2/r2/templates/reddit.wired +++ b/r2/r2/templates/reddit.wired @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/reddit.xml b/r2/r2/templates/reddit.xml index 904f40975..2a84ede20 100644 --- a/r2/r2/templates/reddit.xml +++ b/r2/r2/templates/reddit.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/redditfooter.html b/r2/r2/templates/redditfooter.html index d01bfd81f..64fa09378 100644 --- a/r2/r2/templates/redditfooter.html +++ b/r2/r2/templates/redditfooter.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/redditheader.html b/r2/r2/templates/redditheader.html index 349e5938e..27f1b35db 100644 --- a/r2/r2/templates/redditheader.html +++ b/r2/r2/templates/redditheader.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/redditheader.mobile b/r2/r2/templates/redditheader.mobile index 42585a75f..00cbeda9c 100644 --- a/r2/r2/templates/redditheader.mobile +++ b/r2/r2/templates/redditheader.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/redditmin.html b/r2/r2/templates/redditmin.html index bb1e6e4d9..bac37400c 100644 --- a/r2/r2/templates/redditmin.html +++ b/r2/r2/templates/redditmin.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ############ <%inherit file="reddit.html"/> diff --git a/r2/r2/templates/reddittraffic.html b/r2/r2/templates/reddittraffic.html index 91f650afc..158f04ac7 100644 --- a/r2/r2/templates/reddittraffic.html +++ b/r2/r2/templates/reddittraffic.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/resetpassword.html b/r2/r2/templates/resetpassword.html index b7f4e5d3e..8750e803d 100644 --- a/r2/r2/templates/resetpassword.html +++ b/r2/r2/templates/resetpassword.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/searchbar.html b/r2/r2/templates/searchbar.html index f824550c6..44a184190 100644 --- a/r2/r2/templates/searchbar.html +++ b/r2/r2/templates/searchbar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -34,7 +34,7 @@ search_params = thing.search_params)} </div> - %if thing.prev_search: + %if thing.prev_search and thing.elapsed_time > 0: <div class="summary"> <% label = _("about %(num)d results in %(second)s.") diff --git a/r2/r2/templates/searchbar.htmllite b/r2/r2/templates/searchbar.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/searchbar.htmllite +++ b/r2/r2/templates/searchbar.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/searchbar.mobile b/r2/r2/templates/searchbar.mobile index afd7d0880..41730fd4e 100644 --- a/r2/r2/templates/searchbar.mobile +++ b/r2/r2/templates/searchbar.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/searchbar.xml b/r2/r2/templates/searchbar.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/searchbar.xml +++ b/r2/r2/templates/searchbar.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/searchfail.html b/r2/r2/templates/searchfail.html new file mode 100644 index 000000000..ade747cf8 --- /dev/null +++ b/r2/r2/templates/searchfail.html @@ -0,0 +1,42 @@ +## The contents of this file are subject to the Common Public Attribution +## License Version 1.0. (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License at +## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public +## License Version 1.1, but Sections 14 and 15 have been added to cover use of +## software over a computer network and provide for limited attribution for the +## Original Developer. In addition, Exhibit A has been modified to be consistent +## with Exhibit B. +## +## Software distributed under the License is distributed on an "AS IS" basis, +## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +## the specific language governing rights and limitations under the License. +## +## The Original Code is Reddit. +## +## The Original Developer is the Initial Developer. The Initial Developer of +## the Original Code is CondeNet, Inc. +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 +## CondeNet, Inc. All Rights Reserved. +################################################################################ + +<script type="text/javascript"> + var searchfail_timeout = new Date(); + + function tryagain() { + elapsed = new Date() - searchfail_timeout; + + seconds = elapsed / 1000; + + if (seconds < 10) { + alert("Please don't pound our servers! " + + "Give them a few minutes to cool off."); + } else { + window.location.reload(); + } + } +</script> + +<div class="searchfail"> + ${unsafe(thing.errmsg)} +</div> diff --git a/r2/r2/templates/searchfail.htmllite b/r2/r2/templates/searchfail.htmllite new file mode 100644 index 000000000..e69de29bb diff --git a/r2/r2/templates/searchfail.mobile b/r2/r2/templates/searchfail.mobile new file mode 100644 index 000000000..e69de29bb diff --git a/r2/r2/templates/searchfail.xml b/r2/r2/templates/searchfail.xml new file mode 100644 index 000000000..e69de29bb diff --git a/r2/r2/templates/searchform.html b/r2/r2/templates/searchform.html index 4f7c31f1b..e034eb181 100644 --- a/r2/r2/templates/searchform.html +++ b/r2/r2/templates/searchform.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/selfserveblurb.html b/r2/r2/templates/selfserveblurb.html index bb0119436..04599eae6 100644 --- a/r2/r2/templates/selfserveblurb.html +++ b/r2/r2/templates/selfserveblurb.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/selftext.html b/r2/r2/templates/selftext.html index 08e05d831..c3c0173c9 100644 --- a/r2/r2/templates/selftext.html +++ b/r2/r2/templates/selftext.html @@ -6,16 +6,16 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## +## ## All portions of the code written by CondeNet are Copyright (c) 2006-2008 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/share.email b/r2/r2/templates/share.email index 522e43f87..45507af99 100644 --- a/r2/r2/templates/share.email +++ b/r2/r2/templates/share.email @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! from r2.lib.template_helpers import get_domain%> diff --git a/r2/r2/templates/sidebox.html b/r2/r2/templates/sidebox.html index 01ed17f13..c89d7ea14 100644 --- a/r2/r2/templates/sidebox.html +++ b/r2/r2/templates/sidebox.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/sidecontentbox.html b/r2/r2/templates/sidecontentbox.html index 6f4d19100..3b0f60425 100644 --- a/r2/r2/templates/sidecontentbox.html +++ b/r2/r2/templates/sidecontentbox.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/sponsorshipbox.html b/r2/r2/templates/sponsorshipbox.html index c55736369..d69679f91 100644 --- a/r2/r2/templates/sponsorshipbox.html +++ b/r2/r2/templates/sponsorshipbox.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -25,7 +25,7 @@ name = c.site._fullname %> <div class="thing sponsorshipbox id-${name}"> - <span>${_("this reddit is sponsored by")}</span> + <span>${c.site.sponsorship_text}</span> <div> <a class="title" href="${c.site.sponsorship_url}"> <img alt="sponsor" src="${c.site.sponsorship_img}" /> diff --git a/r2/r2/templates/starkcomment.html b/r2/r2/templates/starkcomment.html index 2f9ca2ab3..f343dfb00 100644 --- a/r2/r2/templates/starkcomment.html +++ b/r2/r2/templates/starkcomment.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%inherit file="comment.html"/> diff --git a/r2/r2/templates/subreddit.html b/r2/r2/templates/subreddit.html index 52e0d04e7..f877198b3 100644 --- a/r2/r2/templates/subreddit.html +++ b/r2/r2/templates/subreddit.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/subreddit.mobile b/r2/r2/templates/subreddit.mobile index 39cce184b..b6321f3b4 100644 --- a/r2/r2/templates/subreddit.mobile +++ b/r2/r2/templates/subreddit.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/subreddit.xml b/r2/r2/templates/subreddit.xml index befb0b13c..fa7578d4d 100644 --- a/r2/r2/templates/subreddit.xml +++ b/r2/r2/templates/subreddit.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/subredditinfobar.html b/r2/r2/templates/subredditinfobar.html index 68846fc6a..29cdd6639 100644 --- a/r2/r2/templates/subredditinfobar.html +++ b/r2/r2/templates/subredditinfobar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/subredditstylesheet.html b/r2/r2/templates/subredditstylesheet.html index bd59788eb..3ef37dc2b 100644 --- a/r2/r2/templates/subredditstylesheet.html +++ b/r2/r2/templates/subredditstylesheet.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/subreddittopbar.html b/r2/r2/templates/subreddittopbar.html index cdc7ce213..a9b8e7fde 100644 --- a/r2/r2/templates/subreddittopbar.html +++ b/r2/r2/templates/subreddittopbar.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/subscriptionbox.html b/r2/r2/templates/subscriptionbox.html index 3c742a182..3ec7f3c8a 100644 --- a/r2/r2/templates/subscriptionbox.html +++ b/r2/r2/templates/subscriptionbox.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%namespace file="utils.html" import="plain_link"/> diff --git a/r2/r2/templates/takedownpane.html b/r2/r2/templates/takedownpane.html index 30112e3af..8a125fafa 100644 --- a/r2/r2/templates/takedownpane.html +++ b/r2/r2/templates/takedownpane.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/translatedstring.html b/r2/r2/templates/translatedstring.html index 5ff89bc20..83a3363d4 100644 --- a/r2/r2/templates/translatedstring.html +++ b/r2/r2/templates/translatedstring.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/translation.html b/r2/r2/templates/translation.html index df45a1302..b2d3c83a0 100644 --- a/r2/r2/templates/translation.html +++ b/r2/r2/templates/translation.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/translator_message.html b/r2/r2/templates/translator_message.html new file mode 100644 index 000000000..2610bacd9 --- /dev/null +++ b/r2/r2/templates/translator_message.html @@ -0,0 +1,47 @@ +## The contents of this file are subject to the Common Public Attribution +## License Version 1.0. (the "License"); you may not use this file except in +## compliance with the License. You may obtain a copy of the License at +## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public +## License Version 1.1, but Sections 14 and 15 have been added to cover use of +## software over a computer network and provide for limited attribution for the +## Original Developer. In addition, Exhibit A has been modified to be consistent +## with Exhibit B. +## +## Software distributed under the License is distributed on an "AS IS" basis, +## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +## the specific language governing rights and limitations under the License. +## +## The Original Code is Reddit. +## +## The Original Developer is the Initial Developer. The Initial Developer of +## the Original Code is CondeNet, Inc. +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## CondeNet, Inc. All Rights Reserved. +################################################################################ +I've added you to the access list for editing ${thing.en_name} (${thing.lang_name}) on our staging machine: + +http://${g.domain}/ + +%if g.translator_username and g.translator_password: +The user name to get past the web server is "${g.translator_username}" and the pw is "${g.translator_password}" (without quotes in both cases, and with spaces for the latter). +%endif +If that works as expected, you should be confronted by a site which looks exactly like reddit.com. +Log into reddit with your existing username (${thing.user.name}) and password, and you should be able to go to this link without a 404: + +http://${g.domain}/admin/i18n/edit/${thing.locale} + +Specific things to be aware of: + + * Save often. The operation should be pretty cheap for the webserver if a little taxing to your browser. + * If you get a blank page at any point after submitting, please let me know -- that means something has gone wrong! + * Strings in orange have to carry over untranslated into the translated string. These are python formatting placeholders for text that will probably be untranslated or translated separately. + * Hitting "try translation" will compile the translation file and should pop open a translated version of the site which should reflect your latest pass of translations. If you hit instead "try translation with numbers", it will do the same thing except it will also add a numeric placeholder to each translation that matches the list + +Let me know if the context of the phrases is unclear. Also let me know if there is no way to (unawkwardly) translate a string. I've tried to remove as many grammar restrictions as possible in longer strings, but I'm sure there could still be some incompatibilities. + +No worries about grammar either: the point of adding the preview option is to check to see if it looks/reads correctly to a native speaker. There's a lot to translate, so feel free to pick at it as you have the time. Also, I'd recommend doing the longer (multiline) strings last. There is some flakiness with those that I've had a heck of a time tracking down. + +Thanks for doing this, and let me know if any problems/suggestions come up. + + diff --git a/r2/r2/templates/trophycase.html b/r2/r2/templates/trophycase.html index e272feba3..7657b8487 100644 --- a/r2/r2/templates/trophycase.html +++ b/r2/r2/templates/trophycase.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of the ## Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ############################################################################### @@ -51,10 +51,18 @@ </td> </%def> -%if c.user_is_admin and thing.cup_date: - <div> +%if c.user_is_admin and thing.cup_info: + <div class="cup-info-box"> + cup: + + <img src="${thing.cup_info['img_url']}" alt="[image not found]" /> + <br/> + « + <tt>${thing.cup_info["label_template"] % dict(user=thing.user.name)}</tt> + » + <br/> show cup until: - ${thing.cup_date.astimezone(g.display_tz).strftime("%Y-%m-%d %H:%M:%S %Z")} + ${thing.cup_info["expiration"].astimezone(g.display_tz).strftime("%Y-%m-%d %H:%M:%S %Z")} ${ynbutton(_("remove"), _("removed"), "removecup", "hide_thing", hidden_data=dict(account=thing.user.name))} diff --git a/r2/r2/templates/unfoundpage.html b/r2/r2/templates/unfoundpage.html index 4f13de28d..e23d237af 100644 --- a/r2/r2/templates/unfoundpage.html +++ b/r2/r2/templates/unfoundpage.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/unfoundpage.htmllite b/r2/r2/templates/unfoundpage.htmllite index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/unfoundpage.htmllite +++ b/r2/r2/templates/unfoundpage.htmllite @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/unfoundpage.mobile b/r2/r2/templates/unfoundpage.mobile index 4f13de28d..844a4e8bf 100644 --- a/r2/r2/templates/unfoundpage.mobile +++ b/r2/r2/templates/unfoundpage.mobile @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/unfoundpage.xml b/r2/r2/templates/unfoundpage.xml index a080b61ce..35a416a26 100644 --- a/r2/r2/templates/unfoundpage.xml +++ b/r2/r2/templates/unfoundpage.xml @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/uploadedimage.html b/r2/r2/templates/uploadedimage.html index e49ba36df..ef85678e2 100644 --- a/r2/r2/templates/uploadedimage.html +++ b/r2/r2/templates/uploadedimage.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/userawards.html b/r2/r2/templates/userawards.html index df2d470f9..031fc92d4 100644 --- a/r2/r2/templates/userawards.html +++ b/r2/r2/templates/userawards.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ @@ -36,7 +36,7 @@ <div class="award-square-container"> %if thing.manuals: - <h1>${_("Awards given out regularly:")}</h1> + <h1>${_("Ongoing awards, and their most recent winners:")}</h1> %else: <h1> </h1> %endif @@ -80,7 +80,7 @@ %endfor %if thing.manuals: - ${other_awards(_("Special one-time awards:"), thing.manuals)} + ${other_awards(_("Special awards:"), thing.manuals)} %endif %if c.user_is_admin and thing.invisibles: diff --git a/r2/r2/templates/userlist.html b/r2/r2/templates/userlist.html index 6ea6341ef..a18c32443 100644 --- a/r2/r2/templates/userlist.html +++ b/r2/r2/templates/userlist.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/usertableitem.html b/r2/r2/templates/usertableitem.html index 010eb2f2e..9eaea1864 100644 --- a/r2/r2/templates/usertableitem.html +++ b/r2/r2/templates/usertableitem.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/usertext.html b/r2/r2/templates/usertext.html index 7d38c950b..55430b8ec 100644 --- a/r2/r2/templates/usertext.html +++ b/r2/r2/templates/usertext.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/utils.html b/r2/r2/templates/utils.html index 26547a821..caa75939d 100644 --- a/r2/r2/templates/utils.html +++ b/r2/r2/templates/utils.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/verifyemail.email b/r2/r2/templates/verifyemail.email index 86c6fe308..7cb7b0fd9 100644 --- a/r2/r2/templates/verifyemail.email +++ b/r2/r2/templates/verifyemail.email @@ -16,7 +16,7 @@ ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. ## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/templates/widgetdemopanel.html b/r2/r2/templates/widgetdemopanel.html index 4578805af..dfdbb10a5 100644 --- a/r2/r2/templates/widgetdemopanel.html +++ b/r2/r2/templates/widgetdemopanel.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ <%! diff --git a/r2/r2/templates/wrappeduser.html b/r2/r2/templates/wrappeduser.html index 7bdd9e118..3f802b52e 100644 --- a/r2/r2/templates/wrappeduser.html +++ b/r2/r2/templates/wrappeduser.html @@ -6,17 +6,17 @@ ## software over a computer network and provide for limited attribution for the ## Original Developer. In addition, Exhibit A has been modified to be consistent ## with Exhibit B. -## +## ## Software distributed under the License is distributed on an "AS IS" basis, ## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for ## the specific language governing rights and limitations under the License. -## +## ## The Original Code is Reddit. -## +## ## The Original Developer is the Initial Developer. The Initial Developer of ## the Original Code is CondeNet, Inc. -## -## All portions of the code written by CondeNet are Copyright (c) 2006-2009 +## +## All portions of the code written by CondeNet are Copyright (c) 2006-2010 ## CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/tests/__init__.py b/r2/r2/tests/__init__.py index 2dc29e0c8..23754f806 100644 --- a/r2/r2/tests/__init__.py +++ b/r2/r2/tests/__init__.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import os diff --git a/r2/r2/tests/functional/__init__.py b/r2/r2/tests/functional/__init__.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/tests/functional/__init__.py +++ b/r2/r2/tests/functional/__init__.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/tests/test_models.py b/r2/r2/tests/test_models.py index 5ccd33a26..5546c5a94 100644 --- a/r2/r2/tests/test_models.py +++ b/r2/r2/tests/test_models.py @@ -6,16 +6,16 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/r2/websetup.py b/r2/r2/websetup.py index dbdbf4dca..0bf697f7d 100644 --- a/r2/r2/websetup.py +++ b/r2/r2/websetup.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import paste.deploy diff --git a/r2/setup.py b/r2/setup.py index dbc0dd8ed..f6a958477 100644 --- a/r2/setup.py +++ b/r2/setup.py @@ -8,17 +8,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ diff --git a/r2/supervise_watcher.py b/r2/supervise_watcher.py index 13b5b9cad..2f85cea00 100644 --- a/r2/supervise_watcher.py +++ b/r2/supervise_watcher.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ import os, re, sys, time, smtplib diff --git a/r2/translation.py b/r2/translation.py index 04ad93e10..9bca7870f 100644 --- a/r2/translation.py +++ b/r2/translation.py @@ -6,17 +6,17 @@ # software over a computer network and provide for limited attribution for the # Original Developer. In addition, Exhibit A has been modified to be consistent # with Exhibit B. -# +# # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for # the specific language governing rights and limitations under the License. -# +# # The Original Code is Reddit. -# +# # The Original Developer is the Initial Developer. The Initial Developer of the # Original Code is CondeNet, Inc. -# -# All portions of the code written by CondeNet are Copyright (c) 2006-2009 +# +# All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ from distutils.cmd import Command