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 , 2009.
+# FIRST AUTHOR , 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 \n"
"Language-Team: LANGUAGE \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 "%(num)s%(persons)s"
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
@@ -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 .
+#
+
+"""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+\s*$|'
+ # internal calls (such as "mcount")
+ r'^.*\((\d+)\)$'
+ )
+
+ _cg_primary_re = re.compile(
+ r'^\[(?P\d+)\]?' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?:(?P\d+)(?:\+(?P\d+))?)?' +
+ r'\s+(?P\S.*?)' +
+ r'(?:\s+\d+)>)?' +
+ r'\s\[(\d+)\]$'
+ )
+
+ _cg_parent_re = re.compile(
+ r'^\s+(?P\d+\.\d+)?' +
+ r'\s+(?P\d+\.\d+)?' +
+ r'\s+(?P\d+)(?:/(?P\d+))?' +
+ r'\s+(?P\S.*?)' +
+ r'(?:\s+\d+)>)?' +
+ r'\s\[(?P\d+)\]$'
+ )
+
+ _cg_child_re = _cg_parent_re
+
+ _cg_cycle_header_re = re.compile(
+ r'^\[(?P\d+)\]?' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?P\d+\.\d+)' +
+ r'\s+(?:(?P\d+)(?:\+(?P\d+))?)?' +
+ r'\s+\d+)\sas\sa\swhole>' +
+ r'\s\[(\d+)\]$'
+ )
+
+ _cg_cycle_member_re = re.compile(
+ r'^\s+(?P\d+\.\d+)?' +
+ r'\s+(?P\d+\.\d+)?' +
+ r'\s+(?P\d+)(?:\+(?P\d+))?' +
+ r'\s+(?P\S.*?)' +
+ r'(?:\s+\d+)>)?' +
+ r'\s\[(?P\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: 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\d+)',
+ '%': r'(?P\S+)',
+ 'linenr info': r'(?P\(no location information\)|\S+:\d+)',
+ 'image name': r'(?P\S+(?:\s\(tgid:[^)]*\))?)',
+ 'app name': r'(?P\S+)',
+ 'symbol name': r'(?P\(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\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[|+ ]*)(?P\d+), (?P[^,]+), (?P.*)')
+
+ 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\w+)' +
+ r'\s+"(?P[^"]*)"' +
+ r'\s+"(?P[^"]*)"' +
+ r'\s+"(?P[^"]*)"' +
+ r'\s+(?P\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(" or ", 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 = '%s" % 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 = ''' 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_ON = ""
+MD_START = '
'
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('(?', re.I | re.S)
-img = re.compile('', re.I | re.S)
-href_re = re.compile('([^<]+)')
-a_re = re.compile('>([^<]+)')
-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 = "
Comment Broken
"
- #remove images
- text = img.sub('', text)
- #wipe malicious javascript
- text = jscript_url.sub('', text)
- def href_handler(m):
- url = m.group(1).replace('&', '&')
- link = '%s' % l.replace('&','&')
- #unescape double escaping in links
- def inner_a_handler(m):
- l = m.group(1)
- return '>%s' % 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 + '
' + text + '
' + 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 = "
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 = $("");
+ 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('
' +
- $.unsafe(parent) +
- '
');
+ thing.find(".noncollapsed .md")
+ .before('
' +
+ $.unsafe(parent) +
+ '
');
}
$(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 ab602af97..ef7cb6513 100644
Binary files a/r2/r2/public/static/kill.png and b/r2/r2/public/static/kill.png differ
diff --git a/r2/r2/public/static/mail.png b/r2/r2/public/static/mail.png
index 11d09a118..745b8ef08 100644
Binary files a/r2/r2/public/static/mail.png and b/r2/r2/public/static/mail.png differ
diff --git a/r2/r2/public/static/mailgray.png b/r2/r2/public/static/mailgray.png
index 91675e670..8d319052f 100644
Binary files a/r2/r2/public/static/mailgray.png and b/r2/r2/public/static/mailgray.png differ
diff --git a/r2/r2/public/static/red-arrow.png b/r2/r2/public/static/red-arrow.png
new file mode 100644
index 000000000..9eba80903
Binary files /dev/null and b/r2/r2/public/static/red-arrow.png differ
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 @@
- %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 @@
%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 @@
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 %>
+
${self.collapsed()}
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')}">
-
+
+
+
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
+ %>
+
+
+
Request Help
+
+
+ reddit is a community, and as such there are a lot of outlets to get help for what ails you.
+
+
+
+
Are your submissions not showing up? Subreddit marked as spam? Is the spam filter acting up?
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()">
%else:
${self.score(thing, thing.likes, tag='div')}
- %endif
+ %endif
${self.arrow(thing, 0, thing.likes == False)}
${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.
################################################################################
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:
+
%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)">
+
+ %else:
+ onclick="return hidecomment(this)">
+ %endif
+ [${_("+") if collapse else _("-")}]
+
<%
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
-
+%def>
+
+<%def name="subject()">
+ ${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)">
+
+
+ ${_("[+] load the full conversation.")}
+
+
+%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}
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.
###############################################################################
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)}
(*) ${_("incomplete")}
- ${plain_link(_("volunteer to translate"), "/feedback")}
+ ${plain_link(_("volunteer to translate"), "/i18n")}
@@ -177,6 +177,20 @@
${_("messaging options")}
+ ${checkbox(_("show message conversations in the inbox"), \
+ "threaded_messages")}
+
+ ${_("(only applies when you go to the 'messages' panel)")}
+
+
+ %if c.user.pref_threaded_messages:
+ ${checkbox(_("collapse messages after I've read them"), \
+ "collapse_read_messages")}
+
+ ${_("(otherwise, you'll have to collapse them yourself)")}
+
+
+ %endif
${checkbox(_("mark messages as read when I open my inbox"), \
"mark_messages_read")}
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)">
+
${thing.childlisting}
%def>
@@ -124,7 +125,7 @@ thing id-${what._fullname}
%>
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 @@
+ %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
%def>
-%if c.user_is_admin and thing.cup_date:
-
+%if c.user_is_admin and thing.cup_info:
+
+ cup:
+
+
+
+ «
+ ${thing.cup_info["label_template"] % dict(user=thing.user.name)}
+ »
+
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 @@
%if thing.manuals:
-
${_("Awards given out regularly:")}
+
${_("Ongoing awards, and their most recent winners:")}
%else:
%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