From 31a8ff428869614db3cae06ab24dbdb1e3d98064 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 17 Jul 2010 11:33:08 -0500 Subject: Initial mediagoblin structure --- .gitignore | 9 +++++++ mediagoblin/__init__.py | 0 mediagoblin/app.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ mediagoblin/routing.py | 7 ++++++ mediagoblin/util.py | 11 +++++++++ mediagoblin/views.py | 4 ++++ setup.py | 17 +++++++++++++ 7 files changed, 112 insertions(+) create mode 100644 .gitignore create mode 100644 mediagoblin/__init__.py create mode 100644 mediagoblin/app.py create mode 100644 mediagoblin/routing.py create mode 100644 mediagoblin/util.py create mode 100644 mediagoblin/views.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0ed4802a --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +dist/ +bin/ +develop-eggs/ +build/ +eggs/ +.installed.cfg +wsgit.egg-info +*.pyc +*.pyo \ No newline at end of file diff --git a/mediagoblin/__init__.py b/mediagoblin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/app.py b/mediagoblin/app.py new file mode 100644 index 00000000..41ab7f20 --- /dev/null +++ b/mediagoblin/app.py @@ -0,0 +1,64 @@ +import sys +import urllib + +from webob import Request, exc +import routes + +from mediagoblin import routing, util + + +class Error(Exception): pass +class ImproperlyConfigured(Error): pass + + +def load_controller(string): + module_name, func_name = string.split(':', 1) + __import__(module_name) + module = sys.modules[module_name] + func = getattr(module, func_name) + return func + + +class MediagoblinApp(object): + """ + Really basic wsgi app using routes and WebOb. + """ + def __init__(self, user_template_path=None): + self.template_env = util.get_jinja_env(user_template_path) + + def __call__(self, environ, start_response): + request = Request(environ) + path_info = request.path_info + route_match = routing.mapping.match(path_info) + + # No matching page? + if route_match is None: + # Try to do see if we have a match with a trailing slash + # added and if so, redirect + if not path_info.endswith('/') \ + and request.method == 'GET' \ + and routing.mapping.match(path_info + '/'): + new_path_info = path_info + '/' + if request.GET: + new_path_info = '%s?%s' % ( + new_path_info, urllib.urlencode(request.GET)) + redirect = exc.HTTPTemporaryRedirect(location=new_path_info) + return request.get_response(redirect)(environ, start_response) + + # Okay, no matches. 404 time! + return exc.HTTPNotFound()(environ, start_response) + + controller = load_controller(route_match['controller']) + request.start_response = start_response + + request.matchdict = route_match + request.app = self + request.template_env = self.template_env + request.urlgen = routes.URLGenerator(routing.mapping, environ) + + return controller(request)(environ, start_response) + + +def paste_app_factory(global_config, **kw): + return MediagoblinApp( + user_template_path=kw.get('local_templates')) diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py new file mode 100644 index 00000000..fec08370 --- /dev/null +++ b/mediagoblin/routing.py @@ -0,0 +1,7 @@ +from routes import Mapper + +mapping = Mapper() +mapping.minimization = False + +mapping.connect( + "index", "/", controller="mediagoblin.views:root_view") diff --git a/mediagoblin/util.py b/mediagoblin/util.py new file mode 100644 index 00000000..2af9b380 --- /dev/null +++ b/mediagoblin/util.py @@ -0,0 +1,11 @@ +import jinja2 + +def get_jinja_env(user_template_path=None): + if user_template_path: + loader = jinja2.ChoiceLoader( + [jinja2.FileSystemLoader(user_template_path), + jinja2.PackageLoader('mediagoblin', 'templates')]) + else: + loader = jinja2.PackageLoader('mediagoblin', 'templates') + + return jinja2.Environment(loader=loader, autoescape=True) diff --git a/mediagoblin/views.py b/mediagoblin/views.py new file mode 100644 index 00000000..1b109453 --- /dev/null +++ b/mediagoblin/views.py @@ -0,0 +1,4 @@ +from webob import Response, exc + +def root_view(request): + return Response("This is the root") diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..c19e801f --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup, find_packages + +import sys + +setup( + name = "mediagoblin", + version = "0.0.1", + packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), + zip_safe=False, + license = 'AGPLv3', + author = 'Christopher Webber', + author_email = 'cwebber@dustycloud.org', + entry_points = """\ + [paste.app_factory] + mediagoblin = mediagoblin.app:paste_app_factory + """, + ) -- cgit v1.2.3 From 73e0dbcca32ed18c0ab63cfde8b34cd112b9e528 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 17 Jul 2010 13:32:57 -0500 Subject: Basic but useless connection to the database --- mediagoblin/app.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 41ab7f20..4095acc2 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -3,6 +3,7 @@ import urllib from webob import Request, exc import routes +import pymongo from mediagoblin import routing, util @@ -23,8 +24,9 @@ class MediagoblinApp(object): """ Really basic wsgi app using routes and WebOb. """ - def __init__(self, user_template_path=None): + def __init__(self, database, user_template_path=None): self.template_env = util.get_jinja_env(user_template_path) + self.db = database def __call__(self, environ, start_response): request = Request(environ) @@ -60,5 +62,9 @@ class MediagoblinApp(object): def paste_app_factory(global_config, **kw): + connection = pymongo.Connection() + db = kw.get('db_name', 'mediagoblin') + return MediagoblinApp( + db, user_template_path=kw.get('local_templates')) -- cgit v1.2.3 From 0f63a9440d440aac04042bd6125c70a2cb8116d7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 18 Jul 2010 11:20:18 -0500 Subject: A few adustments to the routing and etc --- mediagoblin/app.py | 7 ++++--- mediagoblin/routing.py | 15 +++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 4095acc2..7231b786 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -27,11 +27,12 @@ class MediagoblinApp(object): def __init__(self, database, user_template_path=None): self.template_env = util.get_jinja_env(user_template_path) self.db = database + self.routing = routing.get_mapper() def __call__(self, environ, start_response): request = Request(environ) path_info = request.path_info - route_match = routing.mapping.match(path_info) + route_match = self.routing.match(path_info) # No matching page? if route_match is None: @@ -39,7 +40,7 @@ class MediagoblinApp(object): # added and if so, redirect if not path_info.endswith('/') \ and request.method == 'GET' \ - and routing.mapping.match(path_info + '/'): + and self.routing.match(path_info + '/'): new_path_info = path_info + '/' if request.GET: new_path_info = '%s?%s' % ( @@ -56,7 +57,7 @@ class MediagoblinApp(object): request.matchdict = route_match request.app = self request.template_env = self.template_env - request.urlgen = routes.URLGenerator(routing.mapping, environ) + request.urlgen = routes.URLGenerator(self.routing, environ) return controller(request)(environ, start_response) diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index fec08370..0b345371 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -1,7 +1,14 @@ from routes import Mapper -mapping = Mapper() -mapping.minimization = False +def get_mapper(): + mapping = Mapper() + mapping.minimization = False -mapping.connect( - "index", "/", controller="mediagoblin.views:root_view") + mapping.connect( + "index", "/", + controller="mediagoblin.views:root_view") + mapping.connect( + "test_submit", "/test_submit/", + controller="mediagoblin.views:submit_test") + + return mapping -- cgit v1.2.3 From fbf7880e6873a541da5f45f90d9e0fd31119514a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 18 Jul 2010 11:22:24 -0500 Subject: Starting with the test submit view using wtforms --- mediagoblin/templates/mediagoblin/test_submit.html | 18 ++++++++++++ mediagoblin/views.py | 32 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/test_submit.html diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html new file mode 100644 index 00000000..0d2fd258 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -0,0 +1,18 @@ + + +
+ + {% for field in image_form %} + + + + + {% endfor %} + + + + +
{{ field.label }}{{ field }}
+
+ + diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 1b109453..ef0fddad 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -1,4 +1,36 @@ from webob import Response, exc +import wtforms def root_view(request): return Response("This is the root") + + +class ImageSubmitForm(wtforms.Form): + title = wtforms.TextField( + 'Title', + [wtforms.validators.Length(min=1, max=500)]) + description = wtforms.TextAreaField('Description of this work') + file = wtforms.FileField('File') + + +def submit_test(request): + image_form = ImageSubmitForm(request.POST) + if request.method == 'POST' and image_form.validate(): + # create entry and save in database + + # save file to disk + ## TODO + + # resize if necessary + ## Hm. This should be done on a separate view? + + # redirect + pass + + # render + template = request.template_env.get_template( + 'mediagoblin/test_submit.html') + return Response( + template.render( + {'request': request, + 'image_form': image_form})) -- cgit v1.2.3 From bda3405342feb7f239ccaa2e7cebe76a48909309 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 18 Jul 2010 15:21:51 -0500 Subject: Still totally useless but at least it writes to the database --- mediagoblin/app.py | 2 +- mediagoblin/templates/mediagoblin/test_submit.html | 3 ++- mediagoblin/views.py | 8 +++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 7231b786..ef4feae3 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -64,7 +64,7 @@ class MediagoblinApp(object): def paste_app_factory(global_config, **kw): connection = pymongo.Connection() - db = kw.get('db_name', 'mediagoblin') + db = connection[kw.get('db_name', 'mediagoblin')] return MediagoblinApp( db, diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 0d2fd258..bf91d26b 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -1,6 +1,7 @@ -
+ {% for field in image_form %} diff --git a/mediagoblin/views.py b/mediagoblin/views.py index ef0fddad..116237b7 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -1,3 +1,5 @@ +import datetime + from webob import Response, exc import wtforms @@ -17,7 +19,11 @@ def submit_test(request): image_form = ImageSubmitForm(request.POST) if request.method == 'POST' and image_form.validate(): # create entry and save in database - + work_id = request.app.db.works.insert( + {'title': image_form.title.data, + 'created': datetime.datetime.now(), + 'description': image_form.description.data}) + # save file to disk ## TODO -- cgit v1.2.3 From b61874b245a082ae77deef4b0948ddbfeed5a8b0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 18 Jul 2010 15:59:23 -0500 Subject: Added session support w/ beaker --- mediagoblin/app.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index ef4feae3..f688b989 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -1,9 +1,10 @@ import sys import urllib -from webob import Request, exc +from beaker.middleware import SessionMiddleware import routes import pymongo +from webob import Request, exc from mediagoblin import routing, util @@ -58,6 +59,7 @@ class MediagoblinApp(object): request.app = self request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) + request.session = request.environ['beaker.session'] return controller(request)(environ, start_response) @@ -66,6 +68,11 @@ def paste_app_factory(global_config, **kw): connection = pymongo.Connection() db = connection[kw.get('db_name', 'mediagoblin')] - return MediagoblinApp( - db, - user_template_path=kw.get('local_templates')) + mgoblin_app = MediagoblinApp( + db, user_template_path=kw.get('local_templates')) + beakered_app = SessionMiddleware( + mgoblin_app, + {'session.type': 'file', + 'session.cookie_expires': True}) + + return beakered_app -- cgit v1.2.3 From c4d71564761aa5490bc911585bb5021be8c90b54 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 18 Jul 2010 17:59:40 -0500 Subject: beakered_app removed from the paste_app_factory. Deployers should wrap the app w/ beaker themselves --- mediagoblin/app.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index f688b989..1ae01686 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -70,9 +70,5 @@ def paste_app_factory(global_config, **kw): mgoblin_app = MediagoblinApp( db, user_template_path=kw.get('local_templates')) - beakered_app = SessionMiddleware( - mgoblin_app, - {'session.type': 'file', - 'session.cookie_expires': True}) - return beakered_app + return mgoblin_app -- cgit v1.2.3 From 0c04118b76ff087949afcb6e4213b82820f10642 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 24 Mar 2011 19:00:55 -0500 Subject: Adding requirements :) --- setup.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c19e801f..617bb3f6 100644 --- a/setup.py +++ b/setup.py @@ -7,11 +7,22 @@ setup( version = "0.0.1", packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), zip_safe=False, + # scripts and dependencies + install_requires = [ + 'setuptools', + 'PasteScript', + 'beaker', + 'routes', + 'pymongo', + 'webob', + 'wtforms', + ], + license = 'AGPLv3', author = 'Christopher Webber', author_email = 'cwebber@dustycloud.org', entry_points = """\ [paste.app_factory] - mediagoblin = mediagoblin.app:paste_app_factory + app = mediagoblin.app:paste_app_factory """, ) -- cgit v1.2.3 From 7846e40608be39369c43934646d120f4f79ebd17 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 24 Mar 2011 19:06:31 -0500 Subject: Commenting out beaker till we start using it :) --- mediagoblin/app.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 1ae01686..98f8bc1d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -59,7 +59,10 @@ class MediagoblinApp(object): request.app = self request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) - request.session = request.environ['beaker.session'] + + # Do we really want to load this via middleware? Maybe? + # let's comment it out till we start using it :) + #request.session = request.environ['beaker.session'] return controller(request)(environ, start_response) -- cgit v1.2.3 From 508775bd2360c441bde1045bc89abe4152e72650 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 24 Mar 2011 19:54:06 -0500 Subject: Requiring mongokit --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 617bb3f6..e6c784d2 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ setup( 'beaker', 'routes', 'pymongo', + 'mongokit', 'webob', 'wtforms', ], -- cgit v1.2.3 From d232e0f6be4be977634f1a2bbd39ca401dfb296d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 24 Mar 2011 20:19:25 -0500 Subject: Adding a skeletal models.py --- mediagoblin/models.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 mediagoblin/models.py diff --git a/mediagoblin/models.py b/mediagoblin/models.py new file mode 100644 index 00000000..3471ddc7 --- /dev/null +++ b/mediagoblin/models.py @@ -0,0 +1,32 @@ +from mongokit import Document, Set +import datetime + + +class MediaEntry(Document): + structure = { + 'title': unicode, + 'created': datetime.datetime, + 'description': unicode, + 'media_type': unicode, + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. + 'file_store': unicode, + 'tags': Set(unicode)} + + +class User(Document): + structure = { + 'username': unicode, + 'created': datetime.datetime, + 'plugin_data': dict, # plugins can dump stuff here. + 'pw_hash': unicode, + } + + +REGISTER_MODELS = [MediaEntry, User] + +def register_models(connection): + """ + Register all models in REGISTER_MODELS with this connection. + """ + pass -- cgit v1.2.3 From db61f7d15255b7f9bf697108be2175018a780810 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Mar 2011 21:27:52 -0500 Subject: A simple register_modules helper function. --- mediagoblin/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 3471ddc7..07d841bf 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -29,4 +29,5 @@ def register_models(connection): """ Register all models in REGISTER_MODELS with this connection. """ - pass + connection.register(REGISTER_MODELS) + -- cgit v1.2.3 From fc9bb821eaac0f615eee690cd2473360ed6cbb64 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 26 Mar 2011 09:10:04 -0500 Subject: required_values, default_values! For the only two models we have. --- mediagoblin/models.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 07d841bf..b14ada9f 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -13,6 +13,13 @@ class MediaEntry(Document): 'file_store': unicode, 'tags': Set(unicode)} + required_fields = [ + 'title', 'created', + 'media_type', 'file_store'] + + default_values = { + 'date_creation':datetime.datetime.utcnow} + class User(Document): structure = { @@ -22,6 +29,12 @@ class User(Document): 'pw_hash': unicode, } + required_fields = ['username', 'created', 'pw_hash'] + + default_values = { + 'date_creation':datetime.datetime.utcnow} + + REGISTER_MODELS = [MediaEntry, User] -- cgit v1.2.3 From 4329be147b3ee0f60e3c17a6c95845cac347fa28 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 26 Mar 2011 11:45:11 -0500 Subject: date_creation should be created --- mediagoblin/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index b14ada9f..6ae7d6f9 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -1,4 +1,5 @@ from mongokit import Document, Set + import datetime @@ -18,7 +19,7 @@ class MediaEntry(Document): 'media_type', 'file_store'] default_values = { - 'date_creation':datetime.datetime.utcnow} + 'created': datetime.datetime.utcnow} class User(Document): @@ -32,12 +33,12 @@ class User(Document): required_fields = ['username', 'created', 'pw_hash'] default_values = { - 'date_creation':datetime.datetime.utcnow} - + 'created': datetime.datetime.utcnow} REGISTER_MODELS = [MediaEntry, User] + def register_models(connection): """ Register all models in REGISTER_MODELS with this connection. -- cgit v1.2.3 From 2b4e236ac34a2d11dde748d514b31428f9a0fa2b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 26 Mar 2011 13:03:32 -0500 Subject: Properly load in the database and register the connection with the models --- mediagoblin/app.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 98f8bc1d..992d641b 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -3,10 +3,10 @@ import urllib from beaker.middleware import SessionMiddleware import routes -import pymongo +import mongokit from webob import Request, exc -from mediagoblin import routing, util +from mediagoblin import routing, util, models class Error(Exception): pass @@ -25,11 +25,14 @@ class MediagoblinApp(object): """ Really basic wsgi app using routes and WebOb. """ - def __init__(self, database, user_template_path=None): + def __init__(self, connection, database_path, user_template_path=None): self.template_env = util.get_jinja_env(user_template_path) - self.db = database + self.connection = connection + self.db = connection['database_path'] self.routing = routing.get_mapper() + models.register_models(connection) + def __call__(self, environ, start_response): request = Request(environ) path_info = request.path_info @@ -59,6 +62,7 @@ class MediagoblinApp(object): request.app = self request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) + request.db = self.db # Do we really want to load this via middleware? Maybe? # let's comment it out till we start using it :) @@ -68,10 +72,11 @@ class MediagoblinApp(object): def paste_app_factory(global_config, **kw): - connection = pymongo.Connection() - db = connection[kw.get('db_name', 'mediagoblin')] + connection = mongokit.Connection( + kw.get('db_host'), kw.get('db_port')) mgoblin_app = MediagoblinApp( - db, user_template_path=kw.get('local_templates')) + connection, kw.get('db_name', 'mediagoblin'), + user_template_path=kw.get('local_templates')) return mgoblin_app -- cgit v1.2.3 From 2e30e3690adf21ba0612bb863b27e65bbb2f8863 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 17:29:59 -0500 Subject: Ignore mediagoblin egg-info --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0ed4802a..7db77c06 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,6 @@ develop-eggs/ build/ eggs/ .installed.cfg -wsgit.egg-info +mediagoblin.egg-info *.pyc -*.pyo \ No newline at end of file +*.pyo -- cgit v1.2.3 From 65d7374c3752105c66ba8d55fa0943ad66c47b0e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 17:30:42 -0500 Subject: erp, connection[database_path] not connection['database_path'] obviously :P --- mediagoblin/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 992d641b..478b25d6 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -28,7 +28,7 @@ class MediagoblinApp(object): def __init__(self, connection, database_path, user_template_path=None): self.template_env = util.get_jinja_env(user_template_path) self.connection = connection - self.db = connection['database_path'] + self.db = connection[database_path] self.routing = routing.get_mapper() models.register_models(connection) -- cgit v1.2.3 From 6f86cfe95c9de40a1e0baaf2b19f3377a1db5f32 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 17:31:18 -0500 Subject: __collection__ should be auto-defined as media_entries --- mediagoblin/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 6ae7d6f9..41f4fb04 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -4,6 +4,8 @@ import datetime class MediaEntry(Document): + __collection__ = 'media_entries' + structure = { 'title': unicode, 'created': datetime.datetime, @@ -12,7 +14,8 @@ class MediaEntry(Document): 'media_data': dict, # extra data relevant to this media_type 'plugin_data': dict, # plugins can dump stuff here. 'file_store': unicode, - 'tags': Set(unicode)} + 'attachments': [dict], + 'tags': [unicode]} required_fields = [ 'title', 'created', @@ -20,7 +23,9 @@ class MediaEntry(Document): default_values = { 'created': datetime.datetime.utcnow} - + + def main_mediafile(self): + pass class User(Document): structure = { -- cgit v1.2.3 From ef7cdac5b97374418ef94891981539ea07216fe4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 17:32:27 -0500 Subject: A testing submit view that doesn't work but is getting closer to working. --- mediagoblin/templates/mediagoblin/test_submit.html | 9 +++------ mediagoblin/templates/mediagoblin/utils/wtforms.html | 18 ++++++++++++++++++ mediagoblin/views.py | 20 ++++++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/utils/wtforms.html diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index bf91d26b..2fae634c 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -1,14 +1,11 @@ +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} +
- {% for field in image_form %} - - - - - {% endfor %} + {{ wtforms_util.render_table(image_form) }} diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html new file mode 100644 index 00000000..641f51d5 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -0,0 +1,18 @@ +{% macro render_table(form) -%} + {% for field in form %} + + + + + {% endfor %} +{%- endmacro %} diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 116237b7..eca40203 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -3,6 +3,8 @@ import datetime from webob import Response, exc import wtforms +from mediagoblin import models + def root_view(request): return Response("This is the root") @@ -19,13 +21,21 @@ def submit_test(request): image_form = ImageSubmitForm(request.POST) if request.method == 'POST' and image_form.validate(): # create entry and save in database - work_id = request.app.db.works.insert( - {'title': image_form.title.data, - 'created': datetime.datetime.now(), - 'description': image_form.description.data}) + + entry = request.db.MediaEntry() + entry['title'] = request.POST['title'] + entry['description'] = request.POST.get(['description'])o + entry['media_type'] = u'image' + + # TODO this does NOT look save, we should clean the filename somenow? + entry['file_store'] = request.POST['file'].filename + + entry.save(validate=True) # save file to disk ## TODO + #open('/tmp/read_file.png', 'wb').write(request.POST['file'].file.read()) + # resize if necessary ## Hm. This should be done on a separate view? @@ -33,6 +43,8 @@ def submit_test(request): # redirect pass + + # render template = request.template_env.get_template( 'mediagoblin/test_submit.html') -- cgit v1.2.3 From e5572c607726599ccbf66a40194b96d12584f38f Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Sun, 27 Mar 2011 18:47:23 -0400 Subject: Added copyright notices --- mediagoblin/__init__.py | 16 ++++++++++++++++ mediagoblin/app.py | 16 ++++++++++++++++ mediagoblin/models.py | 16 ++++++++++++++++ mediagoblin/routing.py | 16 ++++++++++++++++ mediagoblin/util.py | 16 ++++++++++++++++ mediagoblin/views.py | 16 ++++++++++++++++ setup.py | 18 +++++++++++++++++- 7 files changed, 113 insertions(+), 1 deletion(-) diff --git a/mediagoblin/__init__.py b/mediagoblin/__init__.py index e69de29b..033b9173 100644 --- a/mediagoblin/__init__.py +++ b/mediagoblin/__init__.py @@ -0,0 +1,16 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 478b25d6..632a0c25 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + import sys import urllib diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 41f4fb04..c05fe3de 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + from mongokit import Document, Set import datetime diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index 0b345371..c60f121c 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + from routes import Mapper def get_mapper(): diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 2af9b380..578261b9 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + import jinja2 def get_jinja_env(user_template_path=None): diff --git a/mediagoblin/views.py b/mediagoblin/views.py index eca40203..e286e950 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + import datetime from webob import Response, exc diff --git a/setup.py b/setup.py index e6c784d2..1f9f852d 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + from setuptools import setup, find_packages import sys @@ -21,7 +37,7 @@ setup( license = 'AGPLv3', author = 'Christopher Webber', - author_email = 'cwebber@dustycloud.org', + author_email = 'cwebber@gnu.org', entry_points = """\ [paste.app_factory] app = mediagoblin.app:paste_app_factory -- cgit v1.2.3 From cf99711dcd83f96646ea55a6e13324191e5b268a Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Sun, 27 Mar 2011 18:48:15 -0400 Subject: Added copying and authors files --- AUTHORS | 0 COPYING | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 661 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..e69de29b diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..dba13ed2 --- /dev/null +++ b/COPYING @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. -- cgit v1.2.3 From 869704d6502da17a8f2062978f82cc82af68cdc6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 23:25:50 -0500 Subject: A semi-verbose braindump of what I think GNU MediaGoblin will use / look like / be. --- READMEish.org | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 READMEish.org diff --git a/READMEish.org b/READMEish.org new file mode 100644 index 00000000..7f40a23f --- /dev/null +++ b/READMEish.org @@ -0,0 +1,188 @@ +GNU MediaGoblin + +* About + +What is MediaGoblin? I'm shooting for: + + - Initially, a place to store all your photos that's as awesome as, + more awesome than, existing proprietary solutions + - Later, a place for all sorts of media, such as video, music, etc + hosting. + - Federated, like statusnet/ostatus (we should use ostatus, in fact!) + - Customizable + - A place for people to collaborate and show off original and derived + creations + - Free, as in freedom. Under the GNU AGPL, v3 or later. Encourages + free formats and free licensing for content, too. + +Wow! That's pretty ambitious. Hopefully we're cool enough to do it. +I think we can. + +It's also necessary, for multiple reasons. Centralization and +proprietization of media on the internet is a serious problem and +makes the web go from a system of extreme resilience to a system +of frightening fragility. People should be able to own their data. +Etc. If you're reading this, chances are you already agree though. :) + +* Milestones + +Excepting the first, not necessarily in this order. + +** Basic image hosting +** Multi-media hosting (including video and audio) +** API(s) +** Federation + +Maybe this is 0.2 :) + +** Plugin system + +* Technology + +I have a pretty specific set of tools that I expect to use in this +project. Those are: + + - *[[http://python.org/][Python]]:* because I love, and know well, the language + - *[[http://www.mongodb.org/][MongoDB]]:* a "document database". Because it's extremely flexible + (and scales up well, but I guess not down well) + - *[[http://namlook.github.com/mongokit/][MongoKit]]:* a lightweight ORM for mongodb. Helps us define our + structures better, does schema validation, schema evolution, and + helps make things more fun and pythonic. + - *[[http://jinja.pocoo.org/docs/][Jinja2]]:* for templating. Pretty much django templates++ (wow, I + can actually pass arguments into method calls instead of tediously + writing custom tags!) + - *[[http://wtforms.simplecodes.com/][WTForms]]:* for form handling, validation, abstraction. Almost just + like Django's templates, + - *[[http://pythonpaste.org/webob/][WebOb]]:* gives nice request/response objects (also somewhat djangoish) + - *[[http://pythonpaste.org/deploy/][Paste Deploy]] and [[http://pythonpaste.org/script/][Paste Script]]:* as the default way of configuring + and launching the application. Since MediaGoblin will be fairly + wsgi minimalist though, you can probably use other ways to launch + it, though this will be the default. + - *[[http://routes.groovie.org/][Routes]]:* for URL routing. It works well enough. + - *[[http://jquery.com/][JQuery]]:* for all sorts of things on the javascript end of things, + for all sorts of reasons. + - *[[http://beaker.groovie.org/][Beaker]]:* for sessions, because that seems like it's generally + considered the way to go I guess. + - *[[http://somethingaboutorange.com/mrl/projects/nose/1.0.0/][nose]]:* for unit tests, because it makes testing a bit nicer. + - *[[http://celeryproject.org/][Celery]]:* for task queueing (think resizing images, encoding + video) because some people like it, and even the people I know who + don't don't seem to know of anything better :) + - *[[http://www.rabbitmq.com/][RabbitMQ]]:* for sending tasks to celery, because I guess that's + what most people do. Might be optional, might also let people use + MongoDB for this if they want. + +** Why python + +Because I (Chris Webber) know Python, love Python, am capable of +actually making this thing happen in Python (I've worked on a lot of +large free software web applications before in Python, including +[[http://mirocommunity.org/][Miro Community]], the [[http://miroguide.org][Miro Guide]], a large portion of +[[http://creativecommons.org/][Creative Commons' site]], and a whole bunch of things while working at +[[http://www.imagescape.com/][Imaginary Landscape]]). I know Python, I can make this happen in +Python, me starting a project like this makes sense if it's done in +Python. + +You might say that PHP is way more deployable, that rails has way more +cool developers riding around on fixie bikes, and all of those things +are true, but I know Python, like Python, and think that Python is +pretty great. I do think that deployment in Python is not as good as +with PHP, but I think the days of shared hosting are (thankfully) +coming to an end, and will probably be replaced by cheap virtual +machines spun up on the fly for people who want that sort of stuff, +and Python will be a huge part of that future, maybe even more than +PHP will. The deployment tools are getting better. Maybe we can use +something like Silver Lining. Maybe we can just distribute as .debs +or .rpms. We'll figure it out. + +But if I'm starting this project, which I am, it's gonna be in Python. + +** Why mongodb + +In case you were wondering, I am not a NOSQL fanboy, I do not go +around telling people that MongoDB is web scale. Actually my choice +for MongoDB isn't scalability, though scaling up really nicely is a +pretty good feature and sets us up well in case large volume sites +eventually do use MediaGoblin. But there's another side of +scalability, and that's scaling down, which is important for +federation, maybe even more important than scaling up in an ideal +universe where everyone ran servers out of their own housing. As a +memory-mapped database, MongoDB is pretty hungry, so actually I spent +a lot of time debating whether the inability to scale down as nicely +as something like SQL has with sqlite meant that it was out. + +But I decided in the end that I really want MongoDB, not for +scalability, but for flexibility. Schema evolution pains in SQL are +almost enough reason for me to want MongoDB, but not quite. The real +reason is because I want the ability to eventually handle multiple +media types through MediaGoblin, and also allow for plugins, without +the rigidity of tables making that difficult. In other words, +something like: + +#+BEGIN_SRC javascript +{"title": "Me talking until you are bored", + "description": "blah blah blah", + "media_type": "audio", + "media_data": { + "length": "2:30", + "codec": "OGG Vorbis"}, + "plugin_data": { + "licensing": { + "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}} +#+END_SRC + +Being able to just dump media-specific information in a media_data +hashtable is pretty great, and even better is having a plugin system +where you can just let plugins have their own entire key-value space +cleanly inside the document that doesn't interfere with anyone else's +stuff. If we were to let plugins to deposit their own information +inside the database, either we'd let plugins create their own tables +which makes SQL migrations even harder than they already are, or we'd +probably end up creating a table with a column for key, a column for +value, and a column for type in one huge table called "plugin_data" or +something similar. (Yo dawg, I heard you liked plugins, so I put a +database in your database so you can query while you query.) Gross. + +I also don't want things to be too lose so that we forget or lose the +structure of things, and that's one reason why I want to use MongoKit, +because we can cleanly define a much structure as we want and verify +that documents match that structure generally without adding too much +bloat or overhead (mongokit is a pretty lightweight wrapper and +doesn't inject extra mongokit-specific stuff into the database, which +is nice and nicer than many other ORMs in that way). + +** Why wsgi minimalism / Why not Django + +If you notice in the technology list above, I list a lot of components +that are very [[http://www.djangoproject.com/][Django-like]], but not actually Django components. What +can I say, I really like a lot of the ideas in Django! Which leads to +the question: why not just use Django? + +While I really like Django's ideas and a lot of its components, I also +feel that most of the best ideas in Django I want have been +implemented as good or even better outside of Django. I could just +use Django and replace the templating system with Jinja2, and the form +system with wtforms, and the database with MongoDB and MongoKit, but +at that point, how much of Django is really left? + +I also am sometimes saddened and irritated by how coupled all of +Django's components are. Loosely coupled yes, but still coupled. +WSGI has done a good job of providing a base layer for running +applications on and [[http://pythonpaste.org/webob/do-it-yourself.html][if you know how to do it yourself]] it's not hard or +many lines of code at all to bind them together without any framework +at all (not even say [[http://pylonshq.com/][Pylons]], [[http://docs.pylonsproject.org/projects/pyramid/dev/][Pyramid]], or [[http://flask.pocoo.org/][Flask]] which I think are still +great projects, especially for people who want this sort of thing but +have no idea how to get started). And even at this already really +early stage of writing MediaGoblin, that glue work is mostly done. + +Not to say I don't think Django isn't great for a lot of things. For +a lot of stuff, it's still the best, but not for MediaGoblin, I think. + +One thing that Django does super well though is documentation. It +still has some faults, but even with those considered I can hardly +think of any other project in Python that has as nice of documentation +as Django. It may be worth +[[http://pycon.blip.tv/file/4881071/][learning some lessons on documentation from Django]], on that note. + +I'd really like to have a good, thorough hacking-howto and +deployment-howto, especially in the former making some notes on how to +make it easier for Django hackers to get started. -- cgit v1.2.3 From ebc4ab71a2d29d72474e70c42700efa90e900aab Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Mar 2011 23:38:27 -0500 Subject: HTML export of the READMEish braindump. --- READMEish.html | 426 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ READMEish.org | 4 + 2 files changed, 430 insertions(+) create mode 100644 READMEish.html diff --git a/READMEish.html b/READMEish.html new file mode 100644 index 00000000..9981da11 --- /dev/null +++ b/READMEish.html @@ -0,0 +1,426 @@ + + + + +GNU MediaGoblin + + + + + + + + + + + +
+ +

GNU MediaGoblin

+ + + + +
+

1 About

+
+ + +

+What is MediaGoblin? I'm shooting for: +

+
    +
  • Initially, a place to store all your photos that's as awesome as, + more awesome than, existing proprietary solutions +
  • +
  • Later, a place for all sorts of media, such as video, music, etc + hosting. +
  • +
  • Federated, like statusnet/ostatus (we should use ostatus, in fact!) +
  • +
  • Customizable +
  • +
  • A place for people to collaborate and show off original and derived + creations +
  • +
  • Free, as in freedom. Under the GNU AGPL, v3 or later. Encourages + free formats and free licensing for content, too. +
  • +
+ +

+Wow! That's pretty ambitious. Hopefully we're cool enough to do it. +I think we can. +

+

+It's also necessary, for multiple reasons. Centralization and +proprietization of media on the internet is a serious problem and +makes the web go from a system of extreme resilience to a system +of frightening fragility. People should be able to own their data. +Etc. If you're reading this, chances are you already agree though. :) +

+
+ +
+ +
+

2 Milestones

+
+ + +

+Excepting the first, not necessarily in this order. +

+ +
+ +
+

2.1 Basic image hosting

+
+ +
+ +
+ +
+

2.2 Multi-media hosting (including video and audio)

+
+ +
+ +
+ +
+

2.3 API(s)

+
+ +
+ +
+ +
+

2.4 Federation

+
+ + +

+Maybe this is 0.2 :) +

+
+ +
+ +
+

2.5 Plugin system

+
+ + +
+
+ +
+ +
+

3 Technology

+
+ + +

+I have a pretty specific set of tools that I expect to use in this +project. Those are: +

+
    +
  • Python: because I love, and know well, the language +
  • +
  • MongoDB: a "document database". Because it's extremely flexible + (and scales up well, but I guess not down well) +
  • +
  • MongoKit: a lightweight ORM for mongodb. Helps us define our + structures better, does schema validation, schema evolution, and + helps make things more fun and pythonic. +
  • +
  • Jinja2: for templating. Pretty much django templates++ (wow, I + can actually pass arguments into method calls instead of tediously + writing custom tags!) +
  • +
  • WTForms: for form handling, validation, abstraction. Almost just + like Django's templates, +
  • +
  • WebOb: gives nice request/response objects (also somewhat djangoish) +
  • +
  • Paste Deploy and Paste Script: as the default way of configuring + and launching the application. Since MediaGoblin will be fairly + wsgi minimalist though, you can probably use other ways to launch + it, though this will be the default. +
  • +
  • Routes: for URL routing. It works well enough. +
  • +
  • JQuery: for all sorts of things on the javascript end of things, + for all sorts of reasons. +
  • +
  • Beaker: for sessions, because that seems like it's generally + considered the way to go I guess. +
  • +
  • nose: for unit tests, because it makes testing a bit nicer. +
  • +
  • Celery: for task queueing (think resizing images, encoding + video) because some people like it, and even the people I know who + don't don't seem to know of anything better :) +
  • +
  • RabbitMQ: for sending tasks to celery, because I guess that's + what most people do. Might be optional, might also let people use + MongoDB for this if they want. +
  • +
+ + +
+ +
+

3.1 Why python

+
+ + +

+Because I (Chris Webber) know Python, love Python, am capable of +actually making this thing happen in Python (I've worked on a lot of +large free software web applications before in Python, including +Miro Community, the Miro Guide, a large portion of +Creative Commons' site, and a whole bunch of things while working at +Imaginary Landscape). I know Python, I can make this happen in +Python, me starting a project like this makes sense if it's done in +Python. +

+

+You might say that PHP is way more deployable, that rails has way more +cool developers riding around on fixie bikes, and all of those things +are true, but I know Python, like Python, and think that Python is +pretty great. I do think that deployment in Python is not as good as +with PHP, but I think the days of shared hosting are (thankfully) +coming to an end, and will probably be replaced by cheap virtual +machines spun up on the fly for people who want that sort of stuff, +and Python will be a huge part of that future, maybe even more than +PHP will. The deployment tools are getting better. Maybe we can use +something like Silver Lining. Maybe we can just distribute as .debs +or .rpms. We'll figure it out. +

+

+But if I'm starting this project, which I am, it's gonna be in Python. +

+
+ +
+ +
+

3.2 Why mongodb

+
+ + +

+In case you were wondering, I am not a NOSQL fanboy, I do not go +around telling people that MongoDB is web scale. Actually my choice +for MongoDB isn't scalability, though scaling up really nicely is a +pretty good feature and sets us up well in case large volume sites +eventually do use MediaGoblin. But there's another side of +scalability, and that's scaling down, which is important for +federation, maybe even more important than scaling up in an ideal +universe where everyone ran servers out of their own housing. As a +memory-mapped database, MongoDB is pretty hungry, so actually I spent +a lot of time debating whether the inability to scale down as nicely +as something like SQL has with sqlite meant that it was out. +

+

+But I decided in the end that I really want MongoDB, not for +scalability, but for flexibility. Schema evolution pains in SQL are +almost enough reason for me to want MongoDB, but not quite. The real +reason is because I want the ability to eventually handle multiple +media types through MediaGoblin, and also allow for plugins, without +the rigidity of tables making that difficult. In other words, +something like: +

+ + + +
{"title": "Me talking until you are bored",
+ "description": "blah blah blah",
+ "media_type": "audio",
+ "media_data": {
+     "length": "2:30",
+     "codec": "OGG Vorbis"},
+ "plugin_data": {
+     "licensing": {
+         "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}}
+
+ + + +

+Being able to just dump media-specific information in a media_data +hashtable is pretty great, and even better is having a plugin system +where you can just let plugins have their own entire key-value space +cleanly inside the document that doesn't interfere with anyone else's +stuff. If we were to let plugins to deposit their own information +inside the database, either we'd let plugins create their own tables +which makes SQL migrations even harder than they already are, or we'd +probably end up creating a table with a column for key, a column for +value, and a column for type in one huge table called "plugin_data" or +something similar. (Yo dawg, I heard you liked plugins, so I put a +database in your database so you can query while you query.) Gross. +

+

+I also don't want things to be too lose so that we forget or lose the +structure of things, and that's one reason why I want to use MongoKit, +because we can cleanly define a much structure as we want and verify +that documents match that structure generally without adding too much +bloat or overhead (mongokit is a pretty lightweight wrapper and +doesn't inject extra mongokit-specific stuff into the database, which +is nice and nicer than many other ORMs in that way). +

+
+ +
+ +
+

3.3 Why wsgi minimalism / Why not Django

+
+ + +

+If you notice in the technology list above, I list a lot of components +that are very Django-like, but not actually Django components. What +can I say, I really like a lot of the ideas in Django! Which leads to +the question: why not just use Django? +

+

+While I really like Django's ideas and a lot of its components, I also +feel that most of the best ideas in Django I want have been +implemented as good or even better outside of Django. I could just +use Django and replace the templating system with Jinja2, and the form +system with wtforms, and the database with MongoDB and MongoKit, but +at that point, how much of Django is really left? +

+

+I also am sometimes saddened and irritated by how coupled all of +Django's components are. Loosely coupled yes, but still coupled. +WSGI has done a good job of providing a base layer for running +applications on and if you know how to do it yourself it's not hard or +many lines of code at all to bind them together without any framework +at all (not even say Pylons, Pyramid, or Flask which I think are still +great projects, especially for people who want this sort of thing but +have no idea how to get started). And even at this already really +early stage of writing MediaGoblin, that glue work is mostly done. +

+

+Not to say I don't think Django isn't great for a lot of things. For +a lot of stuff, it's still the best, but not for MediaGoblin, I think. +

+

+One thing that Django does super well though is documentation. It +still has some faults, but even with those considered I can hardly +think of any other project in Python that has as nice of documentation +as Django. It may be worth +learning some lessons on documentation from Django, on that note. +

+

+I'd really like to have a good, thorough hacking-howto and +deployment-howto, especially in the former making some notes on how to +make it easier for Django hackers to get started. +

+
+
+
+

Author: Christopher Allan Webber

+

Org version 7.5 with Emacs version 24

+Validate XHTML 1.0 +
+
+ + diff --git a/READMEish.org b/READMEish.org index 7f40a23f..c4e95122 100644 --- a/READMEish.org +++ b/READMEish.org @@ -1,3 +1,7 @@ +#+latex_header: \documentclass[12pt]{article} +#+latex_header: \usepackage[margin=1in]{geometry} +#+OPTIONS: ^:nil + GNU MediaGoblin * About -- cgit v1.2.3 From f7294dd96138b26830888d0b77d8de8ad6d1a320 Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Mon, 28 Mar 2011 10:28:10 -0400 Subject: Added catalogue number --- FOO300 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 FOO300 diff --git a/FOO300 b/FOO300 new file mode 100644 index 00000000..0acf17a8 --- /dev/null +++ b/FOO300 @@ -0,0 +1,15 @@ + +This certifies that GNU MediaGoblin has been given the designation of: + + FOO 300 + +In the Foo Communications ("FooCorp") catalogue of permanent record. + +Signed: + + + + + Matt Lee + + Foo Communications, LLC \ No newline at end of file -- cgit v1.2.3 From 6755f50e8e073c651bf9f26824068396bc216405 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 2 Apr 2011 10:29:54 -0500 Subject: Basic authentication tools using py-bcrypt --- mediagoblin/auth/__init__.py | 0 mediagoblin/auth/lib.py | 66 ++++++++++++++++++++++++++++++++++++++++++++ setup.py | 1 + 3 files changed, 67 insertions(+) create mode 100644 mediagoblin/auth/__init__.py create mode 100644 mediagoblin/auth/lib.py diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py new file mode 100644 index 00000000..29b955a0 --- /dev/null +++ b/mediagoblin/auth/lib.py @@ -0,0 +1,66 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os + +import bcrypt + + +def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None): + """ + Check to see if this password matches. + + Args: + - raw_pass: user submitted password to check for authenticity. + - stored_hash: The hash of the raw password (and possibly extra + salt) to check against + - extra_salt: (optional) If this password is with stored with a + non-database extra salt (probably in the config file) for extra + security, factor this into the check. + + Returns: + True or False depending on success. + """ + if extra_salt: + raw_pass = u"%s:%s" % (extra_salt, raw_pass) + + hashed_pass = bcrypt.hashpw(raw_pass, stored_hash) + + # Reduce risk of timing attacks by hashing again with a random + # number (thx to zooko on this advice, which I hopefully + # incorporated right.) + # + # See also: + rand_salt = bcrypt.gensalt(5) + randplus_stored_hash = bcrypt.hashpw(stored_hash, rand_salt) + randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt) + + return randplus_stored_hash == randplus_hashed_pass + + +def bcrypt_gen_password_hash(raw_pass, extra_salt=None): + """ + Generate a salt for this new password. + + Args: + - raw_pass: user submitted password + - extra_salt: (optional) If this password is with stored with a + non-database extra salt + """ + if extra_salt: + raw_pass = u"%s:%s" % (extra_salt, raw_pass) + + return bcrypt.hashpw(raw_pass, bcrypt.gensalt()) diff --git a/setup.py b/setup.py index 1f9f852d..5f386eef 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ setup( 'mongokit', 'webob', 'wtforms', + 'py-bcrypt', ], license = 'AGPLv3', -- cgit v1.2.3 From 4b5f4e8791064a154963a28e2614a2ce95eafc12 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 2 Apr 2011 10:48:34 -0500 Subject: Unit tests for our bcrypt auth stuff. Our first tests! --- mediagoblin/tests/__init__.py | 0 mediagoblin/tests/test_auth.py | 49 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 ++ 3 files changed, 51 insertions(+) create mode 100644 mediagoblin/tests/__init__.py create mode 100644 mediagoblin/tests/test_auth.py diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py new file mode 100644 index 00000000..5b66bb3c --- /dev/null +++ b/mediagoblin/tests/test_auth.py @@ -0,0 +1,49 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from mediagoblin.auth import lib as auth_lib + + +######################## +# Test bcrypt auth funcs +######################## + +def test_bcrypt_check_password(): + # Check known 'lollerskates' password against check function + assert auth_lib.bcrypt_check_password( + 'lollerskates', + '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO') + + # Same thing, but with extra fake salt. + assert auth_lib.bcrypt_check_password( + 'lollerskates', + '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6', + '3><7R45417') + + +def test_bcrypt_gen_password_hash(): + pw = 'youwillneverguessthis' + + # Normal password hash generation, and check on that hash + hashed_pw = auth_lib.bcrypt_gen_password_hash(pw) + assert auth_lib.bcrypt_check_password( + pw, hashed_pw) + + # Same thing, extra salt. + hashed_pw = auth_lib.bcrypt_gen_password_hash(pw, '3><7R45417') + assert auth_lib.bcrypt_check_password( + pw, hashed_pw, '3><7R45417') diff --git a/setup.py b/setup.py index 5f386eef..f38b2b60 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,9 @@ setup( 'webob', 'wtforms', 'py-bcrypt', + 'nose', ], + test_suite='nose.collector', license = 'AGPLv3', author = 'Christopher Webber', -- cgit v1.2.3 From 62615b8133fcb3ee961a0d81cb01f993b5b34c03 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 2 Apr 2011 11:20:36 -0500 Subject: Where did this o come from. --- mediagoblin/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/views.py b/mediagoblin/views.py index e286e950..37ed3a62 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -40,7 +40,7 @@ def submit_test(request): entry = request.db.MediaEntry() entry['title'] = request.POST['title'] - entry['description'] = request.POST.get(['description'])o + entry['description'] = request.POST.get(['description']) entry['media_type'] = u'image' # TODO this does NOT look save, we should clean the filename somenow? -- cgit v1.2.3 From db78002412c588273bc6177bc1c1b6ab6d1c37a0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 2 Apr 2011 12:42:07 -0500 Subject: Also make sure the auth system successfully returns False when login failboats. --- mediagoblin/tests/test_auth.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 5b66bb3c..d7397723 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -28,9 +28,14 @@ def test_bcrypt_check_password(): 'lollerskates', '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO') + assert not auth_lib.bcrypt_check_password( + 'notthepassword', + '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO') + + # Same thing, but with extra fake salt. - assert auth_lib.bcrypt_check_password( - 'lollerskates', + assert not auth_lib.bcrypt_check_password( + 'notthepassword', '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6', '3><7R45417') @@ -42,8 +47,13 @@ def test_bcrypt_gen_password_hash(): hashed_pw = auth_lib.bcrypt_gen_password_hash(pw) assert auth_lib.bcrypt_check_password( pw, hashed_pw) + assert not auth_lib.bcrypt_check_password( + 'notthepassword', hashed_pw) + # Same thing, extra salt. hashed_pw = auth_lib.bcrypt_gen_password_hash(pw, '3><7R45417') assert auth_lib.bcrypt_check_password( pw, hashed_pw, '3><7R45417') + assert not auth_lib.bcrypt_check_password( + 'notthepassword', hashed_pw, '3><7R45417') -- cgit v1.2.3 From 73a6e206e679b707ba6b0e138b74e96b94da75f4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 09:58:35 -0500 Subject: Put the User object officially in the 'users' document collection --- mediagoblin/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index c05fe3de..31ddf13c 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -44,6 +44,8 @@ class MediaEntry(Document): pass class User(Document): + __collection__ = 'users' + structure = { 'username': unicode, 'created': datetime.datetime, -- cgit v1.2.3 From e0bc23d3700cd37926e0d95057d7cd2daab69d78 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 13:33:45 -0500 Subject: We should return a unicode object in bcrypt_gen_password_hash --- mediagoblin/auth/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 29b955a0..8de67d14 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -63,4 +63,4 @@ def bcrypt_gen_password_hash(raw_pass, extra_salt=None): if extra_salt: raw_pass = u"%s:%s" % (extra_salt, raw_pass) - return bcrypt.hashpw(raw_pass, bcrypt.gensalt()) + return unicode(bcrypt.hashpw(raw_pass, bcrypt.gensalt())) -- cgit v1.2.3 From a0598d5cae99f1a8c01c01390dff5f1f94e12d0f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 13:35:01 -0500 Subject: Base mediagoblin template, and register templates --- .../templates/mediagoblin/auth/register.html | 16 ++++++++++ .../mediagoblin/auth/register_success.html | 8 +++++ mediagoblin/templates/mediagoblin/base.html | 36 ++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/auth/register.html create mode 100644 mediagoblin/templates/mediagoblin/auth/register_success.html create mode 100644 mediagoblin/templates/mediagoblin/base.html diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html new file mode 100644 index 00000000..6a051654 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -0,0 +1,16 @@ +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} + +
{{ field.label }}{{ field }}
{{field.label}} + {{field}} + {% if field.errors %} +
+
    + {% for error in field.errors %} +
  • {{error}}
  • + {% endfor %} +
+ {% endif %} +
+ {{ wtforms_util.render_table(register_form) }} + + + + +
+
+{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/register_success.html b/mediagoblin/templates/mediagoblin/auth/register_success.html new file mode 100644 index 00000000..afbd57d7 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/register_success.html @@ -0,0 +1,8 @@ +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} +

+ Register successful! :D
+ You should get a confirmation email soon. +

+{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html new file mode 100644 index 00000000..d2ee7ff7 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/base.html @@ -0,0 +1,36 @@ + + + {% block title %}Mediagoblin{% endblock title %} + {# #} + + + + + {% block mediagoblin_body %} + {% block mediagoblin_header %} + + + + + + + + + +
{% block mediagoblin_header_title %}Mediagoblin Home{% endblock %}
+ {% block mediagoblin_header_subtitle %} + perhaps some subtitle here + {% endblock %}
+ {% endblock %} +
+ {% block mediagoblin_content %} + {% endblock mediagoblin_content %} +
+ {% endblock mediagoblin_body %} + + -- cgit v1.2.3 From 24181820162ad73823dcebf902c951200b90559b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 13:35:18 -0500 Subject: Registering almost works right :) --- mediagoblin/auth/forms.py | 37 +++++++++++++++++++++++ mediagoblin/auth/routing.py | 11 +++++++ mediagoblin/auth/views.py | 72 +++++++++++++++++++++++++++++++++++++++++++++ mediagoblin/models.py | 7 +++-- mediagoblin/routing.py | 7 +++++ 5 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 mediagoblin/auth/forms.py create mode 100644 mediagoblin/auth/routing.py create mode 100644 mediagoblin/auth/views.py diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py new file mode 100644 index 00000000..ce786002 --- /dev/null +++ b/mediagoblin/auth/forms.py @@ -0,0 +1,37 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import wtforms + + +class RegistrationForm(wtforms.Form): + username = wtforms.TextField( + 'Username', + [wtforms.validators.Required(), + wtforms.validators.Length(min=3, max=30), + wtforms.validators.Regexp(r'^\w+$')]) + password = wtforms.TextField( + 'Password', + [wtforms.validators.Required(), + wtforms.validators.Length(min=8, max=30), + wtforms.validators.EqualTo('confirm_password')]) + confirm_password = wtforms.TextField( + 'Confirm password', + [wtforms.validators.Required()]) + email = wtforms.TextField( + 'Email address', + [wtforms.validators.Required(), + wtforms.validators.Email()]) diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py new file mode 100644 index 00000000..5b604fdd --- /dev/null +++ b/mediagoblin/auth/routing.py @@ -0,0 +1,11 @@ +from routes.route import Route + +auth_routes = [ + Route('mediagoblin.auth.register', '/register/', + controller='mediagoblin.auth.views:register'), + Route('mediagoblin.auth.register_success', '/register/success/', + controller='mediagoblin.auth.views:register_success'), + Route('mediagoblin.auth.login', '/login/', + controller='mediagoblin.auth.views:login'), + Route('mediagoblin.auth.logout', '/logout/', + controller='mediagoblin.auth.views:logout')] diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py new file mode 100644 index 00000000..d970679b --- /dev/null +++ b/mediagoblin/auth/views.py @@ -0,0 +1,72 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from webob import Response, exc + +from mediagoblin.auth import lib as auth_lib +from mediagoblin.auth import forms as auth_forms + + +def register(request): + """ + Your classic registration view! + """ + register_form = auth_forms.RegistrationForm(request.POST) + + if request.method == 'POST' and register_form.validate(): + # TODO: Make sure the user doesn't exist already + users_with_username = \ + request.db.User.find({'username': request.POST['username']}).count() + + if users_with_username: + register_form.username.errors.append( + u'Sorry, a user with that name already exists.') + + else: + # Create the user + entry = request.db.User() + entry['username'] = request.POST['username'] + entry['email'] = request.POST['email'] + entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + request.POST['password']) + entry.save(validate=True) + + # TODO: Send email authentication request + + # Redirect to register_success + return exc.HTTPTemporaryRedirect( + location=request.urlgen("mediagoblin.auth.register_success")) + + # render + template = request.template_env.get_template( + 'mediagoblin/auth/register.html') + return Response( + template.render( + {'request': request, + 'register_form': register_form})) + + +def register_success(request): + template = request.template_env.get_template( + 'mediagoblin/auth/register_success.html') + return Response( + template.render( + {'request': request})) + + +def login(): + pass diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 31ddf13c..b1d63181 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -48,15 +48,18 @@ class User(Document): structure = { 'username': unicode, + 'email': unicode, 'created': datetime.datetime, 'plugin_data': dict, # plugins can dump stuff here. 'pw_hash': unicode, + 'email_verified': bool, } - required_fields = ['username', 'created', 'pw_hash'] + required_fields = ['username', 'created', 'pw_hash', 'email'] default_values = { - 'created': datetime.datetime.utcnow} + 'created': datetime.datetime.utcnow, + 'email_verified': False} REGISTER_MODELS = [MediaEntry, User] diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index c60f121c..f5b67f38 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -16,6 +16,9 @@ from routes import Mapper +from mediagoblin.auth.routing import auth_routes + + def get_mapper(): mapping = Mapper() mapping.minimization = False @@ -27,4 +30,8 @@ def get_mapper(): "test_submit", "/test_submit/", controller="mediagoblin.views:submit_test") + mapping.extend(auth_routes, '/auth') + return mapping + + -- cgit v1.2.3 From 73cb7b8efccd5f220de04005e3b933018f8c227c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 14:58:51 -0500 Subject: Return an HTTPFound, not HTTPTemporaryRedirect --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d970679b..d60e9157 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -48,7 +48,7 @@ def register(request): # TODO: Send email authentication request # Redirect to register_success - return exc.HTTPTemporaryRedirect( + return exc.HTTPFound( location=request.urlgen("mediagoblin.auth.register_success")) # render -- cgit v1.2.3 From f5def6fe239f0f1b2dabfe122ca8b3b51aabb6d3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 15:02:06 -0500 Subject: Use the passwordfield for password fields, obviously ;o --- mediagoblin/auth/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index ce786002..86d82a61 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -23,12 +23,12 @@ class RegistrationForm(wtforms.Form): [wtforms.validators.Required(), wtforms.validators.Length(min=3, max=30), wtforms.validators.Regexp(r'^\w+$')]) - password = wtforms.TextField( + password = wtforms.PasswordField( 'Password', [wtforms.validators.Required(), - wtforms.validators.Length(min=8, max=30), + wtforms.validators.Length(min=6, max=30), wtforms.validators.EqualTo('confirm_password')]) - confirm_password = wtforms.TextField( + confirm_password = wtforms.PasswordField( 'Confirm password', [wtforms.validators.Required()]) email = wtforms.TextField( -- cgit v1.2.3 From c15c9843b452a1c6468f8c0d1b2f358eb31a1e10 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 15:31:16 -0500 Subject: Added a fake_login_attempt utility. --- mediagoblin/auth/lib.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 8de67d14..5db4982b 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -16,7 +16,7 @@ import os -import bcrypt +import random def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None): @@ -64,3 +64,20 @@ def bcrypt_gen_password_hash(raw_pass, extra_salt=None): raw_pass = u"%s:%s" % (extra_salt, raw_pass) return unicode(bcrypt.hashpw(raw_pass, bcrypt.gensalt())) + + +def fake_login_attempt(): + """ + Pretend we're trying to login. + + Nothing actually happens here, we're just trying to take up some + time. + """ + rand_salt = bcrypt.gensalt(5) + + hashed_pass = bcrypt.hashpw(str(random.random()), rand_salt) + + randplus_stored_hash = bcrypt.hashpw(str(random.random()), rand_salt) + randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt) + + randplus_stored_hash == randplus_hashed_pass -- cgit v1.2.3 From 692fd1c981afcfb75fdebe9018d5a63d6e94e461 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 16:32:01 -0500 Subject: starting to write login code --- mediagoblin/auth/views.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d60e9157..cbf7c816 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -68,5 +68,39 @@ def register_success(request): {'request': request})) -def login(): - pass +def login(request): + login_form = auth_forms.LoginForm(request.POST) + + if request.method == 'POST' and login_form.validate(): + #try: + user = request.db.User.find_one( + {'username': request.POST['username']}) + + if user.check_login(request.POST['password']): + # set up login in session + request.session['user_id'] = unicode(user['_id']) + + import pdb + pdb.set_trace() + + + else: + # Prevent detecting who's on this system by testing login + # attempt timings + auth_lib.fake_login_attempt() + + # render + template = request.template_env.get_template( + 'mediagoblin/auth/login.html') + return Response( + template.render( + {'request': request, + 'login_form': login_form})) + + +def logout(request): + template = request.template_env.get_template( + 'mediagoblin/auth/logout.html') + return Response( + template.render( + {'request': request})) -- cgit v1.2.3 From 51479a1d22a15744fecb8eddb367ab1a8dce8328 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 16:37:15 -0500 Subject: Clarified documentation on fake_login_attempt and restored bcrypt import --- mediagoblin/auth/lib.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 5db4982b..907ba200 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -15,9 +15,10 @@ # along with this program. If not, see . import os - import random +import bcrypt + def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None): """ @@ -71,7 +72,9 @@ def fake_login_attempt(): Pretend we're trying to login. Nothing actually happens here, we're just trying to take up some - time. + time, approximately the same amount of time as + bcrypt_check_password, so as to avoid figuring out what users are + on the system by intentionally faking logins a bunch of times. """ rand_salt = bcrypt.gensalt(5) -- cgit v1.2.3 From 14ba9383de2ff03f2af9bf0595c7b8f1fd43ac7a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 16:37:36 -0500 Subject: Use beaker from middleware, it's official. --- mediagoblin/app.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 632a0c25..cc8cec31 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -81,8 +81,7 @@ class MediagoblinApp(object): request.db = self.db # Do we really want to load this via middleware? Maybe? - # let's comment it out till we start using it :) - #request.session = request.environ['beaker.session'] + request.session = request.environ['beaker.session'] return controller(request)(environ, start_response) -- cgit v1.2.3 From 4ad5af85e20799eda5143120657e131e50aef41d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 16:38:13 -0500 Subject: Added a check_login command to User --- mediagoblin/models.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index b1d63181..af10e795 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -14,9 +14,11 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import datetime + from mongokit import Document, Set -import datetime +from mediagoblin.auth import lib as auth_lib class MediaEntry(Document): @@ -61,6 +63,13 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False} + def check_login(self, password): + """ + See if a user can login with this password + """ + return auth_lib.bcrypt_check_password( + password, self['pw_hash']) + REGISTER_MODELS = [MediaEntry, User] -- cgit v1.2.3 From a37767172b7c67dbc35211c9d57dc69d1b1c783f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 17:05:30 -0500 Subject: Logins seem to work. --- mediagoblin/auth/forms.py | 10 ++++++++++ mediagoblin/auth/views.py | 21 +++++++++++++++++---- mediagoblin/templates/mediagoblin/auth/login.html | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/auth/login.html diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 86d82a61..33403544 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -35,3 +35,13 @@ class RegistrationForm(wtforms.Form): 'Email address', [wtforms.validators.Required(), wtforms.validators.Email()]) + + +class LoginForm(wtforms.Form): + username = wtforms.TextField( + 'Username', + [wtforms.validators.Required(), + wtforms.validators.Regexp(r'^\w+$')]) + password = wtforms.PasswordField( + 'Password', + [wtforms.validators.Required()]) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index cbf7c816..16588a5b 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -69,8 +69,15 @@ def register_success(request): def login(request): + """ + Mediagoblin login view. + + If you provide the POST with 'next', it'll redirect to that view. + """ login_form = auth_forms.LoginForm(request.POST) + login_failed = False + if request.method == 'POST' and login_form.validate(): #try: user = request.db.User.find_one( @@ -79,15 +86,19 @@ def login(request): if user.check_login(request.POST['password']): # set up login in session request.session['user_id'] = unicode(user['_id']) + request.session.save() - import pdb - pdb.set_trace() - + if request.POST.has_key('next'): + return exc.HTTPFound(location=request.POST['next']) + else: + return exc.HTTPFound( + location=request.urlgen("index")) else: # Prevent detecting who's on this system by testing login # attempt timings auth_lib.fake_login_attempt() + login_failed = True # render template = request.template_env.get_template( @@ -95,7 +106,9 @@ def login(request): return Response( template.render( {'request': request, - 'login_form': login_form})) + 'login_form': login_form, + 'next': request.GET.get('next') or request.POST.get('next'), + 'login_failed': login_failed})) def logout(request): diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html new file mode 100644 index 00000000..4e775f56 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -0,0 +1,23 @@ +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +

Login:

+ +
+ + {% if login_failed %} +

Login failed!

+ {% endif %} + + + {{ wtforms_util.render_table(login_form) }} + + + + +
+
+{% endblock %} -- cgit v1.2.3 From b97232fa2f8f5fbf5c1999c348a3cae66acf4834 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:23:40 -0500 Subject: Working logout function --- mediagoblin/auth/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 16588a5b..71c2d7a9 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -112,8 +112,8 @@ def login(request): def logout(request): - template = request.template_env.get_template( - 'mediagoblin/auth/logout.html') - return Response( - template.render( - {'request': request})) + # Maybe deleting the user_id parameter would be enough? + request.session.delete() + + return exc.HTTPFound( + location=request.urlgen("index")) -- cgit v1.2.3 From d193896315ea3729759fa92e227c21073f4d4568 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:28:17 -0500 Subject: Also handle when there is no such user --- mediagoblin/auth/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 71c2d7a9..03c31576 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -79,11 +79,10 @@ def login(request): login_failed = False if request.method == 'POST' and login_form.validate(): - #try: user = request.db.User.find_one( {'username': request.POST['username']}) - if user.check_login(request.POST['password']): + if user and user.check_login(request.POST['password']): # set up login in session request.session['user_id'] = unicode(user['_id']) request.session.save() -- cgit v1.2.3 From b058cf15f0ef79fcc4d24f2952e5d55ff0be46cc Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:32:29 -0500 Subject: We should use one instead of find_one to really make sure there's only one such user in the database --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 03c31576..d56dfa43 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -79,7 +79,7 @@ def login(request): login_failed = False if request.method == 'POST' and login_form.validate(): - user = request.db.User.find_one( + user = request.db.User.one( {'username': request.POST['username']}) if user and user.check_login(request.POST['password']): -- cgit v1.2.3 From 58dec5efe56d8affd7aa60f5d01a3c7f3d4fcbb4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:34:05 -0500 Subject: Added setup_user_in_request --- mediagoblin/util.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 578261b9..5a56d432 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import jinja2 +import mongokit def get_jinja_env(user_template_path=None): if user_template_path: @@ -25,3 +26,27 @@ def get_jinja_env(user_template_path=None): loader = jinja2.PackageLoader('mediagoblin', 'templates') return jinja2.Environment(loader=loader, autoescape=True) + + +def setup_user_in_request(request): + """ + Examine a request and tack on a request.user parameter if that's + appropriate. + """ + if not request.session.has_key('user_id'): + return + + try: + user = request.db.User.one({'_id': request.session['user_id']}) + + if user: + request.user = user + else: + # Something's wrong... this user doesn't exist? Invalidate + # this session. + request.session.invalidate() + + except mongokit.MultipleResultsFound: + # Something's wrong... we shouldn't have multiple users with + # the same user id. Invalidate this session. + request.session.invalidate() -- cgit v1.2.3 From 5d6840a0107448550437ce2360dfc905797e47a7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:35:52 -0500 Subject: We should always have a request.user object, even if None. --- mediagoblin/util.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 5a56d432..fe77a0d9 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -36,12 +36,12 @@ def setup_user_in_request(request): if not request.session.has_key('user_id'): return + user = None + try: user = request.db.User.one({'_id': request.session['user_id']}) - if user: - request.user = user - else: + if not user: # Something's wrong... this user doesn't exist? Invalidate # this session. request.session.invalidate() @@ -50,3 +50,5 @@ def setup_user_in_request(request): # Something's wrong... we shouldn't have multiple users with # the same user id. Invalidate this session. request.session.invalidate() + + request.user = user -- cgit v1.2.3 From a3fdcf5ce0fafe3ad50429a9a0870a40717ccb75 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:40:01 -0500 Subject: This should allow for request.user and show users logged in ... except it's not working? --- mediagoblin/app.py | 2 +- mediagoblin/templates/mediagoblin/base.html | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index cc8cec31..a9ae223c 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -79,9 +79,9 @@ class MediagoblinApp(object): request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) request.db = self.db - # Do we really want to load this via middleware? Maybe? request.session = request.environ['beaker.session'] + util.setup_user_in_request(request) return controller(request)(environ, start_response) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index d2ee7ff7..fa126857 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -22,9 +22,27 @@ {% block mediagoblin_header_subtitle %} - perhaps some subtitle here + Clever subtitle here! {% endblock %} + {% if request.user %} + + + + Welcome {{ user['username'] }}! -- + + Logout + + + {% else %} + + + + + Login + + + {% endif %} {% endblock %}
-- cgit v1.2.3 From 59dd5c7e96ef454d7430727415309b43182590fa Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:55:55 -0500 Subject: Functioning request.user, and a functioning greeting for users :) --- mediagoblin/templates/mediagoblin/base.html | 2 +- mediagoblin/util.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index fa126857..546dc264 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -29,7 +29,7 @@ - Welcome {{ user['username'] }}! -- + Welcome {{ request.user['username'] }}! -- Logout diff --git a/mediagoblin/util.py b/mediagoblin/util.py index fe77a0d9..f5709123 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -34,12 +34,14 @@ def setup_user_in_request(request): appropriate. """ if not request.session.has_key('user_id'): + request.user = None return user = None try: - user = request.db.User.one({'_id': request.session['user_id']}) + user = request.db.User.one( + {'_id': mongokit.ObjectId(request.session['user_id'])}) if not user: # Something's wrong... this user doesn't exist? Invalidate -- cgit v1.2.3 From c74e1462feed4c8be9b3004893df2bf236b422cc Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:56:48 -0500 Subject: Since we're searching by id, that try: except: was superfluous. --- mediagoblin/util.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index f5709123..6551a3cc 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -38,19 +38,12 @@ def setup_user_in_request(request): return user = None + user = request.db.User.one( + {'_id': mongokit.ObjectId(request.session['user_id'])}) - try: - user = request.db.User.one( - {'_id': mongokit.ObjectId(request.session['user_id'])}) - - if not user: - # Something's wrong... this user doesn't exist? Invalidate - # this session. - request.session.invalidate() - - except mongokit.MultipleResultsFound: - # Something's wrong... we shouldn't have multiple users with - # the same user id. Invalidate this session. + if not user: + # Something's wrong... this user doesn't exist? Invalidate + # this session. request.session.invalidate() request.user = user -- cgit v1.2.3 From 146ad23e9b651d71cbdddf5be76a28ed5cb60353 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 3 Apr 2011 18:58:23 -0500 Subject: Herp derp GPL notice blocks should even be on routing. --- mediagoblin/auth/routing.py | 16 ++++++++++++++++ mediagoblin/routing.py | 2 -- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 5b604fdd..e304de9b 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -1,3 +1,19 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + from routes.route import Route auth_routes = [ diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index f5b67f38..1401b723 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -33,5 +33,3 @@ def get_mapper(): mapping.extend(auth_routes, '/auth') return mapping - - -- cgit v1.2.3 From 3eae167e0f40b26d480a47f73f1b44deb9752629 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 7 Apr 2011 20:11:06 -0400 Subject: Adds Sphinx docs infrastructure. --- docs/Makefile | 130 ++++++++++++++++++++++++++++++++++ docs/conf.py | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 20 ++++++ 3 files changed, 366 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..81fc3d13 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GNUMediaGoblin.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GNUMediaGoblin.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/GNUMediaGoblin" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GNUMediaGoblin" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..02c190a0 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# GNU MediaGoblin documentation build configuration file, created by +# sphinx-quickstart on Thu Apr 7 20:10:27 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'GNU MediaGoblin' +copyright = u'2011, Chris Webber, et al' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1a1' +# The full version, including alpha/beta/rc tags. +release = '0.1a1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'GNUMediaGoblindoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'GNUMediaGoblin.tex', u'GNU MediaGoblin Documentation', + u'Chris Webber, et al', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'gnumediagoblin', u'GNU MediaGoblin Documentation', + [u'Chris Webber, et al'], 1) +] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..94f6c7f7 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,20 @@ +.. GNU MediaGoblin documentation master file, created by + sphinx-quickstart on Thu Apr 7 20:10:27 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to GNU MediaGoblin's documentation! +=========================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + -- cgit v1.2.3 From f75a49b2f2973b47c95a737427d7fd9c478d8e7a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 08:08:23 -0500 Subject: Adding staticdirect infrastructure from cc.engine --- mediagoblin/staticdirect.py | 72 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 mediagoblin/staticdirect.py diff --git a/mediagoblin/staticdirect.py b/mediagoblin/staticdirect.py new file mode 100644 index 00000000..1c87c7ba --- /dev/null +++ b/mediagoblin/staticdirect.py @@ -0,0 +1,72 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import pkg_resources +import urlparse + +#################################### +# Staticdirect infrastructure. +# Borrowed largely from cc.engine +# by Chris Webber & Creative Commons +# +# This needs documentation! +#################################### + +import pkg_resources +import urlparse + +class StaticDirect(object): + def __init__(self): + self.cache = {} + + def __call__(self, filepath): + if self.cache.has_key(filepath): + return self.cache[filepath] + + static_direction = self.cache[filepath] = self.get(filepath) + return static_direction + + + def get(self, filepath): + # should be implemented by the individual staticdirector + pass + + +class RemoteStaticDirect(StaticDirect): + def __init__(self, remotepath): + StaticDirect.__init__(self) + self.remotepath = remotepath.rstrip('/') + + def get(self, filepath): + return '%s/%s' % ( + self.remotepath, filepath.lstrip('/')) + + +class MultiRemoteStaticDirect(StaticDirect): + """ + For whene separate sections of the static data is served under + separate urls. + """ + def __init__(self, remotepaths): + StaticDirect.__init__(self) + self.remotepaths = remotepaths + + def get(self, filepath): + section, rest = filepath.strip('/').split('/', 1) + + return '%s/%s' % ( + self.remotepaths[section].rstrip('/'), + rest.lstrip('/')) -- cgit v1.2.3 From 9578fe504795fef05f9bfaa802a3d7ee0fa1d440 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 08:11:43 -0500 Subject: Include werkzeug. We'll need it for werkzeug.util.secure_filename at least. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index f38b2b60..8be416b1 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ setup( 'wtforms', 'py-bcrypt', 'nose', + 'werkzeug', ], test_suite='nose.collector', -- cgit v1.2.3 From a6b378ef4d8a30eb1c832ea131167c8f69fc7d34 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 11:41:09 -0500 Subject: file storage filelist cleaning --- mediagoblin/storage.py | 41 +++++++++++++++++++++++++++++++++++++++ mediagoblin/tests/test_storage.py | 32 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 mediagoblin/storage.py create mode 100644 mediagoblin/tests/test_storage.py diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py new file mode 100644 index 00000000..c06cb3a8 --- /dev/null +++ b/mediagoblin/storage.py @@ -0,0 +1,41 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from werkzeug.utils import secure_filename + + +def clean_listy_filepath(listy_filepath): + """ + Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and + clean out any nastiness from it. + + For example: + >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg']) + [u'dir1', u'foo_.._nasty', u'linooks.jpg'] + + Args: + - listy_filepath: a list of filepath components, mediagoblin + storage API style. + + Returns: + A cleaned list of unicode objects. + """ + return [ + unicode(secure_filename(filepath)) + for filepath in listy_filepath] + + diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py new file mode 100644 index 00000000..b7da467c --- /dev/null +++ b/mediagoblin/tests/test_storage.py @@ -0,0 +1,32 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from mediagoblin import storage + + +def test_clean_listy_filepath(): + expected = [u'dir1', u'dir2', u'linooks.jpg'] + assert storage.clean_listy_filepath( + ['dir1', 'dir2', 'linooks.jpg']) == expected + + expected = [u'dir1', u'foo_.._nasty', u'linooks.jpg'] + assert storage.clean_listy_filepath( + ['/dir1/', 'foo/../nasty', 'linooks.jpg']) == expected + + expected = [u'etc', u'passwd'] + assert storage.clean_listy_filepath( + ['../../../etc/', 'passwd']) == expected -- cgit v1.2.3 From 770c12be8d29ab0d6960bbc20ca5c58363da753d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 11:45:38 -0500 Subject: Raise a specific error if a filename component can't be resolved into anything. --- mediagoblin/storage.py | 12 +++++++++++- mediagoblin/tests/test_storage.py | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index c06cb3a8..805be84c 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -18,6 +18,10 @@ from werkzeug.utils import secure_filename +class Error(Exception): pass +class InvalidFilepath(Error): pass + + def clean_listy_filepath(listy_filepath): """ Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and @@ -34,8 +38,14 @@ def clean_listy_filepath(listy_filepath): Returns: A cleaned list of unicode objects. """ - return [ + cleaned_filepath = [ unicode(secure_filename(filepath)) for filepath in listy_filepath] + if u'' in cleaned_filepath: + raise InvalidFilepath( + "A filename component could not be resolved into a usable name.") + + return cleaned_filepath + diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index b7da467c..cdcddf09 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -30,3 +30,12 @@ def test_clean_listy_filepath(): expected = [u'etc', u'passwd'] assert storage.clean_listy_filepath( ['../../../etc/', 'passwd']) == expected + + try: + storage.clean_listy_filepath( + ['../../', 'linooks.jpg']) + except storage.InvalidFilepath: + # Yes, this error should be raise + pass + else: + assert "success" == "failboat" -- cgit v1.2.3 From 797be93ca678c7c0735b0041cf43089d227a6a1c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 14:02:54 -0500 Subject: Most of the StorageInterface stubs in place and documented. --- mediagoblin/storage.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 805be84c..cd61a6aa 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -21,6 +21,8 @@ from werkzeug.utils import secure_filename class Error(Exception): pass class InvalidFilepath(Error): pass +class NotImplementedError(Error): pass + def clean_listy_filepath(listy_filepath): """ @@ -49,3 +51,58 @@ def clean_listy_filepath(listy_filepath): return cleaned_filepath +class StorageInterface(object): + """ + Interface for the storage API. + + This interface doesn't actually provide behavior, but it defines + what kind of storage patterns subclasses should provide. + + It is important to note that the storage API idea of a "filepath" + is actually like ['dir1', 'dir2', 'file.jpg'], so keep that in + mind while reading method documentation. + """ + # def __init__(self, *args, **kwargs): + # pass + + def __raise_not_implemented(self): + """ + Raise a warning about some component not implemented by a + subclass of this interface. + """ + raise NotImplementedError( + "This feature not implemented in this storage API implementation.") + + def file_exists(self, filepath): + """ + Return a boolean asserting whether or not file at filepath + exists in our storage system. + + Returns: + True / False depending on whether file exists or not. + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def get_unique_filename(self, filepath): + """ + If a filename at filepath already exists, generate a new name. + + Eg, if the filename doesn't exist: + >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) + [u'dir1', u'dir2', u'fname.jpg'] + + But if a file does exist, let's get one back with at uuid tacked on: + >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) + ['dir1', 'dir2', 'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def get_file(self, filepath): + # Subclasses should override this method. + self.__raise_not_implemented() + + def delete_file(self, filepath): + # Subclasses should override this method. + self.__raise_not_implemented() -- cgit v1.2.3 From 0b9cf289c3f479ba1acb728b5aa6ec2e1d8b4e49 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 14:05:44 -0500 Subject: Actually, we can implement get_unique_filename, which should be the same across all storage API implementations --- mediagoblin/storage.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index cd61a6aa..3b6a7a2a 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -84,6 +84,14 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() + def get_file(self, filepath): + # Subclasses should override this method. + self.__raise_not_implemented() + + def delete_file(self, filepath): + # Subclasses should override this method. + self.__raise_not_implemented() + def get_unique_filename(self, filepath): """ If a filename at filepath already exists, generate a new name. @@ -96,13 +104,7 @@ class StorageInterface(object): >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) ['dir1', 'dir2', 'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] """ - # Subclasses should override this method. - self.__raise_not_implemented() - - def get_file(self, filepath): - # Subclasses should override this method. - self.__raise_not_implemented() - - def delete_file(self, filepath): - # Subclasses should override this method. - self.__raise_not_implemented() + if self.file_exists(filepath): + return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] + else: + return filepath -- cgit v1.2.3 From ef10e3a2c783d0ac54383e2c659eb9660996535e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 14:08:07 -0500 Subject: u'string', but of course ;) --- mediagoblin/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 3b6a7a2a..8e62a3a6 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -102,7 +102,7 @@ class StorageInterface(object): But if a file does exist, let's get one back with at uuid tacked on: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) - ['dir1', 'dir2', 'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] + [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] """ if self.file_exists(filepath): return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] -- cgit v1.2.3 From b0de01cf0102ec596c2bdec553eb73713e9da103 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 9 Apr 2011 14:26:41 -0500 Subject: More documentation on all the core storage API methods --- mediagoblin/storage.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 8e62a3a6..4e0960c7 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -84,11 +84,22 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() - def get_file(self, filepath): + def get_file(self, filepath, mode): + """ + Return a file-like object for reading/writing from this filepath. + + Should create directories, buckets, whatever, as necessary. + """ # Subclasses should override this method. self.__raise_not_implemented() def delete_file(self, filepath): + """ + Delete or dereference the file at filepath. + + This might need to delete directories, buckets, whatever, for + cleanliness. (Be sure to avoid race conditions on that though) + """ # Subclasses should override this method. self.__raise_not_implemented() -- cgit v1.2.3 From 8736b05d051dc5f2777dc4f86e684e3a3cec6a7c Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 9 Apr 2011 18:43:26 -0400 Subject: Fleshes out documentation. use, what their function is, and urls for library documentation * adds a forward chapter which talks about the documentation * adds an installation stub * adds a software stack chapter that covers what libraries are in * adds a design decisions chapter which covers why we chose the libraries and architecture --- docs/designdecisions.rst | 170 +++++++++++++++++++++++++++++++++++++++++++++++ docs/foreward.rst | 31 +++++++++ docs/index.rst | 13 ++++ docs/installation.rst | 5 ++ docs/softwarestack.rst | 127 +++++++++++++++++++++++++++++++++++ 5 files changed, 346 insertions(+) create mode 100644 docs/designdecisions.rst create mode 100644 docs/foreward.rst create mode 100644 docs/installation.rst create mode 100644 docs/softwarestack.rst diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst new file mode 100644 index 00000000..f30c1ca5 --- /dev/null +++ b/docs/designdecisions.rst @@ -0,0 +1,170 @@ +.. _design-decisions-chapter: + +================== + Design Decisions +================== + +This chapter talks a bit about design decisions. + + +Why Python +========== + +Chris Webber on "Why Python": + + Because I know Python, love Python, am capable of actually making + this thing happen in Python (I've worked on a lot of large free + software web applications before in Python, including `Miro + Community`_, the `Miro Guide`_, a large portion of `Creative + Commons`_, and a whole bunch of things while working at `Imaginary + Landscape`_). I know Python, I can make this happen in Python, me + starting a project like this makes sense if it's done in Python. + + You might say that PHP is way more deployable, that Rails has way + more cool developers riding around on fixie bikes, and all of + those things are true. But I know Python, like Python, and think + that Python is pretty great. I do think that deployment in Python + is not as good as with PHP, but I think the days of shared hosting + are (thankfully) coming to an end, and will probably be replaced + by cheap virtual machines spun up on the fly for people who want + that sort of stuff, and Python will be a huge part of that future, + maybe even more than PHP will. The deployment tools are getting + better. Maybe we can use something like Silver Lining. Maybe we + can just distribute as ``.debs`` or ``.rpms``. We'll figure it + out when we get there. + + Regardless, if I'm starting this project, which I am, it's gonna + be in Python. + +.. _Miro Community: http://mirocommunity.org/ +.. _Miro Guide: http://miroguide.org/ +.. _Creative Commons: http://creativecommons.org/ +.. _Imaginary Landscape: http://www.imagescape.com/ + + +Why WSGI Minimalism +=================== + +Chris Webber on "Why WSGI Minimalism": + + If you notice in the technology list above, I list a lot of + components that are very `Django Project`_, but not actually + Django components. What can I say, I really like a lot of the + ideas in Django! Which leads to the question: why not just use + Django? + + While I really like Django's ideas and a lot of its components, I + also feel that most of the best ideas in Django I want have been + implemented as good or even better outside of Django. I could + just use Django and replace the templating system with Jinja2, and + the form system with wtforms, and the database with MongoDB and + MongoKit, but at that point, how much of Django is really left? + + I also am sometimes saddened and irritated by how coupled all of + Django's components are. Loosely coupled yes, but still coupled. + WSGI has done a good job of providing a base layer for running + applications on and if you know how to do it yourself [1]_, it's + not hard or many lines of code at all to bind them together + without any framework at all (not even say `Pylons`_, `Pyramid`_ + or `Flask`_ which I think are still great projects, especially for + people who want this sort of thing but have no idea how to get + started). And even at this already really early stage of writing + MediaGoblin, that glue work is mostly done. + + Not to say I don't think Django isn't great for a lot of things. + For a lot of stuff, it's still the best, but not for MediaGoblin, + I think. + + One thing that Django does super well though is documentation. It + still has some faults, but even with those considered I can hardly + think of any other project in Python that has as nice of + documentation as Django. It may be worth learning some lessons on + documentation from Django [2]_, on that note. + + I'd really like to have a good, thorough hacking-howto and + deployment-howto, especially in the former making some notes on + how to make it easier for Django hackers to get started. + +.. _Django Project: http://www.djangoproject.com/ +.. _Pylons: http://pylonshq.com/ +.. _Pyramid: http://docs.pylonsproject.org/projects/pyramid/dev/ +.. _Flask: http://flask.pocoo.org/ + +.. [1] http://pythonpaste.org/webob/do-it-yourself.html +.. [2] http://pycon.blip.tv/file/4881071/ + + +Why MongoDB +=========== + +Chris Webber on "Why MongoDB": + + In case you were wondering, I am not a NOSQL fanboy, I do not go + around telling people that MongoDB is web scale. Actually my + choice for MongoDB isn't scalability, though scaling up really + nicely is a pretty good feature and sets us up well in case large + volume sites eventually do use MediaGoblin. But there's another + side of scalability, and that's scaling down, which is important + for federation, maybe even more important than scaling up in an + ideal universe where everyone ran servers out of their own + housing. As a memory-mapped database, MongoDB is pretty hungry, + so actually I spent a lot of time debating whether the inability + to scale down as nicely as something like SQL has with sqlite + meant that it was out. + + But I decided in the end that I really want MongoDB, not for + scalability, but for flexibility. Schema evolution pains in SQL + are almost enough reason for me to want MongoDB, but not quite. + The real reason is because I want the ability to eventually handle + multiple media types through MediaGoblin, and also allow for + plugins, without the rigidity of tables making that difficult. In + other words, something like:: + + {"title": "Me talking until you are bored", + "description": "blah blah blah", + "media_type": "audio", + "media_data": { + "length": "2:30", + "codec": "OGG Vorbis"}, + "plugin_data": { + "licensing": { + "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}} + + + Being able to just dump media-specific information in a media_data + hashtable is pretty great, and even better is having a plugin + system where you can just let plugins have their own entire + key-value space cleanly inside the document that doesn't interfere + with anyone else's stuff. If we were to let plugins to deposit + their own information inside the database, either we'd let plugins + create their own tables which makes SQL migrations even harder + than they already are, or we'd probably end up creating a table + with a column for key, a column for value, and a column for type + in one huge table called "plugin_data" or something similar. (Yo + dawg, I heard you liked plugins, so I put a database in your + database so you can query while you query.) Gross. + + I also don't want things to be too lose so that we forget or lose + the structure of things, and that's one reason why I want to use + MongoKit, because we can cleanly define a much structure as we + want and verify that documents match that structure generally + without adding too much bloat or overhead (mongokit is a pretty + lightweight wrapper and doesn't inject extra mongokit-specific + stuff into the database, which is nice and nicer than many other + ORMs in that way). + + +Why Sphinx for documentation +============================ + +Will Kahn-Greene on "Why Sphinx": + + Sphinx is a fantastic tool for organizing documentation for a + Python-based project that makes it pretty easy to write docs that + are readable in source form and can be "compiled" into HTML, LaTeX + and other formats. + + There are other doc systems out there, but given that GNU + MediaGoblin is being written in Python, it makes sense to use + Sphinx for now. + diff --git a/docs/foreward.rst b/docs/foreward.rst new file mode 100644 index 00000000..4fc8152a --- /dev/null +++ b/docs/foreward.rst @@ -0,0 +1,31 @@ +========== + Foreward +========== + +What is GNU MediaGoblin +======================= + +See the web-site at http://mediagoblin.org/ . + + +Who wrote this documentation +============================ + +* Chris Webber +* Will Kahn-Greene + + +How should I bring up errors in the documentation +================================================= + +There are a few ways--please pick the one most convenient to you! + +1. Send an email to Will ``willg at bluesock dot org``. +2. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . +3. Tell someone on IRC ``#mediagoblin`` on Freenode. + +When you tell us about your issue, please let us know: + +* where you are looking (in git? url of the web-page?) +* what the issue is +* your thoughts on how to resolve it diff --git a/docs/index.rst b/docs/index.rst index 94f6c7f7..6f96ff8c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,11 +6,24 @@ Welcome to GNU MediaGoblin's documentation! =========================================== +This documentation covers the GNU MediaGoblin software. It is versioned +alongside the code and the source for this documentation is located in +the mediagoblin repository in the ``docs/`` directory. + +It is also viewable on the Web site in HTML form. + + Contents: .. toctree:: :maxdepth: 2 + foreward + softwarestack + installation + designdecisions + + Indices and tables ================== diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 00000000..2dfd467d --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,5 @@ +============== + Installation +============== + +FIXME - this page is a stub! diff --git a/docs/softwarestack.rst b/docs/softwarestack.rst new file mode 100644 index 00000000..024f0d5d --- /dev/null +++ b/docs/softwarestack.rst @@ -0,0 +1,127 @@ +======= + Stack +======= + +The software stack for this project might change over time, but this +is what we're thinking right now. + +There's some explanation of design decisions in the +:ref:`design-decisions-chapter`. + + +Python +====== + +* http://python.org/ + +The core team does a lot of work in Python and it's the language we're +most likely to do a project like this in. + + +MongoDB +======= + +* http://www.mongodb.org/ + +A "document database". Because it's extremely flexible and scales up +well, but I guess not down well. + + +MongoKit +======== + +* http://namlook.github.com/mongokit/ + +A lightweight ORM for mongodb. Helps us define our structures better, +does schema validation, schema evolution, and helps make things more +fun and pythonic. + + +Jinja2 +====== + +* http://jinja.pocoo.org/docs/ + +For templating. Pretty much django templates++ but allows us to pass +arguments into method calls instead of writing custom tags. + + +WTForms +======= + +* http://wtforms.simplecodes.com/ + +For form handling, validation, abstraction. Almost just like Django's +templates. + + +WebOb +===== + +* http://pythonpaste.org/webob/ + +Gives nice request/response objects (also somewhat Django-ish). + + +Paste Deploy and Paste Script +============================= + +* http://pythonpaste.org/deploy/ +* http://pythonpaste.org/script/ + +This will be the default way of configuring and launching the +application. Since GNU MediaGoblin will be fairly WSGI minimalist though, +you can probably use other ways to launch it, though this will be the +default. + + +Routes +====== + +* http://routes.groovie.org/ + +For URL Routing. It works well enough. + + +JQuery +====== + +* http://jquery.com/ + +For all sorts of things on the JavaScript end of things, for all sorts +of reasons. + + +Beaker +====== + +* http://beaker.groovie.org/ + +For sessions, because that seems like it's generally considered the +way to go I guess. + + +Nose +==== + +* http://somethingaboutorange.com/mrl/projects/nose/1.0.0/ + +For unit tests because it makes testing a bit nicer. + + +Celery +====== + +* http://celeryproject.org/ + +For task queueing (resizing images, encoding video, ...). + + +RabbitMQ +======== + +* http://www.rabbitmq.com/ + +For sending tasks to celery, because I guess that's what most people +do. Might be optional, might also let people use MongoDB for this if +they want. -- cgit v1.2.3 From 779f2b9411c4e9be108546be2a03e96474d3eccd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 13:38:01 -0500 Subject: Put down structure of BasicFileStorage, and the ._resolve_filepath() method --- mediagoblin/storage.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 4e0960c7..84ceb641 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import os from werkzeug.utils import secure_filename @@ -119,3 +120,41 @@ class StorageInterface(object): return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] else: return filepath + + +class BasicFileStorage(StorageInterface): + """ + Basic local filesystem implementation of storage API + """ + + def __init__(self, base_dir, serve_url=None): + """ + Keyword arguments: + - base_dir: Base directory things will be served out of. MUST + be an absolute path. + - serve_url: URL files will be served from + """ + self.base_dir = base_dir + self.serve_url = serve_url + + def _resolve_filepath(self, filepath): + """ + Transform the given filepath into a local filesystem filepath. + """ + return os.path.join( + self.base_dir, *clean_listy_filepath(filepath)) + + def _create_dirs_for_filepath(self, filepath): + """ + Create any necessary directories for filepath + """ + pass + + def file_exists(self, filepath): + return os.path.exists(self._resolve_filepath(filepath)) + + def get_file(self, filepath, mode): + pass + + def delete_file(self, filepath): + pass -- cgit v1.2.3 From 111885814086313ee1206def7eb63149467a9149 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 14:57:23 -0500 Subject: I don't think we need _create_dirs_for_filepath. --- mediagoblin/storage.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 84ceb641..a1a3b3a4 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -144,12 +144,6 @@ class BasicFileStorage(StorageInterface): return os.path.join( self.base_dir, *clean_listy_filepath(filepath)) - def _create_dirs_for_filepath(self, filepath): - """ - Create any necessary directories for filepath - """ - pass - def file_exists(self, filepath): return os.path.exists(self._resolve_filepath(filepath)) -- cgit v1.2.3 From 644614d4dd73b171d069f73dba84b5c081eb6961 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 15:01:00 -0500 Subject: Added the url_for_file stub to the interface --- mediagoblin/storage.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index a1a3b3a4..87435ff2 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -104,6 +104,14 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() + def url_for_file(self, filepath): + """ + Get the URL for this file. This assumes our storage has been + mounted with some kind of URL which makes this possible. + """ + # Subclasses should override this method. + self.__raise_not_implemented() + def get_unique_filename(self, filepath): """ If a filename at filepath already exists, generate a new name. @@ -152,3 +160,6 @@ class BasicFileStorage(StorageInterface): def delete_file(self, filepath): pass + + def url_for_file(self, filepath): + pass -- cgit v1.2.3 From 17e7093e4b63a9df1ff717de839c6281dbf55e98 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 15:50:32 -0500 Subject: Started BasicFileStorage tests. test_basic_storage__resolve_filepath() done. Also switched to using assert_raises, which is only sane! --- mediagoblin/tests/test_storage.py | 60 +++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index cdcddf09..a30ca149 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -15,6 +15,11 @@ # along with this program. If not, see . +import os +import tempfile + +from nose.tools import assert_raises + from mediagoblin import storage @@ -31,11 +36,50 @@ def test_clean_listy_filepath(): assert storage.clean_listy_filepath( ['../../../etc/', 'passwd']) == expected - try: - storage.clean_listy_filepath( - ['../../', 'linooks.jpg']) - except storage.InvalidFilepath: - # Yes, this error should be raise - pass - else: - assert "success" == "failboat" + assert_raises( + storage.InvalidFilepath, + storage.clean_listy_filepath, + ['../../', 'linooks.jpg']) + + +########################## +# Basic file storage tests +########################## + +def get_tmp_filestorage(mount_url=None): + tmpdir = tempfile.mkdtemp() + this_storage = storage.BasicFileStorage(tmpdir, mount_url) + return tmpdir, this_storage + + +def test_basic_storage__resolve_filepath(): + tmpdir, this_storage = get_tmp_filestorage() + + result = this_storage._resolve_filepath(['dir1', 'dir2', 'filename.jpg']) + assert result == os.path.join( + tmpdir, 'dir1/dir2/filename.jpg') + + result = this_storage._resolve_filepath(['../../etc/', 'passwd']) + assert result == os.path.join( + tmpdir, 'etc/passwd') + + assert_raises( + storage.InvalidFilepath, + this_storage._resolve_filepath, + ['../../', 'etc', 'passwd']) + + +def test_basic_storage_file_exists(): + pass + + +def test_basic_storage_get_file(): + pass + + +def test_basic_storage_delete_file(): + pass + + +def test_basic_storage_url_for_file(): + pass -- cgit v1.2.3 From 92fb87ae8d3260c3a5da45aa7b0c75e401e81791 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 16:23:55 -0500 Subject: Unit tests for BasicFileStorage.file_exists() --- mediagoblin/tests/test_storage.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index a30ca149..ff49ec9b 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -70,6 +70,19 @@ def test_basic_storage__resolve_filepath(): def test_basic_storage_file_exists(): + tmpdir, this_storage = get_tmp_filestorage() + + os.makedirs(os.path.join(tmpdir, 'dir1', 'dir2')) + filename = os.path.join(tmpdir, 'dir1', 'dir2', 'filename.txt') + with open(filename, 'w') as ourfile: + ourfile.write("I'm having a lovely day!") + + assert this_storage.file_exists(['dir1', 'dir2', 'filename.txt']) + assert not this_storage.file_exists(['dir1', 'dir2', 'thisfile.lol']) + assert not this_storage.file_exists(['dnedir1', 'dnedir2', 'somefile.lol']) + + +def test_basic_storage_get_unique_filename(): pass -- cgit v1.2.3 From 2d1a60739ecfb64c16e35940b7cee1eb018eb448 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 16:44:47 -0500 Subject: get_unique_filepath not get_unique_filename! --- mediagoblin/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 87435ff2..ad8f8829 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -112,7 +112,7 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() - def get_unique_filename(self, filepath): + def get_unique_filepath(self, filepath): """ If a filename at filepath already exists, generate a new name. -- cgit v1.2.3 From 2fdec8270d786624cfe570f949eb8f0f89054eb6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 16:50:52 -0500 Subject: We should import uuid, because we use it! --- mediagoblin/storage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index ad8f8829..89b86315 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import os +import uuid from werkzeug.utils import secure_filename -- cgit v1.2.3 From 20e3ee115d5db738b071e99172d2ea97c6c0443e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 16:51:25 -0500 Subject: Test BasicFileStorage.get_unique_filepath() --- mediagoblin/tests/test_storage.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index ff49ec9b..79f1c8ea 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -19,6 +19,7 @@ import os import tempfile from nose.tools import assert_raises +from werkzeug.utils import secure_filename from mediagoblin import storage @@ -82,8 +83,24 @@ def test_basic_storage_file_exists(): assert not this_storage.file_exists(['dnedir1', 'dnedir2', 'somefile.lol']) -def test_basic_storage_get_unique_filename(): - pass +def test_basic_storage_get_unique_filepath(): + tmpdir, this_storage = get_tmp_filestorage() + + # write something that exists + os.makedirs(os.path.join(tmpdir, 'dir1', 'dir2')) + filename = os.path.join(tmpdir, 'dir1', 'dir2', 'filename.txt') + with open(filename, 'w') as ourfile: + ourfile.write("I'm having a lovely day!") + + # now we want something new, with the same name! + new_filepath = this_storage.get_unique_filepath( + ['dir1', 'dir2', 'filename.txt']) + assert new_filepath[:-1] == [u'dir1', u'dir2'] + + new_filename = new_filepath[-1] + assert new_filename.endswith('filename.txt') + assert len(new_filename) > len('filename.txt') + assert new_filename == secure_filename(new_filename) def test_basic_storage_get_file(): -- cgit v1.2.3 From cee7a1c163c0400610234f0f62455ba6d7e3160b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 10 Apr 2011 17:03:23 -0500 Subject: get_file() implementation for BasicFileStorage --- mediagoblin/storage.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 89b86315..e6e3a59d 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -86,7 +86,7 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() - def get_file(self, filepath, mode): + def get_file(self, filepath, mode='r'): """ Return a file-like object for reading/writing from this filepath. @@ -156,8 +156,16 @@ class BasicFileStorage(StorageInterface): def file_exists(self, filepath): return os.path.exists(self._resolve_filepath(filepath)) - def get_file(self, filepath, mode): - pass + def get_file(self, filepath, mode='r'): + # Make directories if necessary + if len(filepath) > 1: + directory = self._resolve_filepath(filepath[:-1]) + if not os.path.exists('directory'): + os.makedirs(directory) + + # Grab and return the file in the mode specified + return open(self._resolve_filepath(filepath), mode) + def delete_file(self, filepath): pass -- cgit v1.2.3 From a1302608736bbf14652bc1fc0bcc0f369453e0c2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 11 Apr 2011 08:39:23 -0500 Subject: Started the workflow document. Currently just mockups. Soon: more techy info. --- docs/workflow.rst | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 docs/workflow.rst diff --git a/docs/workflow.rst b/docs/workflow.rst new file mode 100644 index 00000000..218a6abd --- /dev/null +++ b/docs/workflow.rst @@ -0,0 +1,130 @@ +======================================================== + Workflow, and other structurally significant braindumps +======================================================== + +This document attempts to describe the envisioned workflow of +mediagoblin, from a structural standpoint. For now, *nothing* in this +document is probably the eventual, final way that things will work. +Eventually as things come to exist, this document will hopefully be +refactored to describe how things *do* work. + +This documented on hopes, dreams, rainbows, and unicorns. And it will +come to fulfillment through a lot of hard work. + + +Look and feel +============= + +Default look and feel +--------------------- + +Mairin Duffy made mockups for something called Design Hub. That +project did a number of things differently than the way we intend to +go, but it's probably a good idea to steal a good number of ideas from +here. + +http://mairin.wordpress.com/2010/03/09/another-design-hub-mockup/ + +User profile mockup +------------------- + +Here's an ascii art mockup on how things might look for a user's page:: + + _____ + |_( )_| USER NAME + | | | + |_/_\_| + + Recent artwork: + ___________________ ___________________________ + | ___ ___ ___ | |_About_User_Name___________| + | |pic| |pic| |pic| | | | + | |___| |___| |___| | | Some sort of self- | + | ___ ___ ___ | | description probably goes | + < | |pic| |pic| |pic| | > | here | + | |___| |___| |___| | | | + | ___ ___ ___ | | | + | |pic| |pic| |pic| | | | + | |___| |___| |___| | | | + |___________________| |___________________________| + + ___________________________ + Recent favorites: |_Recent_activity___________| + ___________________ | New picture: DragonFace | + | ___ ___ ___ | | 4/2/2010 | + | |pic| |pic| |pic| | |---------------------------| + | |___| |___| |___| | | Sup yall this is some kind| + | ___ ___ ___ | | of mini blogpost. Maybe | + < | |pic| |pic| |pic| | > | the interface will allow | + | |___| |___| |___| | | for this? | + | ___ ___ ___ | |___________________________| + | |pic| |pic| |pic| | + | |___| |___| |___| | ___________________________ + |___________________| |_External_comments_here____| + | Dang! This stuff rocks | + | - Joe 4/2/2010 | + |---------------------------| + | Nice job on the dragon | + | - Morgan 4/2/2010 | + '---------------------------' + +So there's this type of interface that puts a lot of different types +of info on the same screen. I'm not sure that I like it. It's +possible we'll go with something much more minimalist. Maybe we'll go +with something "tabbed" the way statusnet / http://identi.ca is on +user pages. + +It's possible that we could support multiple profile styles here, +and you could load whatever profile style you want as set by user +preferences? + + +Uploading mockup +---------------- + +Here's an uploading mockup:: + + Upload an image + + [ Title ] + + Upload: [ ] [Browse] + ___________________________________________ + | | + | | + | o0O | + | o ' | + | o_.' | + | | + | Uploading... OK | <-, + | Resizing... OK | | + | | Area replaced w/ resized + | | image when done + |___________________________________________| + ________________ + License |_CC BY-SA_____|V| + ___________________________________________ + | Description goes here. | + | You can type it up in here and everything | + | and it'll show up under the image. | + | | + | Possibly we should allow some kind of | + | markup... maybe markdown? | + '___________________________________________' + + __________________________________________ + |> Advanced | + ------------------------------------------ + + +Customizability +--------------- + +General site theming customizability is pretty easy! Since we're +using `Jinja `_ we can just set up +user-overriding directories. + +We'll also figure out some sort of way to provide theming "packages", +eventually. + + -- cgit v1.2.3 From 3c013c5b79776190639af748913ce8634b1b7e59 Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Mon, 11 Apr 2011 15:18:41 -0400 Subject: Adding a file for testing of CIA bot --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test diff --git a/test b/test new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 00fdc7bdee4f27ad04237bae49aa87ef75a69fb4 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 12 Apr 2011 19:56:04 -0400 Subject: Fixes docs. * fixes some typos * tweaks some language issues that occured because I took Chris' stuff out of the context of the original READMEish structure * ditches installation for deploymenthowto and hackinghowto --- docs/deploymenthowto.rst | 5 +++++ docs/designdecisions.rst | 9 ++++----- docs/hackinghowto.rst | 5 +++++ docs/index.rst | 3 ++- docs/installation.rst | 5 ----- 5 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 docs/deploymenthowto.rst create mode 100644 docs/hackinghowto.rst delete mode 100644 docs/installation.rst diff --git a/docs/deploymenthowto.rst b/docs/deploymenthowto.rst new file mode 100644 index 00000000..64baf5c8 --- /dev/null +++ b/docs/deploymenthowto.rst @@ -0,0 +1,5 @@ +================== + Deployment HOWTO +================== + +FIXME - write this! diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index f30c1ca5..b5992fc1 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -47,7 +47,7 @@ Why WSGI Minimalism Chris Webber on "Why WSGI Minimalism": - If you notice in the technology list above, I list a lot of + If you notice in the technology listI list a lot of components that are very `Django Project`_, but not actually Django components. What can I say, I really like a lot of the ideas in Django! Which leads to the question: why not just use @@ -144,12 +144,12 @@ Chris Webber on "Why MongoDB": dawg, I heard you liked plugins, so I put a database in your database so you can query while you query.) Gross. - I also don't want things to be too lose so that we forget or lose + I also don't want things to be too loose so that we forget or lose the structure of things, and that's one reason why I want to use MongoKit, because we can cleanly define a much structure as we want and verify that documents match that structure generally - without adding too much bloat or overhead (mongokit is a pretty - lightweight wrapper and doesn't inject extra mongokit-specific + without adding too much bloat or overhead (MongoKit is a pretty + lightweight wrapper and doesn't inject extra MongoKit-specific stuff into the database, which is nice and nicer than many other ORMs in that way). @@ -167,4 +167,3 @@ Will Kahn-Greene on "Why Sphinx": There are other doc systems out there, but given that GNU MediaGoblin is being written in Python, it makes sense to use Sphinx for now. - diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst new file mode 100644 index 00000000..93cd5ddc --- /dev/null +++ b/docs/hackinghowto.rst @@ -0,0 +1,5 @@ +=============== + Hacking HOWTO +=============== + +FIXME - write this! diff --git a/docs/index.rst b/docs/index.rst index 6f96ff8c..965d5d7a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,7 +20,8 @@ Contents: foreward softwarestack - installation + deploymenthowto + hackinghowto designdecisions diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 2dfd467d..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Installation -============== - -FIXME - this page is a stub! -- cgit v1.2.3 From 5698a579b2a9c99729f915f0590c798ca36d279b Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 12 Apr 2011 22:35:48 -0400 Subject: Adds license/copyright header. --- mediagoblin/tests/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py index e69de29b..98a67908 100644 --- a/mediagoblin/tests/__init__.py +++ b/mediagoblin/tests/__init__.py @@ -0,0 +1,15 @@ +# GNU Mediagoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . -- cgit v1.2.3 From 56d507b60bf2393dbeed8b81524b6b922dbc6ad0 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 12 Apr 2011 22:36:19 -0400 Subject: Adds documentation. * wrote up some basic bits of a hacking howto * added a better deployment howto stub --- docs/deploymenthowto.rst | 6 +++- docs/hackinghowto.rst | 88 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/docs/deploymenthowto.rst b/docs/deploymenthowto.rst index 64baf5c8..39cf73af 100644 --- a/docs/deploymenthowto.rst +++ b/docs/deploymenthowto.rst @@ -2,4 +2,8 @@ Deployment HOWTO ================== -FIXME - write this! +Step 1: Write code that can be deployed. + +Step 2: ? + +Step 3: Write the deployment guide and profit! diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 93cd5ddc..8356f435 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -2,4 +2,90 @@ Hacking HOWTO =============== -FIXME - write this! +So you want to hack on GNU MediaGoblin +====================================== + +First thing to do is check out the Web site where we list all the +project infrastructure including: + +* the mailing list +* the IRC channel +* the bug tracker + +Additionally, we have information on how to get involved, who to talk +to, what needs to be worked on, and other things besides! + + +How to set up an environment for hacking +======================================== + +The following assumes you have these things installed: + +1. virtualenv: + + http://pypi.python.org/pypi/virtualenv + +2. virtualenv wrapper: + + http://www.doughellmann.com/projects/virtualenvwrapper/ + +3. git: + + http://git-scm.com/ + + +Follow these steps: + +1. clone the repository:: + + git clone http://git.gitorious.org/mediagoblin/mediagoblin.git + +2. create a virtual environment:: + + mkvirtualenv mediagoblin + +3. if that doesn't put you in the virtual environment you created, + then do:: + + workon mediagoblin + +4. run:: + + python setup.py develop + + +When you want to work on GNU MediaGoblin, make sure to enter your +virtual environment:: + + workon mediagoblin + +Any changes you make to the code will show up in your virtual +environment--there's no need to continuously run ``python setup.py +develop``. + + +Running the test suite +====================== + +Run:: + + python setup.py test + + +Creating a new file +=================== + +All new files need to have the standard GNU MediaGoblin +license/copyright header. + +For Python files, include the license/copyright header at the top such +that each line of the header starts with ``#``. + +For Jinja2 template files, FIXME. + +For JavaScript files, FIXME. + +For CSS files, FIXME. + +If you're doing the copy-paste thing, make sure to update the +copyright year. -- cgit v1.2.3 From 8e1e744d27fbc887c6d9ce6e937848a25275ed6c Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 13 Apr 2011 10:04:30 -0400 Subject: Changes Mediagoblin -> MediaGoblin. --- mediagoblin/__init__.py | 2 +- mediagoblin/app.py | 6 +++--- mediagoblin/auth/__init__.py | 15 +++++++++++++++ mediagoblin/auth/forms.py | 2 +- mediagoblin/auth/lib.py | 2 +- mediagoblin/auth/routing.py | 2 +- mediagoblin/auth/views.py | 4 ++-- mediagoblin/models.py | 2 +- mediagoblin/routing.py | 2 +- mediagoblin/staticdirect.py | 2 +- mediagoblin/storage.py | 2 +- mediagoblin/templates/mediagoblin/base.html | 6 +++--- mediagoblin/tests/__init__.py | 2 +- mediagoblin/tests/test_auth.py | 2 +- mediagoblin/tests/test_storage.py | 2 +- mediagoblin/util.py | 2 +- mediagoblin/views.py | 2 +- setup.py | 2 +- 18 files changed, 37 insertions(+), 22 deletions(-) diff --git a/mediagoblin/__init__.py b/mediagoblin/__init__.py index 033b9173..dec83661 100644 --- a/mediagoblin/__init__.py +++ b/mediagoblin/__init__.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/app.py b/mediagoblin/app.py index a9ae223c..195d4792 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify @@ -37,7 +37,7 @@ def load_controller(string): return func -class MediagoblinApp(object): +class MediaGoblinApp(object): """ Really basic wsgi app using routes and WebOb. """ @@ -90,7 +90,7 @@ def paste_app_factory(global_config, **kw): connection = mongokit.Connection( kw.get('db_host'), kw.get('db_port')) - mgoblin_app = MediagoblinApp( + mgoblin_app = MediaGoblinApp( connection, kw.get('db_name', 'mediagoblin'), user_template_path=kw.get('local_templates')) diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py index e69de29b..c129cbf8 100644 --- a/mediagoblin/auth/__init__.py +++ b/mediagoblin/auth/__init__.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 33403544..db8aaceb 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 907ba200..7cf021bc 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index e304de9b..92f19371 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d56dfa43..aadde32f 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify @@ -70,7 +70,7 @@ def register_success(request): def login(request): """ - Mediagoblin login view. + MediaGoblin login view. If you provide the POST with 'next', it'll redirect to that view. """ diff --git a/mediagoblin/models.py b/mediagoblin/models.py index af10e795..d5f87a90 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index 1401b723..169917f0 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/staticdirect.py b/mediagoblin/staticdirect.py index 1c87c7ba..49681c22 100644 --- a/mediagoblin/staticdirect.py +++ b/mediagoblin/staticdirect.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index e6e3a59d..a06a6b05 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 546dc264..0934df2b 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -1,6 +1,6 @@ - {% block title %}Mediagoblin{% endblock title %} + {% block title %}MediaGoblin{% endblock title %} {# #} @@ -13,10 +13,10 @@ {% block mediagoblin_logo %} - Mediagoblin + MediaGoblin {% endblock %} - {% block mediagoblin_header_title %}Mediagoblin Home{% endblock %} + {% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py index 98a67908..c129cbf8 100644 --- a/mediagoblin/tests/__init__.py +++ b/mediagoblin/tests/__init__.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index d7397723..94ce6bba 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 79f1c8ea..94e16a8e 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 6551a3cc..d8d981c9 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 37ed3a62..7a3cf098 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify diff --git a/setup.py b/setup.py index 8be416b1..1d790779 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# GNU Mediagoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify -- cgit v1.2.3 From 908dee6b154d6e83add98607124896740dce0139 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 13 Apr 2011 10:13:35 -0400 Subject: Clarifies licensing for the project. --- docs/hackinghowto.rst | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 8356f435..4586188e 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -75,17 +75,21 @@ Run:: Creating a new file =================== -All new files need to have the standard GNU MediaGoblin -license/copyright header. +All new files need to have license/copyright information. -For Python files, include the license/copyright header at the top such -that each line of the header starts with ``#``. +The following kinds of files get the GNU AGPL header: -For Jinja2 template files, FIXME. +* Python files +* JavaScript files +* templates +* other files with code in them -For JavaScript files, FIXME. +The following files get a CC BY header: -For CSS files, FIXME. +* CSS files -If you're doing the copy-paste thing, make sure to update the -copyright year. +The following files don't get a header because that's hard, but are +under the CC BY license: + +* image files +* video files -- cgit v1.2.3 From 76c9ea6b5fbdd1311b926b53b8b2c8afca9a69df Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 13 Apr 2011 10:21:06 -0400 Subject: Adds license/copyright headers to jinja2 templates. --- mediagoblin/templates/mediagoblin/auth/login.html | 17 +++++++++++++++++ mediagoblin/templates/mediagoblin/auth/register.html | 17 +++++++++++++++++ .../templates/mediagoblin/auth/register_success.html | 17 +++++++++++++++++ mediagoblin/templates/mediagoblin/base.html | 17 +++++++++++++++++ mediagoblin/templates/mediagoblin/test_submit.html | 17 +++++++++++++++++ mediagoblin/templates/mediagoblin/utils/wtforms.html | 17 +++++++++++++++++ 6 files changed, 102 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 4e775f56..311a73f8 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% extends "mediagoblin/base.html" %} {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index 6a051654..f3489397 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% extends "mediagoblin/base.html" %} {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} diff --git a/mediagoblin/templates/mediagoblin/auth/register_success.html b/mediagoblin/templates/mediagoblin/auth/register_success.html index afbd57d7..cd82a0b9 100644 --- a/mediagoblin/templates/mediagoblin/auth/register_success.html +++ b/mediagoblin/templates/mediagoblin/auth/register_success.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% extends "mediagoblin/base.html" %} {% block mediagoblin_content %} diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 0934df2b..01c68258 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% block title %}MediaGoblin{% endblock title %} diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 2fae634c..b02f4e40 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 641f51d5..15556936 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -1,3 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} {% macro render_table(form) -%} {% for field in form %} -- cgit v1.2.3 From 5a40e1ec5cb3fc9fe4dbc8078bb45627bf597f72 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 14 Apr 2011 22:28:02 -0400 Subject: Overhauls TOC of manual This work is based on discussion and etherpadding (is that a verb) on April 14th between Deb, Greg, Karen, Will, and Chris. It was an epic collaborative sprint. --- docs/codedocs.rst | 5 ++++ docs/contributinghowto.rst | 58 ++++++++++++++++++++++++++++++++++++++++++ docs/foreward.rst | 23 +++++++++++++---- docs/hackinghowto.rst | 21 ++++++++++++++-- docs/index.rst | 16 ++++++------ docs/mediagoblin.rst | 63 ++++++++++++++++++++++++++++++++++++++++++++++ docs/theminghowto.rst | 5 ++++ docs/workflow.rst | 12 ++++++--- 8 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 docs/codedocs.rst create mode 100644 docs/contributinghowto.rst create mode 100644 docs/mediagoblin.rst create mode 100644 docs/theminghowto.rst diff --git a/docs/codedocs.rst b/docs/codedocs.rst new file mode 100644 index 00000000..09f91274 --- /dev/null +++ b/docs/codedocs.rst @@ -0,0 +1,5 @@ +==================== + Code Documentation +==================== + +FIXME - stub! diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst new file mode 100644 index 00000000..1b34badc --- /dev/null +++ b/docs/contributinghowto.rst @@ -0,0 +1,58 @@ +==================== + Contributing HOWTO +==================== + +We're super glad you want to contribute! + +There are a variety of ways you can help us and become part of the +team. We're not just looking for coders! We're also looking for +documentation writers, users, testers, evangelists, painters, bakers, +candle-stick makers... + +However, if you are a coder and you're looking to code, check out the +:ref:`hacking-howto`. + +The rest of this chapter talks about different things we need your +help with. + +**File bugs** + + Filing bugs is an important part of any project. For more + information on filing bugs, see :ref:`filing-bugs`. + + +**Translate GNU MediaGoblin** + + Knowing more than one language is an important skill. If you are + multi-lingual and are interested in translating GNU MediaGoblin, + see :ref:`translating`. + +FIXME - add additional things here + + +.. _filing-bugs: + +File bugs +========= + +GNU MediaGoblin uses a bug tracker called `Redmine +`. + +The bug tracker is at http://bugs.foocorp.net/ and bugs go in the +``GNU mediagoblin`` project. + +FIXME - how to file a good bug report + + +.. _translating: + +Translate GNU MediaGoblin +========================= + +FIXME - need to write this + + +Where to go when you get stuck +============================== + +FIXME - need to write this diff --git a/docs/foreward.rst b/docs/foreward.rst index 4fc8152a..0a3630a1 100644 --- a/docs/foreward.rst +++ b/docs/foreward.rst @@ -2,17 +2,30 @@ Foreward ========== -What is GNU MediaGoblin -======================= +About this manual +================= -See the web-site at http://mediagoblin.org/ . +This is the GNU MediaGoblin manual. This documentation targets the +following groups of individuals: + +* people who want to use the software +* people who want to deploy the software +* contributors + +This manual is a living document and is in the ``mediagoblin`` +repository in the ``docs/`` directory. Who wrote this documentation ============================ -* Chris Webber -* Will Kahn-Greene +In no particular order: + +* Chris +* Will +* Deb +* Greg +* Karen How should I bring up errors in the documentation diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 4586188e..986219e1 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -1,9 +1,12 @@ +.. _hacking-howto: + =============== Hacking HOWTO =============== -So you want to hack on GNU MediaGoblin -====================================== + +So you want to hack on GNU MediaGoblin? +======================================= First thing to do is check out the Web site where we list all the project infrastructure including: @@ -75,6 +78,8 @@ Run:: Creating a new file =================== +FIXME - this needs to be updated when it's set in stone. + All new files need to have license/copyright information. The following kinds of files get the GNU AGPL header: @@ -93,3 +98,15 @@ under the CC BY license: * image files * video files + + +Quickstart for Django programmers +================================= + +FIXME - write this + + +Bite-sized bugs to start with +============================= + +FIXME - write this diff --git a/docs/index.rst b/docs/index.rst index 965d5d7a..98d37969 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,23 +6,21 @@ Welcome to GNU MediaGoblin's documentation! =========================================== -This documentation covers the GNU MediaGoblin software. It is versioned -alongside the code and the source for this documentation is located in -the mediagoblin repository in the ``docs/`` directory. - -It is also viewable on the Web site in HTML form. - - -Contents: +Table of Contents: .. toctree:: :maxdepth: 2 foreward - softwarestack + mediagoblin deploymenthowto + contributinghowto hackinghowto + theminghowto + softwarestack designdecisions + workflow + codedocs Indices and tables diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst new file mode 100644 index 00000000..6c3a8dfa --- /dev/null +++ b/docs/mediagoblin.rst @@ -0,0 +1,63 @@ +================= + GNU MediaGoblin +================= + +What is GNU MediaGoblin +======================= + +Three years ago, a number of free software luminaries got together at +the FSF office to answer the question, "What should software freedom +look like on the participatory web?" Those thinkers included Richard +Stallman - founder of the free software movement and instigator of the +GNU project, Evan Prodromou - the driving force behind Status.net, a +highly sucessful federated micro-blogging service, and FIXME. + +Since that time Identi.ca and Libre.fm have answered the +freedom-loving web-user's need for micro-blogging and music sharing. +Now, GNU MediaGoblin is building a format for users to share photos. +Later versions of MediaGoblin will include support for video and other +media as well as tools to encourage collaboration on media projects. + + +Why are we doing this? +====================== + +Centralization and proprietization of media on the internet is a +serious problem and makes the web go from a system of extreme +resilience to a system of frightening fragility. We believe people +should be able to own their data and that measn someone has to build +the tools to make it possible. We decide that in this case, that +someone would be us! + + +Who are you? +============ + +Free software activists and folks who have worked on a variety of +other projects like Libre.fm, GNU Social, Status.net, Miro, Miro +Community, OpenHatch and other projects as well. We're admirers and +contributors. We're writers and painters. We're friendly and +dedicated to computer user freedom. + + +How can I participate? +====================== + +See `Get Involved `. + + +How is this licensed? +===================== + +FIXME - write this once we work out the details + + +Is this an official GNU Project? What does that mean? +====================================================== + +We are! It means that we meet the GNU Project's rigourous standards +for free software. To find out more about what that means, check out +`the GNU site `. + +Please feel free to contact us with further questions! + diff --git a/docs/theminghowto.rst b/docs/theminghowto.rst new file mode 100644 index 00000000..6ded4ac7 --- /dev/null +++ b/docs/theminghowto.rst @@ -0,0 +1,5 @@ +=============== + Theming HOWTO +=============== + +FIXME - stub! diff --git a/docs/workflow.rst b/docs/workflow.rst index 218a6abd..b72031de 100644 --- a/docs/workflow.rst +++ b/docs/workflow.rst @@ -1,6 +1,12 @@ -======================================================== - Workflow, and other structurally significant braindumps -======================================================== +========================================================================== + Design Document: Workflow, and other structurally significant braindumps +========================================================================== + +.. Note:: + + When we get a wiki, this will get moved there. It's here for now + mostly because we didn't have a better place for it. + This document attempts to describe the envisioned workflow of mediagoblin, from a structural standpoint. For now, *nothing* in this -- cgit v1.2.3 From 3c1a9d753c6f376927ff938d4f201838722e8c10 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 15 Apr 2011 08:15:13 -0500 Subject: Ignore the docs/_build directory. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7db77c06..709c250d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ eggs/ mediagoblin.egg-info *.pyc *.pyo +docs/_build/ \ No newline at end of file -- cgit v1.2.3 From b1bb050b27e0a5d87e41b3228a394c8006ecce8e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 09:36:36 -0500 Subject: Added delete_file, url_for_file methods to BasicFileStorage --- mediagoblin/storage.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index a06a6b05..4dbb2cfd 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -22,6 +22,7 @@ from werkzeug.utils import secure_filename class Error(Exception): pass class InvalidFilepath(Error): pass +class NoWebServing(Error): pass class NotImplementedError(Error): pass @@ -136,15 +137,15 @@ class BasicFileStorage(StorageInterface): Basic local filesystem implementation of storage API """ - def __init__(self, base_dir, serve_url=None): + def __init__(self, base_dir, base_url=None): """ Keyword arguments: - base_dir: Base directory things will be served out of. MUST be an absolute path. - - serve_url: URL files will be served from + - base_url: URL files will be served from """ self.base_dir = base_dir - self.serve_url = serve_url + self.base_url = base_url def _resolve_filepath(self, filepath): """ @@ -166,9 +167,16 @@ class BasicFileStorage(StorageInterface): # Grab and return the file in the mode specified return open(self._resolve_filepath(filepath), mode) - def delete_file(self, filepath): - pass + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + os.remove(self._resolve_filepath(filepath)) def url_for_file(self, filepath): - pass + if not self.base_url: + raise NoWebServing( + "base_url not set, cannot provide file urls") + + return urlparse.urljoin( + self.base_url, + '/'.join(clean_listy_filepath(filepath))) -- cgit v1.2.3 From b0bfb766d95cf7eeed2c56aa7a84c496f5f5a6f2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 10:27:03 -0500 Subject: when running get_unique_filepath, clean_listy_filepath from the get-go --- mediagoblin/storage.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 4dbb2cfd..d697276a 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -126,6 +126,10 @@ class StorageInterface(object): >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] """ + # Make sure we have a clean filepath to start with, since + # we'll be possibly tacking on stuff to the filename. + filepath = clean_listy_filepath(filepath) + if self.file_exists(filepath): return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] else: -- cgit v1.2.3 From d0e3a5341e96de3356d70baeca13dedd32d401dd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 10:59:23 -0500 Subject: "if not os.path.exists(directory)", not "if not os.path.exists('directory')" --- mediagoblin/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index d697276a..90322f5a 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -165,7 +165,7 @@ class BasicFileStorage(StorageInterface): # Make directories if necessary if len(filepath) > 1: directory = self._resolve_filepath(filepath[:-1]) - if not os.path.exists('directory'): + if not os.path.exists(directory): os.makedirs(directory) # Grab and return the file in the mode specified -- cgit v1.2.3 From d2be0838a7492a8fe7eeeb19257735e235e9fe26 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 11:00:53 -0500 Subject: Tests for BasicFileStorage.get_file() --- mediagoblin/tests/test_storage.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 94e16a8e..38c820bf 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -104,7 +104,39 @@ def test_basic_storage_get_unique_filepath(): def test_basic_storage_get_file(): - pass + tmpdir, this_storage = get_tmp_filestorage() + + # Write a brand new file + filepath = ['dir1', 'dir2', 'ourfile.txt'] + + with this_storage.get_file(filepath, 'w') as our_file: + our_file.write('First file') + with this_storage.get_file(filepath, 'r') as our_file: + assert our_file.read() == 'First file' + assert os.path.exists(os.path.join(tmpdir, 'dir1/dir2/ourfile.txt')) + with file(os.path.join(tmpdir, 'dir1/dir2/ourfile.txt'), 'r') as our_file: + assert our_file.read() == 'First file' + + # Write to the same path but try to get a unique file. + new_filepath = this_storage.get_unique_filepath(filepath) + assert not os.path.exists(os.path.join(tmpdir, *new_filepath)) + + with this_storage.get_file(new_filepath, 'w') as our_file: + our_file.write('Second file') + with this_storage.get_file(new_filepath, 'r') as our_file: + assert our_file.read() == 'Second file' + assert os.path.exists(os.path.join(tmpdir, *new_filepath)) + with file(os.path.join(tmpdir, *new_filepath), 'r') as our_file: + assert our_file.read() == 'Second file' + + # Read from an existing file + manually_written_file = os.makedirs( + os.path.join(tmpdir, 'testydir')) + with file(os.path.join(tmpdir, 'testydir/testyfile.txt'), 'w') as testyfile: + testyfile.write('testy file! so testy.') + + with this_storage.get_file(['testydir', 'testyfile.txt']) as testyfile: + assert testyfile.read() == 'testy file! so testy.' def test_basic_storage_delete_file(): -- cgit v1.2.3 From d024806a0b3c027a19b0b0462a7633c457c01f8a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 11:03:32 -0500 Subject: Tests for BasicFileStorage.delete_file() --- mediagoblin/tests/test_storage.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 38c820bf..6a73cd82 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -140,7 +140,22 @@ def test_basic_storage_get_file(): def test_basic_storage_delete_file(): - pass + tmpdir, this_storage = get_tmp_filestorage() + + assert not os.path.exists( + os.path.join(tmpdir, 'dir1/dir2/ourfile.txt')) + + filepath = ['dir1', 'dir2', 'ourfile.txt'] + with this_storage.get_file(filepath, 'w') as our_file: + our_file.write('Testing this file') + + assert os.path.exists( + os.path.join(tmpdir, 'dir1/dir2/ourfile.txt')) + + this_storage.delete_file(filepath) + + assert not os.path.exists( + os.path.join(tmpdir, 'dir1/dir2/ourfile.txt')) def test_basic_storage_url_for_file(): -- cgit v1.2.3 From f61a41b89d9143b23661e7e9b0ed5cef7d85a413 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 12:46:58 -0500 Subject: Import urlparse! Duh. I should remember to turn flymake-mode on. --- mediagoblin/storage.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 90322f5a..c39f5325 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import os +import urlparse import uuid from werkzeug.utils import secure_filename @@ -106,7 +107,7 @@ class StorageInterface(object): # Subclasses should override this method. self.__raise_not_implemented() - def url_for_file(self, filepath): + def file_url(self, filepath): """ Get the URL for this file. This assumes our storage has been mounted with some kind of URL which makes this possible. @@ -176,7 +177,7 @@ class BasicFileStorage(StorageInterface): # checks to avoid race conditions). os.remove(self._resolve_filepath(filepath)) - def url_for_file(self, filepath): + def file_url(self, filepath): if not self.base_url: raise NoWebServing( "base_url not set, cannot provide file urls") -- cgit v1.2.3 From 01da9e6a0e2f688940da497b48d2222c6e4546a6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 16 Apr 2011 12:47:15 -0500 Subject: Test for BasicFileStorage.file_url() --- mediagoblin/tests/test_storage.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 6a73cd82..0db9df84 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -159,4 +159,24 @@ def test_basic_storage_delete_file(): def test_basic_storage_url_for_file(): - pass + # Not supplying a base_url should actually just bork. + tmpdir, this_storage = get_tmp_filestorage() + assert_raises( + storage.NoWebServing, + this_storage.file_url, + ['dir1', 'dir2', 'filename.txt']) + + # base_url without domain + tmpdir, this_storage = get_tmp_filestorage('/media/') + result = this_storage.file_url( + ['dir1', 'dir2', 'filename.txt']) + expected = '/media/dir1/dir2/filename.txt' + assert result == expected + + # base_url with domain + tmpdir, this_storage = get_tmp_filestorage( + 'http://media.example.org/ourmedia/') + result = this_storage.file_url( + ['dir1', 'dir2', 'filename.txt']) + expected = 'http://media.example.org/ourmedia/dir1/dir2/filename.txt' + assert result == expected -- cgit v1.2.3 From 5afb92275cddb1c971a80a4516c9a42de475c2d5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 09:18:12 -0500 Subject: Encourage storage systems to passively accept extraneous keyword arguments w/ **kwargs. Also did that for BasicFileStorage. --- mediagoblin/storage.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index c39f5325..d9a57c2a 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -65,9 +65,17 @@ class StorageInterface(object): It is important to note that the storage API idea of a "filepath" is actually like ['dir1', 'dir2', 'file.jpg'], so keep that in mind while reading method documentation. + + You should set up your __init__ method with whatever keyword + arguments are appropriate to your storage system, but you should + also passively accept all extraneous keyword arguments like: + + def __init__(self, **kwargs): + pass + + See BasicFileStorage as a simple implementation of the + StorageInterface. """ - # def __init__(self, *args, **kwargs): - # pass def __raise_not_implemented(self): """ @@ -142,7 +150,7 @@ class BasicFileStorage(StorageInterface): Basic local filesystem implementation of storage API """ - def __init__(self, base_dir, base_url=None): + def __init__(self, base_dir, base_url=None, **kwargs): """ Keyword arguments: - base_dir: Base directory things will be served out of. MUST -- cgit v1.2.3 From 904f61c2988af2e27701a9ea47140abab12624aa Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 09:30:10 -0500 Subject: documentation for get_jinja_env --- mediagoblin/util.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index d8d981c9..bd509256 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -18,6 +18,13 @@ import jinja2 import mongokit def get_jinja_env(user_template_path=None): + """ + Set up the Jinja environment, possibly allowing for user + overridden templates. + + (In the future we may have another system for providing theming; + for now this is good enough.) + """ if user_template_path: loader = jinja2.ChoiceLoader( [jinja2.FileSystemLoader(user_template_path), -- cgit v1.2.3 From cb8ea0fe3f44f21c13e16f8d6363f56f31c52b27 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 09:43:03 -0500 Subject: Moved app.load_controller -> util.import_component and added tests. --- mediagoblin/app.py | 16 +++++----------- mediagoblin/tests/test_util.py | 30 ++++++++++++++++++++++++++++++ mediagoblin/util.py | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 mediagoblin/tests/test_util.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 195d4792..0316b43c 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -14,10 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import sys import urllib -from beaker.middleware import SessionMiddleware import routes import mongokit from webob import Request, exc @@ -29,14 +27,6 @@ class Error(Exception): pass class ImproperlyConfigured(Error): pass -def load_controller(string): - module_name, func_name = string.split(':', 1) - __import__(module_name) - module = sys.modules[module_name] - func = getattr(module, func_name) - return func - - class MediaGoblinApp(object): """ Really basic wsgi app using routes and WebOb. @@ -71,7 +61,7 @@ class MediaGoblinApp(object): # Okay, no matches. 404 time! return exc.HTTPNotFound()(environ, start_response) - controller = load_controller(route_match['controller']) + controller = util.import_component(route_match['controller']) request.start_response = start_response request.matchdict = route_match @@ -87,9 +77,13 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **kw): + # Get the database connection connection = mongokit.Connection( kw.get('db_host'), kw.get('db_port')) + # Set up the storage systems. + ## TODO: allow for extra storage systems that aren't just + ## BasicFileStorage. mgoblin_app = MediaGoblinApp( connection, kw.get('db_name', 'mediagoblin'), user_template_path=kw.get('local_templates')) diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py new file mode 100644 index 00000000..0e7a2967 --- /dev/null +++ b/mediagoblin/tests/test_util.py @@ -0,0 +1,30 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin import util + + +def _import_component_testing_method(silly_string): + # Just for the sake of testing that our component importer works. + return u"'%s' is the silliest string I've ever seen" % silly_string + + +def test_import_component(): + imported_func = util.import_component( + 'mediagoblin.tests.test_util:_import_component_testing_method') + result = imported_func('hooobaladoobala') + expected = u"'hooobaladoobala' is the silliest string I've ever seen" + assert result == expected diff --git a/mediagoblin/util.py b/mediagoblin/util.py index bd509256..cf03a93e 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import sys + import jinja2 import mongokit @@ -54,3 +56,19 @@ def setup_user_in_request(request): request.session.invalidate() request.user = user + + +def import_component(import_string): + """ + Import a module component defined by STRING. Probably a method, + class, or global variable. + + Args: + - import_string: a string that defines what to import. Written + in the format of "module1.module2:component" + """ + module_name, func_name = import_string.split(':', 1) + __import__(module_name) + module = sys.modules[module_name] + func = getattr(module, func_name) + return func -- cgit v1.2.3 From ffa2293549fed20ff0d9fc5d90e6aaaadfa8000f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 10:24:36 -0500 Subject: storage.storage_system_from_paste_config() utility, w/ tests --- mediagoblin/storage.py | 49 +++++++++++++++++++++++++++++++++++++++ mediagoblin/tests/test_storage.py | 34 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index d9a57c2a..8a594e83 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -15,11 +15,14 @@ # along with this program. If not, see . import os +import re import urlparse import uuid from werkzeug.utils import secure_filename +from mediagoblin import util + class Error(Exception): pass class InvalidFilepath(Error): pass @@ -193,3 +196,49 @@ class BasicFileStorage(StorageInterface): return urlparse.urljoin( self.base_url, '/'.join(clean_listy_filepath(filepath))) + + +def storage_system_from_paste_config(paste_config, storage_prefix): + """ + Utility for setting up a storage system from the paste app config. + + Note that a special argument may be passed in to the paste_config + which is "${storage_prefix}_storage_class" which will provide an + import path to a storage system. This defaults to + "mediagoblin.storage:BasicFileStorage" if otherwise undefined. + + Arguments: + - paste_config: dictionary of config parameters + - storage_prefix: the storage system we're setting up / will be + getting keys/arguments from. For example 'publicstore' will + grab all arguments that are like 'publicstore_FOO'. + + Returns: + An instantiated storage system. + + Example: + storage_system_from_paste_config( + {'publicstore_base_url': '/media/', + 'publicstore_base_dir': '/var/whatever/media/'}, + 'publicstore') + + Will return: + BasicFileStorage( + base_url='/media/', + base_dir='/var/whatever/media') + """ + prefix_re = re.compile('^%s_(.+)$' % re.escape(storage_prefix)) + + config_params = dict( + [(prefix_re.match(key).groups()[0], value) + for key, value in paste_config.iteritems() + if prefix_re.match(key)]) + + if config_params.has_key('storage_class'): + storage_class = config_params['storage_class'] + config_params.pop('storage_class') + else: + storage_class = "mediagoblin.storage:BasicFileStorage" + + storage_class = util.import_component(storage_class) + return storage_class(**config_params) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 0db9df84..61dd5dca 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -24,6 +24,10 @@ from werkzeug.utils import secure_filename from mediagoblin import storage +################ +# Test utilities +################ + def test_clean_listy_filepath(): expected = [u'dir1', u'dir2', u'linooks.jpg'] assert storage.clean_listy_filepath( @@ -43,6 +47,36 @@ def test_clean_listy_filepath(): ['../../', 'linooks.jpg']) +class FakeStorageSystem(): + def __init__(self, foobie, blech, **kwargs): + self.foobie = foobie + self.blech = blech + + +def test_storage_system_from_paste_config(): + this_storage = storage.storage_system_from_paste_config( + {'somestorage_base_url': 'http://example.org/moodia/', + 'somestorage_base_dir': '/tmp/', + 'somestorage_garbage_arg': 'garbage_arg', + 'garbage_arg': 'trash'}, + 'somestorage') + assert this_storage.base_url == 'http://example.org/moodia/' + assert this_storage.base_dir == '/tmp/' + assert this_storage.__class__ is storage.BasicFileStorage + + this_storage = storage.storage_system_from_paste_config( + {'somestorage_foobie': 'eiboof', + 'somestorage_blech': 'hcelb', + 'somestorage_garbage_arg': 'garbage_arg', + 'garbage_arg': 'trash', + 'somestorage_storage_class': + 'mediagoblin.tests.test_storage:FakeStorageSystem'}, + 'somestorage') + assert this_storage.foobie == 'eiboof' + assert this_storage.blech == 'hcelb' + assert this_storage.__class__ is FakeStorageSystem + + ########################## # Basic file storage tests ########################## -- cgit v1.2.3 From d807b7252d56f415bdc948007e69b05858f3d765 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 10:26:52 -0500 Subject: Reorganization of storage.py. Ordering: Errors, Storage interface / implementation, utils. --- mediagoblin/storage.py | 63 +++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 8a594e83..5d7e70d6 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -23,6 +23,9 @@ from werkzeug.utils import secure_filename from mediagoblin import util +######## +# Errors +######## class Error(Exception): pass class InvalidFilepath(Error): pass @@ -31,32 +34,9 @@ class NoWebServing(Error): pass class NotImplementedError(Error): pass -def clean_listy_filepath(listy_filepath): - """ - Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and - clean out any nastiness from it. - - For example: - >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg']) - [u'dir1', u'foo_.._nasty', u'linooks.jpg'] - - Args: - - listy_filepath: a list of filepath components, mediagoblin - storage API style. - - Returns: - A cleaned list of unicode objects. - """ - cleaned_filepath = [ - unicode(secure_filename(filepath)) - for filepath in listy_filepath] - - if u'' in cleaned_filepath: - raise InvalidFilepath( - "A filename component could not be resolved into a usable name.") - - return cleaned_filepath - +############################################### +# Storage interface & basic file implementation +############################################### class StorageInterface(object): """ @@ -198,6 +178,37 @@ class BasicFileStorage(StorageInterface): '/'.join(clean_listy_filepath(filepath))) +########### +# Utilities +########### + +def clean_listy_filepath(listy_filepath): + """ + Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and + clean out any nastiness from it. + + For example: + >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg']) + [u'dir1', u'foo_.._nasty', u'linooks.jpg'] + + Args: + - listy_filepath: a list of filepath components, mediagoblin + storage API style. + + Returns: + A cleaned list of unicode objects. + """ + cleaned_filepath = [ + unicode(secure_filename(filepath)) + for filepath in listy_filepath] + + if u'' in cleaned_filepath: + raise InvalidFilepath( + "A filename component could not be resolved into a usable name.") + + return cleaned_filepath + + def storage_system_from_paste_config(paste_config, storage_prefix): """ Utility for setting up a storage system from the paste app config. -- cgit v1.2.3 From 5afdd7a1de50fcf31a7e051929f311f3da8332b2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 10:36:46 -0500 Subject: Actually set up the storage systems --- mediagoblin/app.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 0316b43c..1aab1efb 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -20,7 +20,7 @@ import routes import mongokit from webob import Request, exc -from mediagoblin import routing, util, models +from mediagoblin import routing, util, models, storage class Error(Exception): pass @@ -31,13 +31,24 @@ class MediaGoblinApp(object): """ Really basic wsgi app using routes and WebOb. """ - def __init__(self, connection, database_path, user_template_path=None): + def __init__(self, connection, database_path, + public_store, queue_store, + user_template_path=None): + # Get the template environment self.template_env = util.get_jinja_env(user_template_path) + + # Set up storage systems + self.public_store = public_store + self.queue_store = queue_store + + # Set up database self.connection = connection self.db = connection[database_path] + models.register_models(connection) + + # set up routing self.routing = routing.get_mapper() - models.register_models(connection) def __call__(self, environ, start_response): request = Request(environ) @@ -82,10 +93,14 @@ def paste_app_factory(global_config, **kw): kw.get('db_host'), kw.get('db_port')) # Set up the storage systems. - ## TODO: allow for extra storage systems that aren't just - ## BasicFileStorage. + public_store = storage.storage_system_from_paste_config( + kw, 'publicstore') + queue_store = storage.storage_system_from_paste_config( + kw, 'queuestore') + mgoblin_app = MediaGoblinApp( connection, kw.get('db_name', 'mediagoblin'), + public_store=public_store, queue_store=queue_store, user_template_path=kw.get('local_templates')) return mgoblin_app -- cgit v1.2.3 From af37cf47b03d0bbf370fc542b7d5f4c1dfc4e1c7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 12:42:48 -0500 Subject: Buildout'ifying things. - added buildout's bootstrap.py - added buildout.cfg - adjustments to .gitignore. --- .gitignore | 4 +- bootstrap.py | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ buildout.cfg | 12 +++ 3 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 bootstrap.py create mode 100644 buildout.cfg diff --git a/.gitignore b/.gitignore index 709c250d..b9f1554e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,10 @@ bin/ develop-eggs/ build/ eggs/ +parts/ .installed.cfg mediagoblin.egg-info *.pyc *.pyo -docs/_build/ \ No newline at end of file +docs/_build/ +user_dev/ diff --git a/bootstrap.py b/bootstrap.py new file mode 100644 index 00000000..5f2cb083 --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,260 @@ +############################################################################## +# +# Copyright (c) 2006 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""Bootstrap a buildout-based project + +Simply run this script in a directory containing a buildout.cfg. +The script accepts buildout command-line options, so you can +use the -c option to specify an alternate configuration file. +""" + +import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess +from optparse import OptionParser + +if sys.platform == 'win32': + def quote(c): + if ' ' in c: + return '"%s"' % c # work around spawn lamosity on windows + else: + return c +else: + quote = str + +# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. +stdout, stderr = subprocess.Popen( + [sys.executable, '-Sc', + 'try:\n' + ' import ConfigParser\n' + 'except ImportError:\n' + ' print 1\n' + 'else:\n' + ' print 0\n'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() +has_broken_dash_S = bool(int(stdout.strip())) + +# In order to be more robust in the face of system Pythons, we want to +# run without site-packages loaded. This is somewhat tricky, in +# particular because Python 2.6's distutils imports site, so starting +# with the -S flag is not sufficient. However, we'll start with that: +if not has_broken_dash_S and 'site' in sys.modules: + # We will restart with python -S. + args = sys.argv[:] + args[0:0] = [sys.executable, '-S'] + args = map(quote, args) + os.execv(sys.executable, args) +# Now we are running with -S. We'll get the clean sys.path, import site +# because distutils will do it later, and then reset the path and clean +# out any namespace packages from site-packages that might have been +# loaded by .pth files. +clean_path = sys.path[:] +import site +sys.path[:] = clean_path +for k, v in sys.modules.items(): + if k in ('setuptools', 'pkg_resources') or ( + hasattr(v, '__path__') and + len(v.__path__)==1 and + not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): + # This is a namespace package. Remove it. + sys.modules.pop(k) + +is_jython = sys.platform.startswith('java') + +setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' +distribute_source = 'http://python-distribute.org/distribute_setup.py' + +# parsing arguments +def normalize_to_url(option, opt_str, value, parser): + if value: + if '://' not in value: # It doesn't smell like a URL. + value = 'file://%s' % ( + urllib.pathname2url( + os.path.abspath(os.path.expanduser(value))),) + if opt_str == '--download-base' and not value.endswith('/'): + # Download base needs a trailing slash to make the world happy. + value += '/' + else: + value = None + name = opt_str[2:].replace('-', '_') + setattr(parser.values, name, value) + +usage = '''\ +[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] + +Bootstraps a buildout-based project. + +Simply run this script in a directory containing a buildout.cfg, using the +Python that you want bin/buildout to use. + +Note that by using --setup-source and --download-base to point to +local resources, you can keep this script from going over the network. +''' + +parser = OptionParser(usage=usage) +parser.add_option("-v", "--version", dest="version", + help="use a specific zc.buildout version") +parser.add_option("-d", "--distribute", + action="store_true", dest="use_distribute", default=False, + help="Use Distribute rather than Setuptools.") +parser.add_option("--setup-source", action="callback", dest="setup_source", + callback=normalize_to_url, nargs=1, type="string", + help=("Specify a URL or file location for the setup file. " + "If you use Setuptools, this will default to " + + setuptools_source + "; if you use Distribute, this " + "will default to " + distribute_source +".")) +parser.add_option("--download-base", action="callback", dest="download_base", + callback=normalize_to_url, nargs=1, type="string", + help=("Specify a URL or directory for downloading " + "zc.buildout and either Setuptools or Distribute. " + "Defaults to PyPI.")) +parser.add_option("--eggs", + help=("Specify a directory for storing eggs. Defaults to " + "a temporary directory that is deleted when the " + "bootstrap script completes.")) +parser.add_option("-t", "--accept-buildout-test-releases", + dest='accept_buildout_test_releases', + action="store_true", default=False, + help=("Normally, if you do not specify a --version, the " + "bootstrap script and buildout gets the newest " + "*final* versions of zc.buildout and its recipes and " + "extensions for you. If you use this flag, " + "bootstrap and buildout will get the newest releases " + "even if they are alphas or betas.")) +parser.add_option("-c", None, action="store", dest="config_file", + help=("Specify the path to the buildout configuration " + "file to be used.")) + +options, args = parser.parse_args() + +# if -c was provided, we push it back into args for buildout's main function +if options.config_file is not None: + args += ['-c', options.config_file] + +if options.eggs: + eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) +else: + eggs_dir = tempfile.mkdtemp() + +if options.setup_source is None: + if options.use_distribute: + options.setup_source = distribute_source + else: + options.setup_source = setuptools_source + +if options.accept_buildout_test_releases: + args.append('buildout:accept-buildout-test-releases=true') +args.append('bootstrap') + +try: + import pkg_resources + import setuptools # A flag. Sometimes pkg_resources is installed alone. + if not hasattr(pkg_resources, '_distribute'): + raise ImportError +except ImportError: + ez_code = urllib2.urlopen( + options.setup_source).read().replace('\r\n', '\n') + ez = {} + exec ez_code in ez + setup_args = dict(to_dir=eggs_dir, download_delay=0) + if options.download_base: + setup_args['download_base'] = options.download_base + if options.use_distribute: + setup_args['no_fake'] = True + ez['use_setuptools'](**setup_args) + if 'pkg_resources' in sys.modules: + reload(sys.modules['pkg_resources']) + import pkg_resources + # This does not (always?) update the default working set. We will + # do it. + for path in sys.path: + if path not in pkg_resources.working_set.entries: + pkg_resources.working_set.add_entry(path) + +cmd = [quote(sys.executable), + '-c', + quote('from setuptools.command.easy_install import main; main()'), + '-mqNxd', + quote(eggs_dir)] + +if not has_broken_dash_S: + cmd.insert(1, '-S') + +find_links = options.download_base +if not find_links: + find_links = os.environ.get('bootstrap-testing-find-links') +if find_links: + cmd.extend(['-f', quote(find_links)]) + +if options.use_distribute: + setup_requirement = 'distribute' +else: + setup_requirement = 'setuptools' +ws = pkg_resources.working_set +setup_requirement_path = ws.find( + pkg_resources.Requirement.parse(setup_requirement)).location +env = dict( + os.environ, + PYTHONPATH=setup_requirement_path) + +requirement = 'zc.buildout' +version = options.version +if version is None and not options.accept_buildout_test_releases: + # Figure out the most recent final version of zc.buildout. + import setuptools.package_index + _final_parts = '*final-', '*final' + def _final_version(parsed_version): + for part in parsed_version: + if (part[:1] == '*') and (part not in _final_parts): + return False + return True + index = setuptools.package_index.PackageIndex( + search_path=[setup_requirement_path]) + if find_links: + index.add_find_links((find_links,)) + req = pkg_resources.Requirement.parse(requirement) + if index.obtain(req) is not None: + best = [] + bestv = None + for dist in index[req.project_name]: + distv = dist.parsed_version + if _final_version(distv): + if bestv is None or distv > bestv: + best = [dist] + bestv = distv + elif distv == bestv: + best.append(dist) + if best: + best.sort() + version = best[-1].version +if version: + requirement = '=='.join((requirement, version)) +cmd.append(requirement) + +if is_jython: + import subprocess + exitcode = subprocess.Popen(cmd, env=env).wait() +else: # Windows prefers this, apparently; otherwise we would prefer subprocess + exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) +if exitcode != 0: + sys.stdout.flush() + sys.stderr.flush() + print ("An error occurred when trying to install zc.buildout. " + "Look above this message for any errors that " + "were output by easy_install.") + sys.exit(exitcode) + +ws.add_entry(eggs_dir) +ws.require(requirement) +import zc.buildout.buildout +zc.buildout.buildout.main(args) +if not options.eggs: # clean up temporary egg directory + shutil.rmtree(eggs_dir) diff --git a/buildout.cfg b/buildout.cfg new file mode 100644 index 00000000..e82e3827 --- /dev/null +++ b/buildout.cfg @@ -0,0 +1,12 @@ +[buildout] +develop = . +parts = mediagoblin + +[mediagoblin] +recipe=zc.recipe.egg +interpreter=python +eggs=mediagoblin +entry-points = + nosetests=nose:run_exit + paster=paste.script.command:run + -- cgit v1.2.3 From 3a69a5dcd60abea2a149a0b2702634bd8d3d5694 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 12:44:39 -0500 Subject: Base MediaGoblin paste deploy config file. Should do what's necessary, work out of the box, be deployable. --- mediagoblin.ini | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mediagoblin.ini diff --git a/mediagoblin.ini b/mediagoblin.ini new file mode 100644 index 00000000..4d940e80 --- /dev/null +++ b/mediagoblin.ini @@ -0,0 +1,33 @@ +[DEFAULT] +debug = true + +[composite:main] +use = egg:Paste#urlmap +/ = mediagoblin +/mgoblin_media/ = publicstore_serve + +[app:mediagoblin] +use = egg:mediagoblin#app +filter-with = beaker +queuestore_base_dir = %(here)s/user_dev/media/queue +publicstore_base_dir = %(here)s/user_dev/media/public +publicstore_base_url = /mgoblin_media/ +## Uncomment this to put some user-overriding templates here +#local_templates = %(here)s/user_dev/templates/ + +[app:publicstore_serve] +use = egg:Paste#static +document_root = %(here)s/user_dev/media/public + +[server:main] +use = egg:Paste#http +host = 127.0.0.1 +port = 6543 + +[filter:beaker] +use = egg:Beaker#beaker_session +cache_dir = %(here)s/user_dev/beaker +beaker.session.key = mediagoblin +# beaker.session.secret = somesupersecret +beaker.session.data_dir = %(here)s/user_dev/beaker/sessions/data +beaker.session.lock_dir = %(here)s/user_dev/beaker/sessions/lock -- cgit v1.2.3 From df0953ce453cd82989537df598613db2c0d3b055 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 13:44:10 -0500 Subject: Buildout script which creates user_dev directory and necessary subdirectories for the user. --- buildout.cfg | 6 ++++- mediagoblin/buildout_recipes.py | 50 +++++++++++++++++++++++++++++++++++++++++ setup.py | 3 +++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 mediagoblin/buildout_recipes.py diff --git a/buildout.cfg b/buildout.cfg index e82e3827..2b36fb7c 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -1,6 +1,6 @@ [buildout] develop = . -parts = mediagoblin +parts = mediagoblin make_user_dev_dirs [mediagoblin] recipe=zc.recipe.egg @@ -10,3 +10,7 @@ entry-points = nosetests=nose:run_exit paster=paste.script.command:run + +[make_user_dev_dirs] +recipe = mediagoblin:make_user_dev_dirs +path = user_dev \ No newline at end of file diff --git a/mediagoblin/buildout_recipes.py b/mediagoblin/buildout_recipes.py new file mode 100644 index 00000000..abb01b9e --- /dev/null +++ b/mediagoblin/buildout_recipes.py @@ -0,0 +1,50 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import logging +import os + + +MAKE_SUBDIRECTORIES = ['media/queue', 'media/public', 'beaker'] + + +class MakeUserDevDirs(object): + """ + Simple recipe for making subdirectories for user buildout convenience + """ + def __init__(self, buildout, name, options): + self.buildout, self.name, self.options = buildout, name, options + + if self.options['path'].startswith('/'): + self.path = self.options['path'] + else: + self.path = os.path.join( + self.buildout['buildout']['directory'], + self.options['path']) + + def install(self): + for make_subdir in MAKE_SUBDIRECTORIES: + fulldir = os.path.join(self.path, make_subdir) + + if not os.path.exists(fulldir): + logging.getLogger(self.name).info( + 'Creating directory %s' % fulldir) + os.makedirs(fulldir) + + return () + + update = install diff --git a/setup.py b/setup.py index 1d790779..b47be4c3 100644 --- a/setup.py +++ b/setup.py @@ -45,5 +45,8 @@ setup( entry_points = """\ [paste.app_factory] app = mediagoblin.app:paste_app_factory + + [zc.buildout] + make_user_dev_dirs = mediagoblin.buildout_recipes:MakeUserDevDirs """, ) -- cgit v1.2.3 From 719f82bad308321554a8fdd21333b8afd370d5a3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 14:04:07 -0500 Subject: Updated hackinghowto.rst with info on how to use the new buildout stuff. --- docs/hackinghowto.rst | 49 +++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 986219e1..31925413 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -22,20 +22,17 @@ to, what needs to be worked on, and other things besides! How to set up an environment for hacking ======================================== -The following assumes you have these things installed: +If running Debian GNU/Linux or a Debian-derived distro such as Mint or +Ubuntu, running the following should install necessary dependencies: -1. virtualenv: - - http://pypi.python.org/pypi/virtualenv - -2. virtualenv wrapper: - - http://www.doughellmann.com/projects/virtualenvwrapper/ - -3. git: - - http://git-scm.com/ + sudo apt-get install mongodb git-core python python-dev python-lxml +Note: The following instructions describe a development environment +that uses `zc.buildout `_ because it +involves less steps to get things running and less knowledge of python +packaging. However, if you prefer to use +`virtualenv `_, +that should work just fine. Follow these steps: @@ -43,28 +40,20 @@ Follow these steps: git clone http://git.gitorious.org/mediagoblin/mediagoblin.git -2. create a virtual environment:: - - mkvirtualenv mediagoblin - -3. if that doesn't put you in the virtual environment you created, - then do:: - - workon mediagoblin - -4. run:: +2. Bootstrap and run buildout:: - python setup.py develop + cd mediagoblin + python bootstrap.py && ./bin/buildout +Now whenever you want to update mediagoblin's dependencies, just run:: -When you want to work on GNU MediaGoblin, make sure to enter your -virtual environment:: + ./bin/buildout - workon mediagoblin -Any changes you make to the code will show up in your virtual -environment--there's no need to continuously run ``python setup.py -develop``. +Using this method, buildout should create a user_dev directory, in +which certain things will be stored (media, beaker session stuff, +etc). You can change this, but for development purposes this default +should be fine. Running the test suite @@ -72,7 +61,7 @@ Running the test suite Run:: - python setup.py test + ./bin/nosetests Creating a new file -- cgit v1.2.3 From dae6add99e73cc9c4385d7f7a907f12dea6c4578 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 14:05:56 -0500 Subject: How to run the server --- docs/hackinghowto.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 31925413..e44c42c2 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -56,6 +56,14 @@ etc). You can change this, but for development purposes this default should be fine. +Running the server +================== + +Run:: + + ./bin/paster serve mediagoblin.ini --reload + + Running the test suite ====================== -- cgit v1.2.3 From 582c4d5fb21f8584314d1ff6a81931e467ec7a04 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 16:30:51 -0500 Subject: Add the staticdirector stuff to the mediagoblin wsgi app. --- mediagoblin.ini | 6 ++++++ mediagoblin/app.py | 22 +++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index 4d940e80..87f45ea6 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -5,6 +5,7 @@ debug = true use = egg:Paste#urlmap / = mediagoblin /mgoblin_media/ = publicstore_serve +/mgoblin_static/ = mediagoblin_static [app:mediagoblin] use = egg:mediagoblin#app @@ -12,6 +13,7 @@ filter-with = beaker queuestore_base_dir = %(here)s/user_dev/media/queue publicstore_base_dir = %(here)s/user_dev/media/public publicstore_base_url = /mgoblin_media/ +direct_remote_path = /mgoblin_static/ ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ @@ -19,6 +21,10 @@ publicstore_base_url = /mgoblin_media/ use = egg:Paste#static document_root = %(here)s/user_dev/media/public +[app:mediagoblin_static] +use = egg:Paste#static +document_root = %(here)s/mediagoblin/static/ + [server:main] use = egg:Paste#http host = 127.0.0.1 diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 1aab1efb..5171da99 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -20,7 +20,7 @@ import routes import mongokit from webob import Request, exc -from mediagoblin import routing, util, models, storage +from mediagoblin import routing, util, models, storage, staticdirect class Error(Exception): pass @@ -33,6 +33,7 @@ class MediaGoblinApp(object): """ def __init__(self, connection, database_path, public_store, queue_store, + staticdirector, user_template_path=None): # Get the template environment self.template_env = util.get_jinja_env(user_template_path) @@ -49,10 +50,14 @@ class MediaGoblinApp(object): # set up routing self.routing = routing.get_mapper() + # set up staticdirector tool + self.staticdirector = staticdirector def __call__(self, environ, start_response): request = Request(environ) path_info = request.path_info + + ## Routing / controller loading stuff route_match = self.routing.match(path_info) # No matching page? @@ -75,11 +80,13 @@ class MediaGoblinApp(object): controller = util.import_component(route_match['controller']) request.start_response = start_response + ## Attach utilities to the request object request.matchdict = route_match request.app = self request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) request.db = self.db + request.staticdirect = self.staticdirector # Do we really want to load this via middleware? Maybe? request.session = request.environ['beaker.session'] util.setup_user_in_request(request) @@ -98,9 +105,22 @@ def paste_app_factory(global_config, **kw): queue_store = storage.storage_system_from_paste_config( kw, 'queuestore') + # Set up the staticdirect system + if kw.has_key('direct_remote_path'): + staticdirector = staticdirect.RemoteStaticDirect( + kw['direct_remote_path'].strip()) + elif kw.has_key('direct_remote_paths'): + staticdirector = staticdirect.MultiRemoteStaticDirect( + dict([line.strip().split(' ', 1) + for line in kw['direct_remote_paths'].strip().splitlines()])) + else: + raise ImproperlyConfigured( + "One of direct_remote_path or direct_remote_paths must be provided") + mgoblin_app = MediaGoblinApp( connection, kw.get('db_name', 'mediagoblin'), public_store=public_store, queue_store=queue_store, + staticdirector=staticdirector, user_template_path=kw.get('local_templates')) return mgoblin_app -- cgit v1.2.3 From 0dd659459654dcaa683170e032ba493ab793d016 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 16:36:01 -0500 Subject: Move the request.app stuff to the same area --- mediagoblin/app.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 5171da99..0157748c 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -82,14 +82,16 @@ class MediaGoblinApp(object): ## Attach utilities to the request object request.matchdict = route_match - request.app = self - request.template_env = self.template_env request.urlgen = routes.URLGenerator(self.routing, environ) - request.db = self.db - request.staticdirect = self.staticdirector # Do we really want to load this via middleware? Maybe? request.session = request.environ['beaker.session'] util.setup_user_in_request(request) + # Attach self as request.app + # Also attach a few utilities from request.app for convenience? + request.app = self + request.template_env = self.template_env + request.db = self.db + request.staticdirect = self.staticdirector return controller(request)(environ, start_response) -- cgit v1.2.3 From 54e219fed13e3587d3a53497fb4fcad2e997988e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 17 Apr 2011 16:45:36 -0500 Subject: Makes most sense for [server:main] to be at bottom --- mediagoblin.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index 87f45ea6..c6dd4f76 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -25,11 +25,6 @@ document_root = %(here)s/user_dev/media/public use = egg:Paste#static document_root = %(here)s/mediagoblin/static/ -[server:main] -use = egg:Paste#http -host = 127.0.0.1 -port = 6543 - [filter:beaker] use = egg:Beaker#beaker_session cache_dir = %(here)s/user_dev/beaker @@ -37,3 +32,8 @@ beaker.session.key = mediagoblin # beaker.session.secret = somesupersecret beaker.session.data_dir = %(here)s/user_dev/beaker/sessions/data beaker.session.lock_dir = %(here)s/user_dev/beaker/sessions/lock + +[server:main] +use = egg:Paste#http +host = 127.0.0.1 +port = 6543 -- cgit v1.2.3 From c66d0f5c669aac298344b26a1fe6ab5f3edc5625 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 19 Apr 2011 12:37:20 -0400 Subject: Hackinghowto tweaks * adjusts some whitespace and formatting * tweaks language and section breakdown --- docs/hackinghowto.rst | 75 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index e44c42c2..db8ddca6 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -19,41 +19,68 @@ Additionally, we have information on how to get involved, who to talk to, what needs to be worked on, and other things besides! -How to set up an environment for hacking -======================================== +How to set up and maintain an environment for hacking +===================================================== -If running Debian GNU/Linux or a Debian-derived distro such as Mint or -Ubuntu, running the following should install necessary dependencies: - sudo apt-get install mongodb git-core python python-dev python-lxml +Getting requirements +-------------------- -Note: The following instructions describe a development environment -that uses `zc.buildout `_ because it -involves less steps to get things running and less knowledge of python -packaging. However, if you prefer to use -`virtualenv `_, -that should work just fine. +First, you need to have the following installed before you can build +an environment for hacking on GNU MediaGoblin: -Follow these steps: +* Python 2.6 or 2.7 - http://www.python.org/ -1. clone the repository:: + You'll need Python as well as the dev files for building modules. - git clone http://git.gitorious.org/mediagoblin/mediagoblin.git +* python-lxml - http://lxml.de/ +* git - http://git-scm.com/ +* MongoDB - http://www.mongodb.org/ + +If you're running Debian GNU/Linux or a Debian-derived distribution +such as Mint or Ubuntu, running the following should install these +requirements:: + + sudo apt-get install mongodb git-core python python-dev python-lxml + + +Running bootstrap and buildout +------------------------------ + +After installing the requirements, follow these steps: + +1. Clone the repository:: + + git clone http://git.gitorious.org/mediagoblin/mediagoblin.git 2. Bootstrap and run buildout:: - cd mediagoblin - python bootstrap.py && ./bin/buildout + cd mediagoblin + python bootstrap.py && ./bin/buildout + + +That's it! Using this method, buildout should create a ``user_dev`` +directory, in which certain things will be stored (media, beaker +session stuff, etc). You can change this, but for development +purposes this default should be fine. + + +.. Note:: + + We used `zc.buildout `_ because it + involves fewer steps to get things running and less knowledge of + Python packaging. However, if you prefer to use `virtualenv + `_, that should work just + fine. -Now whenever you want to update mediagoblin's dependencies, just run:: - ./bin/buildout +Updating dependencies +--------------------- +While hacking on GNU MediaGoblin over time, you'll eventually have to +update the dependencies. To do that, run:: -Using this method, buildout should create a user_dev directory, in -which certain things will be stored (media, beaker session stuff, -etc). You can change this, but for development purposes this default -should be fine. + ./bin/buildout Running the server @@ -61,7 +88,7 @@ Running the server Run:: - ./bin/paster serve mediagoblin.ini --reload + ./bin/paster serve mediagoblin.ini --reload Running the test suite @@ -69,7 +96,7 @@ Running the test suite Run:: - ./bin/nosetests + ./bin/nosetests Creating a new file -- cgit v1.2.3 From bb3eaf20eaf6a413d5561b848ac6b051e36a2f79 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 19 Apr 2011 19:04:22 -0500 Subject: New requires_active_login decorator! --- mediagoblin/decorators.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 mediagoblin/decorators.py diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py new file mode 100644 index 00000000..c6b4b545 --- /dev/null +++ b/mediagoblin/decorators.py @@ -0,0 +1,44 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from webob import exc + + +def _make_safe(decorator, original): + """ + Copy the function data from the old function to the decorator. + """ + decorator.__name__ = original.__name__ + decorator.__dict__ = original.__dict__ + decorator.__doc__ = original.__doc__ + return decorator + + +def require_active_login(controller): + """ + Require an active login from the user. + """ + def new_controller_func(request, *args, **kwargs): + if not request.user or not request.user.get('session') == 'active': + # TODO: Indicate to the user that they were redirected + # here because an *active* user is required. + return exc.HTTPFound( + location=request.urlgen("mediagoblin.auth.login")) + + return controller(request, *args, **kwargs) + + return _make_safe(new_controller_func, controller) -- cgit v1.2.3 From e323a06851cf2a5c7f26d4a969185323c20c8d9d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 19 Apr 2011 19:05:46 -0500 Subject: Start of the submit view, but not much there quite yet. --- mediagoblin/routing.py | 5 ++- mediagoblin/submit/__init__.py | 0 mediagoblin/submit/forms.py | 26 +++++++++++++++ mediagoblin/submit/routing.py | 22 +++++++++++++ mediagoblin/submit/views.py | 37 ++++++++++++++++++++++ .../templates/mediagoblin/submit/start.html | 35 ++++++++++++++++++++ 6 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 mediagoblin/submit/__init__.py create mode 100644 mediagoblin/submit/forms.py create mode 100644 mediagoblin/submit/routing.py create mode 100644 mediagoblin/submit/views.py create mode 100644 mediagoblin/templates/mediagoblin/submit/start.html diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index 169917f0..b47bec8d 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -17,6 +17,7 @@ from routes import Mapper from mediagoblin.auth.routing import auth_routes +from mediagoblin.submit.routing import submit_routes def get_mapper(): @@ -26,10 +27,8 @@ def get_mapper(): mapping.connect( "index", "/", controller="mediagoblin.views:root_view") - mapping.connect( - "test_submit", "/test_submit/", - controller="mediagoblin.views:submit_test") mapping.extend(auth_routes, '/auth') + mapping.extend(submit_routes, '/submit') return mapping diff --git a/mediagoblin/submit/__init__.py b/mediagoblin/submit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py new file mode 100644 index 00000000..fe51e7fd --- /dev/null +++ b/mediagoblin/submit/forms.py @@ -0,0 +1,26 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import wtforms + + +class SubmitStartForm(wtforms.Form): + title = wtforms.TextField( + 'Title', + [wtforms.validators.Length(min=1, max=500)]) + description = wtforms.TextAreaField('Description of this work') + file = wtforms.FileField('File') diff --git a/mediagoblin/submit/routing.py b/mediagoblin/submit/routing.py new file mode 100644 index 00000000..b2713540 --- /dev/null +++ b/mediagoblin/submit/routing.py @@ -0,0 +1,22 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from routes.route import Route + +submit_routes = [ + Route('mediagoblin.submit.start', '/', + controller='mediagoblin.submit.views:submit_start'), + ] diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py new file mode 100644 index 00000000..aa0f8121 --- /dev/null +++ b/mediagoblin/submit/views.py @@ -0,0 +1,37 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from webob import Response, exc + +from mediagoblin.decorators import require_active_login +from mediagoblin.submit import forms as submit_forms + + +@require_active_login +def submit_start(request): + """ + First view for submitting a file. + """ + submit_form = submit_forms.SubmitStartForm() + + # render + template = request.template_env.get_template( + 'mediagoblin/submit/start.html') + return Response( + template.render( + {'request': request, + 'submit_form': submit_form})) diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html new file mode 100644 index 00000000..562d9050 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -0,0 +1,35 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +

Submit yer media

+ +
+ + {{ wtforms_util.render_table(submit_form) }} + + + + +
+
+{% endblock %} -- cgit v1.2.3 From 6648c52ba8c186d469fb9d1102d2c11f0518011e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 19 Apr 2011 19:11:38 -0500 Subject: Use request.app.db, not request.db --- mediagoblin/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index cf03a93e..c9c57dfc 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -47,7 +47,7 @@ def setup_user_in_request(request): return user = None - user = request.db.User.one( + user = request.app.db.User.one( {'_id': mongokit.ObjectId(request.session['user_id'])}) if not user: -- cgit v1.2.3 From ddff7cce3e480f938d4d69b8d9e55e8dcf4bd562 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 19 Apr 2011 19:16:56 -0500 Subject: util.setup_user_in_request must be called last --- mediagoblin/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 0157748c..ae6db8f7 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -85,7 +85,6 @@ class MediaGoblinApp(object): request.urlgen = routes.URLGenerator(self.routing, environ) # Do we really want to load this via middleware? Maybe? request.session = request.environ['beaker.session'] - util.setup_user_in_request(request) # Attach self as request.app # Also attach a few utilities from request.app for convenience? request.app = self @@ -93,6 +92,8 @@ class MediaGoblinApp(object): request.db = self.db request.staticdirect = self.staticdirector + util.setup_user_in_request(request) + return controller(request)(environ, start_response) -- cgit v1.2.3 From fad67707e1ce6e3e31d34f26e357450ba8101700 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 19 Apr 2011 22:42:08 -0400 Subject: License/copyright changes * changes COPYING to explain licensing for all of GNU MediaGoblin * adds design decision regarding why we picked the licensing we did * adds CC0 and AGPLv3 texts * removes licensing bits from hacking howto--we should put that somewhere else --- AGPLv3.txt | 661 ++++++++++++++++++++++++++++++++++++++++++++++ CC0_1.0.txt | 121 +++++++++ COPYING | 670 ++--------------------------------------------- docs/designdecisions.rst | 70 +++++ docs/hackinghowto.rst | 25 -- 5 files changed, 872 insertions(+), 675 deletions(-) create mode 100644 AGPLv3.txt create mode 100644 CC0_1.0.txt diff --git a/AGPLv3.txt b/AGPLv3.txt new file mode 100644 index 00000000..dba13ed2 --- /dev/null +++ b/AGPLv3.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/CC0_1.0.txt b/CC0_1.0.txt new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/CC0_1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/COPYING b/COPYING index dba13ed2..fc930ccb 100644 --- a/COPYING +++ b/COPYING @@ -1,661 +1,31 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 +========= + COPYING +========= - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +GNU MediaGoblin is composed of the following kinds of files: - Preamble +* software files: Python, JavaScript and HTML templates +* non-software data: CSS, images, and video +* documentation - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. +Software files +============== - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. +Python, JavaScript, and template files files are released under the +AGPL v3. The text of this license is located in ``AGPLv3.txt``. - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. +Non-software data +================= - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. +CSS, images and video are all released under a CC0 license. The text +of this license is located in ``CC0_1.0.txt``. - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - The precise terms and conditions for copying, distribution and -modification follow. +Documentation +============= - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU Affero General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. +All documentation is under the ``docs/`` directory. These materials +are all released under a CC0 license. The text of this license is +located in ``CC0_1.0.txt``. diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index b5992fc1..62a529ff 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -167,3 +167,73 @@ Will Kahn-Greene on "Why Sphinx": There are other doc systems out there, but given that GNU MediaGoblin is being written in Python, it makes sense to use Sphinx for now. + + +Why AGPLv3 and CC0? +=================== + +Chris, Brett, Will, Rob, Matt, et al curated into a story where +everyone is the hero by Will on "Why AGPLv3 and CC0": + + The `AGPL v3`_ preserves the freedoms guaranteed by the GPL v3 in + the context of software as a service. Using this license ensures + that users of the service have the ability to examine the source, + deploy their own instance, and implement their own version. This + is really important to us and a core mission component of this + project. Thus we decided that the software parts should be under + this license. + + However, the project is made up of more than just software: + there's CSS, images, and other output-related things. We wanted + the templates/images/css side of the project all permissive and + permissive in the same absolutely permissive way. We're licensing + these under a CC0 license. + + That brings us to the templates where there's some code and some + output. We decided the templates are part of the output of the + software and not the software itself. We wanted the output of the + software to be licensed in a hassle-free way so that when someone + deploys their own GNU MediaGoblin instance with their own + templates, they don't have to deal with the copyleft aspects of + the AGPLv3 and we'd be fine with that because the changes they're + making are identity-related. So at first we decided to license + HTML templates (written in Jinja2) under a CC0 license and then + we'd add an exception to the AGPLv3 for the software such that the + templates can make calls into the software and yet be a separately + licensed work. However, Brett brought up the question of whether + this allows some unscrupulous person to make changes to the + software through the templates in such a way that they're not + bound by the AGPLv3: i.e. a loophole. We thought about this + loophole and between this and the extra legalese involved in + releasing the templates under a CC0 license with the exception to + the AGPLv3 for Python and JavaScript, we decided that it's just + way simpler if the templates were also licensed under the AGPLv3. + + Then we have the licensing for the documentation. Given that the + documentation is tied to the software content-wise, we don't feel + like we have to worry about ensuring freedom of the documentation + or worry about attribution concerns. Thus we're licensing the + documentation under a CC0 license as well. + + Lastly, we have branding. This covers logos and other things that + are distinctive to GNU MediaGoblin that we feel represents this + project. Since we don't currently have any branding, this is an + open issue, but we're thinking we'll go with a CC BY-SA license. + + By licensing in this way, we make sure that users of the software + receive the freedoms that the AGPLv3 ensures regardless of what + fate befalls this project. + + So to summarize: + + * software (Python, JavaScript, HTML templates) is licensed + under AGPLv3 + * non-software things (CSS, images, video) are licensed under CC0 + because this is output of the software + * documentation is licensed under a CC0 license + * we'll figure out licensing for branding assets later + + This is all codified in the ``COPYING`` file. + +.. _AGPL v3: http://www.gnu.org/licenses/agpl.html +.. _CC0 v1: http://creativecommons.org/publicdomain/zero/1.0/ diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index db8ddca6..96a7e1a4 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -99,31 +99,6 @@ Run:: ./bin/nosetests -Creating a new file -=================== - -FIXME - this needs to be updated when it's set in stone. - -All new files need to have license/copyright information. - -The following kinds of files get the GNU AGPL header: - -* Python files -* JavaScript files -* templates -* other files with code in them - -The following files get a CC BY header: - -* CSS files - -The following files don't get a header because that's hard, but are -under the CC BY license: - -* image files -* video files - - Quickstart for Django programmers ================================= -- cgit v1.2.3 From 6a338d8e0ea0c8f643e01699e014c298e34c3006 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 22 Apr 2011 22:02:55 -0400 Subject: Updates contributing howto * lots of changes to the contributing howto from Matt, Greg, Will, and Chris * adds references between the contributing howto and other chapters * adds a design decision regarding copyright assignment --- docs/contributinghowto.rst | 87 ++++++++++++++++++++++++++++++++++++++++++---- docs/deploymenthowto.rst | 2 ++ docs/designdecisions.rst | 16 +++++++++ docs/index.rst | 2 +- docs/theminghowto.rst | 2 ++ 5 files changed, 102 insertions(+), 7 deletions(-) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index 1b34badc..a44c361f 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -15,9 +15,21 @@ However, if you are a coder and you're looking to code, check out the The rest of this chapter talks about different things we need your help with. + +**Become a user** + + We're building GNU MediaGoblin for us and for you but really + you're one of us and I am you and we are we and GNU MediaGoblin is + the walrus. + + Sign up for an account. Use the service. Relish in the thought + that this service comes with a heaping side of Freedom and you can + salt and pepper it to your liking. + + **File bugs** - Filing bugs is an important part of any project. For more + Filing bugs is a critical part of any project. For more information on filing bugs, see :ref:`filing-bugs`. @@ -27,7 +39,50 @@ help with. multi-lingual and are interested in translating GNU MediaGoblin, see :ref:`translating`. -FIXME - add additional things here + +**Create a theme** + + As people deploy their own GNU MediaGoblin instances, good themes + are a must have! For more information on theming, see + :ref:`theming-howto`. + + +**Spread the word** + + The seductive call of Free Software services is a powerful one, + but many cannot hear it because it'd drowned out by the rush hour + traffic honking of proprietary walled gardens and faux free + services. Yuck! Be the sweet chirrup of the bird amidst the din! + Tell others that there is a better way to live! + + FIXME - do we want to talk about ways to spread the word? + + FIXME - how can people notify us that they're spreading the word? + + +**Run your own instance** + + Are there things about our instance you want to change? Are there + things about other instances you wish were different? That's + great--you can run your own instance! + + For more information on deploying your own instance, see + :ref:`deployment-howto`. + + +Contributing thank you drawings / copyright assignment +====================================================== + +Copyright assignment with GNU MediaGoblin to the `FSF +`_ is highly encouraged but not mandatory. To +incentivize both this and people to make cool contributions to our +project, if you make useful contributions to GNU MediaGoblin *and* do +a copyright assignment to the Free Software Foundation, the founder of +the project, Chris Webber, will make a custom drawing of a goblin +dedicated specifically to you. + +For why we're doing copyright assignment, see the +:ref:`design-decisions-chapter`. .. _filing-bugs: @@ -36,12 +91,30 @@ File bugs ========= GNU MediaGoblin uses a bug tracker called `Redmine -`. +`_. The bug tracker is at http://bugs.foocorp.net/ and bugs go in the ``GNU mediagoblin`` project. -FIXME - how to file a good bug report +A good bug report has the following things in it: + +1. A short summary that's 60 characters or less. + +2. A description that describes the issue (bug, feature request, ...) + as well as the context. + + * If it's a bug, can you reproduce it? Is the issue specific to a + browser, computer, image, ...? + + * If it's a feature request, are there related links on the Internet + for more information? Would you be willing to help implement or + test the feature? + +That's it! When someone looks into the issue and has questions, +they'll contact you! + +If you don't hear from anyone in a couple of weeks, find someone on +IRC. .. _translating: @@ -49,10 +122,12 @@ FIXME - how to file a good bug report Translate GNU MediaGoblin ========================= -FIXME - need to write this +Coming soon when we set up translation infrastructure. Where to go when you get stuck ============================== -FIXME - need to write this +Go to `our Web site `_ where we list the +various places we hang out and how to get a hold of us. + diff --git a/docs/deploymenthowto.rst b/docs/deploymenthowto.rst index 39cf73af..684ac1b1 100644 --- a/docs/deploymenthowto.rst +++ b/docs/deploymenthowto.rst @@ -1,3 +1,5 @@ +.. _deployment-howto: + ================== Deployment HOWTO ================== diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index 62a529ff..b48f7d80 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -237,3 +237,19 @@ everyone is the hero by Will on "Why AGPLv3 and CC0": .. _AGPL v3: http://www.gnu.org/licenses/agpl.html .. _CC0 v1: http://creativecommons.org/publicdomain/zero/1.0/ + + +Why copyright assignment? +========================= + +Will Kahn-Greene on "Why copyright assignment?": + + GNU MediaGoblin is a GNU project with the copyrights held by the + FSF. Like other GNU projects, we require copyright assignment to + the FSF which gives the FSF the legal ability to defend the + AGPL-covered status of the software and distribute it. + + This is important to us because it guarantees that this software + we're working so hard on will be available to everyone and will + survive us. As long as someone is interested in using it and/or + working on it, it will live on. diff --git a/docs/index.rst b/docs/index.rst index 98d37969..fb92d139 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,8 +13,8 @@ Table of Contents: foreward mediagoblin - deploymenthowto contributinghowto + deploymenthowto hackinghowto theminghowto softwarestack diff --git a/docs/theminghowto.rst b/docs/theminghowto.rst index 6ded4ac7..23f9cb1b 100644 --- a/docs/theminghowto.rst +++ b/docs/theminghowto.rst @@ -1,3 +1,5 @@ +.. _theming-howto: + =============== Theming HOWTO =============== -- cgit v1.2.3 From efb291d633b7ad2a8246b9b7f4ae0c7603b7572f Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 22 Apr 2011 22:08:49 -0400 Subject: Fixes CC0 language CC0 is a waiver and not a license, so this fixes all the language accordingly. --- docs/designdecisions.rst | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index b48f7d80..6156d523 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -186,34 +186,35 @@ everyone is the hero by Will on "Why AGPLv3 and CC0": However, the project is made up of more than just software: there's CSS, images, and other output-related things. We wanted the templates/images/css side of the project all permissive and - permissive in the same absolutely permissive way. We're licensing - these under a CC0 license. + permissive in the same absolutely permissive way. We're waiving + our copyrights to non-software things under the CC0 waiver. That brings us to the templates where there's some code and some - output. We decided the templates are part of the output of the + output. The template engine we're using is called Jinja2. It + mixes HTML markup with Python code to render the output of the + software. We decided the templates are part of the output of the software and not the software itself. We wanted the output of the software to be licensed in a hassle-free way so that when someone deploys their own GNU MediaGoblin instance with their own templates, they don't have to deal with the copyleft aspects of the AGPLv3 and we'd be fine with that because the changes they're - making are identity-related. So at first we decided to license - HTML templates (written in Jinja2) under a CC0 license and then - we'd add an exception to the AGPLv3 for the software such that the - templates can make calls into the software and yet be a separately - licensed work. However, Brett brought up the question of whether - this allows some unscrupulous person to make changes to the - software through the templates in such a way that they're not - bound by the AGPLv3: i.e. a loophole. We thought about this - loophole and between this and the extra legalese involved in - releasing the templates under a CC0 license with the exception to - the AGPLv3 for Python and JavaScript, we decided that it's just - way simpler if the templates were also licensed under the AGPLv3. + making are identity-related. So at first we decided to waive our + copyrights to the templates with a CC0 waiver and then add an + exception to the AGPLv3 for the software such that the templates + can make calls into the software and yet be a separately licensed + work. However, Brett brought up the question of whether this + allows some unscrupulous person to make changes to the software + through the templates in such a way that they're not bound by the + AGPLv3: i.e. a loophole. We thought about this loophole and + between this and the extra legalese involved in the exception to + the AGPLv3, we decided that it's just way simpler if the templates + were also licensed under the AGPLv3. Then we have the licensing for the documentation. Given that the documentation is tied to the software content-wise, we don't feel like we have to worry about ensuring freedom of the documentation - or worry about attribution concerns. Thus we're licensing the - documentation under a CC0 license as well. + or worry about attribution concerns. Thus we're waiving our + copyrights to the documentation under CC0 as well. Lastly, we have branding. This covers logos and other things that are distinctive to GNU MediaGoblin that we feel represents this @@ -226,12 +227,14 @@ everyone is the hero by Will on "Why AGPLv3 and CC0": So to summarize: - * software (Python, JavaScript, HTML templates) is licensed + * software (Python, JavaScript, HTML templates): licensed under AGPLv3 - * non-software things (CSS, images, video) are licensed under CC0 - because this is output of the software - * documentation is licensed under a CC0 license - * we'll figure out licensing for branding assets later + * non-software things (CSS, images, video): copyrights waived + under CC0 because this is output of the software + * documentation: copyrights waived under CC0 because it's not part + of the software + * branding assets: we're kicking this can down the road, but + probably CC BY-SA This is all codified in the ``COPYING`` file. -- cgit v1.2.3 From 7eba0306d84adb35af9d1ad2568f11f0cdd2f7a7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 08:46:02 -0500 Subject: Provide a next= url when we require logging in --- mediagoblin/decorators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index c6b4b545..81b88c9d 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -37,7 +37,9 @@ def require_active_login(controller): # TODO: Indicate to the user that they were redirected # here because an *active* user is required. return exc.HTTPFound( - location=request.urlgen("mediagoblin.auth.login")) + location="%s?next=%s" % ( + request.urlgen("mediagoblin.auth.login"), + request.path_info)) return controller(request, *args, **kwargs) -- cgit v1.2.3 From 4d75522b91c13c365f79929bd7760ac6090b2a8b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 08:52:23 -0500 Subject: Give User a status, also add uploader user field to MediaEntry --- mediagoblin/models.py | 55 ++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index d5f87a90..364f7ebf 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -21,30 +21,6 @@ from mongokit import Document, Set from mediagoblin.auth import lib as auth_lib -class MediaEntry(Document): - __collection__ = 'media_entries' - - structure = { - 'title': unicode, - 'created': datetime.datetime, - 'description': unicode, - 'media_type': unicode, - 'media_data': dict, # extra data relevant to this media_type - 'plugin_data': dict, # plugins can dump stuff here. - 'file_store': unicode, - 'attachments': [dict], - 'tags': [unicode]} - - required_fields = [ - 'title', 'created', - 'media_type', 'file_store'] - - default_values = { - 'created': datetime.datetime.utcnow} - - def main_mediafile(self): - pass - class User(Document): __collection__ = 'users' @@ -55,13 +31,16 @@ class User(Document): 'plugin_data': dict, # plugins can dump stuff here. 'pw_hash': unicode, 'email_verified': bool, + 'status': unicode, } required_fields = ['username', 'created', 'pw_hash', 'email'] default_values = { 'created': datetime.datetime.utcnow, - 'email_verified': False} + 'email_verified': False, + # TODO: shouldn't be active by default, must have email registration + 'status': 'active'} def check_login(self, password): """ @@ -71,6 +50,32 @@ class User(Document): password, self['pw_hash']) +class MediaEntry(Document): + __collection__ = 'media_entries' + + structure = { + 'uploader': User, + 'title': unicode, + 'created': datetime.datetime, + 'description': unicode, + 'media_type': unicode, + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. + 'file_store': unicode, + 'attachments': [dict], + 'tags': [unicode]} + + required_fields = [ + 'title', 'created', + 'media_type', 'file_store'] + + default_values = { + 'created': datetime.datetime.utcnow} + + def main_mediafile(self): + pass + + REGISTER_MODELS = [MediaEntry, User] -- cgit v1.2.3 From 7bf3f5db0fe720bfb5cb9d85dfb01cdeae13af9d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 09:03:25 -0500 Subject: Adding a space for custom validators, though we haven't used it yet :) --- mediagoblin/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 364f7ebf..f3d380cf 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -21,6 +21,15 @@ from mongokit import Document, Set from mediagoblin.auth import lib as auth_lib +################### +# Custom validators +################### + +######## +# Models +######## + + class User(Document): __collection__ = 'users' -- cgit v1.2.3 From 74ae6b112a645bff68956dd2bf090507c0c230a9 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 10:51:55 -0500 Subject: making state for MediaEntry objects, also adding attributes: - media_files - attachment_files - queue_files - thumbnail_file --- mediagoblin/models.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index f3d380cf..9e0ee8ca 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -70,16 +70,24 @@ class MediaEntry(Document): 'media_type': unicode, 'media_data': dict, # extra data relevant to this media_type 'plugin_data': dict, # plugins can dump stuff here. - 'file_store': unicode, - 'attachments': [dict], - 'tags': [unicode]} + 'tags': [unicode], + 'state': unicode, + + # The following should be lists of lists, in appropriate file + # record form + 'media_files': list, + 'attachment_files': list, + 'queue_files': list, + + # This one should just be a single file record + 'thumbnail_file': [unicode]} required_fields = [ - 'title', 'created', - 'media_type', 'file_store'] + 'uploader', 'title', 'created', 'media_type'] default_values = { - 'created': datetime.datetime.utcnow} + 'created': datetime.datetime.utcnow, + 'state': u'unprocessed'} def main_mediafile(self): pass -- cgit v1.2.3 From e745ce10c9bdec967f349478db7163b8f137926a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 11:30:20 -0500 Subject: we should check for request.user['status'] not request.user['session'], clearly. --- mediagoblin/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 81b88c9d..1774ce4e 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -33,7 +33,7 @@ def require_active_login(controller): Require an active login from the user. """ def new_controller_func(request, *args, **kwargs): - if not request.user or not request.user.get('session') == 'active': + if not request.user or not request.user.get('status') == u'active': # TODO: Indicate to the user that they were redirected # here because an *active* user is required. return exc.HTTPFound( -- cgit v1.2.3 From 574d1511d6a111efd4c6da78ef03593e4bcb2056 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 12:54:11 -0500 Subject: Probably better to request.POST.get? --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index aadde32f..15e33e17 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -87,7 +87,7 @@ def login(request): request.session['user_id'] = unicode(user['_id']) request.session.save() - if request.POST.has_key('next'): + if request.POST.get('next'): return exc.HTTPFound(location=request.POST['next']) else: return exc.HTTPFound( -- cgit v1.2.3 From f6f524bf5990c116d59868dd0edeafcc1ba58e09 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 12:56:01 -0500 Subject: submit_start written in a way that, by golly, you'd think maybe it'd work --- mediagoblin/submit/views.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index aa0f8121..1d93e070 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -16,6 +16,7 @@ from webob import Response, exc +from werkzeug.utils import secure_filename from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms @@ -28,6 +29,39 @@ def submit_start(request): """ submit_form = submit_forms.SubmitStartForm() + if request.method == 'POST' and submit_form.validate(): + # create entry and save in database + entry = request.db.MediaEntry() + entry['title'] = request.POST['title'] + entry['description'] = request.POST.get(['description']) + entry['media_type'] = u'image' # heh + entry['uploader'] = request.user + + # Save, just so we can get the entry id for the sake of using + # it to generate the file path + entry.save(validate=False) + + # Now store generate the queueing related filename + queue_filepath = request.app.queue_store.get_unique_filepath( + ['media_entries', + unicode(request.user['_id']), + unicode(entry['_id']), + secure_filename(request.POST['file'].filename)]) + + # queue appropriately + queue_file = request.app.queue_store.get_file( + queue_filepath, 'wb') + + queue_file.write(request.POST['file'].file.read()) + + # Add queued filename to the entry + entry.setdefault('queue_files', []).add(queue_filepath) + entry.save(validate=True) + + # redirect + return exc.HTTPFound( + location=request.urlgen("mediagoblin.submit.submit_success")) + # render template = request.template_env.get_template( 'mediagoblin/submit/start.html') @@ -35,3 +69,13 @@ def submit_start(request): template.render( {'request': request, 'submit_form': submit_form})) + + +@require_active_login +def submit_success(request): + # render + template = request.template_env.get_template( + 'mediagoblin/submit/success.html') + return Response( + template.render( + {'request': request})) -- cgit v1.2.3 From 6e41c71c4924b04947ef657b2f220accc4a57595 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 12:56:32 -0500 Subject: Adding the hidden next field to the login page so we actually do redirect --- mediagoblin/templates/mediagoblin/auth/login.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 311a73f8..f2e7b664 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -36,5 +36,9 @@ + + {% if next %} + + {% endif %} {% endblock %} -- cgit v1.2.3 From 2732c28676f1bd36c17bd1afe30cdd3cae3ceb59 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 13:06:27 -0500 Subject: A stupid success view. --- mediagoblin/submit/routing.py | 2 ++ .../templates/mediagoblin/submit/success.html | 24 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/submit/success.html diff --git a/mediagoblin/submit/routing.py b/mediagoblin/submit/routing.py index b2713540..3f61b1f4 100644 --- a/mediagoblin/submit/routing.py +++ b/mediagoblin/submit/routing.py @@ -19,4 +19,6 @@ from routes.route import Route submit_routes = [ Route('mediagoblin.submit.start', '/', controller='mediagoblin.submit.views:submit_start'), + Route('mediagoblin.submit.success', '/', + controller='mediagoblin.submit.views:submit_success'), ] diff --git a/mediagoblin/templates/mediagoblin/submit/success.html b/mediagoblin/templates/mediagoblin/submit/success.html new file mode 100644 index 00000000..d38517fa --- /dev/null +++ b/mediagoblin/templates/mediagoblin/submit/success.html @@ -0,0 +1,24 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} + Woohoo! Submitted! +{% endblock %} -- cgit v1.2.3 From e21e7bfeb41a8ed6ab8fa3b27132efd84355ff36 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 13:15:09 -0500 Subject: Enclose queue_file writing in with statement so that it's closed correctly. --- mediagoblin/submit/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1d93e070..54201796 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -52,7 +52,8 @@ def submit_start(request): queue_file = request.app.queue_store.get_file( queue_filepath, 'wb') - queue_file.write(request.POST['file'].file.read()) + with queue_file: + queue_file.write(request.POST['file'].file.read()) # Add queued filename to the entry entry.setdefault('queue_files', []).add(queue_filepath) -- cgit v1.2.3 From 204392362ffbe94159838cdff6c4d3b6968a003d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 13:29:15 -0500 Subject: Submission of image works :) /me pours some sparkling grape juice --- mediagoblin/submit/routing.py | 2 +- mediagoblin/submit/views.py | 7 +++---- mediagoblin/templates/mediagoblin/submit/success.html | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mediagoblin/submit/routing.py b/mediagoblin/submit/routing.py index 3f61b1f4..cff28acb 100644 --- a/mediagoblin/submit/routing.py +++ b/mediagoblin/submit/routing.py @@ -19,6 +19,6 @@ from routes.route import Route submit_routes = [ Route('mediagoblin.submit.start', '/', controller='mediagoblin.submit.views:submit_start'), - Route('mediagoblin.submit.success', '/', + Route('mediagoblin.submit.success', '/success/', controller='mediagoblin.submit.views:submit_success'), ] diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 54201796..1f55336f 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -27,7 +27,7 @@ def submit_start(request): """ First view for submitting a file. """ - submit_form = submit_forms.SubmitStartForm() + submit_form = submit_forms.SubmitStartForm(request.POST) if request.method == 'POST' and submit_form.validate(): # create entry and save in database @@ -56,12 +56,12 @@ def submit_start(request): queue_file.write(request.POST['file'].file.read()) # Add queued filename to the entry - entry.setdefault('queue_files', []).add(queue_filepath) + entry.setdefault('queue_files', []).append(queue_filepath) entry.save(validate=True) # redirect return exc.HTTPFound( - location=request.urlgen("mediagoblin.submit.submit_success")) + location=request.urlgen("mediagoblin.submit.success")) # render template = request.template_env.get_template( @@ -72,7 +72,6 @@ def submit_start(request): 'submit_form': submit_form})) -@require_active_login def submit_success(request): # render template = request.template_env.get_template( diff --git a/mediagoblin/templates/mediagoblin/submit/success.html b/mediagoblin/templates/mediagoblin/submit/success.html index d38517fa..afc9f9d1 100644 --- a/mediagoblin/templates/mediagoblin/submit/success.html +++ b/mediagoblin/templates/mediagoblin/submit/success.html @@ -17,8 +17,6 @@ #} {% extends "mediagoblin/base.html" %} -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - {% block mediagoblin_content %} Woohoo! Submitted! {% endblock %} -- cgit v1.2.3 From 03afc828ce11523c46d81c1fa4667ec9604ef528 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 23 Apr 2011 14:13:33 -0500 Subject: Properly require files when users submit --- mediagoblin/submit/views.py | 72 +++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1f55336f..926c7011 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -15,6 +15,8 @@ # along with this program. If not, see . +from cgi import FieldStorage + from webob import Response, exc from werkzeug.utils import secure_filename @@ -30,38 +32,44 @@ def submit_start(request): submit_form = submit_forms.SubmitStartForm(request.POST) if request.method == 'POST' and submit_form.validate(): - # create entry and save in database - entry = request.db.MediaEntry() - entry['title'] = request.POST['title'] - entry['description'] = request.POST.get(['description']) - entry['media_type'] = u'image' # heh - entry['uploader'] = request.user - - # Save, just so we can get the entry id for the sake of using - # it to generate the file path - entry.save(validate=False) - - # Now store generate the queueing related filename - queue_filepath = request.app.queue_store.get_unique_filepath( - ['media_entries', - unicode(request.user['_id']), - unicode(entry['_id']), - secure_filename(request.POST['file'].filename)]) - - # queue appropriately - queue_file = request.app.queue_store.get_file( - queue_filepath, 'wb') - - with queue_file: - queue_file.write(request.POST['file'].file.read()) - - # Add queued filename to the entry - entry.setdefault('queue_files', []).append(queue_filepath) - entry.save(validate=True) - - # redirect - return exc.HTTPFound( - location=request.urlgen("mediagoblin.submit.success")) + if not (request.POST.has_key('file') + and isinstance(request.POST['file'], FieldStorage) + and request.POST['file'].file): + submit_form.file.errors.append( + u'You must provide a file.') + else: + # create entry and save in database + entry = request.db.MediaEntry() + entry['title'] = request.POST['title'] + entry['description'] = request.POST.get(['description']) + entry['media_type'] = u'image' # heh + entry['uploader'] = request.user + + # Save, just so we can get the entry id for the sake of using + # it to generate the file path + entry.save(validate=False) + + # Now store generate the queueing related filename + queue_filepath = request.app.queue_store.get_unique_filepath( + ['media_entries', + unicode(request.user['_id']), + unicode(entry['_id']), + secure_filename(request.POST['file'].filename)]) + + # queue appropriately + queue_file = request.app.queue_store.get_file( + queue_filepath, 'wb') + + with queue_file: + queue_file.write(request.POST['file'].file.read()) + + # Add queued filename to the entry + entry.setdefault('queue_files', []).append(queue_filepath) + entry.save(validate=True) + + # redirect + return exc.HTTPFound( + location=request.urlgen("mediagoblin.submit.success")) # render template = request.template_env.get_template( -- cgit v1.2.3 From 6bcab715b86dabe20aef7ba07960d50e4913ee15 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 24 Apr 2011 10:04:53 -0500 Subject: Time to require celery! --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b47be4c3..38f1a4d4 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,7 @@ setup( 'py-bcrypt', 'nose', 'werkzeug', + 'celery', ], test_suite='nose.collector', -- cgit v1.2.3 From df9809c2098d18b0272c40154b5e40d67b703214 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 24 Apr 2011 14:48:55 -0500 Subject: Make certain bits of info accessable as global variables from anywhere --- mediagoblin/app.py | 10 ++++++++++ mediagoblin/globals.py | 24 ++++++++++++++++++++++++ mediagoblin/tests/test_globals.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 mediagoblin/globals.py create mode 100644 mediagoblin/tests/test_globals.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index ae6db8f7..78ad19a4 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -21,6 +21,7 @@ import mongokit from webob import Request, exc from mediagoblin import routing, util, models, storage, staticdirect +from mediagoblin.globals import setup_globals class Error(Exception): pass @@ -53,6 +54,15 @@ class MediaGoblinApp(object): # set up staticdirector tool self.staticdirector = staticdirector + # certain properties need to be accessed globally eg from + # validators, etc, which might not access to the request + # object. + setup_globals( + db_connection=connection, + database=self.db, + public_store=self.public_store, + queue_store=self.queue_store) + def __call__(self, environ, start_response): request = Request(environ) path_info = request.path_info diff --git a/mediagoblin/globals.py b/mediagoblin/globals.py new file mode 100644 index 00000000..59a94558 --- /dev/null +++ b/mediagoblin/globals.py @@ -0,0 +1,24 @@ +""" +In some places, we need to access the database, public_store, queue_store +""" + +############################# +# General mediagoblin globals +############################# + +# mongokit.Connection +db_connection = None + +# mongokit.Connection +database = None + +# should be the same as the +public_store = None +queue_store = None + + +def setup_globals(**kwargs): + from mediagoblin import globals as mg_globals + + for key, value in kwargs.iteritems(): + setattr(mg_globals, key, value) diff --git a/mediagoblin/tests/test_globals.py b/mediagoblin/tests/test_globals.py new file mode 100644 index 00000000..6d2e01da --- /dev/null +++ b/mediagoblin/tests/test_globals.py @@ -0,0 +1,29 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin import globals as mg_globals + +def test_setup_globals(): + mg_globals.setup_globals( + db_connection='my favorite db_connection!', + database='my favorite database!', + public_store='my favorite public_store!', + queue_store='my favorite queue_store!') + + assert mg_globals.db_connection == 'my favorite db_connection!' + assert mg_globals.database == 'my favorite database!' + assert mg_globals.public_store == 'my favorite public_store!' + assert mg_globals.queue_store == 'my favorite queue_store!' -- cgit v1.2.3 From 5740a0d6aa8647c182c39680fecf6b902485a9b2 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 18:50:48 -0400 Subject: Updates to hacking howto * adds "what's where" section which isn't wildly interesting right now but it's somewhat interesting * adds "wiping environment" section --- docs/hackinghowto.rst | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 96a7e1a4..50c59d08 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -41,7 +41,8 @@ If you're running Debian GNU/Linux or a Debian-derived distribution such as Mint or Ubuntu, running the following should install these requirements:: - sudo apt-get install mongodb git-core python python-dev python-lxml + sudo apt-get install mongodb git-core python python-dev \ + python-lxml Running bootstrap and buildout @@ -78,11 +79,26 @@ Updating dependencies --------------------- While hacking on GNU MediaGoblin over time, you'll eventually have to -update the dependencies. To do that, run:: +update your development environment. To do that, run:: ./bin/buildout +Wiping your environment for a clean-slate +----------------------------------------- + +Delete the following directories: + +* bin/ +* develop-eggs/ +* eggs/ +* mediagoblin.egg-info/ +* parts/ +* user_dev/ + +FIXME - how to drop data from mongodb? + + Running the server ================== @@ -99,6 +115,32 @@ Run:: ./bin/nosetests +What's where +============ + +After you've run buildout, you're faced with the following directory +tree:: + + mediagoblin/ + |- mediagoblin/ source code + | |- tests/ + | |- templates/ + | |- auth/ + | \- submit/ + |- docs/ documentation + | + | the rest of these directories are generated by + | buildout. + | + |- bin/ scripts + |- develop-eggs/ + |- eggs/ + |- mediagoblin.egg-info/ + |- parts/ + |- user_dev/ sessions, etc + + + Quickstart for Django programmers ================================= -- cgit v1.2.3 From cafc7451ccdf0dc1d86eba92f3f75254c367d2f7 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 18:55:07 -0400 Subject: Minor tweaks to design decisions text --- docs/designdecisions.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index 6156d523..3398c24b 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -17,11 +17,11 @@ Chris Webber on "Why Python": software web applications before in Python, including `Miro Community`_, the `Miro Guide`_, a large portion of `Creative Commons`_, and a whole bunch of things while working at `Imaginary - Landscape`_). I know Python, I can make this happen in Python, me - starting a project like this makes sense if it's done in Python. + Landscape`_). Me starting a project like this makes sense if it's + done in Python. You might say that PHP is way more deployable, that Rails has way - more cool developers riding around on fixie bikes, and all of + more cool developers riding around on fixie bikes---and all of those things are true. But I know Python, like Python, and think that Python is pretty great. I do think that deployment in Python is not as good as with PHP, but I think the days of shared hosting @@ -159,14 +159,16 @@ Why Sphinx for documentation Will Kahn-Greene on "Why Sphinx": - Sphinx is a fantastic tool for organizing documentation for a + `Sphinx`_ is a fantastic tool for organizing documentation for a Python-based project that makes it pretty easy to write docs that are readable in source form and can be "compiled" into HTML, LaTeX and other formats. There are other doc systems out there, but given that GNU - MediaGoblin is being written in Python, it makes sense to use - Sphinx for now. + MediaGoblin is being written in Python and I've done a ton of + documentation using Sphinx, it makes sense to use Sphinx for now. + +.. _Sphinx: http://sphinx.pocoo.org/ Why AGPLv3 and CC0? -- cgit v1.2.3 From 34366952a21f040ee5ca3df899a82f9e6bd9cffe Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 19:46:48 -0400 Subject: Heavy documentation updates * Nixed codedocs and software stack chapters in favor of a chapter on Beardomatic! * Switched workflow to vision and added an additional caveat at the top --- docs/beardomatic.rst | 84 +++++++++++++++++++++++++++++ docs/codedocs.rst | 5 -- docs/index.rst | 5 +- docs/softwarestack.rst | 127 ------------------------------------------- docs/vision.rst | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/workflow.rst | 136 ---------------------------------------------- 6 files changed, 228 insertions(+), 271 deletions(-) create mode 100644 docs/beardomatic.rst delete mode 100644 docs/codedocs.rst delete mode 100644 docs/softwarestack.rst create mode 100644 docs/vision.rst delete mode 100644 docs/workflow.rst diff --git a/docs/beardomatic.rst b/docs/beardomatic.rst new file mode 100644 index 00000000..5ebeb239 --- /dev/null +++ b/docs/beardomatic.rst @@ -0,0 +1,84 @@ +=========================================== + Beardomatic: Infrastructure Documentation +=========================================== + +What the hell is Beardomatic? +============================= + +You might be wondering, "Gah! What the hell is Beardomatic!?" + +Well, I'll tell you. GNU MediaGoblin is a piece of software that sits +on a stack of libraries that do a bunch of stuff. It makes it easier +to differentiate the bits of code that encompass GNU MediaGoblin from +the bits of code that GNU MediaGoblin sit on top of. Thus, we came up +with the TOTALLY AWESOME name Beardomatic. + +Now you might be saying, "Holy crap!? Another web framework? Are you +going to write a mocking framework and an enumeration library, too!?" + +No, we're not. We're just calling this Beardomatic so that it's +easier to talk about things. However, at some point, we can take +these infrastructure bits from GNU MediaGoblin and turn them into a +full-blown "web framework". We wouldn't do this to compete for +mindshare with other web frameworks. We would do this to make it +easier for us to bootstrap other similar projects. + + +Beardomatic software stack +========================== + +Beardomatic is a software stack "web framework" composed of the +following bits: + +* Project infrastructure + + * `Python `_: the language we're using to write + this + + * `Nose `_: + for unit tests + + * `buildout `_: for getting dependencies, + building a runtime environment, ... + +* Data storage + + * `MongoDB `_: the document database backend + for storage + +* Web application + + * `Paste Deploy `_ and + `Paste Script `_: we'll use this for + configuring and launching the application + + * `WebOb `_: nice abstraction layer + from HTTP requests, responses and WSGI bits + + * `Routes `_: for URL routing + + * `Beaker `_: for handling sessions + + * `Jinja2 `_: the templating engine + + * `MongoKit `_: the lightweight + ORM for MongoDB we're using which will make it easier to define + structures and all that + + * `WTForms `_: for handling, + validation, and abstraction from HTML forms + + * `Celery `_: for task queuing (resizing + images, encoding video, ...) + + * `RabbitMQ `_: for sending tasks to celery + +* Front end + + * `JQuery `_: for groovy JavaScript things + + +How to ... in Beardomatic? +========================== + +FIXME - write this diff --git a/docs/codedocs.rst b/docs/codedocs.rst deleted file mode 100644 index 09f91274..00000000 --- a/docs/codedocs.rst +++ /dev/null @@ -1,5 +0,0 @@ -==================== - Code Documentation -==================== - -FIXME - stub! diff --git a/docs/index.rst b/docs/index.rst index fb92d139..fc8cc642 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,10 +17,9 @@ Table of Contents: deploymenthowto hackinghowto theminghowto - softwarestack designdecisions - workflow - codedocs + vision + beardomatic Indices and tables diff --git a/docs/softwarestack.rst b/docs/softwarestack.rst deleted file mode 100644 index 024f0d5d..00000000 --- a/docs/softwarestack.rst +++ /dev/null @@ -1,127 +0,0 @@ -======= - Stack -======= - -The software stack for this project might change over time, but this -is what we're thinking right now. - -There's some explanation of design decisions in the -:ref:`design-decisions-chapter`. - - -Python -====== - -* http://python.org/ - -The core team does a lot of work in Python and it's the language we're -most likely to do a project like this in. - - -MongoDB -======= - -* http://www.mongodb.org/ - -A "document database". Because it's extremely flexible and scales up -well, but I guess not down well. - - -MongoKit -======== - -* http://namlook.github.com/mongokit/ - -A lightweight ORM for mongodb. Helps us define our structures better, -does schema validation, schema evolution, and helps make things more -fun and pythonic. - - -Jinja2 -====== - -* http://jinja.pocoo.org/docs/ - -For templating. Pretty much django templates++ but allows us to pass -arguments into method calls instead of writing custom tags. - - -WTForms -======= - -* http://wtforms.simplecodes.com/ - -For form handling, validation, abstraction. Almost just like Django's -templates. - - -WebOb -===== - -* http://pythonpaste.org/webob/ - -Gives nice request/response objects (also somewhat Django-ish). - - -Paste Deploy and Paste Script -============================= - -* http://pythonpaste.org/deploy/ -* http://pythonpaste.org/script/ - -This will be the default way of configuring and launching the -application. Since GNU MediaGoblin will be fairly WSGI minimalist though, -you can probably use other ways to launch it, though this will be the -default. - - -Routes -====== - -* http://routes.groovie.org/ - -For URL Routing. It works well enough. - - -JQuery -====== - -* http://jquery.com/ - -For all sorts of things on the JavaScript end of things, for all sorts -of reasons. - - -Beaker -====== - -* http://beaker.groovie.org/ - -For sessions, because that seems like it's generally considered the -way to go I guess. - - -Nose -==== - -* http://somethingaboutorange.com/mrl/projects/nose/1.0.0/ - -For unit tests because it makes testing a bit nicer. - - -Celery -====== - -* http://celeryproject.org/ - -For task queueing (resizing images, encoding video, ...). - - -RabbitMQ -======== - -* http://www.rabbitmq.com/ - -For sending tasks to celery, because I guess that's what most people -do. Might be optional, might also let people use MongoDB for this if -they want. diff --git a/docs/vision.rst b/docs/vision.rst new file mode 100644 index 00000000..fad248df --- /dev/null +++ b/docs/vision.rst @@ -0,0 +1,142 @@ +========================================= + Design Document: GNU MediaGoblin vision +========================================= + +.. Note:: + + When we get a wiki, this will get moved there. It's here for now + mostly because we didn't have a better place for it. + +.. Note:: + + By the time you read this, it's very likely it'll be out of date. + + +This document attempts to describe the envisioned workflow of GNU +MediaGoblin, from a structural standpoint. For now, *nothing* in this +document is probably the eventual, final way that things will work. +Eventually as things come to exist, this document will hopefully be +refactored to describe how things *do* work. + +This documented on hopes, dreams, rainbows, and unicorns. And it will +come to fulfillment through a lot of hard work. Your hard work and my +hard work. + + +Look and feel +============= + +Default look and feel +--------------------- + +Mairin Duffy made mockups for something called Design Hub. That +project did a number of things differently than the way we intend to +go, but it's probably a good idea to steal a good number of ideas from +here. + +http://mairin.wordpress.com/2010/03/09/another-design-hub-mockup/ + + +User profile mockup +------------------- + +Here's an ascii art mockup on how things might look for a user's page:: + + _____ + |_( )_| USER NAME + | | | + |_/_\_| + + Recent artwork: + ___________________ ___________________________ + | ___ ___ ___ | |_About_User_Name___________| + | |pic| |pic| |pic| | | | + | |___| |___| |___| | | Some sort of self- | + | ___ ___ ___ | | description probably goes | + < | |pic| |pic| |pic| | > | here | + | |___| |___| |___| | | | + | ___ ___ ___ | | | + | |pic| |pic| |pic| | | | + | |___| |___| |___| | | | + |___________________| |___________________________| + + ___________________________ + Recent favorites: |_Recent_activity___________| + ___________________ | New picture: DragonFace | + | ___ ___ ___ | | 4/2/2010 | + | |pic| |pic| |pic| | |---------------------------| + | |___| |___| |___| | | Sup yall this is some kind| + | ___ ___ ___ | | of mini blogpost. Maybe | + < | |pic| |pic| |pic| | > | the interface will allow | + | |___| |___| |___| | | for this? | + | ___ ___ ___ | |___________________________| + | |pic| |pic| |pic| | + | |___| |___| |___| | ___________________________ + |___________________| |_External_comments_here____| + | Dang! This stuff rocks | + | - Joe 4/2/2010 | + |---------------------------| + | Nice job on the dragon | + | - Morgan 4/2/2010 | + '---------------------------' + +So there's this type of interface that puts a lot of different types +of info on the same screen. I'm not sure that I like it. It's +possible we'll go with something much more minimalist. Maybe we'll go +with something "tabbed" the way statusnet / http://identi.ca is on +user pages. + +It's possible that we could support multiple profile styles here, +and you could load whatever profile style you want as set by user +preferences? + + +Uploading mockup +---------------- + +Here's an uploading mockup:: + + Upload an image + + [ Title ] + + Upload: [ ] [Browse] + ___________________________________________ + | | + | | + | o0O | + | o ' | + | o_.' | + | | + | Uploading... OK | <-, + | Resizing... OK | | + | | Area replaced w/ resized + | | image when done + |___________________________________________| + ________________ + License |_CC BY-SA_____|V| + ___________________________________________ + | Description goes here. | + | You can type it up in here and everything | + | and it'll show up under the image. | + | | + | Possibly we should allow some kind of | + | markup... maybe markdown? | + '___________________________________________' + + __________________________________________ + |> Advanced | + ------------------------------------------ + + +Customizability +--------------- + +General site theming customizability is pretty easy! Since we're +using `Jinja `_ we can just set up +user-overriding directories. + +We'll also figure out some sort of way to provide theming "packages", +eventually. + + diff --git a/docs/workflow.rst b/docs/workflow.rst deleted file mode 100644 index b72031de..00000000 --- a/docs/workflow.rst +++ /dev/null @@ -1,136 +0,0 @@ -========================================================================== - Design Document: Workflow, and other structurally significant braindumps -========================================================================== - -.. Note:: - - When we get a wiki, this will get moved there. It's here for now - mostly because we didn't have a better place for it. - - -This document attempts to describe the envisioned workflow of -mediagoblin, from a structural standpoint. For now, *nothing* in this -document is probably the eventual, final way that things will work. -Eventually as things come to exist, this document will hopefully be -refactored to describe how things *do* work. - -This documented on hopes, dreams, rainbows, and unicorns. And it will -come to fulfillment through a lot of hard work. - - -Look and feel -============= - -Default look and feel ---------------------- - -Mairin Duffy made mockups for something called Design Hub. That -project did a number of things differently than the way we intend to -go, but it's probably a good idea to steal a good number of ideas from -here. - -http://mairin.wordpress.com/2010/03/09/another-design-hub-mockup/ - -User profile mockup -------------------- - -Here's an ascii art mockup on how things might look for a user's page:: - - _____ - |_( )_| USER NAME - | | | - |_/_\_| - - Recent artwork: - ___________________ ___________________________ - | ___ ___ ___ | |_About_User_Name___________| - | |pic| |pic| |pic| | | | - | |___| |___| |___| | | Some sort of self- | - | ___ ___ ___ | | description probably goes | - < | |pic| |pic| |pic| | > | here | - | |___| |___| |___| | | | - | ___ ___ ___ | | | - | |pic| |pic| |pic| | | | - | |___| |___| |___| | | | - |___________________| |___________________________| - - ___________________________ - Recent favorites: |_Recent_activity___________| - ___________________ | New picture: DragonFace | - | ___ ___ ___ | | 4/2/2010 | - | |pic| |pic| |pic| | |---------------------------| - | |___| |___| |___| | | Sup yall this is some kind| - | ___ ___ ___ | | of mini blogpost. Maybe | - < | |pic| |pic| |pic| | > | the interface will allow | - | |___| |___| |___| | | for this? | - | ___ ___ ___ | |___________________________| - | |pic| |pic| |pic| | - | |___| |___| |___| | ___________________________ - |___________________| |_External_comments_here____| - | Dang! This stuff rocks | - | - Joe 4/2/2010 | - |---------------------------| - | Nice job on the dragon | - | - Morgan 4/2/2010 | - '---------------------------' - -So there's this type of interface that puts a lot of different types -of info on the same screen. I'm not sure that I like it. It's -possible we'll go with something much more minimalist. Maybe we'll go -with something "tabbed" the way statusnet / http://identi.ca is on -user pages. - -It's possible that we could support multiple profile styles here, -and you could load whatever profile style you want as set by user -preferences? - - -Uploading mockup ----------------- - -Here's an uploading mockup:: - - Upload an image - - [ Title ] - - Upload: [ ] [Browse] - ___________________________________________ - | | - | | - | o0O | - | o ' | - | o_.' | - | | - | Uploading... OK | <-, - | Resizing... OK | | - | | Area replaced w/ resized - | | image when done - |___________________________________________| - ________________ - License |_CC BY-SA_____|V| - ___________________________________________ - | Description goes here. | - | You can type it up in here and everything | - | and it'll show up under the image. | - | | - | Possibly we should allow some kind of | - | markup... maybe markdown? | - '___________________________________________' - - __________________________________________ - |> Advanced | - ------------------------------------------ - - -Customizability ---------------- - -General site theming customizability is pretty easy! Since we're -using `Jinja `_ we can just set up -user-overriding directories. - -We'll also figure out some sort of way to provide theming "packages", -eventually. - - -- cgit v1.2.3 From e231d9e8bb8c5bf6f0705b47592c9aadaf2eb269 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 24 Apr 2011 18:47:23 -0500 Subject: setup_celery_from_config tool. Haven't tried if it works, but looks right... --- mediagoblin/celery_setup/__init__.py | 121 +++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 mediagoblin/celery_setup/__init__.py diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py new file mode 100644 index 00000000..171b9a6f --- /dev/null +++ b/mediagoblin/celery_setup/__init__.py @@ -0,0 +1,121 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os + +from paste.deploy.converters import asbool, asint, aslist + + +KNOWN_CONFIG_BOOLS = [ + 'CELERY_RESULT_PERSISTENT', + 'CELERY_CREATE_MISSING_QUEUES', + 'BROKER_USE_SSL', 'BROKER_CONNECTION_RETRY', + 'CELERY_ALWAYS_EAGER', 'CELERY_EAGER_PROPAGATES_EXCEPTIONS', + 'CELERY_IGNORE_RESULT', 'CELERY_TRACK_STARTED', + 'CELERY_DISABLE_RATE_LIMITS', 'CELERY_ACKS_LATE', + 'CELERY_STORE_ERRORS_EVEN_IF_IGNORED', + 'CELERY_SEND_TASK_ERROR_EMAILS', + 'CELERY_SEND_EVENTS', 'CELERY_SEND_TASK_SENT_EVENT', + 'CELERYD_LOG_COLOR', 'CELERY_REDIRECT_STDOUTS', + ] + +KNOWN_CONFIG_INTS = [ + 'CELERYD_CONCURRENCY', + 'CELERYD_PREFETCH_MULTIPLIER', + 'CELERY_AMQP_TASK_RESULT_EXPIRES', + 'CELERY_AMQP_TASK_RESULT_CONNECTION_MAX', + 'REDIS_PORT', 'REDIS_DB', + 'BROKER_PORT', 'BROKER_CONNECTION_TIMEOUT', + 'CELERY_BROKER_CONNECTION_MAX_RETRIES', + 'CELERY_TASK_RESULT_EXPIRES', 'CELERY_MAX_CACHED_RESULTS', + 'CELERY_DEFAULT_RATE_LIMIT', # ?? + 'CELERYD_MAX_TASKS_PER_CHILD', 'CELERYD_TASK_TIME_LIMIT', + 'CELERYD_TASK_SOFT_TIME_LIMIT', + 'MAIL_PORT', 'CELERYBEAT_MAX_LOOP_INTERVAL', + ] + +KNOWN_CONFIG_FLOATS = [ + 'CELERYD_ETA_SCHEDULER_PRECISION', + ] + +KNOWN_CONFIG_LISTS = [ + 'CELERY_ROUTES', 'CELERY_IMPORTS', + ] + + +## Needs special processing: +# ADMINS, ??? +# there are a lot more; we should list here or process specially. + + +def asfloat(obj): + try: + return float(obj) + except (TypeError, ValueError), e: + raise ValueError( + "Bad float value: %r" % obj) + + +def setup_celery_from_config(app_config, global_config): + """ + Take a mediagoblin app config and the global config from a paste + factory and try to set up a celery settings module from this. + """ + if asbool(app_config.get('use_celery_environment_var')) == True: + # Don't setup celery based on our config file. + return + + celery_conf_section = app_config.get('celery_section', 'celery') + if global_config.has_key(celery_conf_section): + celery_conf = global_config[celery_conf_section] + else: + celery_conf = {} + + celery_settings = {} + + # set up mongodb stuff + celery_mongo_settings = {} + if app_config.has_key('db_host'): + celery_mongo_settings['host'] = app_config['db_host'] + celery_settings['BROKER_HOST'] = app_config['db_host'] + if app_config.has_key('db_port'): + celery_mongo_settings['port'] = asint(app_config['db_port']) + celery_settings['BROKER_PORT'] = asint(app_config['db_port']) + celery_mongo_settings['database'] = app_config.get('db_name', 'mediagoblin') + + celery_settings['CELERY_MONGODB_BACKEND_SETTINGS'] = celery_mongo_settings + celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb' + + # Add anything else + for key, value in celery_conf.iteritems(): + key = key.upper() + if key in KNOWN_CONFIG_BOOLS: + value = asbool(value) + elif value in KNOWN_CONFIG_INTS: + value = asint(value) + elif value in KNOWN_CONFIG_FLOATS: + value = asfloat(value) + elif value in KNOWN_CONFIG_LISTS: + value = aslist(value) + celery_settings[key] = value + + from mediagoblin.celery_setup import dummy_settings_module + + for key, value in celery_settings.iteritems(): + setattr(dummy_settings_module, key, value) + + os.environ['CELERY_CONFIG_MODULE'] = \ + 'mediagoblin.celery_setup.dummy_settings_module' -- cgit v1.2.3 From 427ee0de13951a66d684d2a6afe33f45df7966b4 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 21:19:00 -0400 Subject: Adds Matt to docs contributors list --- docs/foreward.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/foreward.rst b/docs/foreward.rst index 0a3630a1..c1d60587 100644 --- a/docs/foreward.rst +++ b/docs/foreward.rst @@ -26,6 +26,7 @@ In no particular order: * Deb * Greg * Karen +* Matt How should I bring up errors in the documentation -- cgit v1.2.3 From 81be691a20edaeffc27d1cc160e0576ae5f9cd51 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 21:29:39 -0400 Subject: Changes version to 0.0.1. --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 02c190a0..6030b74d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, Chris Webber, et al' # built documents. # # The short X.Y version. -version = '0.1a1' +version = '0.0.1' # The full version, including alpha/beta/rc tags. -release = '0.1a1' +release = '0.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -- cgit v1.2.3 From 75b70b90c3235d9883a799c4aea659879b5b3d89 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 21:29:50 -0400 Subject: Fixes mdashes and other minor things. --- docs/contributinghowto.rst | 2 +- docs/foreward.rst | 10 +++++----- docs/mediagoblin.rst | 21 ++++++++++++--------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index a44c361f..cb5cd909 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -64,7 +64,7 @@ help with. Are there things about our instance you want to change? Are there things about other instances you wish were different? That's - great--you can run your own instance! + great---you can run your own instance! For more information on deploying your own instance, see :ref:`deployment-howto`. diff --git a/docs/foreward.rst b/docs/foreward.rst index c1d60587..edc75e30 100644 --- a/docs/foreward.rst +++ b/docs/foreward.rst @@ -16,8 +16,8 @@ This manual is a living document and is in the ``mediagoblin`` repository in the ``docs/`` directory. -Who wrote this documentation -============================ +Who wrote this documentation? +============================= In no particular order: @@ -29,10 +29,10 @@ In no particular order: * Matt -How should I bring up errors in the documentation -================================================= +I found an error in the docs---who do I tell? +============================================= -There are a few ways--please pick the one most convenient to you! +There are a few ways---please pick the one most convenient to you! 1. Send an email to Will ``willg at bluesock dot org``. 2. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst index 6c3a8dfa..a6194dc4 100644 --- a/docs/mediagoblin.rst +++ b/docs/mediagoblin.rst @@ -5,12 +5,13 @@ What is GNU MediaGoblin ======================= -Three years ago, a number of free software luminaries got together at -the FSF office to answer the question, "What should software freedom -look like on the participatory web?" Those thinkers included Richard -Stallman - founder of the free software movement and instigator of the -GNU project, Evan Prodromou - the driving force behind Status.net, a -highly sucessful federated micro-blogging service, and FIXME. +Three years ago (2008), a number of free software luminaries got +together at the FSF office to answer the question, "What should +software freedom look like on the participatory web?" Those thinkers +included Richard Stallman---founder of the free software movement and +instigator of the GNU project, Evan Prodromou---the driving force +behind Status.net, a highly sucessful federated micro-blogging +service, and FIXME. Since that time Identi.ca and Libre.fm have answered the freedom-loving web-user's need for micro-blogging and music sharing. @@ -46,10 +47,12 @@ How can I participate? See `Get Involved `. -How is this licensed? -===================== +How is GNU MediaGoblin licensed? +================================ -FIXME - write this once we work out the details +GNU MediaGoblin software is released under an AGPLv3 license. + +See the ``COPYING`` file in the source for details. Is this an official GNU Project? What does that mean? -- cgit v1.2.3 From eb2986152aab5767ae40d1b870c7f6cb256f045d Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 24 Apr 2011 21:53:57 -0400 Subject: Fixes traceback on registration values must be unicode. --- mediagoblin/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 9e0ee8ca..eef59ed4 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -49,7 +49,7 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, # TODO: shouldn't be active by default, must have email registration - 'status': 'active'} + 'status': u'active'} def check_login(self, password): """ -- cgit v1.2.3 From bb64a6073cc1ab4f2a28e3b4652ec51f3fc1d674 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 24 Apr 2011 20:55:02 -0500 Subject: Commit dummy_settings_module, of course. --- mediagoblin/celery_setup/dummy_settings_module.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mediagoblin/celery_setup/dummy_settings_module.py diff --git a/mediagoblin/celery_setup/dummy_settings_module.py b/mediagoblin/celery_setup/dummy_settings_module.py new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 5784c4e963b12e0b866ba806f8d2e5c045780d45 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 24 Apr 2011 20:57:38 -0500 Subject: Actually call setup_celery_from_config when launching from paste. Also changed **kw to **app_config, which is more useful of a variable name. --- mediagoblin/app.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 78ad19a4..3ea405e9 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -22,6 +22,7 @@ from webob import Request, exc from mediagoblin import routing, util, models, storage, staticdirect from mediagoblin.globals import setup_globals +from mediagoblin.celery_setup import setup_celery_from_config class Error(Exception): pass @@ -107,33 +108,37 @@ class MediaGoblinApp(object): return controller(request)(environ, start_response) -def paste_app_factory(global_config, **kw): +def paste_app_factory(global_config, **app_config): # Get the database connection connection = mongokit.Connection( - kw.get('db_host'), kw.get('db_port')) + app_config.get('db_host'), app_config.get('db_port')) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( - kw, 'publicstore') + app_config, 'publicstore') queue_store = storage.storage_system_from_paste_config( - kw, 'queuestore') + app_config, 'queuestore') # Set up the staticdirect system - if kw.has_key('direct_remote_path'): + if app_config.has_key('direct_remote_path'): staticdirector = staticdirect.RemoteStaticDirect( - kw['direct_remote_path'].strip()) - elif kw.has_key('direct_remote_paths'): + app_config['direct_remote_path'].strip()) + elif app_config.has_key('direct_remote_paths'): + direct_remote_path_lines = app_config[ + 'direct_remote_paths'].strip().splitlines() staticdirector = staticdirect.MultiRemoteStaticDirect( dict([line.strip().split(' ', 1) - for line in kw['direct_remote_paths'].strip().splitlines()])) + for line in direct_remote_path_lines])) else: raise ImproperlyConfigured( "One of direct_remote_path or direct_remote_paths must be provided") + setup_celery_from_config(app_config, global_config) + mgoblin_app = MediaGoblinApp( - connection, kw.get('db_name', 'mediagoblin'), + connection, app_config.get('db_name', 'mediagoblin'), public_store=public_store, queue_store=queue_store, staticdirector=staticdirector, - user_template_path=kw.get('local_templates')) + user_template_path=app_config.get('local_templates')) return mgoblin_app -- cgit v1.2.3 From 1bb0fdf2f4f568019c3449f269c69f406507bd7c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 26 Apr 2011 15:46:56 -0500 Subject: HTTPFound more accurate than HTTPMovedPermanently. (Just observed this in cc.engine, making observation here also while I'm at it :)) --- mediagoblin/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 3ea405e9..59b943dd 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -82,7 +82,7 @@ class MediaGoblinApp(object): if request.GET: new_path_info = '%s?%s' % ( new_path_info, urllib.urlencode(request.GET)) - redirect = exc.HTTPTemporaryRedirect(location=new_path_info) + redirect = exc.HTTPFound(location=new_path_info) return request.get_response(redirect)(environ, start_response) # Okay, no matches. 404 time! -- cgit v1.2.3 From 84489d7d4a3b3c0a897a9c4fe5176484bcf31d82 Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Wed, 27 Apr 2011 10:55:35 -0400 Subject: Updated copyright --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6030b74d..967d84d0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,7 +41,7 @@ master_doc = 'index' # General information about the project. project = u'GNU MediaGoblin' -copyright = u'2011, Chris Webber, et al' +copyright = u'2011, Free Software Foundation, Inc and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the -- cgit v1.2.3 From 9d952fdc7930dcdf1c2ee5ca6094c80a998d86ba Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 27 Apr 2011 22:42:17 -0400 Subject: Reworked contributing docs based on Asheesh's thoughts I chatted with Asheesh on IRC today and asked him to look over the contributer howto. He had a lot of thoughts and I factored most/all of them in. It's much better now. --- docs/beardomatic.rst | 2 + docs/contributinghowto.rst | 115 ++++++++++++++++++++++++++++----------------- docs/deploymenthowto.rst | 2 + docs/foreward.rst | 7 +-- docs/hackinghowto.rst | 61 ++++++++++++++++++++++-- 5 files changed, 139 insertions(+), 48 deletions(-) diff --git a/docs/beardomatic.rst b/docs/beardomatic.rst index 5ebeb239..14130f6a 100644 --- a/docs/beardomatic.rst +++ b/docs/beardomatic.rst @@ -1,3 +1,5 @@ +.. _beardomatic-chapter: + =========================================== Beardomatic: Infrastructure Documentation =========================================== diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index cb5cd909..3b3fe163 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -2,72 +2,104 @@ Contributing HOWTO ==================== -We're super glad you want to contribute! +Join the community! +=================== + +We're super glad you want to join our community! There are a variety of ways you can help us and become part of the team. We're not just looking for coders! We're also looking for -documentation writers, users, testers, evangelists, painters, bakers, -candle-stick makers... +documentation writers, users, testers, evangelists, user-interface +designers, graphics designers, user-experience designers, system +administrators, friends, painters, bakers, candle-stick makers... -However, if you are a coder and you're looking to code, check out the -:ref:`hacking-howto`. +Here are some things you can do today: -The rest of this chapter talks about different things we need your -help with. + **Hang out with us** -**Become a user** + You should hang out with us! We like people like you! - We're building GNU MediaGoblin for us and for you but really - you're one of us and I am you and we are we and GNU MediaGoblin is - the walrus. - - Sign up for an account. Use the service. Relish in the thought - that this service comes with a heaping side of Freedom and you can - salt and pepper it to your liking. + At a bare minimum, join the `mailing list + `_ and say, "Hi!" + We also hang out on IRC in ``#mediagoblin`` on Freenode.net. -**File bugs** - Filing bugs is a critical part of any project. For more - information on filing bugs, see :ref:`filing-bugs`. + **File bugs** + Filing bugs is a critical part of any project. For more + information on filing bugs, see :ref:`filing-bugs`. -**Translate GNU MediaGoblin** - Knowing more than one language is an important skill. If you are - multi-lingual and are interested in translating GNU MediaGoblin, - see :ref:`translating`. + **Write/Fix some code** + If you are a coder and you're looking to code, check out the + :ref:`hacking-howto`. We even have tips on *becoming* a coder + and we're willing to help you! -**Create a theme** - As people deploy their own GNU MediaGoblin instances, good themes - are a must have! For more information on theming, see - :ref:`theming-howto`. + **Run your own instance** + + Are there things about our instance you want to change? Are + there things about other instances you wish were different? + Want to test upcoming changes? Want to create patches to + implement things you need? That's great---you can run your + own instance! + + For more information on deploying your own instance, see + :ref:`deployment-howto`. -**Spread the word** + **Spread the word** - The seductive call of Free Software services is a powerful one, - but many cannot hear it because it'd drowned out by the rush hour - traffic honking of proprietary walled gardens and faux free - services. Yuck! Be the sweet chirrup of the bird amidst the din! - Tell others that there is a better way to live! + The seductive call of Free Software services is a powerful + one, but many cannot hear it because it'd drowned out by the + rush hour traffic honking of proprietary walled gardens and + faux free services. Yuck! Be the sweet chirrup of the bird + amidst the din! Tell others that there is a better way to + live! - FIXME - do we want to talk about ways to spread the word? + FIXME - do we want to talk about ways to spread the word? - FIXME - how can people notify us that they're spreading the word? + FIXME - how can people notify us that they're spreading the + word? -**Run your own instance** +We're still working on project infrastructure. We hope to have the +bits in place for these additional things to do in the coming months: - Are there things about our instance you want to change? Are there - things about other instances you wish were different? That's - great---you can run your own instance! + **Become a user** + + We're building GNU MediaGoblin for us and for you but really + you're one of us and I am you and we are we and GNU + MediaGoblin is the walrus. - For more information on deploying your own instance, see - :ref:`deployment-howto`. + Sign up for an account. Use the service. Relish in the + thought that this service comes with a heaping side of Freedom + and you can salt and pepper it to your liking. + + + **Help other users** + + Have you spent time with GNU MediaGoblin? If so, your + experience and wisdom are invaluable and you're the best + person we can think of to help other users with their + questions. + + + **Translate GNU MediaGoblin** + + Knowing more than one language is an important skill. If you + are multi-lingual and are interested in translating GNU + MediaGoblin, see :ref:`translating`. + + + **Create a theme** + + As people deploy their own GNU MediaGoblin instances, good + themes are a must have! For more information on theming, see + :ref:`theming-howto`. Contributing thank you drawings / copyright assignment @@ -93,8 +125,7 @@ File bugs GNU MediaGoblin uses a bug tracker called `Redmine `_. -The bug tracker is at http://bugs.foocorp.net/ and bugs go in the -``GNU mediagoblin`` project. +The bug tracker is at ``_. A good bug report has the following things in it: diff --git a/docs/deploymenthowto.rst b/docs/deploymenthowto.rst index 684ac1b1..d943e276 100644 --- a/docs/deploymenthowto.rst +++ b/docs/deploymenthowto.rst @@ -9,3 +9,5 @@ Step 1: Write code that can be deployed. Step 2: ? Step 3: Write the deployment guide and profit! + +But seriously, this is a stub since we're not quite there, yet. diff --git a/docs/foreward.rst b/docs/foreward.rst index edc75e30..d2b9c417 100644 --- a/docs/foreward.rst +++ b/docs/foreward.rst @@ -27,6 +27,7 @@ In no particular order: * Greg * Karen * Matt +* Asheesh I found an error in the docs---who do I tell? @@ -34,9 +35,9 @@ I found an error in the docs---who do I tell? There are a few ways---please pick the one most convenient to you! -1. Send an email to Will ``willg at bluesock dot org``. -2. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . -3. Tell someone on IRC ``#mediagoblin`` on Freenode. +1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . +2. Tell someone on IRC ``#mediagoblin`` on Freenode. +3. Send an email to Will ``willg at bluesock dot org``. When you tell us about your issue, please let us know: diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 50c59d08..8b40e37d 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -8,8 +8,9 @@ So you want to hack on GNU MediaGoblin? ======================================= -First thing to do is check out the Web site where we list all the -project infrastructure including: +First thing to do is check out the `Web site +`_ where we list all the project +infrastructure including: * the mailing list * the IRC channel @@ -87,6 +88,13 @@ update your development environment. To do that, run:: Wiping your environment for a clean-slate ----------------------------------------- +.. Note:: + + Unless you're doing development and working on and testing creating + a new instance, you will probably never have to do this. Will + plans to do this work and thus he documented it. + + Delete the following directories: * bin/ @@ -96,7 +104,8 @@ Delete the following directories: * parts/ * user_dev/ -FIXME - how to drop data from mongodb? +FIXME - how to drop data from mongodb? we should probably write a +script. Running the server @@ -151,3 +160,49 @@ Bite-sized bugs to start with ============================= FIXME - write this + + +Tips for people new to coding +============================= + +Python +------ + +GNU MediaGoblin is written using a programming language called `Python +`_. + +There are two different incompatible iterations of Python which I'll +refer to as Python 2 and Python 3. GNU MediaGoblin is written in +Python 2 and requires Python 2.6 or 2.7. At some point, we might +switch to Python 3, but that's a future thing. + +You can learn how to code in Python 2 from several excellent books +that are freely available on the Internet: + +* `Learn Python the Hard Way `_ +* `Dive Into Pyton `_ +* `Python for Software Design `_ +* `A Byte of Python `_ + +These are all excellent texts. + +FIXME - are there good quality Python tutorial videos? + + +Libraries +--------- + +GNU MediaGoblin uses a variety of libraries in order to do what it +does. These libraries are listed in the :ref:`beardomatic-chapter` +along with links to the project Web sites and documentation for the +libraries. + +There are a variety of Python-related conferences every year that have +sessions covering many aspects of these libraries. You can find them +at `Python Miro Community `_ [0]_. + +.. [0] This is a shameless plug. Will Kahn-Greene runs Python Miro + Community. + +If you have questions or need help, find us on the mailing list and on +IRC. -- cgit v1.2.3 From 0c953025122fbbf0fd9d6c52f490802bca3648c0 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 28 Apr 2011 10:38:37 -0400 Subject: Moves "run your own instance" to the future section Chris correctly pointed out that you can't quite run your own instance, yet. But that's the goal! --- docs/contributinghowto.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index 3b3fe163..ff783b9c 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -39,18 +39,6 @@ Here are some things you can do today: and we're willing to help you! - **Run your own instance** - - Are there things about our instance you want to change? Are - there things about other instances you wish were different? - Want to test upcoming changes? Want to create patches to - implement things you need? That's great---you can run your - own instance! - - For more information on deploying your own instance, see - :ref:`deployment-howto`. - - **Spread the word** The seductive call of Free Software services is a powerful @@ -88,6 +76,18 @@ bits in place for these additional things to do in the coming months: questions. + **Run your own instance** + + Are there things about our instance you want to change? Are + there things about other instances you wish were different? + Want to test upcoming changes? Want to create patches to + implement things you need? That's great---you can run your + own instance! + + For more information on deploying your own instance, see + :ref:`deployment-howto`. + + **Translate GNU MediaGoblin** Knowing more than one language is an important skill. If you -- cgit v1.2.3 From 4305e7e64bdf0889f96199a4b6219911fcb08b82 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 28 Apr 2011 10:58:16 -0400 Subject: Adds "Send encouragement" section --- docs/contributinghowto.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index ff783b9c..f10dd72a 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -39,6 +39,16 @@ Here are some things you can do today: and we're willing to help you! + **Send encouragement** + + A nice word from you could send someone into a tizzy of + productive work. Ten nice words could complete a feature. + One hundred nice words could get us to the next milestone. + + Send it to the `mailing list `_ + or hop into ``#mediagoblin`` on Freenode.net and let us know. + + **Spread the word** The seductive call of Free Software services is a powerful -- cgit v1.2.3 From 515b8a48c905d28d682663aa2040850833a5d51a Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 28 Apr 2011 16:27:09 -0400 Subject: Adds placeholder file so _static exists. --- docs/_static/placeholder | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/_static/placeholder diff --git a/docs/_static/placeholder b/docs/_static/placeholder new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 0f03e1d394273775e9cb77d6dd5fed4fe71afcf3 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 30 Apr 2011 08:41:39 -0400 Subject: Adds a README --- README | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 00000000..c6e073a0 --- /dev/null +++ b/README @@ -0,0 +1,38 @@ +======== + README +======== + +What is GNU MediaGoblin? +======================== + +* Initially, a place to store all your photos that’s as awesome as, if + not more awesome than, existing network services (Flickr, SmugMug, + Picasa, etc) +* Later, a place for all sorts of media, such as video, music, etc hosting. +* Federated with OStatus! +* Customizable! +* A place for people to collaborate and show off original and derived + creations Free, as in freedom. We’re a GNU project in the making, + afterall. + + +Is it ready for me to use? +========================== + +Not yet! We're working on it and we hope to have a usable system by +September 2011. + + +Can I help/hang out/participate/whisper sweet nothings in your ear? +=================================================================== + +Yes! Please join us and hang out! For more information on where we +hang out, see `our Join page `_ + + +Where is the documentation? +=========================== + +Documentation is located in the ``docs/`` directory in a "raw" +restructured-text form. It is also mirrored at +http://docs.mediagoblin.org/ in HTML form. -- cgit v1.2.3 From 87b44d61ef4c1ace855540ab35f047a2067e277c Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 30 Apr 2011 08:57:08 -0400 Subject: Adds initial root page This adds an initial root page that's ugly as sin, but makes it easier to test what exists so far (e.g. register, login, submit pictures). --- mediagoblin/templates/mediagoblin/root.html | 39 +++++++++++++++++++++++++++++ mediagoblin/views.py | 6 ++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 mediagoblin/templates/mediagoblin/root.html diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html new file mode 100644 index 00000000..d6fffb8e --- /dev/null +++ b/mediagoblin/templates/mediagoblin/root.html @@ -0,0 +1,39 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} +

Welcome to GNU MediaGoblin!

+ + {% if request.user %} +

+ Submit an item. +

+ + {% else %} +

+ If you have an account, you can + Login. +

+

+ If you don't have an account, please + Register. +

+ + {% endif %} +{% endblock %} diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 7a3cf098..1081ce29 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -22,7 +22,11 @@ import wtforms from mediagoblin import models def root_view(request): - return Response("This is the root") + template = request.template_env.get_template( + 'mediagoblin/root.html') + return Response( + template.render( + {'request': request})) class ImageSubmitForm(wtforms.Form): -- cgit v1.2.3 From 2514dc028029e991a965aba011d9a8e65ee8ea37 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 30 Apr 2011 09:26:03 -0500 Subject: Clarified that copyright assignment is encouraged, but not mandatory. --- docs/designdecisions.rst | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index 3398c24b..93dffbd9 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -244,17 +244,24 @@ everyone is the hero by Will on "Why AGPLv3 and CC0": .. _CC0 v1: http://creativecommons.org/publicdomain/zero/1.0/ -Why copyright assignment? -========================= - -Will Kahn-Greene on "Why copyright assignment?": - - GNU MediaGoblin is a GNU project with the copyrights held by the - FSF. Like other GNU projects, we require copyright assignment to - the FSF which gives the FSF the legal ability to defend the - AGPL-covered status of the software and distribute it. - - This is important to us because it guarantees that this software - we're working so hard on will be available to everyone and will - survive us. As long as someone is interested in using it and/or - working on it, it will live on. +Why (non-mandatory) copyright assignment? +========================================= + +Chris Webber on "Why copyright assignment?": + + GNU MediaGoblin is a GNU project with non-mandatory but heavily + encouraged copyright assignment to the FSF. Most, if not all, of + the core contributors to GNU MediaGoblin will have done a + copyright assignment, but unlike some other GNU projects, it isn't + required here. We think this is the best choice for GNU + MediaGoblin: it ensures that the Free Software Foundation may + protect the software by enforcing the AGPL if the FSF sees fit, + but it also means that we can immediately merge in changes from a + new contributor. It also means that some significant non-FSF + contributors might also be able to enforce the AGPL if seen fit. + + Again, assignment is not mandatory, but it is heavily encouraged, + even incentivized: significant contributors who do a copyright + assignment to the FSF are eligible to have a unique goblin drawing + produced for them by the project's main founder, Christopher Allan + Webber. See :ref:`contributinghowto` for details. -- cgit v1.2.3 From 109c87f829f2feaedac79ceaad394825e75f748c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 30 Apr 2011 09:31:03 -0500 Subject: Changing the wording around the django-like components statement --- docs/designdecisions.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index 93dffbd9..8fe4d1f0 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -47,11 +47,10 @@ Why WSGI Minimalism Chris Webber on "Why WSGI Minimalism": - If you notice in the technology listI list a lot of - components that are very `Django Project`_, but not actually - Django components. What can I say, I really like a lot of the - ideas in Django! Which leads to the question: why not just use - Django? + If you notice in the technology list I list a lot of components + that are very "django-like", but not actually `Django`_ + components. What can I say, I really like a lot of the ideas in + Django! Which leads to the question: why not just use Django? While I really like Django's ideas and a lot of its components, I also feel that most of the best ideas in Django I want have been @@ -85,7 +84,7 @@ Chris Webber on "Why WSGI Minimalism": deployment-howto, especially in the former making some notes on how to make it easier for Django hackers to get started. -.. _Django Project: http://www.djangoproject.com/ +.. _Django: http://www.djangoproject.com/ .. _Pylons: http://pylonshq.com/ .. _Pyramid: http://docs.pylonsproject.org/projects/pyramid/dev/ .. _Flask: http://flask.pocoo.org/ -- cgit v1.2.3 From 845c3ae25071dd53c5e2989f0769a5559fdce8b4 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 30 Apr 2011 11:17:35 -0400 Subject: Adds section on git * instructions for contributing patches * learning git * learning other utilities --- docs/git.rst | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ docs/hackinghowto.rst | 40 +++++++++++++++++++++++++++--- docs/index.rst | 1 + 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 docs/git.rst diff --git a/docs/git.rst b/docs/git.rst new file mode 100644 index 00000000..0db1dacf --- /dev/null +++ b/docs/git.rst @@ -0,0 +1,68 @@ +========================== + Git, Cloning and Patches +========================== + +GNU MediaGoblin uses git for all our version control and we have +the repositories hosted on `Gitorious `_. + +We have two repositories. One is for the project and the other is for +the project website. + + +How to clone the project +======================== + +Do:: + + git clone git://gitorious.org/mediagoblin/mediagoblin.git + + +How to send in patches +====================== + +All patches should be tied to issues in the `issue tracker +`_. +That makes it a lot easier for everyone to track proposed changes and +make sure your hard work doesn't get dropped on the floor! + +If there isn't an issue for what you're working on, please create +one. The better the description of what it is you're trying to +fix/implement, the better everyone else is able to understand why +you're doing what you're doing. + +There are two ways you could send in a patch. + + +How to send in a patch from a publicly available clone +------------------------------------------------------ + +Add a comment to the issue you're working on with the following bits +of information: + +* the url for your clone +* the revs you want looked at +* any details, questions, or other things that should be known + + +How to send in a patch if you don't have a publicly available clone +------------------------------------------------------------------- + +Assuming that the remote is our repository on gitorious and the branch +to compare against is master, do the following: + +1. checkout the branch you did your work in +2. do:: + + git format-patch -o patches origin/master + +3. either: + + * tar up and attach the tarball to the issue you're working on, OR + * attach the patch files to the issue you're working on one at a + time + + +How to learn git +================ + +Check out :ref:`hacking-howto-git`! diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 8b40e37d..1096b970 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -165,8 +165,8 @@ FIXME - write this Tips for people new to coding ============================= -Python ------- +Learning Python +--------------- GNU MediaGoblin is written using a programming language called `Python `_. @@ -189,8 +189,8 @@ These are all excellent texts. FIXME - are there good quality Python tutorial videos? -Libraries ---------- +Learning Libraries GNU MediaGoblin uses +--------------------------------------- GNU MediaGoblin uses a variety of libraries in order to do what it does. These libraries are listed in the :ref:`beardomatic-chapter` @@ -206,3 +206,35 @@ at `Python Miro Community `_ [0]_. If you have questions or need help, find us on the mailing list and on IRC. + + +.. _hacking-howto-git: + +Learning git +------------ + +git is an interesting and very powerful tool. Like all powerful +tools, it has a learning curve. + +If you're new to git, we highly recommend the following resources for +getting the hang of it: + +* `Learn Git `_ --- the GitHub + intro to git +* `Pro Git `_ --- fantastic book +* `Git casts `_ --- screencast covering git + usage +* `Git Reference `_ --- Git reference that makes + it easier to get the hang of git if you're coming from other version + control systems + + +Learning other utilities +------------------------ + +The `OpenHatch `_ site has a series of +`training missions `_ which are +designed to help you learn how to use these tools. + +If you're new to tar, diff and patch, we highly recommend you sign up +with OpenHatch and do the missions. diff --git a/docs/index.rst b/docs/index.rst index fc8cc642..935e354b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,6 +17,7 @@ Table of Contents: deploymenthowto hackinghowto theminghowto + git designdecisions vision beardomatic -- cgit v1.2.3 From 694c235106c66ff30e52fda69f6ae229f36943b5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 30 Apr 2011 11:32:33 -0500 Subject: Import based on the DEFAULT_SETTINGS_MODULE in setup_celery_from_config --- mediagoblin/celery_setup/__init__.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py index 171b9a6f..02b451f0 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/celery_setup/__init__.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import os +import sys from paste.deploy.converters import asbool, asint, aslist @@ -69,10 +70,21 @@ def asfloat(obj): "Bad float value: %r" % obj) -def setup_celery_from_config(app_config, global_config): +DEFAULT_SETTINGS_MODULE = 'mediagoblin.celery_setup.dummy_settings_module' + +def setup_celery_from_config(app_config, global_config, + settings_module=DEFAULT_SETTINGS_MODULE, + set_environ=True): """ Take a mediagoblin app config and the global config from a paste factory and try to set up a celery settings module from this. + + Args: + - app_config: the application config section + - global_config: the entire paste config, all sections + - settings_module: the module to populate, as a string + - set_environ: if set, this will CELERY_CONFIG_MODULE to the + settings_module """ if asbool(app_config.get('use_celery_environment_var')) == True: # Don't setup celery based on our config file. @@ -112,10 +124,11 @@ def setup_celery_from_config(app_config, global_config): value = aslist(value) celery_settings[key] = value - from mediagoblin.celery_setup import dummy_settings_module + __import__(settings_module) + this_module = sys.modules[settings_module] for key, value in celery_settings.iteritems(): - setattr(dummy_settings_module, key, value) - - os.environ['CELERY_CONFIG_MODULE'] = \ - 'mediagoblin.celery_setup.dummy_settings_module' + setattr(this_module, key, value) + + if set_environ: + os.environ['CELERY_CONFIG_MODULE'] = settings_module -- cgit v1.2.3 From 94459eadb8f1dae635e43c99958d37977db720c7 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 30 Apr 2011 14:42:14 -0400 Subject: Changes beardomatic things to codebase things --- docs/beardomatic.rst | 86 ---------------------------------------------------- docs/codebase.rst | 65 +++++++++++++++++++++++++++++++++++++++ docs/index.rst | 2 +- 3 files changed, 66 insertions(+), 87 deletions(-) delete mode 100644 docs/beardomatic.rst create mode 100644 docs/codebase.rst diff --git a/docs/beardomatic.rst b/docs/beardomatic.rst deleted file mode 100644 index 14130f6a..00000000 --- a/docs/beardomatic.rst +++ /dev/null @@ -1,86 +0,0 @@ -.. _beardomatic-chapter: - -=========================================== - Beardomatic: Infrastructure Documentation -=========================================== - -What the hell is Beardomatic? -============================= - -You might be wondering, "Gah! What the hell is Beardomatic!?" - -Well, I'll tell you. GNU MediaGoblin is a piece of software that sits -on a stack of libraries that do a bunch of stuff. It makes it easier -to differentiate the bits of code that encompass GNU MediaGoblin from -the bits of code that GNU MediaGoblin sit on top of. Thus, we came up -with the TOTALLY AWESOME name Beardomatic. - -Now you might be saying, "Holy crap!? Another web framework? Are you -going to write a mocking framework and an enumeration library, too!?" - -No, we're not. We're just calling this Beardomatic so that it's -easier to talk about things. However, at some point, we can take -these infrastructure bits from GNU MediaGoblin and turn them into a -full-blown "web framework". We wouldn't do this to compete for -mindshare with other web frameworks. We would do this to make it -easier for us to bootstrap other similar projects. - - -Beardomatic software stack -========================== - -Beardomatic is a software stack "web framework" composed of the -following bits: - -* Project infrastructure - - * `Python `_: the language we're using to write - this - - * `Nose `_: - for unit tests - - * `buildout `_: for getting dependencies, - building a runtime environment, ... - -* Data storage - - * `MongoDB `_: the document database backend - for storage - -* Web application - - * `Paste Deploy `_ and - `Paste Script `_: we'll use this for - configuring and launching the application - - * `WebOb `_: nice abstraction layer - from HTTP requests, responses and WSGI bits - - * `Routes `_: for URL routing - - * `Beaker `_: for handling sessions - - * `Jinja2 `_: the templating engine - - * `MongoKit `_: the lightweight - ORM for MongoDB we're using which will make it easier to define - structures and all that - - * `WTForms `_: for handling, - validation, and abstraction from HTML forms - - * `Celery `_: for task queuing (resizing - images, encoding video, ...) - - * `RabbitMQ `_: for sending tasks to celery - -* Front end - - * `JQuery `_: for groovy JavaScript things - - -How to ... in Beardomatic? -========================== - -FIXME - write this diff --git a/docs/codebase.rst b/docs/codebase.rst new file mode 100644 index 00000000..2c73e7d3 --- /dev/null +++ b/docs/codebase.rst @@ -0,0 +1,65 @@ +.. _codebase-chapter: + +======================== + Codebase Documentation +======================== + +This chapter covers the libraries that GNU MediaGoblin uses as well as +various recipes for getting things done. + + +Software Stack +============== + +* Project infrastructure + + * `Python `_: the language we're using to write + this + + * `Nose `_: + for unit tests + + * `buildout `_: for getting dependencies, + building a runtime environment, ... + +* Data storage + + * `MongoDB `_: the document database backend + for storage + +* Web application + + * `Paste Deploy `_ and + `Paste Script `_: we'll use this for + configuring and launching the application + + * `WebOb `_: nice abstraction layer + from HTTP requests, responses and WSGI bits + + * `Routes `_: for URL routing + + * `Beaker `_: for handling sessions + + * `Jinja2 `_: the templating engine + + * `MongoKit `_: the lightweight + ORM for MongoDB we're using which will make it easier to define + structures and all that + + * `WTForms `_: for handling, + validation, and abstraction from HTML forms + + * `Celery `_: for task queuing (resizing + images, encoding video, ...) + + * `RabbitMQ `_: for sending tasks to celery + +* Front end + + * `JQuery `_: for groovy JavaScript things + + +Recipes +======= + +FIXME - write this diff --git a/docs/index.rst b/docs/index.rst index 935e354b..16c8ca16 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,9 +18,9 @@ Table of Contents: hackinghowto theminghowto git + codebase designdecisions vision - beardomatic Indices and tables -- cgit v1.2.3 From 1c61a6ca3b477b8eadbfc32d3c7f34f8e3531f14 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 30 Apr 2011 21:53:39 -0500 Subject: A few more corrections to make setup_celery_from_config() work right --- mediagoblin/celery_setup/__init__.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py index 02b451f0..143f9170 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/celery_setup/__init__.py @@ -99,35 +99,41 @@ def setup_celery_from_config(app_config, global_config, celery_settings = {} # set up mongodb stuff + celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb' + if not celery_settings.has_key('BROKER_BACKEND'): + celery_settings['BROKER_BACKEND'] = 'mongodb' + celery_mongo_settings = {} + if app_config.has_key('db_host'): celery_mongo_settings['host'] = app_config['db_host'] - celery_settings['BROKER_HOST'] = app_config['db_host'] + if celery_settings['BROKER_BACKEND'] == 'mongodb': + celery_settings['BROKER_HOST'] = app_config['db_host'] if app_config.has_key('db_port'): celery_mongo_settings['port'] = asint(app_config['db_port']) - celery_settings['BROKER_PORT'] = asint(app_config['db_port']) + if celery_settings['BROKER_BACKEND'] == 'mongodb': + celery_settings['BROKER_PORT'] = asint(app_config['db_port']) celery_mongo_settings['database'] = app_config.get('db_name', 'mediagoblin') celery_settings['CELERY_MONGODB_BACKEND_SETTINGS'] = celery_mongo_settings - celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb' # Add anything else for key, value in celery_conf.iteritems(): key = key.upper() if key in KNOWN_CONFIG_BOOLS: value = asbool(value) - elif value in KNOWN_CONFIG_INTS: + elif key in KNOWN_CONFIG_INTS: value = asint(value) - elif value in KNOWN_CONFIG_FLOATS: + elif key in KNOWN_CONFIG_FLOATS: value = asfloat(value) - elif value in KNOWN_CONFIG_LISTS: + elif key in KNOWN_CONFIG_LISTS: value = aslist(value) celery_settings[key] = value __import__(settings_module) this_module = sys.modules[settings_module] - for key, value in celery_settings.iteritems(): + for key, value in celery_settings.items(): setattr(this_module, key, value) if set_environ: -- cgit v1.2.3 From ef30978ad247e00c8457c53c6aa97683a72a7777 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 30 Apr 2011 21:54:05 -0500 Subject: tests for setup_celery_from_config() --- mediagoblin/celery_setup/__init__.py | 2 +- mediagoblin/tests/fake_celery_module.py | 15 ++++++++++ mediagoblin/tests/test_celery_setup.py | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 mediagoblin/tests/fake_celery_module.py create mode 100644 mediagoblin/tests/test_celery_setup.py diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py index 143f9170..3a7f2a5d 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/celery_setup/__init__.py @@ -133,7 +133,7 @@ def setup_celery_from_config(app_config, global_config, __import__(settings_module) this_module = sys.modules[settings_module] - for key, value in celery_settings.items(): + for key, value in celery_settings.iteritems(): setattr(this_module, key, value) if set_environ: diff --git a/mediagoblin/tests/fake_celery_module.py b/mediagoblin/tests/fake_celery_module.py new file mode 100644 index 00000000..c129cbf8 --- /dev/null +++ b/mediagoblin/tests/fake_celery_module.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py new file mode 100644 index 00000000..4c2f1269 --- /dev/null +++ b/mediagoblin/tests/test_celery_setup.py @@ -0,0 +1,53 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import pkg_resources + +from mediagoblin import celery_setup + + +def test_setup_celery_from_config(): + def _wipe_testmodule_clean(module): + vars_to_wipe = [ + var for var in dir(module) + if not var.startswith('__') and not var.endswith('__')] + for var in vars_to_wipe: + delattr(module, var) + + + celery_setup.setup_celery_from_config( + {}, + {'something': {'or': 'other'}, + 'celery': {'some_variable': 'floop', + 'mail_port': '2000', + 'CELERYD_ETA_SCHEDULER_PRECISION': '1.3', + 'celery_result_persistent': 'true', + 'celery_imports': 'foo.bar.baz this.is.an.import'}}, + 'mediagoblin.tests.fake_celery_module', set_environ=False) + + from mediagoblin.tests import fake_celery_module + assert fake_celery_module.SOME_VARIABLE == 'floop' + assert fake_celery_module.MAIL_PORT == 2000 + assert isinstance(fake_celery_module.MAIL_PORT, int) + assert fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION == 1.3 + assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) + assert fake_celery_module.CELERY_RESULT_PERSISTENT is True + assert fake_celery_module.CELERY_IMPORTS == [ + 'foo.bar.baz', 'this.is.an.import'] + assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { + 'database': 'mediagoblin'} + assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' + assert fake_celery_module.BROKER_BACKEND == 'mongodb' -- cgit v1.2.3 From 524c8f347ff0b5c1fc176543157fa60b208906fe Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 May 2011 09:01:20 -0500 Subject: Second round of tests for setup_celery_from_config(), with some database information --- mediagoblin/tests/test_celery_setup.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index 4c2f1269..da18b0ef 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -27,7 +27,6 @@ def test_setup_celery_from_config(): for var in vars_to_wipe: delattr(module, var) - celery_setup.setup_celery_from_config( {}, {'something': {'or': 'other'}, @@ -51,3 +50,36 @@ def test_setup_celery_from_config(): 'database': 'mediagoblin'} assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' assert fake_celery_module.BROKER_BACKEND == 'mongodb' + + _wipe_testmodule_clean(fake_celery_module) + + celery_setup.setup_celery_from_config( + {'db_host': 'mongodb.example.org', + 'db_port': '8080', + 'db_name': 'captain_lollerskates', + 'celery_section': 'vegetable'}, + {'something': {'or': 'other'}, + 'vegetable': {'some_variable': 'poolf', + 'mail_port': '2020', + 'CELERYD_ETA_SCHEDULER_PRECISION': '3.1', + 'celery_result_persistent': 'false', + 'celery_imports': 'baz.bar.foo import.is.a.this'}}, + 'mediagoblin.tests.fake_celery_module', set_environ=False) + + from mediagoblin.tests import fake_celery_module + assert fake_celery_module.SOME_VARIABLE == 'poolf' + assert fake_celery_module.MAIL_PORT == 2020 + assert isinstance(fake_celery_module.MAIL_PORT, int) + assert fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION == 3.1 + assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) + assert fake_celery_module.CELERY_RESULT_PERSISTENT is False + assert fake_celery_module.CELERY_IMPORTS == [ + 'baz.bar.foo', 'import.is.a.this'] + assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { + 'database': 'captain_lollerskates', + 'host': 'mongodb.example.org', + 'port': 8080} + assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' + assert fake_celery_module.BROKER_BACKEND == 'mongodb' + assert fake_celery_module.BROKER_HOST == 'mongodb.example.org' + assert fake_celery_module.BROKER_PORT == 8080 -- cgit v1.2.3 From 1e48a8308a035e78398c4982d60cfa8f947f41e3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 May 2011 10:17:04 -0500 Subject: Now we have something useful: mediagoblin.celery_setup.from_celery auto-configures a celery config module from your paste config --- mediagoblin/celery_setup/from_celery.py | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 mediagoblin/celery_setup/from_celery.py diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py new file mode 100644 index 00000000..851cbaa1 --- /dev/null +++ b/mediagoblin/celery_setup/from_celery.py @@ -0,0 +1,87 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os + +import mongokit +from paste.deploy.loadwsgi import NicerConfigParser + +from mediagoblin import storage +from mediagoblin.celery_setup import setup_celery_from_config +from mediagoblin.globals import setup_globals + + +OUR_MODULENAME = 'mediagoblin.celery_setup.from_celery' + + +def setup_self(setup_globals_func=setup_globals): + """ + Transform this module into a celery config module by reading the + mediagoblin config file. Set the environment variable + MEDIAGOBLIN_CONFIG to specify where this config file is at and + what section it uses. + + By default it defaults to 'mediagoblin.ini:app:mediagoblin'. + + The first colon ":" is a delimiter between the filename and the + config section, so in this case the filename is 'mediagoblin.ini' + and the section where mediagoblin is defined is 'app:mediagoblin'. + + Args: + - 'setup_globals_func': this is for testing purposes only. Don't + set this! + """ + mgoblin_conf_file, mgoblin_section = os.environ.get( + 'MEDIAGOBLIN_CONFIG', 'mediagoblin.ini:app:mediagoblin').split(':', 1) + if not os.path.exists(mgoblin_conf_file): + raise IOError( + "MEDIAGOBLIN_CONFIG not set or file does not exist") + + parser = NicerConfigParser(mgoblin_conf_file) + parser.read(mgoblin_conf_file) + parser._defaults.setdefault( + 'here', os.path.dirname(os.path.abspath(mgoblin_conf_file))) + parser._defaults.setdefault( + '__file__', os.path.abspath(mgoblin_conf_file)) + + mgoblin_section = dict(parser.items(mgoblin_section)) + mgoblin_conf = dict( + [(section_name, dict(parser.items(section_name))) + for section_name in parser.sections()]) + setup_celery_from_config( + mgoblin_section, mgoblin_conf, + settings_module=OUR_MODULENAME, + set_environ=False) + + connection = mongokit.Connection( + mgoblin_section.get('db_host'), mgoblin_section.get('db_port')) + db = connection[mgoblin_section.get('db_name', 'mediagoblin')] + + # Set up the storage systems. + public_store = storage.storage_system_from_paste_config( + mgoblin_section, 'publicstore') + queue_store = storage.storage_system_from_paste_config( + mgoblin_section, 'queuestore') + + setup_globals_func( + db_connection=connection, + database=db, + public_store=public_store, + queue_store=queue_store) + + +if os.environ['CELERY_CONFIG_MODULE'] == OUR_MODULENAME: + setup_self() -- cgit v1.2.3 From 4a3f04323597410048b16f65dc67c8254b713140 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 May 2011 10:17:39 -0500 Subject: Include dependent scripts... maybe we'll change this later --- buildout.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/buildout.cfg b/buildout.cfg index 2b36fb7c..520d5907 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -5,6 +5,7 @@ parts = mediagoblin make_user_dev_dirs [mediagoblin] recipe=zc.recipe.egg interpreter=python +dependent-scripts = true eggs=mediagoblin entry-points = nosetests=nose:run_exit -- cgit v1.2.3 From 132a68b54696c6a405cd9061bfe1dbe4feafb795 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 May 2011 18:22:27 -0500 Subject: Require sphinx & jinja2 for good measure :) --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 38f1a4d4..5f3ebf95 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,8 @@ setup( 'nose', 'werkzeug', 'celery', + 'jinja2', + 'sphinx', ], test_suite='nose.collector', -- cgit v1.2.3 From 258b62c6a2046e0a378ee4da2bd2390acf535990 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 May 2011 19:41:22 -0500 Subject: Register the models when using from_celery --- mediagoblin/celery_setup/from_celery.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 851cbaa1..9bd7fe07 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -19,7 +19,7 @@ import os import mongokit from paste.deploy.loadwsgi import NicerConfigParser -from mediagoblin import storage +from mediagoblin import storage, models from mediagoblin.celery_setup import setup_celery_from_config from mediagoblin.globals import setup_globals @@ -69,6 +69,7 @@ def setup_self(setup_globals_func=setup_globals): connection = mongokit.Connection( mgoblin_section.get('db_host'), mgoblin_section.get('db_port')) db = connection[mgoblin_section.get('db_name', 'mediagoblin')] + models.register_models(connection) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( -- cgit v1.2.3 From 3dca2776a63886adcaac4bde188fb9ec8e74cfe2 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 2 May 2011 12:20:53 -0400 Subject: Fixes dead references in docs. --- docs/contributinghowto.rst | 2 ++ docs/designdecisions.rst | 2 +- docs/hackinghowto.rst | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index f10dd72a..a452f2d0 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -1,3 +1,5 @@ +.. _contributing-howto-chapter: + ==================== Contributing HOWTO ==================== diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index 8fe4d1f0..cd902f83 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -263,4 +263,4 @@ Chris Webber on "Why copyright assignment?": even incentivized: significant contributors who do a copyright assignment to the FSF are eligible to have a unique goblin drawing produced for them by the project's main founder, Christopher Allan - Webber. See :ref:`contributinghowto` for details. + Webber. See :ref:`contributing-howto-chapter` for details. diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 1096b970..26267b7f 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -193,7 +193,7 @@ Learning Libraries GNU MediaGoblin uses --------------------------------------- GNU MediaGoblin uses a variety of libraries in order to do what it -does. These libraries are listed in the :ref:`beardomatic-chapter` +does. These libraries are listed in the :ref:`codebase-chapter` along with links to the project Web sites and documentation for the libraries. -- cgit v1.2.3 From 8ac897c3b6834120eeaec6e8cd1646032b1b3739 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 3 May 2011 09:49:56 -0500 Subject: Add the base.css and reference it so other people can start working on it :) --- mediagoblin/static/css/base.css | 1 + mediagoblin/templates/mediagoblin/base.html | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 mediagoblin/static/css/base.css diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css new file mode 100644 index 00000000..93b0b1a2 --- /dev/null +++ b/mediagoblin/static/css/base.css @@ -0,0 +1 @@ +/* stuff goes here :) */ \ No newline at end of file diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 01c68258..71c2e550 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -18,8 +18,8 @@ {% block title %}MediaGoblin{% endblock title %} - {# #} + -- cgit v1.2.3 From 9610848c298fff67da83abd495a44be86dd4eea3 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Tue, 3 May 2011 12:07:01 -0400 Subject: Lots of documentation changes * added a YouCanHelp directive to replace FIXMEs and encourage contributors to help out * moved some bits around between the hacking howto and the codebase documents * expanded on the stub nature of the theming howto * tweaked some other text --- docs/codebase.rst | 61 ++++++++++++++++++++++++++++++++++++++ docs/conf.py | 4 +-- docs/contributinghowto.rst | 5 ++++ docs/hackinghowto.rst | 73 ++++++++++++++++++++++++++-------------------- docs/mediagoblin.rst | 2 +- docs/mgext/__init__.py | 0 docs/mgext/youcanhelp.py | 44 ++++++++++++++++++++++++++++ docs/theminghowto.rst | 3 +- 8 files changed, 156 insertions(+), 36 deletions(-) create mode 100644 docs/mgext/__init__.py create mode 100644 docs/mgext/youcanhelp.py diff --git a/docs/codebase.rst b/docs/codebase.rst index 2c73e7d3..1f6ce220 100644 --- a/docs/codebase.rst +++ b/docs/codebase.rst @@ -7,6 +7,18 @@ This chapter covers the libraries that GNU MediaGoblin uses as well as various recipes for getting things done. +.. Note:: + + This chapter is in flux. Clearly there are things here that aren't + documented. If there's something you have questions about, please + ask! + + See `the join page on the website `_ + for where we hang out. + +For more information on how to get started hacking on GNU MediaGoblin, +see :ref:`hacking-howto`. + Software Stack ============== @@ -59,6 +71,55 @@ Software Stack * `JQuery `_: for groovy JavaScript things + +What's where +============ + +After you've run buildout, you're faced with the following directory +tree:: + + mediagoblin/ + |- mediagoblin/ source code + | |- tests/ + | |- templates/ + | |- auth/ + | \- submit/ + |- docs/ documentation + | + | the rest of these directories are generated by + | buildout. + | + |- bin/ scripts + |- develop-eggs/ + |- eggs/ + |- mediagoblin.egg-info/ + |- parts/ + |- user_dev/ sessions, etc + + +As you can see, all the code for GNU MediaGoblin is in the +``mediagoblin`` directory. + +Here are some interesting files and what they do: + +:routing.py: maps url paths to views +:views.py: views handle http requests +:models.py: holds the mongodb schemas---these are the data structures + we're working with + +You'll notice that there are several sub-directories: tests, +templates, auth, submit, ... + +``tests`` holds the unit test code. + +``templates`` holds all the templates for the output. + +``auth`` and ``submit`` are modules that enacpsulate authentication +and media item submission. If you look in these directories, you'll +see they have their own ``routing.py``, ``view.py``, and +``models.py`` in addition to some other code. + + Recipes ======= diff --git a/docs/conf.py b/docs/conf.py index 967d84d0..fedaf33c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- @@ -25,7 +25,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ["mgext.youcanhelp"] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index a452f2d0..56a80b91 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -4,11 +4,16 @@ Contributing HOWTO ==================== +.. _join-the-community-section: + Join the community! =================== We're super glad you want to join our community! +See `the join page on the website `_ for +where we hang out. + There are a variety of ways you can help us and become part of the team. We're not just looking for coders! We're also looking for documentation writers, users, testers, evangelists, user-interface diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 26267b7f..fe2411bb 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -9,16 +9,20 @@ So you want to hack on GNU MediaGoblin? ======================================= First thing to do is check out the `Web site -`_ where we list all the project +`_ where we list all the project infrastructure including: -* the mailing list * the IRC channel -* the bug tracker +* the mailing list +* the issue tracker Additionally, we have information on how to get involved, who to talk to, what needs to be worked on, and other things besides! +Second thing to do is take a look at :ref:`codebase-chapter` where +we've started documenting how GNU MediaGoblin is built and how to add +new things. + How to set up and maintain an environment for hacking ===================================================== @@ -80,10 +84,16 @@ Updating dependencies --------------------- While hacking on GNU MediaGoblin over time, you'll eventually have to -update your development environment. To do that, run:: +update your development environment because the dependencies have +changed. To do that, run:: ./bin/buildout +.. Note:: + + You only need to do this when dependencies are updated. You don't + need to do this when you've made code changes. + Wiping your environment for a clean-slate ----------------------------------------- @@ -104,8 +114,12 @@ Delete the following directories: * parts/ * user_dev/ -FIXME - how to drop data from mongodb? we should probably write a -script. + +.. YouCanHelp:: + + If you're familiar with MongoDB and bash, we'd love to get a bash + script that removes all the GNU MediaGoblin data from an existing + MongoDB instance. Let us know! Running the server @@ -124,42 +138,34 @@ Run:: ./bin/nosetests -What's where -============ +Quickstart for Django programmers +================================= -After you've run buildout, you're faced with the following directory -tree:: +We're not using Django, but the codebase is very Django-like in its +structure. - mediagoblin/ - |- mediagoblin/ source code - | |- tests/ - | |- templates/ - | |- auth/ - | \- submit/ - |- docs/ documentation - | - | the rest of these directories are generated by - | buildout. - | - |- bin/ scripts - |- develop-eggs/ - |- eggs/ - |- mediagoblin.egg-info/ - |- parts/ - |- user_dev/ sessions, etc +* ``routing.py`` is like ``urls.py`` in Django +* ``models.py`` has mongokit ORM definitions +* ``views.py`` is where the views go +We're using MongoDB. Basically, instead of a relational database with +tables, you have a big JSON structure which acts a lot like a Python +dict. -Quickstart for Django programmers -================================= +.. YouCanHelp:: -FIXME - write this + If there are other things that you think would help orient someone + new to GNU MediaGoblin but coming from Django, let us know! Bite-sized bugs to start with ============================= -FIXME - write this +**May 3rd, 2011**: We don't have a list of bite-sized bugs, yet, but +this is important to us. If you're interested in things to work on, +let us know on `the mailing list `_ or +on the `IRC channel `_. Tips for people new to coding @@ -186,7 +192,10 @@ that are freely available on the Internet: These are all excellent texts. -FIXME - are there good quality Python tutorial videos? +.. YouCanHelp:: + + If you know of other good quality Python tutorials and Python + tutorial videos, let us know! Learning Libraries GNU MediaGoblin uses diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst index a6194dc4..6d511850 100644 --- a/docs/mediagoblin.rst +++ b/docs/mediagoblin.rst @@ -44,7 +44,7 @@ dedicated to computer user freedom. How can I participate? ====================== -See `Get Involved `. +See `Get Involved `_ on the website.. How is GNU MediaGoblin licensed? diff --git a/docs/mgext/__init__.py b/docs/mgext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/docs/mgext/youcanhelp.py b/docs/mgext/youcanhelp.py new file mode 100644 index 00000000..a99d0e4d --- /dev/null +++ b/docs/mgext/youcanhelp.py @@ -0,0 +1,44 @@ +from docutils import nodes + +from sphinx.util.compat import Directive, make_admonition + +class youcanhelp_node(nodes.Admonition, nodes.Element): + pass + +class YouCanHelp(Directive): + has_content = True + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + ad = make_admonition( + youcanhelp_node, + self.name, + ["You Can Help!"], + self.options, + self.content, + self.lineno, + self.content_offset, + self.block_text, + self.state, + self.state_machine) + ad[0].line = self.lineno + return ad + +def visit_youcanhelp_node(self, node): + self.visit_admonition(node) + +def depart_youcanhelp_node(self, node): + self.depart_admonition(node) + +def setup(app): + app.add_node( + youcanhelp_node, + html=(visit_youcanhelp_node, depart_youcanhelp_node), + latex=(visit_youcanhelp_node, depart_youcanhelp_node), + text=(visit_youcanhelp_node, depart_youcanhelp_node) + ) + + app.add_directive('youcanhelp', YouCanHelp) diff --git a/docs/theminghowto.rst b/docs/theminghowto.rst index 23f9cb1b..7b40685f 100644 --- a/docs/theminghowto.rst +++ b/docs/theminghowto.rst @@ -4,4 +4,5 @@ Theming HOWTO =============== -FIXME - stub! +We haven't implemented the necessary scaffolding to allow for theming +yet. Thus, this chapter is a stub. -- cgit v1.2.3 From db1a438f3e6f8c5c8cec20b9326a21baf4579306 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 3 May 2011 19:49:39 +0200 Subject: Added functionality to support user email verification, email = TBD, verification = done. Signed-off-by: Joar Wandborg --- mediagoblin/auth/routing.py | 4 +++- mediagoblin/auth/views.py | 23 ++++++++++++++++++ mediagoblin/models.py | 7 +++--- .../templates/mediagoblin/auth/verify_email.html | 28 ++++++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/auth/verify_email.html diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 92f19371..59762840 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -24,4 +24,6 @@ auth_routes = [ Route('mediagoblin.auth.login', '/login/', controller='mediagoblin.auth.views:login'), Route('mediagoblin.auth.logout', '/logout/', - controller='mediagoblin.auth.views:logout')] + controller='mediagoblin.auth.views:logout'), + Route('mediagoblin.auth.verify_email', '/verify_email/', + controller='mediagoblin.auth.views:verify_email')] diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 15e33e17..dfb6899f 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -116,3 +116,26 @@ def logout(request): return exc.HTTPFound( location=request.urlgen("index")) + +def verify_email(request): + import bson.objectid + user = request.db.User.find_one( + {'_id': bson.objectid.ObjectId( unicode( request.GET.get('userid') ) )}) + + verification_successful = bool + + if user and user['verification_key'] == unicode( request.GET.get('token') ): + user['status'] = u'active' + user['email_verified'] = True + verification_successful = True + user.save() + else: + verification_successful = False + + template = request.template_env.get_template( + 'mediagoblin/auth/verify_email.html') + return Response( + template.render( + {'request': request, + 'user': user, + 'verification_successful': verification_successful})) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index eef59ed4..62cab4a5 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import datetime +import datetime, uuid from mongokit import Document, Set @@ -41,6 +41,7 @@ class User(Document): 'pw_hash': unicode, 'email_verified': bool, 'status': unicode, + 'verification_key': unicode } required_fields = ['username', 'created', 'pw_hash', 'email'] @@ -48,8 +49,8 @@ class User(Document): default_values = { 'created': datetime.datetime.utcnow, 'email_verified': False, - # TODO: shouldn't be active by default, must have email registration - 'status': u'active'} + 'status': u'needs_email_verification', + 'verification_key': unicode( uuid.uuid4() ) } def check_login(self, password): """ diff --git a/mediagoblin/templates/mediagoblin/auth/verify_email.html b/mediagoblin/templates/mediagoblin/auth/verify_email.html new file mode 100644 index 00000000..fe9094bd --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/verify_email.html @@ -0,0 +1,28 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} +

+ {% if verification_successful %} + Your email address has been verified! + {% else %} + The verification key or user id is incorrect + {% endif %} +

+{% endblock %} -- cgit v1.2.3 From 65f24846540052ec58174296190578a3323cac12 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 3 May 2011 20:03:54 +0200 Subject: Added server-log.txt to .gitignore Signed-off-by: Joar Wandborg --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b9f1554e..6f6fc624 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ mediagoblin.egg-info *.pyo docs/_build/ user_dev/ +server-log.txt \ No newline at end of file -- cgit v1.2.3 From 41f446f4f2642e1cbcdba7e129978743ae598758 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 3 May 2011 21:45:13 -0500 Subject: Add a rudimentary media processing function. Haven't completely checked it for workingness, and not the final form this will take :) --- mediagoblin/process_media/__init__.py | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 mediagoblin/process_media/__init__.py diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py new file mode 100644 index 00000000..0d02a13f --- /dev/null +++ b/mediagoblin/process_media/__init__.py @@ -0,0 +1,50 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import Image +import mongokit +from celery.task import task + +from mediagoblin.globals import database, queue_store, public_store + + +THUMB_SIZE = 200, 200 + + +@task +def process_media_initial(media_id): + entry = database.MediaEntry.one( + {'_id': mongokit.ObjectId(media_id)}) + + queued_filepath = entry['queue_files'].pop() + queued_file = queue_store.get_file(queued_filepath, 'r') + + with queued_file: + thumb = Image(queued_file) + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + + thumb_filepath = public_store.get_unique_filepath( + ['media_entries', + unicode(entry['_id']), + 'thumbnail.jpg']) + + with public_store.get_file(thumb_filepath, 'w') as thumb_file: + thumb.save(thumb_file, "JPEG") + + queue_store.delete(queued_filepath) + entry.setdefault('media_files', []).append(thumb_filepath) + entry.state = 'processed' + entry.save() -- cgit v1.2.3 From 883cf4973464ec19b8360d699584294446a13559 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 3 May 2011 21:45:24 -0500 Subject: Require PIL --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 5f3ebf95..853a5a3b 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ setup( 'celery', 'jinja2', 'sphinx', + 'PIL', ], test_suite='nose.collector', -- cgit v1.2.3 From 88816492a3776618e2a2a9ad40d49445ebba410d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 3 May 2011 21:48:02 -0500 Subject: Force imports of stuff like mediagoblin.process_media which has tasks we need --- mediagoblin/celery_setup/__init__.py | 6 ++++++ mediagoblin/tests/test_celery_setup.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py index 3a7f2a5d..551b2741 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/celery_setup/__init__.py @@ -70,6 +70,8 @@ def asfloat(obj): "Bad float value: %r" % obj) +MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media'] + DEFAULT_SETTINGS_MODULE = 'mediagoblin.celery_setup.dummy_settings_module' def setup_celery_from_config(app_config, global_config, @@ -130,6 +132,10 @@ def setup_celery_from_config(app_config, global_config, value = aslist(value) celery_settings[key] = value + # add mandatory celery imports + celery_imports = celery_settings.setdefault('CELERY_IMPORTS', []) + celery_imports.extend(MANDATORY_CELERY_IMPORTS) + __import__(settings_module) this_module = sys.modules[settings_module] diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index da18b0ef..558eb458 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -45,7 +45,7 @@ def test_setup_celery_from_config(): assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) assert fake_celery_module.CELERY_RESULT_PERSISTENT is True assert fake_celery_module.CELERY_IMPORTS == [ - 'foo.bar.baz', 'this.is.an.import'] + 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.process_media'] assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { 'database': 'mediagoblin'} assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' @@ -74,7 +74,7 @@ def test_setup_celery_from_config(): assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) assert fake_celery_module.CELERY_RESULT_PERSISTENT is False assert fake_celery_module.CELERY_IMPORTS == [ - 'baz.bar.foo', 'import.is.a.this'] + 'baz.bar.foo', 'import.is.a.this', 'mediagoblin.process_media'] assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { 'database': 'captain_lollerskates', 'host': 'mongodb.example.org', -- cgit v1.2.3 From 4d4f6050d84125f4fd3845e42965fd21d07a5176 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 4 May 2011 08:00:08 -0500 Subject: send_email tool and email sending tests --- mediagoblin/tests/test_util.py | 41 ++++++++++++++++++++ mediagoblin/util.py | 87 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index 0e7a2967..5bc31fd6 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -14,9 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import email + from mediagoblin import util +util._activate_testing() + + def _import_component_testing_method(silly_string): # Just for the sake of testing that our component importer works. return u"'%s' is the silliest string I've ever seen" % silly_string @@ -28,3 +33,39 @@ def test_import_component(): result = imported_func('hooobaladoobala') expected = u"'hooobaladoobala' is the silliest string I've ever seen" assert result == expected + + +def test_send_email(): + util._clear_test_inboxes() + + # send the email + util.send_email( + "sender@mediagoblin.example.org", + ["amanda@example.org", "akila@example.org"], + "Testing is so much fun!", + """HAYYY GUYS! + +I hope you like unit tests JUST AS MUCH AS I DO!""") + + # check the main inbox + assert len(util.EMAIL_TEST_INBOX) == 1 + message = util.EMAIL_TEST_INBOX.pop() + assert message['From'] == "sender@mediagoblin.example.org" + assert message['To'] == "amanda@example.org, akila@example.org" + assert message['Subject'] == "Testing is so much fun!" + assert message.get_payload(decode=True) == """HAYYY GUYS! + +I hope you like unit tests JUST AS MUCH AS I DO!""" + + # Check everything that the FakeMhost.sendmail() method got is correct + assert len(util.EMAIL_TEST_MBOX_INBOX) == 1 + mbox_dict = util.EMAIL_TEST_MBOX_INBOX.pop() + assert mbox_dict['from'] == "sender@mediagoblin.example.org" + assert mbox_dict['to'] == ["amanda@example.org", "akila@example.org"] + mbox_message = email.message_from_string(mbox_dict['message']) + assert mbox_message['From'] == "sender@mediagoblin.example.org" + assert mbox_message['To'] == "amanda@example.org, akila@example.org" + assert mbox_message['Subject'] == "Testing is so much fun!" + assert mbox_message.get_payload(decode=True) == """HAYYY GUYS! + +I hope you like unit tests JUST AS MUCH AS I DO!""" diff --git a/mediagoblin/util.py b/mediagoblin/util.py index c9c57dfc..5b578a00 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -14,11 +14,23 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from email.MIMEText import MIMEText +import smtplib import sys import jinja2 import mongokit + +TESTS_ENABLED = False +def _activate_testing(): + """ + Call this to activate testing in util.py + """ + global TESTS_ENABLED + TESTS_ENABLED = True + + def get_jinja_env(user_template_path=None): """ Set up the Jinja environment, possibly allowing for user @@ -72,3 +84,78 @@ def import_component(import_string): module = sys.modules[module_name] func = getattr(module, func_name) return func + + +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Special email test stuff begins HERE +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# We have two "test inboxes" here: +# +# EMAIL_TEST_INBOX: +# ---------------- +# If you're writing test views, you'll probably want to check this. +# It contains a list of MIMEText messages. +# +# EMAIL_TEST_MBOX_INBOX: +# ---------------------- +# This collects the messages from the FakeMhost inbox. It's reslly +# just here for testing the send_email method itself. +# +# Anyway this contains: +# - from +# - to: a list of email recipient addresses +# - message: not just the body, but the whole message, including +# headers, etc. +# +# ***IMPORTANT!*** +# ---------------- +# Before running tests that call functions which send email, you should +# always call _clear_test_inboxes() to "wipe" the inboxes clean. + +EMAIL_TEST_INBOX = [] +EMAIL_TEST_MBOX_INBOX = [] + + +class FakeMhost(object): + """ + Just a fake mail host so we can capture and test messages + from send_email + """ + def connect(self): + pass + + def sendmail(self, from_addr, to_addrs, message): + EMAIL_TEST_MBOX_INBOX.append( + {'from': from_addr, + 'to': to_addrs, + 'message': message}) + +def _clear_test_inboxes(): + global EMAIL_TEST_INBOX + global EMAIL_TEST_MBOX_INBOX + EMAIL_TEST_INBOX = [] + EMAIL_TEST_MBOX_INBOX = [] + +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def send_email(from_addr, to_addrs, subject, message_body): + # TODO: make a mock mhost if testing is enabled + if TESTS_ENABLED: + mhost = FakeMhost() + else: + mhost = smtplib.SMTP() + + mhost.connect() + + message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8') + message['Subject'] = subject + message['From'] = from_addr + message['To'] = ', '.join(to_addrs) + + if TESTS_ENABLED: + EMAIL_TEST_INBOX.append(message) + + return mhost.sendmail(from_addr, to_addrs, message.as_string()) -- cgit v1.2.3 From 61ec968b0d1a3681bbc049d651f67100b64e1f6d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 4 May 2011 08:11:37 -0500 Subject: A simple, maybe obvious, docstring for util.send_email() --- mediagoblin/util.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 5b578a00..d24b59b6 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -142,6 +142,16 @@ def _clear_test_inboxes(): ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def send_email(from_addr, to_addrs, subject, message_body): + """ + Simple email sending wrapper, use this so we can capture messages + for unit testing purposes. + + Args: + - from_addr: address you're sending the email from + - to_addrs: list of recipient email addresses + - subject: subject of the email + - message_body: email body text + """ # TODO: make a mock mhost if testing is enabled if TESTS_ENABLED: mhost = FakeMhost() -- cgit v1.2.3 From 1b9e2541b9e8c4449f8f78dc91c8caa7b92c7aa5 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 5 May 2011 18:22:27 -0400 Subject: Adds design decision for the name --- docs/designdecisions.rst | 59 +++++++++++++++++++++++++++++++++++++++++++++++ docs/goblin.png | Bin 0 -> 47763 bytes docs/snugglygoblin.png | Bin 0 -> 163754 bytes 3 files changed, 59 insertions(+) create mode 100644 docs/goblin.png create mode 100644 docs/snugglygoblin.png diff --git a/docs/designdecisions.rst b/docs/designdecisions.rst index cd902f83..50dfe3e8 100644 --- a/docs/designdecisions.rst +++ b/docs/designdecisions.rst @@ -7,6 +7,63 @@ This chapter talks a bit about design decisions. +Why GNU MediaGoblin? +==================== + +Chris and Will on "Why GNU MediaGoblin": + + Chris came up with the name MediaGoblin. The name is pretty fun. + It merges the idea that this is a Media hosting project with + Goblin which sort of sounds like gobbling. Here's a piece of + software that gobbles up your media for all to see. + + `According to Wikipedia `_, a + goblin is: + + a legendary evil or mischievous illiterate creature, described + as grotesquely evil or evil-like phantom + + So are we evil? No. Are we mischievous or illiterate? Not + really. So what kind of goblin are we thinking about? We're + thinking about these goblins: + + .. figure:: goblin.png + :alt: Cute goblin with a beret. + + *Figure 1: Cute goblin with a beret. llustrated by Chris + Webber* + + .. figure:: snugglygoblin.png + :scale: 50% + :alt: Snuggly goblin with a beret. + + *Figure 2: Snuggly goblin. Illustrated by Karen Rustad* + + Those are pretty cute goblins. Those are the kinds of goblins + we're thinking about. + + Chris started doing work on the project after thinking about it + for a year. Then, after talking with Matt and Rob, it became an + official GNU project. Thus we now call it GNU MediaGoblin. + + That's a lot of letters, though, so in the interest of brevity and + facilitating easier casual conversation and balancing that with + what's important to us, we have the following rules: + + 1. "GNU MediaGoblin" is the name we're going to use in all official + capacities: web site, documentation, press releases, ... + + 2. In casual conversation, it's ok to use more casual names. + + 3. If you're writing about the project, we ask that you call it GNU + MediaGoblin. + + 4. If you don't like the name, we kindly ask you to take a deep + breath, think a happy thought about cute little goblins playing + on a playground and taking cute pictures of themselves, and let + it go. (Will added this one.) + + Why Python ========== @@ -264,3 +321,5 @@ Chris Webber on "Why copyright assignment?": assignment to the FSF are eligible to have a unique goblin drawing produced for them by the project's main founder, Christopher Allan Webber. See :ref:`contributing-howto-chapter` for details. + + diff --git a/docs/goblin.png b/docs/goblin.png new file mode 100644 index 00000000..e20265e6 Binary files /dev/null and b/docs/goblin.png differ diff --git a/docs/snugglygoblin.png b/docs/snugglygoblin.png new file mode 100644 index 00000000..f325ae4b Binary files /dev/null and b/docs/snugglygoblin.png differ -- cgit v1.2.3 From 11e5b19701a0bc7e5fd5b39c1e28d9e6b81ad4b0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 06:51:07 -0500 Subject: Moving wiping to a clean slate beneath running server/ test suite --- docs/hackinghowto.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index fe2411bb..f7e46dae 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -95,6 +95,22 @@ changed. To do that, run:: need to do this when you've made code changes. +Running the server +================== + +Run:: + + ./bin/paster serve mediagoblin.ini --reload + + +Running the test suite +====================== + +Run:: + + ./bin/nosetests + + Wiping your environment for a clean-slate ----------------------------------------- @@ -122,22 +138,6 @@ Delete the following directories: MongoDB instance. Let us know! -Running the server -================== - -Run:: - - ./bin/paster serve mediagoblin.ini --reload - - -Running the test suite -====================== - -Run:: - - ./bin/nosetests - - Quickstart for Django programmers ================================= -- cgit v1.2.3 From 4509880386a4fc8c0d3d0e7c2176776593af8f02 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 06:54:57 -0500 Subject: Made a link to the script wiping tool feature request ticket --- docs/hackinghowto.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index f7e46dae..ef49fc43 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -133,9 +133,9 @@ Delete the following directories: .. YouCanHelp:: - If you're familiar with MongoDB and bash, we'd love to get a bash - script that removes all the GNU MediaGoblin data from an existing - MongoDB instance. Let us know! + If you're familiar with MongoDB and bash, we'd love to get a + `script that removes all the GNU MediaGoblin data from an existing + instance `_. Let us know! Quickstart for Django programmers -- cgit v1.2.3 From 1b734c4d67640b62d93cc41c4061555581e3f77f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 06:56:26 -0500 Subject: It doesn't necessarily have to be bash. --- docs/hackinghowto.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index ef49fc43..46353886 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -133,9 +133,9 @@ Delete the following directories: .. YouCanHelp:: - If you're familiar with MongoDB and bash, we'd love to get a - `script that removes all the GNU MediaGoblin data from an existing - instance `_. Let us know! + If you're familiar with MongoDB, we'd love to get a `script that + removes all the GNU MediaGoblin data from an existing instance + `_. Let us know! Quickstart for Django programmers -- cgit v1.2.3 From 1dddd4e913b21ea9ee3bf29b32916814be563fcf Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 07:44:54 -0500 Subject: A completely evil environment destroying script. --- destroy_environment.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 destroy_environment.py diff --git a/destroy_environment.py b/destroy_environment.py new file mode 100755 index 00000000..bbdeffe9 --- /dev/null +++ b/destroy_environment.py @@ -0,0 +1,22 @@ +#!./bin/python + +import pymongo +import sys, os + +print "*** WARNING! ***" +print " Running this will destroy your mediagoblin database," +print " remove all your media files in user_dev/, etc." + +drop_it = raw_input( + 'Are you SURE you want to destroy your environment? (if so, type "yes")> ') + +if not drop_it == 'yes': + sys.exit(1) + +conn = pymongo.Connection() +conn.drop_database('mediagoblin') + +os.popen('rm -rf user_dev/media') +os.popen('rm -rf user_dev/beaker') + +print "removed all your stuff! okay, now re-run ./bin/buildout" -- cgit v1.2.3 From fa7f9c6184286f2b56f353b21ffaf1e1577569a3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 09:37:24 -0500 Subject: Process media! Successfully! --- mediagoblin/models.py | 9 +++++++-- mediagoblin/process_media/__init__.py | 25 ++++++++++++++++++++----- mediagoblin/submit/views.py | 7 +++++-- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index eef59ed4..cd6a28cc 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -73,11 +73,16 @@ class MediaEntry(Document): 'tags': [unicode], 'state': unicode, + # For now let's assume there can only be one main file queued + # at a time + 'queued_media_file': [unicode], + + # A dictionary of logical names to filepaths + 'media_files': dict, + # The following should be lists of lists, in appropriate file # record form - 'media_files': list, 'attachment_files': list, - 'queue_files': list, # This one should just be a single file record 'thumbnail_file': [unicode]} diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 0d02a13f..69177fee 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -29,11 +29,11 @@ def process_media_initial(media_id): entry = database.MediaEntry.one( {'_id': mongokit.ObjectId(media_id)}) - queued_filepath = entry['queue_files'].pop() + queued_filepath = entry['queued_media_file'] queued_file = queue_store.get_file(queued_filepath, 'r') with queued_file: - thumb = Image(queued_file) + thumb = Image.open(queued_file) thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) thumb_filepath = public_store.get_unique_filepath( @@ -44,7 +44,22 @@ def process_media_initial(media_id): with public_store.get_file(thumb_filepath, 'w') as thumb_file: thumb.save(thumb_file, "JPEG") - queue_store.delete(queued_filepath) - entry.setdefault('media_files', []).append(thumb_filepath) + # we have to re-read because unlike PIL, not everything reads + # things in string representation :) + queued_file = queue_store.get_file(queued_filepath, 'rb') + + with queued_file: + main_filepath = public_store.get_unique_filepath( + ['media_entries', + unicode(entry['_id']), + queued_filepath[-1]]) + + with public_store.get_file(main_filepath, 'wb') as main_file: + main_file.write(queued_file.read()) + + queue_store.delete_file(queued_filepath) + media_files_dict = entry.setdefault('media_files', {}) + media_files_dict['thumb'] = thumb_filepath + media_files_dict['main'] = main_filepath entry.state = 'processed' - entry.save() + entry.save(validate=False) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 926c7011..9c4eb3a4 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -22,6 +22,7 @@ from werkzeug.utils import secure_filename from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms +from mediagoblin.process_media import process_media_initial @require_active_login @@ -52,7 +53,6 @@ def submit_start(request): # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', - unicode(request.user['_id']), unicode(entry['_id']), secure_filename(request.POST['file'].filename)]) @@ -64,9 +64,12 @@ def submit_start(request): queue_file.write(request.POST['file'].file.read()) # Add queued filename to the entry - entry.setdefault('queue_files', []).append(queue_filepath) + entry['queued_media_file'] = queue_filepath entry.save(validate=True) + # queue it for processing + process_media_initial.delay(unicode(entry['_id'])) + # redirect return exc.HTTPFound( location=request.urlgen("mediagoblin.submit.success")) -- cgit v1.2.3 From 12b6ecac0f5188f4b4e07f9fd70e0c4a4a59a5ae Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 10:01:11 -0500 Subject: Erk, we didn't save the state right before --- mediagoblin/process_media/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 69177fee..3c4d0ca1 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -61,5 +61,5 @@ def process_media_initial(media_id): media_files_dict = entry.setdefault('media_files', {}) media_files_dict['thumb'] = thumb_filepath media_files_dict['main'] = main_filepath - entry.state = 'processed' - entry.save(validate=False) + entry['state'] = u'processed' + entry.save() -- cgit v1.2.3 From 4c1e752a089313b11f872771f234c59d1b5b9982 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 10:01:26 -0500 Subject: Actually display submitted stuff on the mainpage. Crappy, but working! --- mediagoblin/templates/mediagoblin/root.html | 14 ++++++++++++++ mediagoblin/views.py | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index d6fffb8e..06a89f3f 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -36,4 +36,18 @@

{% endif %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + +
+
    + {% for entry in media_entries %} +
  • + +
  • + {% endfor %} +
+
+ {% endblock %} diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 1081ce29..3728d4aa 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -22,11 +22,15 @@ import wtforms from mediagoblin import models def root_view(request): + media_entries = request.db.MediaEntry.find( + {u'state': u'processed'}) + template = request.template_env.get_template( 'mediagoblin/root.html') return Response( template.render( - {'request': request})) + {'request': request, + 'media_entries': media_entries})) class ImageSubmitForm(wtforms.Form): -- cgit v1.2.3 From 1c424df505b3c9f9cceb84a4fd0ac1867b7ed9b4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 6 May 2011 10:06:57 -0500 Subject: Instructions on running celeryd --- docs/hackinghowto.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 46353886..fdb53a25 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -103,6 +103,18 @@ Run:: ./bin/paster serve mediagoblin.ini --reload +Running celeryd +=============== + +You need to do this if you want your media to process and actually +show up. It's probably a good idea in development to have the web +server (above) running in one terminal and celeryd in another window. + +Run:: + + CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd + + Running the test suite ====================== -- cgit v1.2.3 From 67e63926f929cf7b6665fba00238fec227b5831e Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 7 May 2011 00:55:32 +0200 Subject: Fixed bug in models.py:User that caused all users created by the same python process to have the same verification_key value Signed-off-by: Joar Wandborg --- mediagoblin/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 62cab4a5..c361feac 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -50,7 +50,7 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, 'status': u'needs_email_verification', - 'verification_key': unicode( uuid.uuid4() ) } + 'verification_key': uuid.uuid4 } def check_login(self, password): """ -- cgit v1.2.3 From 85e1bc316ec7010d06e95b35d3496ad3ecf7ef78 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 7 May 2011 00:57:39 +0200 Subject: mediagoblin.util.send_email now supports both list() and string() in the 'to_addrs' parameter Signed-off-by: Joar Wandborg --- mediagoblin/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index d24b59b6..0d8bcae2 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -163,7 +163,8 @@ def send_email(from_addr, to_addrs, subject, message_body): message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8') message['Subject'] = subject message['From'] = from_addr - message['To'] = ', '.join(to_addrs) + # The shorthand condition takes height for the possibility that the to_addrs argument can be either list() or string() + message['To'] = ', '.join(to_addrs) if type( to_addrs ) == list else to_addrs if TESTS_ENABLED: EMAIL_TEST_INBOX.append(message) -- cgit v1.2.3 From b16ebe0e13247c94a3dc545761af395166956757 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 7 May 2011 02:30:35 +0200 Subject: Changed the method used to generate uuids for verification_key, this one works, thanks paroneayea Signed-off-by: Joar Wandborg --- mediagoblin/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index c361feac..e1198187 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -50,7 +50,7 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, 'status': u'needs_email_verification', - 'verification_key': uuid.uuid4 } + 'verification_key': lambda: unicode( uuid.uuid4() ) } def check_login(self, password): """ -- cgit v1.2.3 From 5c42a82c5ad4fa410219084a6f43bdc414369114 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 7 May 2011 03:08:09 +0200 Subject: Added functionality to send out verification email upon successful registration Signed-off-by: Joar Wandborg --- mediagoblin/auth/views.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index dfb6899f..79c09f5b 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -19,6 +19,7 @@ from webob import Response, exc from mediagoblin.auth import lib as auth_lib from mediagoblin.auth import forms as auth_forms +from mediagoblin.util import send_email def register(request): @@ -44,9 +45,28 @@ def register(request): entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) entry.save(validate=True) - - # TODO: Send email authentication request - + + # TODO: Move this setting to a better place + EMAIL_SENDER_ADDRESS = 'mediagoblin@fakehost' + + ''' TODO Index - Regarding sending of verification email + 1. There is no error handling in place + 2. Due to the distributed nature of GNU MediaGoblin, we should find a way to send some additional information about the specific GNU MediaGoblin instance in the subject line. For example "GNU MediaGoblin @ Wandborg - [...]". + 3. The verification link generation does not detect and adapt to access via the HTTPS protocol. + ''' + + # TODO (1) + send_email( + EMAIL_SENDER_ADDRESS, + entry['email'], + 'GNU MediaGoblin - Verify email', # TODO (2) + 'http://{host}{uri}?userid={userid}&token={verification_key}'.format( # TODO (3) + host = request.host, + uri = request.urlgen('mediagoblin.auth.verify_email'), + userid = unicode( entry['_id'] ), + verification_key = entry['verification_key'] + )) + # Redirect to register_success return exc.HTTPFound( location=request.urlgen("mediagoblin.auth.register_success")) -- cgit v1.2.3 From 8842779b4e059938a0d8b94b1b3c5e3941fe8450 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 6 May 2011 21:54:10 -0400 Subject: Fixes a link in the docs --- docs/mediagoblin.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst index 6d511850..df2190c1 100644 --- a/docs/mediagoblin.rst +++ b/docs/mediagoblin.rst @@ -60,7 +60,7 @@ Is this an official GNU Project? What does that mean? We are! It means that we meet the GNU Project's rigourous standards for free software. To find out more about what that means, check out -`the GNU site `. +`the GNU site `_. Please feel free to contact us with further questions! -- cgit v1.2.3 From 52be418afe95f7a127b12b559867921578d16dee Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 6 May 2011 22:06:36 -0400 Subject: First pass at adding virtualenv instructions. --- docs/hackinghowto.rst | 81 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index fdb53a25..40d14e24 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -49,9 +49,22 @@ requirements:: sudo apt-get install mongodb git-core python python-dev \ python-lxml +After getting the requirements, there are two ways to build a development environment: + +1. Running bootstrap and buildout, OR +2. Creating a virtual environment + +Pick one---don't do both! + + +Creating a dev environment with bootstrap and buildout +------------------------------------------------------ + +.. Note:: + + Either follow the instructions in this section OR follow the ones + in the next one---don't do both! -Running bootstrap and buildout ------------------------------- After installing the requirements, follow these steps: @@ -79,10 +92,6 @@ purposes this default should be fine. `_, that should work just fine. - -Updating dependencies ---------------------- - While hacking on GNU MediaGoblin over time, you'll eventually have to update your development environment because the dependencies have changed. To do that, run:: @@ -95,6 +104,66 @@ changed. To do that, run:: need to do this when you've made code changes. +Creating a dev environment with virtualenv +------------------------------------------ + +.. Note:: + + Either follow the instructions in this section OR follow the ones + in the previous one---don't do both! + +The following assumes you have these things installed: + +1. virtualenv: + + http://pypi.python.org/pypi/virtualenv + +2. virtualenv wrapper: + + http://www.doughellmann.com/projects/virtualenvwrapper/ + +3. git: + + http://git-scm.com/ + + +Follow these steps: + +1. Clone the repository:: + + git clone http://git.gitorious.org/mediagoblin/mediagoblin.git + +2. Create a virtual environment:: + + mkvirtualenv --no-site-packages mediagoblin + +3. If that doesn't put you in the virutal environment you just created, then do:: + + workon mediagoblin + +4. Run:: + + python setup.py develop + + +That's it! + +When you want to work on GNU MediaGoblin, you need to activate the +virtual environment like this:: + + workon mediagoblin + +If you want to deactivate it, you can do this:: + + deactivate + +.. Note:: + + You don't have to do anything additional to move changes you're + making to your virtual environment because the virtual environment + is pointing at the actual code files. + + Running the server ================== -- cgit v1.2.3 From 4564da2210fe42b491c74d3d32e8b5c2ddb246a8 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 7 May 2011 08:49:36 -0400 Subject: Overhauls hacking howto * reworks virtualenv section to be way better * reworks buildout section to mirror virtualenv section * reworks other sections that depend on which development environment building method you chose --- docs/hackinghowto.rst | 214 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 138 insertions(+), 76 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 40d14e24..a2a153aa 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -23,13 +23,21 @@ Second thing to do is take a look at :ref:`codebase-chapter` where we've started documenting how GNU MediaGoblin is built and how to add new things. +Third you'll need to :ref:`get the requirements +`. -How to set up and maintain an environment for hacking -===================================================== +Fourth, you'll need to build a development environment. For this step, there are two options: +1. :ref:`virtualenv ` OR +2. :ref:`buildout and bootstrap ` + +Pick one---don't do both! + + +.. _get-requirements-section: Getting requirements --------------------- +==================== First, you need to have the following installed before you can build an environment for hacking on GNU MediaGoblin: @@ -49,125 +57,169 @@ requirements:: sudo apt-get install mongodb git-core python python-dev \ python-lxml -After getting the requirements, there are two ways to build a development environment: +.. YouCanHelp:: -1. Running bootstrap and buildout, OR -2. Creating a virtual environment + If you have instructions for other GNU/Linux distributions to set + up requirements, let us know! -Pick one---don't do both! +.. _hacking-with-virtualenv: -Creating a dev environment with bootstrap and buildout ------------------------------------------------------- +How to set up and maintain an environment for hacking with virtualenv +===================================================================== .. Note:: Either follow the instructions in this section OR follow the ones - in the next one---don't do both! + in :ref:`hacking-with-buildout`. But don't do both! -After installing the requirements, follow these steps: +**Requirements** + +* virtualenv: http://pypi.python.org/pypi/virtualenv +* virtualenv wrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ +* git: http://git-scm.com/ + + +**Create a development environment** 1. Clone the repository:: git clone http://git.gitorious.org/mediagoblin/mediagoblin.git -2. Bootstrap and run buildout:: +2. Create a virtual environment:: - cd mediagoblin - python bootstrap.py && ./bin/buildout + mkvirtualenv --no-site-packages mediagoblin +3. If that doesn't put you in the virutal environment you just + created, then do:: -That's it! Using this method, buildout should create a ``user_dev`` -directory, in which certain things will be stored (media, beaker -session stuff, etc). You can change this, but for development -purposes this default should be fine. + workon mediagoblin +4. Run:: -.. Note:: + python setup.py develop - We used `zc.buildout `_ because it - involves fewer steps to get things running and less knowledge of - Python packaging. However, if you prefer to use `virtualenv - `_, that should work just - fine. +That's it! -While hacking on GNU MediaGoblin over time, you'll eventually have to -update your development environment because the dependencies have -changed. To do that, run:: - ./bin/buildout +**Activating a virtual environment** -.. Note:: +When you want to work on GNU MediaGoblin, you need to activate the +virtual environment like this:: + + workon mediagoblin - You only need to do this when dependencies are updated. You don't - need to do this when you've made code changes. +**Deactivating a virtual environment** -Creating a dev environment with virtualenv ------------------------------------------- +If you want to deactivate it, you can do this:: -.. Note:: + deactivate - Either follow the instructions in this section OR follow the ones - in the previous one---don't do both! -The following assumes you have these things installed: +**Updating a virtual environment with dependency changes** -1. virtualenv: +1. Enter the virtual environment. - http://pypi.python.org/pypi/virtualenv +2. Run:: -2. virtualenv wrapper: + python setup.py develop - http://www.doughellmann.com/projects/virtualenvwrapper/ -3. git: +**Updating a virtual environment with code changes** - http://git-scm.com/ +You don't need to do anything---code changes are automatically +available. -Follow these steps: +**Deleting a virtual environment** + +At some point you may want to delete your virtual environment. +Perhaps it's to start over. Perhaps it's so you can test building +development environments with virtualenv. + +To do this, do:: + + rmvirtualenv mediagoblin + + +.. _hacking-with-buildout: + +Creating a dev environment with bootstrap and buildout +------------------------------------------------------ + +.. Note:: + + Either follow the instructions in this section OR follow the ones + in :ref:`hacking-with-virtualenv`. But don't do both! + + +**Requirements** + +No additional requirements. + + +**Create a development environment** + +After installing the requirements, follow these steps: 1. Clone the repository:: git clone http://git.gitorious.org/mediagoblin/mediagoblin.git -2. Create a virtual environment:: +2. Bootstrap and run buildout:: - mkvirtualenv --no-site-packages mediagoblin + cd mediagoblin + python bootstrap.py && ./bin/buildout -3. If that doesn't put you in the virutal environment you just created, then do:: - workon mediagoblin +That's it! Using this method, buildout should create a ``user_dev`` +directory, in which certain things will be stored (media, beaker +session stuff, etc). You can change this, but for development +purposes this default should be fine. -4. Run:: - python setup.py develop +**Updating for dependency changes** +While hacking on GNU MediaGoblin over time, you'll eventually have to +update your development environment because the dependencies have +changed. To do that, run:: -That's it! + ./bin/buildout -When you want to work on GNU MediaGoblin, you need to activate the -virtual environment like this:: - workon mediagoblin +**Updating for code changes** -If you want to deactivate it, you can do this:: +You don't need to do anything---code changes are automatically +available. - deactivate -.. Note:: +**Deleting your buildout** + +At some point, you may want to delete your buildout. Perhaps it's to +start over. Perhaps it's to test building development environments +with buildout. + +To do this, do:: - You don't have to do anything additional to move changes you're - making to your virtual environment because the virtual environment - is pointing at the actual code files. + rm -rf bin develop-eggs eggs mediagoblin.egg-info parts user_dev + + +.. _env_with_virtualenv: + +Creating a dev environment with virtualenv +------------------------------------------ Running the server ================== -Run:: +If you did virtualenv, run:: + + paster serve mediagoblin.ini --reload + +If you did buildout, run:: ./bin/paster serve mediagoblin.ini --reload @@ -179,7 +231,11 @@ You need to do this if you want your media to process and actually show up. It's probably a good idea in development to have the web server (above) running in one terminal and celeryd in another window. -Run:: +If you did virtualenv, run:: + + CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery celeryd + +If you did buildout, run:: CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd @@ -187,30 +243,36 @@ Run:: Running the test suite ====================== -Run:: +If you did virtualenv, run:: + + nosetests + +If you did buildout, run:: ./bin/nosetests -Wiping your environment for a clean-slate ------------------------------------------ +Troubleshooting +=============== -.. Note:: +pymongo.errors.AutoReconnect: could not find master/primary +----------------------------------------------------------- - Unless you're doing development and working on and testing creating - a new instance, you will probably never have to do this. Will - plans to do this work and thus he documented it. +If you see this:: + pymongo.errors.AutoReconnect: could not find master/primary -Delete the following directories: +then make sure mongodb is installed and running. -* bin/ -* develop-eggs/ -* eggs/ -* mediagoblin.egg-info/ -* parts/ -* user_dev/ +Wiping your user data +===================== + +.. Note:: + + Unless you're doing development and working on and testing creating + a new instance, you will probably never have to do this. Will + plans to do this work and thus he documented it. .. YouCanHelp:: -- cgit v1.2.3 From 1220e775b9cea52632334e9acfde0cfac85ef25f Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 7 May 2011 09:42:01 -0400 Subject: Fixes headers in hacking howto docs --- docs/hackinghowto.rst | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index a2a153aa..7fd9b349 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -146,8 +146,8 @@ To do this, do:: .. _hacking-with-buildout: -Creating a dev environment with bootstrap and buildout ------------------------------------------------------- +How to set up and maintain an environment for hacking with buildout +=================================================================== .. Note:: @@ -206,12 +206,6 @@ To do this, do:: rm -rf bin develop-eggs eggs mediagoblin.egg-info parts user_dev -.. _env_with_virtualenv: - -Creating a dev environment with virtualenv ------------------------------------------- - - Running the server ================== -- cgit v1.2.3 From 7501000353ed20eda9b2b32e9a0aba63df88f1b5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 May 2011 08:54:53 -0500 Subject: Be sure to read the install instructions! --- docs/hackinghowto.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 7fd9b349..2e6d0d14 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -77,7 +77,7 @@ How to set up and maintain an environment for hacking with virtualenv **Requirements** * virtualenv: http://pypi.python.org/pypi/virtualenv -* virtualenv wrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ +* virtualenv wrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ (be sure to read the `install instructions `_) * git: http://git-scm.com/ -- cgit v1.2.3 From 2704f7a6cbe274b5d1969d511564f928e0ba5d29 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 7 May 2011 09:56:39 -0400 Subject: Tweaks the "if mongodb isn't working" troubleshooting section --- docs/hackinghowto.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 2e6d0d14..dcade418 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -258,6 +258,12 @@ If you see this:: then make sure mongodb is installed and running. +If it's installed, check the mongodb log. On my machine, that's ``/var/log/mongodb/mongodb.log``. If you see something like:: + + old lock file: /var/lib/mongodb/mongod.lock. probably means... + +Then delete the lock file and relaunch mongodb. + Wiping your user data ===================== -- cgit v1.2.3 From 2bae877e6769842900694f49a5e27c1bc31507e0 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 7 May 2011 09:57:37 -0400 Subject: Wraps the virtualenv wrapper line --- docs/hackinghowto.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index dcade418..d3784820 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -77,7 +77,10 @@ How to set up and maintain an environment for hacking with virtualenv **Requirements** * virtualenv: http://pypi.python.org/pypi/virtualenv -* virtualenv wrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ (be sure to read the `install instructions `_) +* virtualenv wrapper: + http://www.doughellmann.com/projects/virtualenvwrapper/ (be sure to + read the `install instructions + `_) * git: http://git-scm.com/ -- cgit v1.2.3 From 27057b42fb68e3f640a1788d6de36649af6455f7 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sat, 7 May 2011 09:57:58 -0400 Subject: Removes the git requirement--that's redundant --- docs/hackinghowto.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index d3784820..73522ec6 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -81,7 +81,6 @@ How to set up and maintain an environment for hacking with virtualenv http://www.doughellmann.com/projects/virtualenvwrapper/ (be sure to read the `install instructions `_) -* git: http://git-scm.com/ **Create a development environment** -- cgit v1.2.3 From 7a5ddb45dcf55c6d651b4a32dc1924e54b77c0f0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 May 2011 13:58:36 -0500 Subject: Reversing buildout and virtualenv instructions because I think virtualenv is easier if you don't know how this stuff works, and it works. --- docs/hackinghowto.rst | 132 ++++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 73522ec6..d829b1c0 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -28,8 +28,8 @@ Third you'll need to :ref:`get the requirements Fourth, you'll need to build a development environment. For this step, there are two options: -1. :ref:`virtualenv ` OR -2. :ref:`buildout and bootstrap ` +1. :ref:`buildout and bootstrap ` (easier) OR +2. :ref:`virtualenv ` (more flexible, but harder) Pick one---don't do both! @@ -63,6 +63,72 @@ requirements:: up requirements, let us know! +.. _hacking-with-buildout: + +How to set up and maintain an environment for hacking with buildout +=================================================================== + +.. Note:: + + Either follow the instructions in this section OR follow the ones + in :ref:`hacking-with-virtualenv`. But don't do both! + + +**Requirements** + +No additional requirements. + + +**Create a development environment** + +After installing the requirements, follow these steps: + +1. Clone the repository:: + + git clone http://git.gitorious.org/mediagoblin/mediagoblin.git + +2. Bootstrap and run buildout:: + + cd mediagoblin + python bootstrap.py && ./bin/buildout + + +That's it! Using this method, buildout should create a ``user_dev`` +directory, in which certain things will be stored (media, beaker +session stuff, etc). You can change this, but for development +purposes this default should be fine. + + +**Updating for dependency changes** + +While hacking on GNU MediaGoblin over time, you'll eventually have to +update your development environment because the dependencies have +changed. To do that, run:: + + ./bin/buildout + + +**Updating for code changes** + +You don't need to do anything---code changes are automatically +available. + + +**Deleting your buildout** + +At some point, you may want to delete your buildout. Perhaps it's to +start over. Perhaps it's to test building development environments +with buildout. + +To do this, do:: + + rm -rf bin develop-eggs eggs mediagoblin.egg-info parts user_dev + +Usually buildout works pretty great and is super easy, but if you get +problems with python-dateutil conflicts on your system, you may need +to use virtualenv instead. + + .. _hacking-with-virtualenv: How to set up and maintain an environment for hacking with virtualenv @@ -146,68 +212,6 @@ To do this, do:: rmvirtualenv mediagoblin -.. _hacking-with-buildout: - -How to set up and maintain an environment for hacking with buildout -=================================================================== - -.. Note:: - - Either follow the instructions in this section OR follow the ones - in :ref:`hacking-with-virtualenv`. But don't do both! - - -**Requirements** - -No additional requirements. - - -**Create a development environment** - -After installing the requirements, follow these steps: - -1. Clone the repository:: - - git clone http://git.gitorious.org/mediagoblin/mediagoblin.git - -2. Bootstrap and run buildout:: - - cd mediagoblin - python bootstrap.py && ./bin/buildout - - -That's it! Using this method, buildout should create a ``user_dev`` -directory, in which certain things will be stored (media, beaker -session stuff, etc). You can change this, but for development -purposes this default should be fine. - - -**Updating for dependency changes** - -While hacking on GNU MediaGoblin over time, you'll eventually have to -update your development environment because the dependencies have -changed. To do that, run:: - - ./bin/buildout - - -**Updating for code changes** - -You don't need to do anything---code changes are automatically -available. - - -**Deleting your buildout** - -At some point, you may want to delete your buildout. Perhaps it's to -start over. Perhaps it's to test building development environments -with buildout. - -To do this, do:: - - rm -rf bin develop-eggs eggs mediagoblin.egg-info parts user_dev - - Running the server ================== -- cgit v1.2.3 From 4c093e85c7457e989b22b5274f240e3ccfdab210 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sun, 8 May 2011 00:55:57 +0200 Subject: Made changes according to http://bugs.foocorp.net/issues/271#note-7 Signed-off-by: Joar Wandborg --- mediagoblin.ini | 1 + mediagoblin/app.py | 4 ++ mediagoblin/auth/views.py | 48 +++++++++++++--------- mediagoblin/celery_setup/from_celery.py | 4 ++ .../templates/mediagoblin/auth/verify_email.html | 4 +- mediagoblin/util.py | 3 +- 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index c6dd4f76..a54eebd5 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -14,6 +14,7 @@ queuestore_base_dir = %(here)s/user_dev/media/queue publicstore_base_dir = %(here)s/user_dev/media/public publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ +email_sender_address = "notice@mediagoblin.org" ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 59b943dd..ca3de6ca 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -36,6 +36,7 @@ class MediaGoblinApp(object): def __init__(self, connection, database_path, public_store, queue_store, staticdirector, + email_sender_address, user_template_path=None): # Get the template environment self.template_env = util.get_jinja_env(user_template_path) @@ -59,6 +60,7 @@ class MediaGoblinApp(object): # validators, etc, which might not access to the request # object. setup_globals( + email_sender_address=email_sender_address, db_connection=connection, database=self.db, public_store=self.public_store, @@ -139,6 +141,8 @@ def paste_app_factory(global_config, **app_config): connection, app_config.get('db_name', 'mediagoblin'), public_store=public_store, queue_store=queue_store, staticdirector=staticdirector, + email_sender_address=app_config.get('email_sender_address', + 'notice@medigoblin.org'), user_template_path=app_config.get('local_templates')) return mgoblin_app diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 79c09f5b..7468def0 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -20,6 +20,7 @@ from webob import Response, exc from mediagoblin.auth import lib as auth_lib from mediagoblin.auth import forms as auth_forms from mediagoblin.util import send_email +from mediagoblin import globals as mgoblin_globals def register(request): @@ -49,23 +50,26 @@ def register(request): # TODO: Move this setting to a better place EMAIL_SENDER_ADDRESS = 'mediagoblin@fakehost' - ''' TODO Index - Regarding sending of verification email - 1. There is no error handling in place - 2. Due to the distributed nature of GNU MediaGoblin, we should find a way to send some additional information about the specific GNU MediaGoblin instance in the subject line. For example "GNU MediaGoblin @ Wandborg - [...]". - 3. The verification link generation does not detect and adapt to access via the HTTPS protocol. - ''' - - # TODO (1) - send_email( - EMAIL_SENDER_ADDRESS, - entry['email'], - 'GNU MediaGoblin - Verify email', # TODO (2) - 'http://{host}{uri}?userid={userid}&token={verification_key}'.format( # TODO (3) - host = request.host, - uri = request.urlgen('mediagoblin.auth.verify_email'), - userid = unicode( entry['_id'] ), - verification_key = entry['verification_key'] - )) + email_template = request.template_env.get_template( + 'mediagoblin/auth/verification_email.txt') + + # TODO: There is no error handling in place + send_email( + mgoblin_globals.email_sender_address, + list(entry['email']), + # TODO + # Due to the distributed nature of GNU MediaGoblin, we should + # find a way to send some additional information about the + # specific GNU MediaGoblin instance in the subject line. For + # example "GNU MediaGoblin @ Wandborg - [...]". + 'GNU MediaGoblin - Verify email', + email_template.render( + username=entry['username'], + verification_url='http://{host}{uri}?userid={userid}&token={verification_key}'.format( + host=request.host, + uri=request.urlgen('mediagoblin.auth.verify_email'), + userid=unicode(entry['_id']), + verification_key=entry['verification_key']))) # Redirect to register_success return exc.HTTPFound( @@ -138,13 +142,19 @@ def logout(request): location=request.urlgen("index")) def verify_email(request): + """ + Email verification view + + validates GET parameters against database and unlocks the user account, if + you are lucky :) + """ import bson.objectid user = request.db.User.find_one( - {'_id': bson.objectid.ObjectId( unicode( request.GET.get('userid') ) )}) + {'_id': bson.objectid.ObjectId(unicode(request.GET.get('userid')))}) verification_successful = bool - if user and user['verification_key'] == unicode( request.GET.get('token') ): + if user and user['verification_key'] == unicode(request.GET.get('token')): user['status'] = u'active' user['email_verified'] = True verification_successful = True diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 9bd7fe07..387538e6 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -22,6 +22,7 @@ from paste.deploy.loadwsgi import NicerConfigParser from mediagoblin import storage, models from mediagoblin.celery_setup import setup_celery_from_config from mediagoblin.globals import setup_globals +from mediagoblin import globals as mgoblin_globals OUR_MODULENAME = 'mediagoblin.celery_setup.from_celery' @@ -81,6 +82,9 @@ def setup_self(setup_globals_func=setup_globals): db_connection=connection, database=db, public_store=public_store, + email_sender_address=mgoblin_section.get( + 'email_sender_address', + 'notice@mediagoblin.org'), queue_store=queue_store) diff --git a/mediagoblin/templates/mediagoblin/auth/verify_email.html b/mediagoblin/templates/mediagoblin/auth/verify_email.html index fe9094bd..b6e6d1f8 100644 --- a/mediagoblin/templates/mediagoblin/auth/verify_email.html +++ b/mediagoblin/templates/mediagoblin/auth/verify_email.html @@ -20,9 +20,9 @@ {% block mediagoblin_content %}

{% if verification_successful %} - Your email address has been verified! + Your email address has been verified! {% else %} - The verification key or user id is incorrect + The verification key or user id is incorrect {% endif %}

{% endblock %} diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 0d8bcae2..d24b59b6 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -163,8 +163,7 @@ def send_email(from_addr, to_addrs, subject, message_body): message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8') message['Subject'] = subject message['From'] = from_addr - # The shorthand condition takes height for the possibility that the to_addrs argument can be either list() or string() - message['To'] = ', '.join(to_addrs) if type( to_addrs ) == list else to_addrs + message['To'] = ', '.join(to_addrs) if TESTS_ENABLED: EMAIL_TEST_INBOX.append(message) -- cgit v1.2.3 From 4942b63711e53162a0ae5e7e5fdfd902df4e5e66 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sun, 8 May 2011 01:58:58 +0200 Subject: Removed unused variable Signed-off-by: Joar Wandborg --- mediagoblin/auth/views.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 7468def0..3ef1e75f 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -47,9 +47,6 @@ def register(request): request.POST['password']) entry.save(validate=True) - # TODO: Move this setting to a better place - EMAIL_SENDER_ADDRESS = 'mediagoblin@fakehost' - email_template = request.template_env.get_template( 'mediagoblin/auth/verification_email.txt') -- cgit v1.2.3 From 07a3a69cd476ac8844f96d5edb916d652bb91e42 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sun, 8 May 2011 02:01:26 +0200 Subject: Added verification email template Signed-off-by: Joar Wandborg --- .../mediagoblin/auth/verification_email.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/auth/verification_email.txt diff --git a/mediagoblin/templates/mediagoblin/auth/verification_email.txt b/mediagoblin/templates/mediagoblin/auth/verification_email.txt new file mode 100644 index 00000000..ce0629eb --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/verification_email.txt @@ -0,0 +1,22 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +Hi {{ username }}, + +to activate your GNU MediaGoblin account, open the following URL in your web browser + +{{ verification_url }} -- cgit v1.2.3 From 8a6a81bcaa557f1d7ceebea8b372be7cc3423ca2 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sun, 8 May 2011 02:03:11 +0200 Subject: Updated default sender address Signed-off-by: Joar Wandborg --- mediagoblin.ini | 2 +- mediagoblin/app.py | 2 +- mediagoblin/celery_setup/from_celery.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index a54eebd5..951971a9 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -14,7 +14,7 @@ queuestore_base_dir = %(here)s/user_dev/media/queue publicstore_base_dir = %(here)s/user_dev/media/public publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ -email_sender_address = "notice@mediagoblin.org" +email_sender_address = "notice@mediagoblin.example.org" ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ diff --git a/mediagoblin/app.py b/mediagoblin/app.py index ca3de6ca..ad9e77df 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -142,7 +142,7 @@ def paste_app_factory(global_config, **app_config): public_store=public_store, queue_store=queue_store, staticdirector=staticdirector, email_sender_address=app_config.get('email_sender_address', - 'notice@medigoblin.org'), + 'notice@mediagoblin.example.org'), user_template_path=app_config.get('local_templates')) return mgoblin_app diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 387538e6..218ebfeb 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -84,7 +84,7 @@ def setup_self(setup_globals_func=setup_globals): public_store=public_store, email_sender_address=mgoblin_section.get( 'email_sender_address', - 'notice@mediagoblin.org'), + 'notice@mediagoblin.example.org'), queue_store=queue_store) -- cgit v1.2.3 From 3eae207c54b6c8fa4c2e122403b4462d93b8b713 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 May 2011 22:44:37 -0500 Subject: [to_email] rather than list(to_email) which makes a nasty series like ['e','m','a','i','l'] --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 3ef1e75f..c3d24c74 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -53,7 +53,7 @@ def register(request): # TODO: There is no error handling in place send_email( mgoblin_globals.email_sender_address, - list(entry['email']), + [entry['email']], # TODO # Due to the distributed nature of GNU MediaGoblin, we should # find a way to send some additional information about the -- cgit v1.2.3 From 29f3fb7052a0a512d5970a936b30175b9c7eef63 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 May 2011 22:45:06 -0500 Subject: Added an email debug mode which, by default, is enabled --- mediagoblin.ini | 2 ++ mediagoblin/app.py | 9 ++++++--- mediagoblin/celery_setup/from_celery.py | 1 + mediagoblin/util.py | 17 ++++++++++++++--- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index 951971a9..b85f22ea 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -15,6 +15,8 @@ publicstore_base_dir = %(here)s/user_dev/media/public publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" +# set to false to enable sending notices +email_debug_mode = true ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ diff --git a/mediagoblin/app.py b/mediagoblin/app.py index ad9e77df..e93e0c4e 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -18,6 +18,7 @@ import urllib import routes import mongokit +from paste.deploy.converters import asbool from webob import Request, exc from mediagoblin import routing, util, models, storage, staticdirect @@ -36,7 +37,7 @@ class MediaGoblinApp(object): def __init__(self, connection, database_path, public_store, queue_store, staticdirector, - email_sender_address, + email_sender_address, email_debug_mode, user_template_path=None): # Get the template environment self.template_env = util.get_jinja_env(user_template_path) @@ -61,6 +62,7 @@ class MediaGoblinApp(object): # object. setup_globals( email_sender_address=email_sender_address, + email_debug_mode=email_debug_mode, db_connection=connection, database=self.db, public_store=self.public_store, @@ -141,8 +143,9 @@ def paste_app_factory(global_config, **app_config): connection, app_config.get('db_name', 'mediagoblin'), public_store=public_store, queue_store=queue_store, staticdirector=staticdirector, - email_sender_address=app_config.get('email_sender_address', - 'notice@mediagoblin.example.org'), + email_sender_address=app_config.get( + 'email_sender_address', 'notice@mediagoblin.example.org'), + email_debug_mode=app_config.get('email_debug_mode'), user_template_path=app_config.get('local_templates')) return mgoblin_app diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 218ebfeb..4ad2c1d1 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -82,6 +82,7 @@ def setup_self(setup_globals_func=setup_globals): db_connection=connection, database=db, public_store=public_store, + email_debug_mode=app_config.get('email_debug_mode'), email_sender_address=mgoblin_section.get( 'email_sender_address', 'notice@mediagoblin.example.org'), diff --git a/mediagoblin/util.py b/mediagoblin/util.py index d24b59b6..8695180a 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -21,6 +21,8 @@ import sys import jinja2 import mongokit +from mediagoblin import globals as mgoblin_globals + TESTS_ENABLED = False def _activate_testing(): @@ -153,9 +155,9 @@ def send_email(from_addr, to_addrs, subject, message_body): - message_body: email body text """ # TODO: make a mock mhost if testing is enabled - if TESTS_ENABLED: + if TESTS_ENABLED or mgoblin_globals.email_debug_mode: mhost = FakeMhost() - else: + elif not mgoblin_globals.email_debug_mode: mhost = smtplib.SMTP() mhost.connect() @@ -168,4 +170,13 @@ def send_email(from_addr, to_addrs, subject, message_body): if TESTS_ENABLED: EMAIL_TEST_INBOX.append(message) - return mhost.sendmail(from_addr, to_addrs, message.as_string()) + elif mgoblin_globals.email_debug_mode: + print u"===== Email =====" + print u"From address: %s" % message['From'] + print u"To addresses: %s" % message['To'] + print u"Subject: %s" % message['Subject'] + print u"-- Body: --" + print message.get_payload(decode=True) + + else: + return mhost.sendmail(from_addr, to_addrs, message.as_string()) -- cgit v1.2.3 From a5b06bb0750afd9d2751f92230d4dcb5c76d61c5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 May 2011 22:45:30 -0500 Subject: Removing unused sys import from setup.py --- setup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.py b/setup.py index 853a5a3b..7b483a57 100644 --- a/setup.py +++ b/setup.py @@ -16,8 +16,6 @@ from setuptools import setup, find_packages -import sys - setup( name = "mediagoblin", version = "0.0.1", -- cgit v1.2.3 From 19f8a24e4187b81f18a0def87b2b170a40977ff1 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Sun, 8 May 2011 11:12:38 +0200 Subject: app.py: Need to pass in port number as 'int' When we configured an explicite db_port in mediagoblin.ini, paster would crash claiming that the port number must be an int. Given that we don't have a "get_conf_int()" function or something similar (yet?), simply convert the port number to int before passing it to the mongo Connection instance. Signed-off-by: Sebastian Spaeth --- mediagoblin/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index e93e0c4e..5c094f38 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -114,8 +114,9 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **app_config): # Get the database connection + port = int(app_config.get('db_port')) connection = mongokit.Connection( - app_config.get('db_host'), app_config.get('db_port')) + app_config.get('db_host'), port) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( -- cgit v1.2.3 From eef100ada52adc4c1f65c7a006b92685f7317ee5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 8 May 2011 07:07:08 -0500 Subject: mgoblin_section.get, not app_config.get (doh) My name's Chris Webber and I ignore pyflakes warnings. --- mediagoblin/celery_setup/from_celery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 4ad2c1d1..0ddfcc76 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -82,7 +82,7 @@ def setup_self(setup_globals_func=setup_globals): db_connection=connection, database=db, public_store=public_store, - email_debug_mode=app_config.get('email_debug_mode'), + email_debug_mode=mgoblin_section.get('email_debug_mode'), email_sender_address=mgoblin_section.get( 'email_sender_address', 'notice@mediagoblin.example.org'), -- cgit v1.2.3 From a1eb1f6051300e5d3ce9d1f32d28a25a567e73d8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 8 May 2011 07:16:50 -0500 Subject: Only convert db port if it's there and use asint to do it (better errors if failing) --- mediagoblin/app.py | 6 ++++-- mediagoblin/celery_setup/from_celery.py | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 5c094f38..913e530e 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -18,7 +18,7 @@ import urllib import routes import mongokit -from paste.deploy.converters import asbool +from paste.deploy.converters import asint from webob import Request, exc from mediagoblin import routing, util, models, storage, staticdirect @@ -114,7 +114,9 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **app_config): # Get the database connection - port = int(app_config.get('db_port')) + port = app_config.get('db_port') + if port: + port = asint(port) connection = mongokit.Connection( app_config.get('db_host'), port) diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 0ddfcc76..6561c622 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -18,6 +18,7 @@ import os import mongokit from paste.deploy.loadwsgi import NicerConfigParser +from paste.deploy.converters import asint from mediagoblin import storage, models from mediagoblin.celery_setup import setup_celery_from_config @@ -67,8 +68,11 @@ def setup_self(setup_globals_func=setup_globals): settings_module=OUR_MODULENAME, set_environ=False) + port = mgoblin_section.get('db_port') + if port: + port = asint(port) connection = mongokit.Connection( - mgoblin_section.get('db_host'), mgoblin_section.get('db_port')) + mgoblin_section.get('db_host'), port) db = connection[mgoblin_section.get('db_name', 'mediagoblin')] models.register_models(connection) -- cgit v1.2.3 From 34900cce8ce0339b645d34749f6f5bed7bd5eef7 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Sun, 8 May 2011 15:46:35 +0200 Subject: Don't escape the verification URL In the verification email we would output the URL using HTML encoded text, so that e.g. & -> &. We don't want that and we know the URL won't contain user contributed content, so it is safe to turn off HTML encoding here. Signed-off-by: Sebastian Spaeth --- mediagoblin/templates/mediagoblin/auth/verification_email.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/auth/verification_email.txt b/mediagoblin/templates/mediagoblin/auth/verification_email.txt index ce0629eb..7863374d 100644 --- a/mediagoblin/templates/mediagoblin/auth/verification_email.txt +++ b/mediagoblin/templates/mediagoblin/auth/verification_email.txt @@ -19,4 +19,4 @@ Hi {{ username }}, to activate your GNU MediaGoblin account, open the following URL in your web browser -{{ verification_url }} +{{ verification_url|safe }} -- cgit v1.2.3 From cd847fd346e048a4bd6c42e065475b3167991213 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 8 May 2011 10:07:39 -0500 Subject: Asbool the email debug mode option --- mediagoblin/app.py | 4 ++-- mediagoblin/celery_setup/from_celery.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 913e530e..2a2f21cc 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -18,7 +18,7 @@ import urllib import routes import mongokit -from paste.deploy.converters import asint +from paste.deploy.converters import asbool, asint from webob import Request, exc from mediagoblin import routing, util, models, storage, staticdirect @@ -148,7 +148,7 @@ def paste_app_factory(global_config, **app_config): staticdirector=staticdirector, email_sender_address=app_config.get( 'email_sender_address', 'notice@mediagoblin.example.org'), - email_debug_mode=app_config.get('email_debug_mode'), + email_debug_mode=asbool(app_config.get('email_debug_mode')), user_template_path=app_config.get('local_templates')) return mgoblin_app diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 6561c622..55e638b9 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -18,7 +18,7 @@ import os import mongokit from paste.deploy.loadwsgi import NicerConfigParser -from paste.deploy.converters import asint +from paste.deploy.converters import asint, asbool from mediagoblin import storage, models from mediagoblin.celery_setup import setup_celery_from_config @@ -86,7 +86,7 @@ def setup_self(setup_globals_func=setup_globals): db_connection=connection, database=db, public_store=public_store, - email_debug_mode=mgoblin_section.get('email_debug_mode'), + email_debug_mode=asbool(mgoblin_section.get('email_debug_mode')), email_sender_address=mgoblin_section.get( 'email_sender_address', 'notice@mediagoblin.example.org'), -- cgit v1.2.3 From ec61f094926c7d64bd76f7d4dc79ce859d6f60ef Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Mon, 9 May 2011 00:23:12 +0200 Subject: Fix description submission in form handling When we submitted an image the description would remain empty. THis was because of some weird typo in form handling. Get an attribute with .get('description') and not with .get(['description']). With this patch, descriptions actually go into the database. Signed-off-by: Sebastian Spaeth --- mediagoblin/submit/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 9c4eb3a4..5e262f12 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -42,7 +42,7 @@ def submit_start(request): # create entry and save in database entry = request.db.MediaEntry() entry['title'] = request.POST['title'] - entry['description'] = request.POST.get(['description']) + entry['description'] = request.POST.get('description') entry['media_type'] = u'image' # heh entry['uploader'] = request.user -- cgit v1.2.3 From 9a16e16ffa9c0477bec6ea0bf1db7efd6f988638 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Sun, 8 May 2011 20:35:54 +0200 Subject: Implement simple media detail page This patch creates a "homepage" for each media. The URL is /u//m/. On it we display the media and some details. It is ugly and lacking some stuff but it works. The only thing left to do is to throw an 404 error if the and the media uploader don't correspond. - Also create a user "home page" while at it. It is merely a place holder for now though. - Link from the entries on the homepage, to the media pages, so we actually find them. Signed-off-by: Sebastian Spaeth --- mediagoblin/routing.py | 3 +- .../templates/mediagoblin/media_details.html | 34 ++++++++++++++ mediagoblin/templates/mediagoblin/root.html | 6 ++- .../templates/mediagoblin/user_pages/media.html | 41 +++++++++++++++++ .../templates/mediagoblin/user_pages/user.html | 26 +++++++++++ mediagoblin/user_pages/__init__.py | 0 mediagoblin/user_pages/routing.py | 24 ++++++++++ mediagoblin/user_pages/views.py | 52 ++++++++++++++++++++++ mediagoblin/views.py | 4 +- 9 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/media_details.html create mode 100644 mediagoblin/templates/mediagoblin/user_pages/media.html create mode 100644 mediagoblin/templates/mediagoblin/user_pages/user.html create mode 100644 mediagoblin/user_pages/__init__.py create mode 100644 mediagoblin/user_pages/routing.py create mode 100644 mediagoblin/user_pages/views.py diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index b47bec8d..356ef678 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -18,7 +18,7 @@ from routes import Mapper from mediagoblin.auth.routing import auth_routes from mediagoblin.submit.routing import submit_routes - +from mediagoblin.user_pages.routing import user_routes def get_mapper(): mapping = Mapper() @@ -30,5 +30,6 @@ def get_mapper(): mapping.extend(auth_routes, '/auth') mapping.extend(submit_routes, '/submit') + mapping.extend(user_routes, '/u') return mapping diff --git a/mediagoblin/templates/mediagoblin/media_details.html b/mediagoblin/templates/mediagoblin/media_details.html new file mode 100644 index 00000000..a00354bc --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_details.html @@ -0,0 +1,34 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + {% if media %} +

Media details for {{media.title}}

+
+ + +
Uploaded: {{ media.created}} +
Description: {{media.description}} +
+ {% else %} +

Sorry, no such media found.

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 06a89f3f..2cb0a9c0 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -43,8 +43,10 @@

    {% for entry in media_entries %}
  • - + +
  • {% endfor %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html new file mode 100644 index 00000000..08cc9251 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -0,0 +1,41 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + {% if media %} +

Media details for {{media.uploader.username}} + / {{media.title}} +

+
+ + +
Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, + media.created.month,media.created.day)}} by {{media.uploader.username}} +
Description: {{media.description}} +
+ {% else %} +

Sorry, no such media found.

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html new file mode 100644 index 00000000..4ad34f51 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -0,0 +1,26 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content -%} + {% if user %} +

User page for '{{user.username}}'

+ {{user}} + {% else %} +

Sorry, no such user found.

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/user_pages/__init__.py b/mediagoblin/user_pages/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py new file mode 100644 index 00000000..10ecd4fd --- /dev/null +++ b/mediagoblin/user_pages/routing.py @@ -0,0 +1,24 @@ +1# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from routes.route import Route + +user_routes = [ + Route('mediagoblin.user_pages.user_home', "/{user}", + controller="mediagoblin.user_pages.views:user_home"), + Route('mediagoblin.user_pages.media_home', r'/{user}/m/{m_id}', + requirements=dict(m_id="[0-9a-fA-F]{24}"), + controller="mediagoblin.user_pages.views:media_home")] diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py new file mode 100644 index 00000000..b1a301d4 --- /dev/null +++ b/mediagoblin/user_pages/views.py @@ -0,0 +1,52 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from webob import Response +from mongokit import ObjectId +import wtforms +#from mongokit import ObjectId + +def user_home(request): + """'Homepage' of a User()""" + user = request.db.User.find_one( + {'username': request.matchdict['user']}) + + medias = request.db.MediaEntry.find() + + template = request.template_env.get_template( + 'mediagoblin/user_pages/user.html') + return Response( + template.render( + {'request': request, + 'user': user, + 'medias': medias})) + +def media_home(request): + """'Homepage' of a MediaEntry()""" + media = request.db.MediaEntry.find_one( + ObjectId(request.matchdict['m_id'])) + + #check that media uploader and user correspondent + if media['uploader'].get('username') != request.matchdict['user']: + #TODO: How do I throw an error 404? + pass + + template = request.template_env.get_template( + 'mediagoblin/user_pages/media.html') + return Response( + template.render( + {'request': request, + 'media': media})) diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 3728d4aa..f4c0598a 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -18,13 +18,13 @@ import datetime from webob import Response, exc import wtforms - +from mongokit import ObjectId from mediagoblin import models def root_view(request): media_entries = request.db.MediaEntry.find( {u'state': u'processed'}) - + template = request.template_env.get_template( 'mediagoblin/root.html') return Response( -- cgit v1.2.3 From 2eef8761d835cfbda42a9e9437ac475ddf12918a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 10 May 2011 16:24:51 -0500 Subject: Indenting these templates because I'm pedantic about tag sections having their content indented :) --- mediagoblin/templates/mediagoblin/media_details.html | 18 +++++++++--------- mediagoblin/templates/mediagoblin/user_pages/user.html | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/media_details.html b/mediagoblin/templates/mediagoblin/media_details.html index a00354bc..1b02c809 100644 --- a/mediagoblin/templates/mediagoblin/media_details.html +++ b/mediagoblin/templates/mediagoblin/media_details.html @@ -20,15 +20,15 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

Media details for {{media.title}}

-
- - -
Uploaded: {{ media.created}} -
Description: {{media.description}} -
+

Media details for {{media.title}}

+
+ + +
Uploaded: {{ media.created}} +
Description: {{media.description}} +
{% else %} -

Sorry, no such media found.

+

Sorry, no such media found.

{% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 4ad34f51..4fa84430 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -18,9 +18,9 @@ {% extends "mediagoblin/base.html" %} {% block mediagoblin_content -%} {% if user %} -

User page for '{{user.username}}'

- {{user}} +

User page for '{{ user.username }}'

+ {{ user }} {% else %} -

Sorry, no such user found.

+

Sorry, no such user found.

{% endif %} {% endblock %} -- cgit v1.2.3 From f62494084460d09a2902ce656bf6dfda6c6b6852 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 10 May 2011 16:25:04 -0500 Subject: 404 appropriately here --- mediagoblin/user_pages/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index b1a301d4..cc613c40 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -17,7 +17,7 @@ from webob import Response from mongokit import ObjectId import wtforms -#from mongokit import ObjectId + def user_home(request): """'Homepage' of a User()""" @@ -34,15 +34,15 @@ def user_home(request): 'user': user, 'medias': medias})) + def media_home(request): """'Homepage' of a MediaEntry()""" media = request.db.MediaEntry.find_one( ObjectId(request.matchdict['m_id'])) - #check that media uploader and user correspondent + #check that media uploader and user correspond if media['uploader'].get('username') != request.matchdict['user']: - #TODO: How do I throw an error 404? - pass + return exc.HTTPNotFound() template = request.template_env.get_template( 'mediagoblin/user_pages/media.html') -- cgit v1.2.3 From 80c1802440380a725d4279f46be1333fe3205e6c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 10 May 2011 16:35:34 -0500 Subject: Removing this horrifying submission test stuff from way back when --- mediagoblin/views.py | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/mediagoblin/views.py b/mediagoblin/views.py index f4c0598a..95d0be7a 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -31,48 +31,3 @@ def root_view(request): template.render( {'request': request, 'media_entries': media_entries})) - - -class ImageSubmitForm(wtforms.Form): - title = wtforms.TextField( - 'Title', - [wtforms.validators.Length(min=1, max=500)]) - description = wtforms.TextAreaField('Description of this work') - file = wtforms.FileField('File') - - -def submit_test(request): - image_form = ImageSubmitForm(request.POST) - if request.method == 'POST' and image_form.validate(): - # create entry and save in database - - entry = request.db.MediaEntry() - entry['title'] = request.POST['title'] - entry['description'] = request.POST.get(['description']) - entry['media_type'] = u'image' - - # TODO this does NOT look save, we should clean the filename somenow? - entry['file_store'] = request.POST['file'].filename - - entry.save(validate=True) - - # save file to disk - ## TODO - #open('/tmp/read_file.png', 'wb').write(request.POST['file'].file.read()) - - - # resize if necessary - ## Hm. This should be done on a separate view? - - # redirect - pass - - - - # render - template = request.template_env.get_template( - 'mediagoblin/test_submit.html') - return Response( - template.render( - {'request': request, - 'image_form': image_form})) -- cgit v1.2.3 From 7222955fbad9d21542e71dafa910973a9cb0e676 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 11 May 2011 10:26:15 -0500 Subject: URLs should end in trailing slashes, or slash redirection doesn't work --- mediagoblin/user_pages/routing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 10ecd4fd..c2dc2fc0 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -1,4 +1,4 @@ -1# GNU MediaGoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # # This program is free software: you can redistribute it and/or modify @@ -17,8 +17,8 @@ from routes.route import Route user_routes = [ - Route('mediagoblin.user_pages.user_home', "/{user}", + Route('mediagoblin.user_pages.user_home', "/{user}/", controller="mediagoblin.user_pages.views:user_home"), - Route('mediagoblin.user_pages.media_home', r'/{user}/m/{m_id}', + Route('mediagoblin.user_pages.media_home', r'/{user}/m/{m_id}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), controller="mediagoblin.user_pages.views:media_home")] -- cgit v1.2.3 From d483b9b4734d271e2b37cd586e22fdad014c9386 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Mon, 9 May 2011 01:08:46 +0200 Subject: Enforce using local dateutil with buildout Natty has a too old system dateutil, but buildout will put the system modules in the search path first. By adding the dateutil spec to the 'egg' requirement, we put the dateutil inclusion of the local egg first and natty compiles (buildouts) fine. Part of http://bugs.foocorp.net/issues/308 Signed-off-by: Sebastian Spaeth --- buildout.cfg | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/buildout.cfg b/buildout.cfg index 520d5907..a77bf93c 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -6,7 +6,9 @@ parts = mediagoblin make_user_dev_dirs recipe=zc.recipe.egg interpreter=python dependent-scripts = true -eggs=mediagoblin +eggs= + python-dateutil>=1.5.0,<2.0.0 + mediagoblin entry-points = nosetests=nose:run_exit paster=paste.script.command:run -- cgit v1.2.3 From 6557056bca7e4bd722212cd9d217dbb23ce8aebd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 07:14:15 -0500 Subject: I don't believe we need READMEish.org anymore. --- READMEish.org | 192 ---------------------------------------------------------- 1 file changed, 192 deletions(-) delete mode 100644 READMEish.org diff --git a/READMEish.org b/READMEish.org deleted file mode 100644 index c4e95122..00000000 --- a/READMEish.org +++ /dev/null @@ -1,192 +0,0 @@ -#+latex_header: \documentclass[12pt]{article} -#+latex_header: \usepackage[margin=1in]{geometry} -#+OPTIONS: ^:nil - -GNU MediaGoblin - -* About - -What is MediaGoblin? I'm shooting for: - - - Initially, a place to store all your photos that's as awesome as, - more awesome than, existing proprietary solutions - - Later, a place for all sorts of media, such as video, music, etc - hosting. - - Federated, like statusnet/ostatus (we should use ostatus, in fact!) - - Customizable - - A place for people to collaborate and show off original and derived - creations - - Free, as in freedom. Under the GNU AGPL, v3 or later. Encourages - free formats and free licensing for content, too. - -Wow! That's pretty ambitious. Hopefully we're cool enough to do it. -I think we can. - -It's also necessary, for multiple reasons. Centralization and -proprietization of media on the internet is a serious problem and -makes the web go from a system of extreme resilience to a system -of frightening fragility. People should be able to own their data. -Etc. If you're reading this, chances are you already agree though. :) - -* Milestones - -Excepting the first, not necessarily in this order. - -** Basic image hosting -** Multi-media hosting (including video and audio) -** API(s) -** Federation - -Maybe this is 0.2 :) - -** Plugin system - -* Technology - -I have a pretty specific set of tools that I expect to use in this -project. Those are: - - - *[[http://python.org/][Python]]:* because I love, and know well, the language - - *[[http://www.mongodb.org/][MongoDB]]:* a "document database". Because it's extremely flexible - (and scales up well, but I guess not down well) - - *[[http://namlook.github.com/mongokit/][MongoKit]]:* a lightweight ORM for mongodb. Helps us define our - structures better, does schema validation, schema evolution, and - helps make things more fun and pythonic. - - *[[http://jinja.pocoo.org/docs/][Jinja2]]:* for templating. Pretty much django templates++ (wow, I - can actually pass arguments into method calls instead of tediously - writing custom tags!) - - *[[http://wtforms.simplecodes.com/][WTForms]]:* for form handling, validation, abstraction. Almost just - like Django's templates, - - *[[http://pythonpaste.org/webob/][WebOb]]:* gives nice request/response objects (also somewhat djangoish) - - *[[http://pythonpaste.org/deploy/][Paste Deploy]] and [[http://pythonpaste.org/script/][Paste Script]]:* as the default way of configuring - and launching the application. Since MediaGoblin will be fairly - wsgi minimalist though, you can probably use other ways to launch - it, though this will be the default. - - *[[http://routes.groovie.org/][Routes]]:* for URL routing. It works well enough. - - *[[http://jquery.com/][JQuery]]:* for all sorts of things on the javascript end of things, - for all sorts of reasons. - - *[[http://beaker.groovie.org/][Beaker]]:* for sessions, because that seems like it's generally - considered the way to go I guess. - - *[[http://somethingaboutorange.com/mrl/projects/nose/1.0.0/][nose]]:* for unit tests, because it makes testing a bit nicer. - - *[[http://celeryproject.org/][Celery]]:* for task queueing (think resizing images, encoding - video) because some people like it, and even the people I know who - don't don't seem to know of anything better :) - - *[[http://www.rabbitmq.com/][RabbitMQ]]:* for sending tasks to celery, because I guess that's - what most people do. Might be optional, might also let people use - MongoDB for this if they want. - -** Why python - -Because I (Chris Webber) know Python, love Python, am capable of -actually making this thing happen in Python (I've worked on a lot of -large free software web applications before in Python, including -[[http://mirocommunity.org/][Miro Community]], the [[http://miroguide.org][Miro Guide]], a large portion of -[[http://creativecommons.org/][Creative Commons' site]], and a whole bunch of things while working at -[[http://www.imagescape.com/][Imaginary Landscape]]). I know Python, I can make this happen in -Python, me starting a project like this makes sense if it's done in -Python. - -You might say that PHP is way more deployable, that rails has way more -cool developers riding around on fixie bikes, and all of those things -are true, but I know Python, like Python, and think that Python is -pretty great. I do think that deployment in Python is not as good as -with PHP, but I think the days of shared hosting are (thankfully) -coming to an end, and will probably be replaced by cheap virtual -machines spun up on the fly for people who want that sort of stuff, -and Python will be a huge part of that future, maybe even more than -PHP will. The deployment tools are getting better. Maybe we can use -something like Silver Lining. Maybe we can just distribute as .debs -or .rpms. We'll figure it out. - -But if I'm starting this project, which I am, it's gonna be in Python. - -** Why mongodb - -In case you were wondering, I am not a NOSQL fanboy, I do not go -around telling people that MongoDB is web scale. Actually my choice -for MongoDB isn't scalability, though scaling up really nicely is a -pretty good feature and sets us up well in case large volume sites -eventually do use MediaGoblin. But there's another side of -scalability, and that's scaling down, which is important for -federation, maybe even more important than scaling up in an ideal -universe where everyone ran servers out of their own housing. As a -memory-mapped database, MongoDB is pretty hungry, so actually I spent -a lot of time debating whether the inability to scale down as nicely -as something like SQL has with sqlite meant that it was out. - -But I decided in the end that I really want MongoDB, not for -scalability, but for flexibility. Schema evolution pains in SQL are -almost enough reason for me to want MongoDB, but not quite. The real -reason is because I want the ability to eventually handle multiple -media types through MediaGoblin, and also allow for plugins, without -the rigidity of tables making that difficult. In other words, -something like: - -#+BEGIN_SRC javascript -{"title": "Me talking until you are bored", - "description": "blah blah blah", - "media_type": "audio", - "media_data": { - "length": "2:30", - "codec": "OGG Vorbis"}, - "plugin_data": { - "licensing": { - "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}} -#+END_SRC - -Being able to just dump media-specific information in a media_data -hashtable is pretty great, and even better is having a plugin system -where you can just let plugins have their own entire key-value space -cleanly inside the document that doesn't interfere with anyone else's -stuff. If we were to let plugins to deposit their own information -inside the database, either we'd let plugins create their own tables -which makes SQL migrations even harder than they already are, or we'd -probably end up creating a table with a column for key, a column for -value, and a column for type in one huge table called "plugin_data" or -something similar. (Yo dawg, I heard you liked plugins, so I put a -database in your database so you can query while you query.) Gross. - -I also don't want things to be too lose so that we forget or lose the -structure of things, and that's one reason why I want to use MongoKit, -because we can cleanly define a much structure as we want and verify -that documents match that structure generally without adding too much -bloat or overhead (mongokit is a pretty lightweight wrapper and -doesn't inject extra mongokit-specific stuff into the database, which -is nice and nicer than many other ORMs in that way). - -** Why wsgi minimalism / Why not Django - -If you notice in the technology list above, I list a lot of components -that are very [[http://www.djangoproject.com/][Django-like]], but not actually Django components. What -can I say, I really like a lot of the ideas in Django! Which leads to -the question: why not just use Django? - -While I really like Django's ideas and a lot of its components, I also -feel that most of the best ideas in Django I want have been -implemented as good or even better outside of Django. I could just -use Django and replace the templating system with Jinja2, and the form -system with wtforms, and the database with MongoDB and MongoKit, but -at that point, how much of Django is really left? - -I also am sometimes saddened and irritated by how coupled all of -Django's components are. Loosely coupled yes, but still coupled. -WSGI has done a good job of providing a base layer for running -applications on and [[http://pythonpaste.org/webob/do-it-yourself.html][if you know how to do it yourself]] it's not hard or -many lines of code at all to bind them together without any framework -at all (not even say [[http://pylonshq.com/][Pylons]], [[http://docs.pylonsproject.org/projects/pyramid/dev/][Pyramid]], or [[http://flask.pocoo.org/][Flask]] which I think are still -great projects, especially for people who want this sort of thing but -have no idea how to get started). And even at this already really -early stage of writing MediaGoblin, that glue work is mostly done. - -Not to say I don't think Django isn't great for a lot of things. For -a lot of stuff, it's still the best, but not for MediaGoblin, I think. - -One thing that Django does super well though is documentation. It -still has some faults, but even with those considered I can hardly -think of any other project in Python that has as nice of documentation -as Django. It may be worth -[[http://pycon.blip.tv/file/4881071/][learning some lessons on documentation from Django]], on that note. - -I'd really like to have a good, thorough hacking-howto and -deployment-howto, especially in the former making some notes on how to -make it easier for Django hackers to get started. -- cgit v1.2.3 From 1504acfddf8e84383733dae33bf6bfbd7ae3df8d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 07:15:11 -0500 Subject: Right, we don't need the exported HTML either. --- READMEish.html | 426 --------------------------------------------------------- 1 file changed, 426 deletions(-) delete mode 100644 READMEish.html diff --git a/READMEish.html b/READMEish.html deleted file mode 100644 index 9981da11..00000000 --- a/READMEish.html +++ /dev/null @@ -1,426 +0,0 @@ - - - - -GNU MediaGoblin - - - - - - - - - - - -

- -

GNU MediaGoblin

- - - - -
-

1 About

-
- - -

-What is MediaGoblin? I'm shooting for: -

-
    -
  • Initially, a place to store all your photos that's as awesome as, - more awesome than, existing proprietary solutions -
  • -
  • Later, a place for all sorts of media, such as video, music, etc - hosting. -
  • -
  • Federated, like statusnet/ostatus (we should use ostatus, in fact!) -
  • -
  • Customizable -
  • -
  • A place for people to collaborate and show off original and derived - creations -
  • -
  • Free, as in freedom. Under the GNU AGPL, v3 or later. Encourages - free formats and free licensing for content, too. -
  • -
- -

-Wow! That's pretty ambitious. Hopefully we're cool enough to do it. -I think we can. -

-

-It's also necessary, for multiple reasons. Centralization and -proprietization of media on the internet is a serious problem and -makes the web go from a system of extreme resilience to a system -of frightening fragility. People should be able to own their data. -Etc. If you're reading this, chances are you already agree though. :) -

-
- -
- -
-

2 Milestones

-
- - -

-Excepting the first, not necessarily in this order. -

- -
- -
-

2.1 Basic image hosting

-
- -
- -
- -
-

2.2 Multi-media hosting (including video and audio)

-
- -
- -
- -
-

2.3 API(s)

-
- -
- -
- -
-

2.4 Federation

-
- - -

-Maybe this is 0.2 :) -

-
- -
- -
-

2.5 Plugin system

-
- - -
-
- -
- -
-

3 Technology

-
- - -

-I have a pretty specific set of tools that I expect to use in this -project. Those are: -

-
    -
  • Python: because I love, and know well, the language -
  • -
  • MongoDB: a "document database". Because it's extremely flexible - (and scales up well, but I guess not down well) -
  • -
  • MongoKit: a lightweight ORM for mongodb. Helps us define our - structures better, does schema validation, schema evolution, and - helps make things more fun and pythonic. -
  • -
  • Jinja2: for templating. Pretty much django templates++ (wow, I - can actually pass arguments into method calls instead of tediously - writing custom tags!) -
  • -
  • WTForms: for form handling, validation, abstraction. Almost just - like Django's templates, -
  • -
  • WebOb: gives nice request/response objects (also somewhat djangoish) -
  • -
  • Paste Deploy and Paste Script: as the default way of configuring - and launching the application. Since MediaGoblin will be fairly - wsgi minimalist though, you can probably use other ways to launch - it, though this will be the default. -
  • -
  • Routes: for URL routing. It works well enough. -
  • -
  • JQuery: for all sorts of things on the javascript end of things, - for all sorts of reasons. -
  • -
  • Beaker: for sessions, because that seems like it's generally - considered the way to go I guess. -
  • -
  • nose: for unit tests, because it makes testing a bit nicer. -
  • -
  • Celery: for task queueing (think resizing images, encoding - video) because some people like it, and even the people I know who - don't don't seem to know of anything better :) -
  • -
  • RabbitMQ: for sending tasks to celery, because I guess that's - what most people do. Might be optional, might also let people use - MongoDB for this if they want. -
  • -
- - -
- -
-

3.1 Why python

-
- - -

-Because I (Chris Webber) know Python, love Python, am capable of -actually making this thing happen in Python (I've worked on a lot of -large free software web applications before in Python, including -Miro Community, the Miro Guide, a large portion of -Creative Commons' site, and a whole bunch of things while working at -Imaginary Landscape). I know Python, I can make this happen in -Python, me starting a project like this makes sense if it's done in -Python. -

-

-You might say that PHP is way more deployable, that rails has way more -cool developers riding around on fixie bikes, and all of those things -are true, but I know Python, like Python, and think that Python is -pretty great. I do think that deployment in Python is not as good as -with PHP, but I think the days of shared hosting are (thankfully) -coming to an end, and will probably be replaced by cheap virtual -machines spun up on the fly for people who want that sort of stuff, -and Python will be a huge part of that future, maybe even more than -PHP will. The deployment tools are getting better. Maybe we can use -something like Silver Lining. Maybe we can just distribute as .debs -or .rpms. We'll figure it out. -

-

-But if I'm starting this project, which I am, it's gonna be in Python. -

-
- -
- -
-

3.2 Why mongodb

-
- - -

-In case you were wondering, I am not a NOSQL fanboy, I do not go -around telling people that MongoDB is web scale. Actually my choice -for MongoDB isn't scalability, though scaling up really nicely is a -pretty good feature and sets us up well in case large volume sites -eventually do use MediaGoblin. But there's another side of -scalability, and that's scaling down, which is important for -federation, maybe even more important than scaling up in an ideal -universe where everyone ran servers out of their own housing. As a -memory-mapped database, MongoDB is pretty hungry, so actually I spent -a lot of time debating whether the inability to scale down as nicely -as something like SQL has with sqlite meant that it was out. -

-

-But I decided in the end that I really want MongoDB, not for -scalability, but for flexibility. Schema evolution pains in SQL are -almost enough reason for me to want MongoDB, but not quite. The real -reason is because I want the ability to eventually handle multiple -media types through MediaGoblin, and also allow for plugins, without -the rigidity of tables making that difficult. In other words, -something like: -

- - - -
{"title": "Me talking until you are bored",
- "description": "blah blah blah",
- "media_type": "audio",
- "media_data": {
-     "length": "2:30",
-     "codec": "OGG Vorbis"},
- "plugin_data": {
-     "licensing": {
-         "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}}
-
- - - -

-Being able to just dump media-specific information in a media_data -hashtable is pretty great, and even better is having a plugin system -where you can just let plugins have their own entire key-value space -cleanly inside the document that doesn't interfere with anyone else's -stuff. If we were to let plugins to deposit their own information -inside the database, either we'd let plugins create their own tables -which makes SQL migrations even harder than they already are, or we'd -probably end up creating a table with a column for key, a column for -value, and a column for type in one huge table called "plugin_data" or -something similar. (Yo dawg, I heard you liked plugins, so I put a -database in your database so you can query while you query.) Gross. -

-

-I also don't want things to be too lose so that we forget or lose the -structure of things, and that's one reason why I want to use MongoKit, -because we can cleanly define a much structure as we want and verify -that documents match that structure generally without adding too much -bloat or overhead (mongokit is a pretty lightweight wrapper and -doesn't inject extra mongokit-specific stuff into the database, which -is nice and nicer than many other ORMs in that way). -

-
- -
- -
-

3.3 Why wsgi minimalism / Why not Django

-
- - -

-If you notice in the technology list above, I list a lot of components -that are very Django-like, but not actually Django components. What -can I say, I really like a lot of the ideas in Django! Which leads to -the question: why not just use Django? -

-

-While I really like Django's ideas and a lot of its components, I also -feel that most of the best ideas in Django I want have been -implemented as good or even better outside of Django. I could just -use Django and replace the templating system with Jinja2, and the form -system with wtforms, and the database with MongoDB and MongoKit, but -at that point, how much of Django is really left? -

-

-I also am sometimes saddened and irritated by how coupled all of -Django's components are. Loosely coupled yes, but still coupled. -WSGI has done a good job of providing a base layer for running -applications on and if you know how to do it yourself it's not hard or -many lines of code at all to bind them together without any framework -at all (not even say Pylons, Pyramid, or Flask which I think are still -great projects, especially for people who want this sort of thing but -have no idea how to get started). And even at this already really -early stage of writing MediaGoblin, that glue work is mostly done. -

-

-Not to say I don't think Django isn't great for a lot of things. For -a lot of stuff, it's still the best, but not for MediaGoblin, I think. -

-

-One thing that Django does super well though is documentation. It -still has some faults, but even with those considered I can hardly -think of any other project in Python that has as nice of documentation -as Django. It may be worth -learning some lessons on documentation from Django, on that note. -

-

-I'd really like to have a good, thorough hacking-howto and -deployment-howto, especially in the former making some notes on how to -make it easier for Django hackers to get started. -

-
-
-
-

Author: Christopher Allan Webber

-

Org version 7.5 with Emacs version 24

-Validate XHTML 1.0 -
-
- - -- cgit v1.2.3 From 829d50f350bf9a98580a01906218aca150b1ea89 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 07:17:02 -0500 Subject: Fixing tyop in README... thanks Daniel Neel! Also clarifying that our public alpha may be in October, which is what we've said elsewhere. --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index c6e073a0..2ef6f78e 100644 --- a/README +++ b/README @@ -12,7 +12,7 @@ What is GNU MediaGoblin? * Federated with OStatus! * Customizable! * A place for people to collaborate and show off original and derived - creations Free, as in freedom. We’re a GNU project in the making, + creations. Free, as in freedom. We’re a GNU project in the making, afterall. @@ -20,7 +20,7 @@ Is it ready for me to use? ========================== Not yet! We're working on it and we hope to have a usable system by -September 2011. +September / October 2011. Can I help/hang out/participate/whisper sweet nothings in your ear? -- cgit v1.2.3 From 20c834ffe409c55e7e9dc6e4110f90f7dd177f35 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 09:18:53 -0500 Subject: Add the jinja2 extension to the jinja loader --- mediagoblin/util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 8695180a..63f0f9c5 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -48,7 +48,9 @@ def get_jinja_env(user_template_path=None): else: loader = jinja2.PackageLoader('mediagoblin', 'templates') - return jinja2.Environment(loader=loader, autoescape=True) + return jinja2.Environment( + loader=loader, autoescape=True, + extensions=['jinja2.ext.i18n']) def setup_user_in_request(request): @@ -180,3 +182,4 @@ def send_email(from_addr, to_addrs, subject, message_body): else: return mhost.sendmail(from_addr, to_addrs, message.as_string()) + -- cgit v1.2.3 From 84d4f04edc468ba24685158fe379d37acb0db538 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 09:44:04 -0500 Subject: Added extraction stuff that's not used but appears to work :) --- babel.ini | 13 +++++++++++++ setup.py | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 babel.ini diff --git a/babel.ini b/babel.ini new file mode 100644 index 00000000..666270df --- /dev/null +++ b/babel.ini @@ -0,0 +1,13 @@ +# Extraction from Python source files +[python: mediagoblin/**.py] +# Extraction from Genshi HTML and text templates +[jinja2: mediagoblin/templates/**.html] +# Extract jinja templates (html) +encoding = utf-8 +[jinja2: mediagoblin/templates/**.txt] +# Extract jinja templates (text) +encoding = utf-8 + +# # Extraction from JavaScript files +# [javascript: mediagoblin/static/js/**.js] +# extract_messages = $._, jQuery._ \ No newline at end of file diff --git a/setup.py b/setup.py index 7b483a57..7d38e526 100644 --- a/setup.py +++ b/setup.py @@ -38,6 +38,7 @@ setup( 'jinja2', 'sphinx', 'PIL', + 'Babel', ], test_suite='nose.collector', @@ -50,5 +51,8 @@ setup( [zc.buildout] make_user_dev_dirs = mediagoblin.buildout_recipes:MakeUserDevDirs + + [babel.extractors] + jinja2 = jinja2.ext:babel_extract """, ) -- cgit v1.2.3 From 36bb98fbbad56d6721c73d7b8877e8d2856d7578 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 09:48:54 -0500 Subject: Translate the welcome message (extracts successfully!) --- mediagoblin/templates/mediagoblin/root.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 2cb0a9c0..e833e3fe 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -18,7 +18,7 @@ {% extends "mediagoblin/base.html" %} {% block mediagoblin_content %} -

Welcome to GNU MediaGoblin!

+

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

{% if request.user %}

-- cgit v1.2.3 From 95aa6b56b29eb59ea14acad078e645af0a35e5b9 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 10:05:35 -0500 Subject: buildout instructions come first since it's easier if it does work --- docs/hackinghowto.rst | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index d829b1c0..b34ce93a 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -215,14 +215,13 @@ To do this, do:: Running the server ================== -If you did virtualenv, run:: - - paster serve mediagoblin.ini --reload - If you did buildout, run:: ./bin/paster serve mediagoblin.ini --reload +If you did virtualenv, run:: + + paster serve mediagoblin.ini --reload Running celeryd =============== @@ -231,26 +230,24 @@ You need to do this if you want your media to process and actually show up. It's probably a good idea in development to have the web server (above) running in one terminal and celeryd in another window. -If you did virtualenv, run:: - - CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery celeryd - If you did buildout, run:: CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd +If you did virtualenv, run:: + + CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery celeryd Running the test suite ====================== -If you did virtualenv, run:: - - nosetests - If you did buildout, run:: ./bin/nosetests +If you did virtualenv, run:: + + nosetests Troubleshooting =============== -- cgit v1.2.3 From 1fc336e7e5c3fb385888976d740eb4df791a701d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 10:20:03 -0500 Subject: adding master.po translations file --- translations/master.po | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 translations/master.po diff --git a/translations/master.po b/translations/master.po new file mode 100644 index 00000000..0e242fee --- /dev/null +++ b/translations/master.po @@ -0,0 +1,23 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-05-12 10:17-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + -- cgit v1.2.3 From 23d23dcf6bbf136eed0759515da73eff08dd328f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 10:22:56 -0500 Subject: Moving translations to mediagoblin/translations --- mediagoblin/translations/master.po | 23 +++++++++++++++++++++++ translations/master.po | 23 ----------------------- 2 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 mediagoblin/translations/master.po delete mode 100644 translations/master.po diff --git a/mediagoblin/translations/master.po b/mediagoblin/translations/master.po new file mode 100644 index 00000000..0e242fee --- /dev/null +++ b/mediagoblin/translations/master.po @@ -0,0 +1,23 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-05-12 10:17-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + diff --git a/translations/master.po b/translations/master.po deleted file mode 100644 index 0e242fee..00000000 --- a/translations/master.po +++ /dev/null @@ -1,23 +0,0 @@ -# Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2011. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-05-12 10:17-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" - -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "" - -- cgit v1.2.3 From 5e593201a6b85ad3860d8b230dc7ff34c0397146 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:23:52 -0400 Subject: Fixed a typo in docs/mediagoblin.rst "...their data and that measn someone..." > "...their data and that means someone..." --- docs/mediagoblin.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst index df2190c1..1b17d606 100644 --- a/docs/mediagoblin.rst +++ b/docs/mediagoblin.rst @@ -26,7 +26,7 @@ Why are we doing this? Centralization and proprietization of media on the internet is a serious problem and makes the web go from a system of extreme resilience to a system of frightening fragility. We believe people -should be able to own their data and that measn someone has to build +should be able to own their data and that means someone has to build the tools to make it possible. We decide that in this case, that someone would be us! -- cgit v1.2.3 From 49fa1a00731418b227d5a41c0867d1c548bcd9f4 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:29:54 -0400 Subject: Fixed another typo in docs/mediagoblin.rst "We decide that in this case, that someone would be us!" > "We decided that in this case, that someone would be us!" --- docs/mediagoblin.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mediagoblin.rst b/docs/mediagoblin.rst index 1b17d606..ea9c83a7 100644 --- a/docs/mediagoblin.rst +++ b/docs/mediagoblin.rst @@ -27,7 +27,7 @@ Centralization and proprietization of media on the internet is a serious problem and makes the web go from a system of extreme resilience to a system of frightening fragility. We believe people should be able to own their data and that means someone has to build -the tools to make it possible. We decide that in this case, that +the tools to make it possible. We decided that in this case, that someone would be us! -- cgit v1.2.3 From c19eed5283aa3a389f4f4f3e9958575797f1132b Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:35:39 -0400 Subject: Fixed a typo in docs/contributinghowto.rst "it'd" > "it's" --- docs/contributinghowto.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributinghowto.rst b/docs/contributinghowto.rst index 56a80b91..e980a5e0 100644 --- a/docs/contributinghowto.rst +++ b/docs/contributinghowto.rst @@ -59,7 +59,7 @@ Here are some things you can do today: **Spread the word** The seductive call of Free Software services is a powerful - one, but many cannot hear it because it'd drowned out by the + one, but many cannot hear it because it's drowned out by the rush hour traffic honking of proprietary walled gardens and faux free services. Yuck! Be the sweet chirrup of the bird amidst the din! Tell others that there is a better way to -- cgit v1.2.3 From 016617a6c943f75da4acff1eb5703ae900ccf7c8 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:46:02 -0400 Subject: Changed "Foreward" to "Foreword" Figured this was a typo. If not, feel free to skip this commit. --- docs/foreward.rst | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 docs/foreward.rst diff --git a/docs/foreward.rst b/docs/foreward.rst deleted file mode 100644 index d2b9c417..00000000 --- a/docs/foreward.rst +++ /dev/null @@ -1,46 +0,0 @@ -========== - Foreward -========== - -About this manual -================= - -This is the GNU MediaGoblin manual. This documentation targets the -following groups of individuals: - -* people who want to use the software -* people who want to deploy the software -* contributors - -This manual is a living document and is in the ``mediagoblin`` -repository in the ``docs/`` directory. - - -Who wrote this documentation? -============================= - -In no particular order: - -* Chris -* Will -* Deb -* Greg -* Karen -* Matt -* Asheesh - - -I found an error in the docs---who do I tell? -============================================= - -There are a few ways---please pick the one most convenient to you! - -1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . -2. Tell someone on IRC ``#mediagoblin`` on Freenode. -3. Send an email to Will ``willg at bluesock dot org``. - -When you tell us about your issue, please let us know: - -* where you are looking (in git? url of the web-page?) -* what the issue is -* your thoughts on how to resolve it -- cgit v1.2.3 From c6d266f6518673ded665d7aa63c91c2aaf7dc403 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:46:59 -0400 Subject: Fixed previous broken commit Made a mistake with the last commit, fixed here. --- docs/foreword.rst | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 docs/foreword.rst diff --git a/docs/foreword.rst b/docs/foreword.rst new file mode 100644 index 00000000..1d423f08 --- /dev/null +++ b/docs/foreword.rst @@ -0,0 +1,46 @@ +========== + Foreword +========== + +About this manual +================= + +This is the GNU MediaGoblin manual. This documentation targets the +following groups of individuals: + +* people who want to use the software +* people who want to deploy the software +* contributors + +This manual is a living document and is in the ``mediagoblin`` +repository in the ``docs/`` directory. + + +Who wrote this documentation? +============================= + +In no particular order: + +* Chris +* Will +* Deb +* Greg +* Karen +* Matt +* Asheesh + + +I found an error in the docs---who do I tell? +============================================= + +There are a few ways---please pick the one most convenient to you! + +1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . +2. Tell someone on IRC ``#mediagoblin`` on Freenode. +3. Send an email to Will ``willg at bluesock dot org``. + +When you tell us about your issue, please let us know: + +* where you are looking (in git? url of the web-page?) +* what the issue is +* your thoughts on how to resolve it -- cgit v1.2.3 From 434fb405e3f0c3e6ff22a6a1fcf91fc84bbdca86 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:48:50 -0400 Subject: Updated table of contents Updated TOC to match "Foreward" > "Foreword" --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 16c8ca16..2f84d6a6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,7 +11,7 @@ Table of Contents: .. toctree:: :maxdepth: 2 - foreward + foreword mediagoblin contributinghowto deploymenthowto -- cgit v1.2.3 From 84440a68f71eb4cb3bf036ea9918ec28948cacd1 Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:52:51 -0400 Subject: Edits to "What's where" diagram in docs/codebase.rst Added comment symbols to distinguish comments from directory names. Changed wording a bit on one part. --- docs/codebase.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/codebase.rst b/docs/codebase.rst index 1f6ce220..37eaf4d2 100644 --- a/docs/codebase.rst +++ b/docs/codebase.rst @@ -79,22 +79,22 @@ After you've run buildout, you're faced with the following directory tree:: mediagoblin/ - |- mediagoblin/ source code + |- mediagoblin/ #source code | |- tests/ | |- templates/ | |- auth/ | \- submit/ - |- docs/ documentation + |- docs/ #documentation | - | the rest of these directories are generated by + | #the below directories are generated by | buildout. | - |- bin/ scripts + |- bin/ #scripts |- develop-eggs/ |- eggs/ |- mediagoblin.egg-info/ |- parts/ - |- user_dev/ sessions, etc + |- user_dev/ #sessions, etc As you can see, all the code for GNU MediaGoblin is in the -- cgit v1.2.3 From bdcd615c3cf290565025a46aa03f986c472be7fc Mon Sep 17 00:00:00 2001 From: Daniel Neel Date: Thu, 12 May 2011 14:54:59 -0400 Subject: Update to previous commit To add an extra comment symbol. --- docs/codebase.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codebase.rst b/docs/codebase.rst index 37eaf4d2..4f5f215f 100644 --- a/docs/codebase.rst +++ b/docs/codebase.rst @@ -87,7 +87,7 @@ tree:: |- docs/ #documentation | | #the below directories are generated by - | buildout. + | #buildout. | |- bin/ #scripts |- develop-eggs/ -- cgit v1.2.3 From 2de317f2f35cfceffdda2c3990ad32b661161fb8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 14:25:28 -0500 Subject: I probably shouldn't break the main page since we don't have the gettext thing in place yet. --- mediagoblin/templates/mediagoblin/root.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index e833e3fe..44d26a65 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -18,7 +18,10 @@ {% extends "mediagoblin/base.html" %} {% block mediagoblin_content %} -

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

+ +

Welcome to GNU MediaGoblin!

+ {# +

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

#} {% if request.user %}

-- cgit v1.2.3 From 21919313dfc18c9f9303cbbb2591c0410379f768 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 14:49:37 -0500 Subject: Fix the email debug inbox --- mediagoblin/util.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 63f0f9c5..946216ba 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -172,7 +172,7 @@ def send_email(from_addr, to_addrs, subject, message_body): if TESTS_ENABLED: EMAIL_TEST_INBOX.append(message) - elif mgoblin_globals.email_debug_mode: + if getattr(mgoblin_globals, 'email_debug_mode', False): print u"===== Email =====" print u"From address: %s" % message['From'] print u"To addresses: %s" % message['To'] @@ -180,6 +180,4 @@ def send_email(from_addr, to_addrs, subject, message_body): print u"-- Body: --" print message.get_payload(decode=True) - else: - return mhost.sendmail(from_addr, to_addrs, message.as_string()) - + return mhost.sendmail(from_addr, to_addrs, message.as_string()) -- cgit v1.2.3 From 8b28bee4c1de6f1190091f5c17c0cf0f948c7071 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 14:57:58 -0500 Subject: Added some locale determination tools --- mediagoblin/tests/test_util.py | 26 ++++++++++++++++++++ mediagoblin/util.py | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index 5bc31fd6..ff40a677 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -69,3 +69,29 @@ I hope you like unit tests JUST AS MUCH AS I DO!""" assert mbox_message.get_payload(decode=True) == """HAYYY GUYS! I hope you like unit tests JUST AS MUCH AS I DO!""" + + +def test_locale_to_lower_upper(): + """ + Test cc.i18n.util.locale_to_lower_upper() + """ + assert util.locale_to_lower_upper('en') == 'en' + assert util.locale_to_lower_upper('en_US') == 'en_US' + assert util.locale_to_lower_upper('en-us') == 'en_US' + + # crazy renditions. Useful? + assert util.locale_to_lower_upper('en-US') == 'en_US' + assert util.locale_to_lower_upper('en_us') == 'en_US' + + +def test_locale_to_lower_lower(): + """ + Test cc.i18n.util.locale_to_lower_lower() + """ + assert util.locale_to_lower_lower('en') == 'en' + assert util.locale_to_lower_lower('en_US') == 'en-us' + assert util.locale_to_lower_lower('en-us') == 'en-us' + + # crazy renditions. Useful? + assert util.locale_to_lower_lower('en-US') == 'en-us' + assert util.locale_to_lower_lower('en_us') == 'en-us' diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 63f0f9c5..2b7948c8 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -183,3 +183,59 @@ def send_email(from_addr, to_addrs, subject, message_body): else: return mhost.sendmail(from_addr, to_addrs, message.as_string()) + +################### +# Translation tools +################### + + +def locale_to_lower_upper(locale): + """ + Take a locale, regardless of style, and format it like "en-us" + """ + if '-' in locale: + lang, country = locale.split('-', 1) + return '%s_%s' % (lang.lower(), country.upper()) + elif '_' in locale: + lang, country = locale.split('_', 1) + return '%s_%s' % (lang.lower(), country.upper()) + else: + return locale.lower() + + +def locale_to_lower_lower(locale): + """ + Take a locale, regardless of style, and format it like "en_US" + """ + if '_' in locale: + lang, country = locale.split('_', 1) + return '%s-%s' % (lang.lower(), country.lower()) + else: + return locale.lower() + + +def get_locale_from_request(request): + """ + Figure out what target language is most appropriate based on the + request + """ + request_form = request.GET or request.POST + + if request_form.has_key('lang'): + return locale_to_lower_upper(request_form['lang']) + + accept_lang_matches = request.accept_language.best_matches() + + # Your routing can explicitly specify a target language + if request.matchdict.has_key('target_lang'): + target_lang = request.matchdict['target_lang'] + elif request.session.has_key('target_lang'): + target_lang = request.session['target_lang'] + # Pull the first acceptable language + elif accept_lang_matches: + target_lang = accept_lang_matches[0] + # Fall back to English + else: + target_lang = 'en' + + return make_locale_lower_upper_style(target_lang) -- cgit v1.2.3 From 0e0e3d9aadd481353c9a4a44b37dcb68c1efbaab Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 15:17:07 -0500 Subject: Separation between setting up the template env and the template loader for a glorious future where we have gettext in template context --- mediagoblin/app.py | 7 +++++-- mediagoblin/util.py | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 2a2f21cc..d124558d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -40,7 +40,7 @@ class MediaGoblinApp(object): email_sender_address, email_debug_mode, user_template_path=None): # Get the template environment - self.template_env = util.get_jinja_env(user_template_path) + self.template_loader = util.get_jinja_loader(user_template_path) # Set up storage systems self.public_store = public_store @@ -103,7 +103,10 @@ class MediaGoblinApp(object): # Attach self as request.app # Also attach a few utilities from request.app for convenience? request.app = self - request.template_env = self.template_env + request.locale = util.get_locale_from_request(request) + + request.template_env = util.get_jinja_env( + self.template_loader, request.locale) request.db = self.db request.staticdirect = self.staticdirector diff --git a/mediagoblin/util.py b/mediagoblin/util.py index f02b5f51..ac977bdb 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -33,23 +33,31 @@ def _activate_testing(): TESTS_ENABLED = True -def get_jinja_env(user_template_path=None): +def get_jinja_loader(user_template_path=None): """ - Set up the Jinja environment, possibly allowing for user + Set up the Jinja template loaders, possibly allowing for user overridden templates. (In the future we may have another system for providing theming; for now this is good enough.) """ if user_template_path: - loader = jinja2.ChoiceLoader( + return jinja2.ChoiceLoader( [jinja2.FileSystemLoader(user_template_path), jinja2.PackageLoader('mediagoblin', 'templates')]) else: - loader = jinja2.PackageLoader('mediagoblin', 'templates') + return jinja2.PackageLoader('mediagoblin', 'templates') + +def get_jinja_env(template_loader, locale): + """ + Set up the Jinja environment, + + (In the future we may have another system for providing theming; + for now this is good enough.) + """ return jinja2.Environment( - loader=loader, autoescape=True, + loader=template_loader, autoescape=True, extensions=['jinja2.ext.i18n']) @@ -237,4 +245,4 @@ def get_locale_from_request(request): else: target_lang = 'en' - return make_locale_lower_upper_style(target_lang) + return locale_to_lower_upper(target_lang) -- cgit v1.2.3 From e461b7771300ab75777b01f4732fdcbc358064f7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 15:26:15 -0500 Subject: moving mediagoblin.po to a filename that makes sense --- .../translations/en/LC_MESSAGES/mediagoblin.po | 23 ++++++++++++++++++++++ mediagoblin/translations/master.po | 23 ---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po delete mode 100644 mediagoblin/translations/master.po diff --git a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..0e242fee --- /dev/null +++ b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,23 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-05-12 10:17-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + diff --git a/mediagoblin/translations/master.po b/mediagoblin/translations/master.po deleted file mode 100644 index 0e242fee..00000000 --- a/mediagoblin/translations/master.po +++ /dev/null @@ -1,23 +0,0 @@ -# Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2011. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-05-12 10:17-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" - -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "" - -- cgit v1.2.3 From b77eec653df14059296fc3185ff9817edfa0825b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 22:33:30 -0500 Subject: Load gettext, and load it into the template environment --- mediagoblin/globals.py | 9 ++++++ mediagoblin/templates/mediagoblin/root.html | 4 +-- .../translations/en/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 502 bytes .../translations/en/LC_MESSAGES/mediagoblin.po | 4 +-- mediagoblin/util.py | 33 ++++++++++++++++++++- 5 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/globals.py b/mediagoblin/globals.py index 59a94558..80d1f01d 100644 --- a/mediagoblin/globals.py +++ b/mediagoblin/globals.py @@ -2,6 +2,9 @@ In some places, we need to access the database, public_store, queue_store """ +import gettext +import pkg_resources + ############################# # General mediagoblin globals ############################# @@ -16,6 +19,12 @@ database = None public_store = None queue_store = None +# gettext +translations = gettext.find( + 'mediagoblin', + pkg_resources.resource_filename( + 'mediagoblin', 'translations'), ['en']) + def setup_globals(**kwargs): from mediagoblin import globals as mg_globals diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 44d26a65..fa78bda2 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -19,9 +19,7 @@ {% block mediagoblin_content %} -

Welcome to GNU MediaGoblin!

- {# -

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

#} +

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

{% if request.user %}

diff --git a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..fb7046cd Binary files /dev/null and b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po index 0e242fee..3bec204e 100644 --- a/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/translations/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-05-12 10:17-0500\n" +"POT-Creation-Date: 2011-05-12 22:28-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: mediagoblin/templates/mediagoblin/root.html:21 +#: mediagoblin/templates/mediagoblin/root.html:22 msgid "Welcome to GNU MediaGoblin!" msgstr "" diff --git a/mediagoblin/util.py b/mediagoblin/util.py index ac977bdb..8c6ec6cc 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -15,6 +15,8 @@ # along with this program. If not, see . from email.MIMEText import MIMEText +import gettext +import pkg_resources import smtplib import sys @@ -56,10 +58,18 @@ def get_jinja_env(template_loader, locale): (In the future we may have another system for providing theming; for now this is good enough.) """ - return jinja2.Environment( + setup_gettext(locale) + + template_env = jinja2.Environment( loader=template_loader, autoescape=True, extensions=['jinja2.ext.i18n']) + template_env.install_gettext_callables( + mgoblin_globals.translations.gettext, + mgoblin_globals.translations.ngettext) + + return template_env + def setup_user_in_request(request): """ @@ -196,6 +206,10 @@ def send_email(from_addr, to_addrs, subject, message_body): ################### +TRANSLATIONS_PATH = pkg_resources.resource_filename( + 'mediagoblin', 'translations') + + def locale_to_lower_upper(locale): """ Take a locale, regardless of style, and format it like "en-us" @@ -246,3 +260,20 @@ def get_locale_from_request(request): target_lang = 'en' return locale_to_lower_upper(target_lang) + + +def setup_gettext(locale): + """ + Setup the gettext instance based on this locale + """ + # Later on when we have plugins we may want to enable the + # multi-translations system they have so we can handle plugin + # translations too + + # TODO: fallback nicely on translations from pt_PT to pt if not + # available, etc. + this_gettext = gettext.translation( + 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) + + mgoblin_globals.setup_globals( + translations=this_gettext) -- cgit v1.2.3 From 7acdbfd36457720789c183260424e0f78139211a Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Wed, 11 May 2011 08:39:57 +0200 Subject: Improve user homepage 1) Only consider user's with 'status': 'active'. We don't want to display unconfirmed/blocked users, right? 2) Actually query user's media in the view and display on their home page. 3) Throw an error 404 if we don't find a valid user, rather than saying, "User not found" (from within the template). 4) Pass in medias as media_entries to remain compatible with the 'root' page. Signed-off-by: Sebastian Spaeth --- .../templates/mediagoblin/user_pages/user.html | 15 ++++++++++++- mediagoblin/user_pages/views.py | 25 ++++++++++++++-------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 4fa84430..85f05e08 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -19,8 +19,21 @@ {% block mediagoblin_content -%} {% if user %}

User page for '{{ user.username }}'

- {{ user }} + + {#- Should we outsource such a media 'gallery' view to it's own file? + It could be useful for the home page and other views too -#} +
    + {%- for entry in media_entries %} +
  • + + +
  • + {%- endfor %} +
{% else %} + {# This *should* not occur as the view makes sure we pass in a user. #}

Sorry, no such user found.

{% endif %} {% endblock %} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index cc613c40..2c9792fa 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -14,17 +14,22 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from webob import Response +from webob import Response, exc from mongokit import ObjectId import wtforms def user_home(request): """'Homepage' of a User()""" - user = request.db.User.find_one( - {'username': request.matchdict['user']}) + user = request.db.User.find_one({ + 'username': request.matchdict['user'], + 'status': 'active'}) + if not user: + return exc.HTTPNotFound() - medias = request.db.MediaEntry.find() + medias = request.db.MediaEntry.find({ + 'uploader': user, + 'state': 'processed'}) template = request.template_env.get_template( 'mediagoblin/user_pages/user.html') @@ -32,16 +37,18 @@ def user_home(request): template.render( {'request': request, 'user': user, - 'medias': medias})) + 'media_entries': medias})) def media_home(request): """'Homepage' of a MediaEntry()""" - media = request.db.MediaEntry.find_one( - ObjectId(request.matchdict['m_id'])) + media = request.db.MediaEntry.find_one({ + '_id': ObjectId(request.matchdict['m_id']), + 'state': 'processed'}) - #check that media uploader and user correspond - if media['uploader'].get('username') != request.matchdict['user']: + # Check that media uploader and user correspond. + if not media or \ + media['uploader'].get('username') != request.matchdict['user']: return exc.HTTPNotFound() template = request.template_env.get_template( -- cgit v1.2.3 From 376e6ef296299570ed3e09fca50536bbbf48328a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 23:17:53 -0500 Subject: locale rather than target_lang in the get parameters --- mediagoblin/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 8c6ec6cc..1f568ed3 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -248,8 +248,8 @@ def get_locale_from_request(request): accept_lang_matches = request.accept_language.best_matches() # Your routing can explicitly specify a target language - if request.matchdict.has_key('target_lang'): - target_lang = request.matchdict['target_lang'] + if request.matchdict.has_key('locale'): + target_lang = request.matchdict['locale'] elif request.session.has_key('target_lang'): target_lang = request.session['target_lang'] # Pull the first acceptable language -- cgit v1.2.3 From bb49e56f8c855ea567d61ad63f93610b31d4eb27 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Mon, 9 May 2011 00:06:38 -0400 Subject: On image submission, do not require title. If none entered, default to filename. --- mediagoblin/models.py | 2 +- mediagoblin/submit/forms.py | 2 +- mediagoblin/submit/views.py | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 69b1f4f0..5b286038 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -89,7 +89,7 @@ class MediaEntry(Document): 'thumbnail_file': [unicode]} required_fields = [ - 'uploader', 'title', 'created', 'media_type'] + 'uploader', 'created', 'media_type'] default_values = { 'created': datetime.datetime.utcnow, diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index fe51e7fd..51ca349d 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -21,6 +21,6 @@ import wtforms class SubmitStartForm(wtforms.Form): title = wtforms.TextField( 'Title', - [wtforms.validators.Length(min=1, max=500)]) + [wtforms.validators.Length(min=-1, max=500)]) description = wtforms.TextAreaField('Description of this work') file = wtforms.FileField('File') diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 5e262f12..1b28e339 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - +from os.path import splitext from cgi import FieldStorage from webob import Response, exc @@ -39,9 +39,11 @@ def submit_start(request): submit_form.file.errors.append( u'You must provide a file.') else: + filename = request.POST['file'].filename + # create entry and save in database entry = request.db.MediaEntry() - entry['title'] = request.POST['title'] + entry['title'] = request.POST['title'] or unicode(splitext(filename)[0]) entry['description'] = request.POST.get('description') entry['media_type'] = u'image' # heh entry['uploader'] = request.user @@ -54,7 +56,7 @@ def submit_start(request): queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', unicode(entry['_id']), - secure_filename(request.POST['file'].filename)]) + secure_filename(filename)]) # queue appropriately queue_file = request.app.queue_store.get_file( -- cgit v1.2.3 From a8e2812b054f49e4085bf6b8c0b9e0c5f1b8d312 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 12 May 2011 23:40:47 -0500 Subject: min=0 makes more sense than min=-1 --- mediagoblin/submit/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 51ca349d..3fd9ea49 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -21,6 +21,6 @@ import wtforms class SubmitStartForm(wtforms.Form): title = wtforms.TextField( 'Title', - [wtforms.validators.Length(min=-1, max=500)]) + [wtforms.validators.Length(min=0, max=500)]) description = wtforms.TextAreaField('Description of this work') file = wtforms.FileField('File') -- cgit v1.2.3 From 0546833c6ea4dcaaa82861819916760dd62d8fa7 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Fri, 13 May 2011 12:18:52 -0400 Subject: Generate unique slugs for newly submitted images. --- mediagoblin/models.py | 11 ++++++++++- mediagoblin/submit/views.py | 3 +++ mediagoblin/tests/test_util.py | 8 ++++++++ mediagoblin/util.py | 15 ++++++++++++++- mediagoblin/views.py | 1 + setup.py | 1 + 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 5b286038..1ecabe3e 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -18,8 +18,9 @@ import datetime, uuid from mongokit import Document, Set +from mediagoblin import util from mediagoblin.auth import lib as auth_lib - +from mediagoblin import globals as mediagoblin_globals ################### # Custom validators @@ -66,6 +67,7 @@ class MediaEntry(Document): structure = { 'uploader': User, 'title': unicode, + 'slug':unicode, 'created': datetime.datetime, 'description': unicode, 'media_type': unicode, @@ -98,6 +100,13 @@ class MediaEntry(Document): def main_mediafile(self): pass + def generate_slug(self): + self['slug'] = util.slugify(self['title']) + + duplicate = mediagoblin_globals.database.media_entries.find_one({'slug': self['slug']}) + + if duplicate: + self['slug'] = "%s-%s" % (self['_id'], self['slug']) REGISTER_MODELS = [MediaEntry, User] diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1b28e339..95a416e2 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -52,6 +52,9 @@ def submit_start(request): # it to generate the file path entry.save(validate=False) + # Generate a slug from the title + entry.generate_slug() + # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index ff40a677..7b00a074 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -70,6 +70,14 @@ I hope you like unit tests JUST AS MUCH AS I DO!""" I hope you like unit tests JUST AS MUCH AS I DO!""" +def test_slugify(): + assert util.slugify('a walk in the park') == 'a-walk-in-the-park' + assert util.slugify('A Walk in the Park') == 'a-walk-in-the-park' + assert util.slugify('a walk in the park') == 'a-walk-in-the-park' + assert util.slugify('a walk in-the-park') == 'a-walk-in-the-park' + assert util.slugify('a w@lk in the park?') == 'a-w-lk-in-the-park' + assert util.slugify(u'a walk in the par\u0107') == 'a-walk-in-the-parc' + assert util.slugify(u'\u00E0\u0042\u00E7\u010F\u00EB\u0066') == 'abcdef' def test_locale_to_lower_upper(): """ diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 1f568ed3..a66e2ba5 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -19,9 +19,10 @@ import gettext import pkg_resources import smtplib import sys - +import re import jinja2 import mongokit +import translitcodec from mediagoblin import globals as mgoblin_globals @@ -107,6 +108,18 @@ def import_component(import_string): func = getattr(module, func_name) return func +_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') + +def slugify(text, delim=u'-'): + """ + Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ + """ + result = [] + for word in _punct_re.split(text.lower()): + word = word.encode('translit/long') + if word: + result.append(word) + return unicode(delim.join(result)) ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### Special email test stuff begins HERE diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 95d0be7a..7f925bb7 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -20,6 +20,7 @@ from webob import Response, exc import wtforms from mongokit import ObjectId from mediagoblin import models +import gettext def root_view(request): media_entries = request.db.MediaEntry.find( diff --git a/setup.py b/setup.py index 7d38e526..08887dee 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ setup( 'sphinx', 'PIL', 'Babel', + 'translitcodec', ], test_suite='nose.collector', -- cgit v1.2.3 From 1013bdaff2f3ab4bb67667b57470d23cf392a3df Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Fri, 13 May 2011 14:16:35 -0400 Subject: Minor fomatting fix. --- mediagoblin/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 1ecabe3e..4a867323 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -67,7 +67,7 @@ class MediaEntry(Document): structure = { 'uploader': User, 'title': unicode, - 'slug':unicode, + 'slug': unicode, 'created': datetime.datetime, 'description': unicode, 'media_type': unicode, -- cgit v1.2.3 From 881b6e2c32d8013d6ffaa151fd1b7d78041fed60 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:33:19 -0500 Subject: Fixing changes --- mediagoblin/static/css/base.css | 71 +++++++++++++++++++- mediagoblin/static/css/base.css~ | 70 ++++++++++++++++++++ mediagoblin/static/images/back.png | Bin 0 -> 26165 bytes mediagoblin/static/images/button_green.png | Bin 0 -> 2054 bytes mediagoblin/static/images/button_red.png | Bin 0 -> 1737 bytes mediagoblin/static/images/header_back.png | Bin 0 -> 26226 bytes mediagoblin/static/images/logo.png | Bin 0 -> 58408 bytes mediagoblin/templates/mediagoblin/base.html | 5 +- mediagoblin/templates/mediagoblin/base.html~ | 72 +++++++++++++++++++++ .../templates/mediagoblin/media_details.html | 2 +- .../templates/mediagoblin/media_details.html~ | 34 ++++++++++ mediagoblin/templates/mediagoblin/root.html | 2 +- mediagoblin/templates/mediagoblin/root.html~ | 56 ++++++++++++++++ 13 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 mediagoblin/static/css/base.css~ create mode 100644 mediagoblin/static/images/back.png create mode 100644 mediagoblin/static/images/button_green.png create mode 100644 mediagoblin/static/images/button_red.png create mode 100644 mediagoblin/static/images/header_back.png create mode 100644 mediagoblin/static/images/logo.png create mode 100644 mediagoblin/templates/mediagoblin/base.html~ create mode 100644 mediagoblin/templates/mediagoblin/media_details.html~ create mode 100644 mediagoblin/templates/mediagoblin/root.html~ diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 93b0b1a2..17f9e012 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1 +1,70 @@ -/* stuff goes here :) */ \ No newline at end of file +body { + background-color: #272727; + background-image: url('back.png'); + color: #f7f7f7; + font-family: sans; + padding:none; + margin:0px; +} + +h1 { + font-family: 'Carter One', arial, serif; + margin-bottom: 20px; + margin-top:50px; +} + +.dottedLine { + width:100%; + height:0px; + border-bottom: dotted 1px #5f5f5f; + position:absolute; + left:0px; + margin-top:-20px; +} + +a { + color: #d12929; + border-bottom: 1px dotted; + text-decoration: none; +} + +.header { + width:100%; + height:60px; + background-image:url('header_back.png'); + padding-top:40px; + margin-bottom:80px; +} + +.container { + width: 800px; + margin-left: auto; + margin-right: auto; +} + +.button { + font-family: 'Carter One', arial, serif; + height: 28px; + min-width: 99px; + box-shadow: 0px 0px 5px #000; + border-radius: 5px; + border: none; + color: #272727; + margin: 10px; + font-size: 1em; + float: left; + display: block; + text-align: center; + padding-top: 4px; + padding-left:11px; + padding-right:11px; +} + +.buttonRed { + background-image: url('button_red.png'); +} + +.buttonGreen { + background-image: url('button_green.png'); +} + diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ new file mode 100644 index 00000000..17f9e012 --- /dev/null +++ b/mediagoblin/static/css/base.css~ @@ -0,0 +1,70 @@ +body { + background-color: #272727; + background-image: url('back.png'); + color: #f7f7f7; + font-family: sans; + padding:none; + margin:0px; +} + +h1 { + font-family: 'Carter One', arial, serif; + margin-bottom: 20px; + margin-top:50px; +} + +.dottedLine { + width:100%; + height:0px; + border-bottom: dotted 1px #5f5f5f; + position:absolute; + left:0px; + margin-top:-20px; +} + +a { + color: #d12929; + border-bottom: 1px dotted; + text-decoration: none; +} + +.header { + width:100%; + height:60px; + background-image:url('header_back.png'); + padding-top:40px; + margin-bottom:80px; +} + +.container { + width: 800px; + margin-left: auto; + margin-right: auto; +} + +.button { + font-family: 'Carter One', arial, serif; + height: 28px; + min-width: 99px; + box-shadow: 0px 0px 5px #000; + border-radius: 5px; + border: none; + color: #272727; + margin: 10px; + font-size: 1em; + float: left; + display: block; + text-align: center; + padding-top: 4px; + padding-left:11px; + padding-right:11px; +} + +.buttonRed { + background-image: url('button_red.png'); +} + +.buttonGreen { + background-image: url('button_green.png'); +} + diff --git a/mediagoblin/static/images/back.png b/mediagoblin/static/images/back.png new file mode 100644 index 00000000..3d7fe844 Binary files /dev/null and b/mediagoblin/static/images/back.png differ diff --git a/mediagoblin/static/images/button_green.png b/mediagoblin/static/images/button_green.png new file mode 100644 index 00000000..0fc234d4 Binary files /dev/null and b/mediagoblin/static/images/button_green.png differ diff --git a/mediagoblin/static/images/button_red.png b/mediagoblin/static/images/button_red.png new file mode 100644 index 00000000..b0f7dcad Binary files /dev/null and b/mediagoblin/static/images/button_red.png differ diff --git a/mediagoblin/static/images/header_back.png b/mediagoblin/static/images/header_back.png new file mode 100644 index 00000000..3647b99d Binary files /dev/null and b/mediagoblin/static/images/header_back.png differ diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png new file mode 100644 index 00000000..8d2f6272 Binary files /dev/null and b/mediagoblin/static/images/logo.png differ diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 71c2e550..07be3c47 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -23,7 +23,8 @@ - +

GNU MediaGoblin at your duty!

+ diff --git a/mediagoblin/templates/mediagoblin/base.html~ b/mediagoblin/templates/mediagoblin/base.html~ new file mode 100644 index 00000000..07be3c47 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/base.html~ @@ -0,0 +1,72 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + + + {% block title %}MediaGoblin{% endblock title %} + + + + +

GNU MediaGoblin at your duty!

+ + + diff --git a/mediagoblin/templates/mediagoblin/media_details.html b/mediagoblin/templates/mediagoblin/media_details.html index 1b02c809..bd63a289 100644 --- a/mediagoblin/templates/mediagoblin/media_details.html +++ b/mediagoblin/templates/mediagoblin/media_details.html @@ -20,7 +20,7 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

Media details for {{media.title}}

+

Media details for {{media.title}}

diff --git a/mediagoblin/templates/mediagoblin/media_details.html~ b/mediagoblin/templates/mediagoblin/media_details.html~ new file mode 100644 index 00000000..1b02c809 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_details.html~ @@ -0,0 +1,34 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + {% if media %} +

Media details for {{media.title}}

+
+ + +
Uploaded: {{ media.created}} +
Description: {{media.description}} +
+ {% else %} +

Sorry, no such media found.

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index fa78bda2..e2b2730a 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -19,7 +19,7 @@ {% block mediagoblin_content %} -

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

+

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

{% if request.user %}

diff --git a/mediagoblin/templates/mediagoblin/root.html~ b/mediagoblin/templates/mediagoblin/root.html~ new file mode 100644 index 00000000..fa78bda2 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/root.html~ @@ -0,0 +1,56 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} + +

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

+ + {% if request.user %} +

+ Submit an item. +

+ + {% else %} +

+ If you have an account, you can + Login. +

+

+ If you don't have an account, please + Register. +

+ + {% endif %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + +
+
    + {% for entry in media_entries %} +
  • + + +
  • + {% endfor %} +
+
+ +{% endblock %} -- cgit v1.2.3 From 20aaec5f683ba23b0b4b18123367c2f93f2dd73d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:33:27 -0500 Subject: Changed base.html back to old version --- mediagoblin/templates/mediagoblin/base.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 07be3c47..d73d8c20 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -23,8 +23,6 @@ -

GNU MediaGoblin at your duty!

- + {% endblock mediagoblin_body %} -- cgit v1.2.3 From 8c01ae42e9ed502c0a37bed2f449076aa183ec83 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:33:46 -0500 Subject: Styled input buttons --- mediagoblin/templates/mediagoblin/auth/login.html | 2 +- mediagoblin/templates/mediagoblin/auth/login.html~ | 44 ++++++++++++++++++++++ .../templates/mediagoblin/auth/register.html | 2 +- .../templates/mediagoblin/auth/register.html~ | 33 ++++++++++++++++ mediagoblin/templates/mediagoblin/test_submit.html | 2 +- .../templates/mediagoblin/test_submit.html~ | 33 ++++++++++++++++ 6 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/auth/login.html~ create mode 100644 mediagoblin/templates/mediagoblin/auth/register.html~ create mode 100644 mediagoblin/templates/mediagoblin/test_submit.html~ diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index f2e7b664..46552a39 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -38,7 +38,7 @@ {% if next %} - + {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/login.html~ b/mediagoblin/templates/mediagoblin/auth/login.html~ new file mode 100644 index 00000000..f2e7b664 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/login.html~ @@ -0,0 +1,44 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +

Login:

+ +
+ + {% if login_failed %} +

Login failed!

+ {% endif %} + + + {{ wtforms_util.render_table(login_form) }} + + + + +
+ + {% if next %} + + {% endif %} +
+{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index f3489397..de3ec71d 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -26,7 +26,7 @@ {{ wtforms_util.render_table(register_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/auth/register.html~ b/mediagoblin/templates/mediagoblin/auth/register.html~ new file mode 100644 index 00000000..f3489397 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/register.html~ @@ -0,0 +1,33 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +
+ + {{ wtforms_util.render_table(register_form) }} + + + + +
+
+{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index b02f4e40..ebf93b59 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -25,7 +25,7 @@ {{ wtforms_util.render_table(image_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/test_submit.html~ b/mediagoblin/templates/mediagoblin/test_submit.html~ new file mode 100644 index 00000000..ebf93b59 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/test_submit.html~ @@ -0,0 +1,33 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + + + +
+ + {{ wtforms_util.render_table(image_form) }} + + + + +
+
+ + -- cgit v1.2.3 From 223b410dce65e0ac940c0abfa29339de826d3c39 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:33:58 -0500 Subject: Styled buttons for real this time --- mediagoblin/static/css/base.css | 12 ++++---- mediagoblin/static/css/base.css~ | 8 ++--- mediagoblin/templates/mediagoblin/auth/login.html | 4 +-- mediagoblin/templates/mediagoblin/auth/login.html~ | 2 +- .../templates/mediagoblin/auth/register.html | 2 +- .../templates/mediagoblin/auth/register.html~ | 2 +- .../templates/mediagoblin/submit/start.html | 2 +- .../templates/mediagoblin/submit/start.html~ | 35 ++++++++++++++++++++++ mediagoblin/templates/mediagoblin/test_submit.html | 2 +- 9 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/submit/start.html~ diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 17f9e012..3576fd1f 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -13,7 +13,7 @@ h1 { margin-top:50px; } -.dottedLine { +.dotted_line { width:100%; height:0px; border-bottom: dotted 1px #5f5f5f; @@ -42,7 +42,7 @@ a { margin-right: auto; } -.button { +.button_red, .button_green { font-family: 'Carter One', arial, serif; height: 28px; min-width: 99px; @@ -60,11 +60,11 @@ a { padding-right:11px; } -.buttonRed { - background-image: url('button_red.png'); +.button_red { + background-image: url('../images/button_red.png'); } -.buttonGreen { - background-image: url('button_green.png'); +.button_green { + background-image: url('../images/button_green.png'); } diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ index 17f9e012..e69a87e7 100644 --- a/mediagoblin/static/css/base.css~ +++ b/mediagoblin/static/css/base.css~ @@ -13,7 +13,7 @@ h1 { margin-top:50px; } -.dottedLine { +.dotted_line { width:100%; height:0px; border-bottom: dotted 1px #5f5f5f; @@ -42,7 +42,7 @@ a { margin-right: auto; } -.button { +.button_red, .button_green { font-family: 'Carter One', arial, serif; height: 28px; min-width: 99px; @@ -60,11 +60,11 @@ a { padding-right:11px; } -.buttonRed { +.button_red { background-image: url('button_red.png'); } -.buttonGreen { +.button_green { background-image: url('button_green.png'); } diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 46552a39..d5a5ddef 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -33,12 +33,12 @@ {{ wtforms_util.render_table(login_form) }} - + {% if next %} - + {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/login.html~ b/mediagoblin/templates/mediagoblin/auth/login.html~ index f2e7b664..19d90907 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html~ +++ b/mediagoblin/templates/mediagoblin/auth/login.html~ @@ -38,7 +38,7 @@ {% if next %} - + {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index de3ec71d..ee2f425b 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -26,7 +26,7 @@ {{ wtforms_util.render_table(register_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/auth/register.html~ b/mediagoblin/templates/mediagoblin/auth/register.html~ index f3489397..de3ec71d 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html~ +++ b/mediagoblin/templates/mediagoblin/auth/register.html~ @@ -26,7 +26,7 @@ {{ wtforms_util.render_table(register_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 562d9050..21a7ed4e 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -28,7 +28,7 @@ {{ wtforms_util.render_table(submit_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/submit/start.html~ b/mediagoblin/templates/mediagoblin/submit/start.html~ new file mode 100644 index 00000000..562d9050 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/submit/start.html~ @@ -0,0 +1,35 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +

Submit yer media

+ +
+ + {{ wtforms_util.render_table(submit_form) }} + + + + +
+
+{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index ebf93b59..86cf4655 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -25,7 +25,7 @@ {{ wtforms_util.render_table(image_form) }} - + -- cgit v1.2.3 From 8d2a42d43561456782d103f4ef40703d7b2bde28 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:34:10 -0500 Subject: Changed all headers to

--- mediagoblin/templates/mediagoblin/auth/login.html | 2 +- mediagoblin/templates/mediagoblin/auth/login.html~ | 2 +- mediagoblin/templates/mediagoblin/base.html~ | 4 +-- .../templates/mediagoblin/media_details.html~ | 2 +- mediagoblin/templates/mediagoblin/root.html~ | 2 +- .../templates/mediagoblin/submit/start.html | 2 +- .../templates/mediagoblin/submit/start.html~ | 2 +- .../templates/mediagoblin/user_pages/media.html | 4 +-- .../templates/mediagoblin/user_pages/media.html~ | 41 ++++++++++++++++++++++ .../templates/mediagoblin/user_pages/user.html | 2 +- .../templates/mediagoblin/user_pages/user.html~ | 39 ++++++++++++++++++++ 11 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/user_pages/media.html~ create mode 100644 mediagoblin/templates/mediagoblin/user_pages/user.html~ diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index d5a5ddef..47b8393d 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -20,7 +20,7 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

Login:

+

Login:

diff --git a/mediagoblin/templates/mediagoblin/auth/login.html~ b/mediagoblin/templates/mediagoblin/auth/login.html~ index 19d90907..d5a5ddef 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html~ +++ b/mediagoblin/templates/mediagoblin/auth/login.html~ @@ -33,7 +33,7 @@ {{ wtforms_util.render_table(login_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/base.html~ b/mediagoblin/templates/mediagoblin/base.html~ index 07be3c47..d73d8c20 100644 --- a/mediagoblin/templates/mediagoblin/base.html~ +++ b/mediagoblin/templates/mediagoblin/base.html~ @@ -23,8 +23,6 @@ -

GNU MediaGoblin at your duty!

- + {% endblock mediagoblin_body %} diff --git a/mediagoblin/templates/mediagoblin/media_details.html~ b/mediagoblin/templates/mediagoblin/media_details.html~ index 1b02c809..bd63a289 100644 --- a/mediagoblin/templates/mediagoblin/media_details.html~ +++ b/mediagoblin/templates/mediagoblin/media_details.html~ @@ -20,7 +20,7 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

Media details for {{media.title}}

+

Media details for {{media.title}}

diff --git a/mediagoblin/templates/mediagoblin/root.html~ b/mediagoblin/templates/mediagoblin/root.html~ index fa78bda2..e2b2730a 100644 --- a/mediagoblin/templates/mediagoblin/root.html~ +++ b/mediagoblin/templates/mediagoblin/root.html~ @@ -19,7 +19,7 @@ {% block mediagoblin_content %} -

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

+

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

{% if request.user %}

diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 21a7ed4e..8b446417 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -20,7 +20,7 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

Submit yer media

+

Submit yer media

diff --git a/mediagoblin/templates/mediagoblin/submit/start.html~ b/mediagoblin/templates/mediagoblin/submit/start.html~ index 562d9050..21a7ed4e 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html~ +++ b/mediagoblin/templates/mediagoblin/submit/start.html~ @@ -28,7 +28,7 @@ {{ wtforms_util.render_table(submit_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 08cc9251..e07cee44 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -20,11 +20,11 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

Media details for Media details for {{media.uploader.username}} / {{media.title}} -

+
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html~ b/mediagoblin/templates/mediagoblin/user_pages/media.html~ new file mode 100644 index 00000000..08cc9251 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html~ @@ -0,0 +1,41 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content %} + + {# temporarily, an "image gallery" that isn't one really ;) #} + {% if media %} +

Media details for {{media.uploader.username}} + / {{media.title}} +

+
+ + +
Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, + media.created.month,media.created.day)}} by {{media.uploader.username}} +
Description: {{media.description}} +
+ {% else %} +

Sorry, no such media found.

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 85f05e08..5c8692fc 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -18,7 +18,7 @@ {% extends "mediagoblin/base.html" %} {% block mediagoblin_content -%} {% if user %} -

User page for '{{ user.username }}'

+

User page for '{{ user.username }}'

{#- Should we outsource such a media 'gallery' view to it's own file? It could be useful for the home page and other views too -#} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html~ b/mediagoblin/templates/mediagoblin/user_pages/user.html~ new file mode 100644 index 00000000..4ae7986e --- /dev/null +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html~ @@ -0,0 +1,39 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} +{% block mediagoblin_content -%} + {% if user %} +

User page for '{{ user.username }}' + + {#- Should we outsource such a media 'gallery' view to it's own file? + It could be useful for the home page and other views too -#} +
    + {%- for entry in media_entries %} +
  • + + +
  • + {%- endfor %} +
+ {% else %} + {# This *should* not occur as the view makes sure we pass in a user. #} +

Sorry, no such user found.

+ {% endif %} +{% endblock %} -- cgit v1.2.3 From 4a0f823e51c575e10430be1a2f3c439eef23d06b Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:34:26 -0500 Subject: Added header to base.html --- mediagoblin/static/css/base.css | 6 +++--- mediagoblin/static/css/base.css~ | 10 ++++----- mediagoblin/templates/mediagoblin/base.html | 31 +++++++--------------------- mediagoblin/templates/mediagoblin/base.html~ | 31 +++++++--------------------- 4 files changed, 22 insertions(+), 56 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 3576fd1f..3b6abd3e 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -28,15 +28,15 @@ a { text-decoration: none; } -.header { +.mediagoblin_header { width:100%; height:60px; - background-image:url('header_back.png'); + background-image:url('../images/header_back.png'); padding-top:40px; margin-bottom:80px; } -.container { +.mediagoblin_content { width: 800px; margin-left: auto; margin-right: auto; diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ index e69a87e7..3b6abd3e 100644 --- a/mediagoblin/static/css/base.css~ +++ b/mediagoblin/static/css/base.css~ @@ -28,15 +28,15 @@ a { text-decoration: none; } -.header { +.mediagoblin_header { width:100%; height:60px; - background-image:url('header_back.png'); + background-image:url('../images/header_back.png'); padding-top:40px; margin-bottom:80px; } -.container { +.mediagoblin_content { width: 800px; margin-left: auto; margin-right: auto; @@ -61,10 +61,10 @@ a { } .button_red { - background-image: url('button_red.png'); + background-image: url('../images/button_red.png'); } .button_green { - background-image: url('button_green.png'); + background-image: url('../images/button_green.png'); } diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index d73d8c20..4b634cf1 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -25,43 +25,26 @@ {% block mediagoblin_body %} {% block mediagoblin_header %} - - - - - - - - - + {% endblock %} {% if request.user %} - - - - {% else %} - - - - {% endif %} -
{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %}
+ {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} {% block mediagoblin_header_subtitle %} Clever subtitle here! - {% endblock %}
Welcome {{ request.user['username'] }}! -- Logout -
Login -
+

+
{% endblock %} -
+
{% block mediagoblin_content %} {% endblock mediagoblin_content %}
diff --git a/mediagoblin/templates/mediagoblin/base.html~ b/mediagoblin/templates/mediagoblin/base.html~ index d73d8c20..4b634cf1 100644 --- a/mediagoblin/templates/mediagoblin/base.html~ +++ b/mediagoblin/templates/mediagoblin/base.html~ @@ -25,43 +25,26 @@ {% block mediagoblin_body %} {% block mediagoblin_header %} - - - - - - - - - + {% endblock %} {% if request.user %} - - - - {% else %} - - - - {% endif %} -
{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %}
+ {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} {% block mediagoblin_header_subtitle %} Clever subtitle here! - {% endblock %}
Welcome {{ request.user['username'] }}! -- Logout -
Login -
+
+
{% endblock %} -
+
{% block mediagoblin_content %} {% endblock mediagoblin_content %}
-- cgit v1.2.3 From cb1e4a3d1f04ef9e7df47ec9ee6b075f264f57d6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:34:35 -0500 Subject: Added @font-face to css --- mediagoblin/static/css/base.css | 11 +++++++++++ mediagoblin/static/css/base.css~ | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 3b6abd3e..169394d0 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -7,6 +7,17 @@ body { margin:0px; } +/* Carter One font */ + +@font-face { + font-family: 'Carter One'; + font-style: normal; + font-weight: normal; + src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=VjW2qt1pkqVtO22ObxgEBRsxEYwM7FgeyaSgU71cLG0') format('woff'); +} + +/* text styles */ + h1 { font-family: 'Carter One', arial, serif; margin-bottom: 20px; diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ index 3b6abd3e..169394d0 100644 --- a/mediagoblin/static/css/base.css~ +++ b/mediagoblin/static/css/base.css~ @@ -7,6 +7,17 @@ body { margin:0px; } +/* Carter One font */ + +@font-face { + font-family: 'Carter One'; + font-style: normal; + font-weight: normal; + src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=VjW2qt1pkqVtO22ObxgEBRsxEYwM7FgeyaSgU71cLG0') format('woff'); +} + +/* text styles */ + h1 { font-family: 'Carter One', arial, serif; margin-bottom: 20px; -- cgit v1.2.3 From 983aa712ad6be83267016de7d10a3e9b027cb1b7 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:34:44 -0500 Subject: labels changed to font-weight normal instead of bold, css structure improved --- mediagoblin/static/css/base.css | 26 +++++++++++++++++--------- mediagoblin/static/css/base.css~ | 4 ++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 169394d0..6c50377f 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -24,21 +24,18 @@ h1 { margin-top:50px; } -.dotted_line { - width:100%; - height:0px; - border-bottom: dotted 1px #5f5f5f; - position:absolute; - left:0px; - margin-top:-20px; -} - a { color: #d12929; border-bottom: 1px dotted; text-decoration: none; } +label { + font-weight: normal; +} + +/* website structure */ + .mediagoblin_header { width:100%; height:60px; @@ -71,6 +68,17 @@ a { padding-right:11px; } +/* common website elements */ + +.dotted_line { + width:100%; + height:0px; + border-bottom: dotted 1px #5f5f5f; + position:absolute; + left:0px; + margin-top:-20px; +} + .button_red { background-image: url('../images/button_red.png'); } diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ index 169394d0..4c5ae9ab 100644 --- a/mediagoblin/static/css/base.css~ +++ b/mediagoblin/static/css/base.css~ @@ -39,6 +39,10 @@ a { text-decoration: none; } +label { + font-weight: normal; +} + .mediagoblin_header { width:100%; height:60px; -- cgit v1.2.3 From 9d4b435a728df8ad85cf2384eaf39be183322a03 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 May 2011 15:38:04 -0500 Subject: Removing backup files and preventing them from showing up via .gitignore --- .gitignore | 3 +- mediagoblin/templates/mediagoblin/auth/login.html~ | 44 ----------------- .../templates/mediagoblin/auth/register.html~ | 33 ------------- mediagoblin/templates/mediagoblin/base.html~ | 53 -------------------- .../templates/mediagoblin/media_details.html~ | 34 ------------- mediagoblin/templates/mediagoblin/root.html~ | 56 ---------------------- .../templates/mediagoblin/submit/start.html~ | 35 -------------- .../templates/mediagoblin/test_submit.html~ | 33 ------------- .../templates/mediagoblin/user_pages/media.html~ | 41 ---------------- .../templates/mediagoblin/user_pages/user.html~ | 39 --------------- 10 files changed, 2 insertions(+), 369 deletions(-) delete mode 100644 mediagoblin/templates/mediagoblin/auth/login.html~ delete mode 100644 mediagoblin/templates/mediagoblin/auth/register.html~ delete mode 100644 mediagoblin/templates/mediagoblin/base.html~ delete mode 100644 mediagoblin/templates/mediagoblin/media_details.html~ delete mode 100644 mediagoblin/templates/mediagoblin/root.html~ delete mode 100644 mediagoblin/templates/mediagoblin/submit/start.html~ delete mode 100644 mediagoblin/templates/mediagoblin/test_submit.html~ delete mode 100644 mediagoblin/templates/mediagoblin/user_pages/media.html~ delete mode 100644 mediagoblin/templates/mediagoblin/user_pages/user.html~ diff --git a/.gitignore b/.gitignore index 6f6fc624..9e01560a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ mediagoblin.egg-info *.pyo docs/_build/ user_dev/ -server-log.txt \ No newline at end of file +server-log.txt +*~ \ No newline at end of file diff --git a/mediagoblin/templates/mediagoblin/auth/login.html~ b/mediagoblin/templates/mediagoblin/auth/login.html~ deleted file mode 100644 index d5a5ddef..00000000 --- a/mediagoblin/templates/mediagoblin/auth/login.html~ +++ /dev/null @@ -1,44 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -

Login:

- -
- - {% if login_failed %} -

Login failed!

- {% endif %} - - - {{ wtforms_util.render_table(login_form) }} - - - - -
- - {% if next %} - - {% endif %} -
-{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html~ b/mediagoblin/templates/mediagoblin/auth/register.html~ deleted file mode 100644 index de3ec71d..00000000 --- a/mediagoblin/templates/mediagoblin/auth/register.html~ +++ /dev/null @@ -1,33 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -
- - {{ wtforms_util.render_table(register_form) }} - - - - -
-
-{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/base.html~ b/mediagoblin/templates/mediagoblin/base.html~ deleted file mode 100644 index 4b634cf1..00000000 --- a/mediagoblin/templates/mediagoblin/base.html~ +++ /dev/null @@ -1,53 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} - - - {% block title %}MediaGoblin{% endblock title %} - - - - - {% block mediagoblin_body %} - {% block mediagoblin_header %} -
-
- {% block mediagoblin_logo %} - MediaGoblin - {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} - {% block mediagoblin_header_subtitle %} - Clever subtitle here! - {% endblock %} - {% if request.user %} - Welcome {{ request.user['username'] }}! -- - - Logout - {% else %} - - Login - {% endif %} -
-
- {% endblock %} -
- {% block mediagoblin_content %} - {% endblock mediagoblin_content %} -
- {% endblock mediagoblin_body %} - - diff --git a/mediagoblin/templates/mediagoblin/media_details.html~ b/mediagoblin/templates/mediagoblin/media_details.html~ deleted file mode 100644 index bd63a289..00000000 --- a/mediagoblin/templates/mediagoblin/media_details.html~ +++ /dev/null @@ -1,34 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} -{% block mediagoblin_content %} - - {# temporarily, an "image gallery" that isn't one really ;) #} - {% if media %} -

Media details for {{media.title}}

-
- - -
Uploaded: {{ media.created}} -
Description: {{media.description}} -
- {% else %} -

Sorry, no such media found.

- {% endif %} -{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html~ b/mediagoblin/templates/mediagoblin/root.html~ deleted file mode 100644 index e2b2730a..00000000 --- a/mediagoblin/templates/mediagoblin/root.html~ +++ /dev/null @@ -1,56 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% block mediagoblin_content %} - -

{% trans %}Welcome to GNU MediaGoblin!{% endtrans %}

- - {% if request.user %} -

- Submit an item. -

- - {% else %} -

- If you have an account, you can - Login. -

-

- If you don't have an account, please - Register. -

- - {% endif %} - - {# temporarily, an "image gallery" that isn't one really ;) #} - -
-
    - {% for entry in media_entries %} -
  • - - -
  • - {% endfor %} -
-
- -{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/submit/start.html~ b/mediagoblin/templates/mediagoblin/submit/start.html~ deleted file mode 100644 index 21a7ed4e..00000000 --- a/mediagoblin/templates/mediagoblin/submit/start.html~ +++ /dev/null @@ -1,35 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - -{% block mediagoblin_content %} -

Submit yer media

- -
- - {{ wtforms_util.render_table(submit_form) }} - - - - -
-
-{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/test_submit.html~ b/mediagoblin/templates/mediagoblin/test_submit.html~ deleted file mode 100644 index ebf93b59..00000000 --- a/mediagoblin/templates/mediagoblin/test_submit.html~ +++ /dev/null @@ -1,33 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} - - - -
- - {{ wtforms_util.render_table(image_form) }} - - - - -
-
- - diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html~ b/mediagoblin/templates/mediagoblin/user_pages/media.html~ deleted file mode 100644 index 08cc9251..00000000 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html~ +++ /dev/null @@ -1,41 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} -{% block mediagoblin_content %} - - {# temporarily, an "image gallery" that isn't one really ;) #} - {% if media %} -

Media details for {{media.uploader.username}} - / {{media.title}} -

-
- - -
Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, - media.created.month,media.created.day)}} by {{media.uploader.username}} -
Description: {{media.description}} -
- {% else %} -

Sorry, no such media found.

- {% endif %} -{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html~ b/mediagoblin/templates/mediagoblin/user_pages/user.html~ deleted file mode 100644 index 4ae7986e..00000000 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html~ +++ /dev/null @@ -1,39 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} -{% block mediagoblin_content -%} - {% if user %} -

User page for '{{ user.username }}' - - {#- Should we outsource such a media 'gallery' view to it's own file? - It could be useful for the home page and other views too -#} -
    - {%- for entry in media_entries %} -
  • - - -
  • - {%- endfor %} -
- {% else %} - {# This *should* not occur as the view makes sure we pass in a user. #} -

Sorry, no such user found.

- {% endif %} -{% endblock %} -- cgit v1.2.3 From e2decbcf1e0c9be461a5ee1ac40d3a7fe5492b36 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 13 May 2011 16:07:37 -0500 Subject: Removing the raw string-ness --- mediagoblin/user_pages/routing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index c2dc2fc0..304f805f 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -19,6 +19,6 @@ from routes.route import Route user_routes = [ Route('mediagoblin.user_pages.user_home', "/{user}/", controller="mediagoblin.user_pages.views:user_home"), - Route('mediagoblin.user_pages.media_home', r'/{user}/m/{m_id}/', + Route('mediagoblin.user_pages.media_home', '/{user}/m/{m_id}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), controller="mediagoblin.user_pages.views:media_home")] -- cgit v1.2.3 From 029cad45c6fb61ac96b7601288a76523f98a247e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 May 2011 19:02:11 -0500 Subject: ./bin/gmg shell! Should make a lot of peoples' hacking lives easier I suspect :) --- mediagoblin/gmg_commands/__init__.py | 106 +++++++++++++++++++++++++++++++++++ setup.py | 4 ++ 2 files changed, 110 insertions(+) create mode 100644 mediagoblin/gmg_commands/__init__.py diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py new file mode 100644 index 00000000..04e2ab6c --- /dev/null +++ b/mediagoblin/gmg_commands/__init__.py @@ -0,0 +1,106 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import code +import argparse +import os + +from paste.deploy.loadwsgi import NicerConfigParser + +from mediagoblin.celery_setup import setup_celery_from_config +from mediagoblin import app, util +from mediagoblin import globals as mgoblin_globals + + +SUBCOMMAND_MAP = { + 'shell': { + 'setup': 'mediagoblin.gmg_commands:shell_parser_setup', + 'func': 'mediagoblin.gmg_commands:shell', + 'help': 'Run a shell with some tools pre-setup'}, + } + + +def shell_parser_setup(subparser): + subparser.add_argument( + '-cf', '--conf_file', default='mediagoblin.ini', + help="Config file used to set up environment") + subparser.add_argument( + '-cs', '--app_section', default='app:mediagoblin', + help="Section of the config file where the app config is stored.") + + +SHELL_BANNER = """\ +GNU MediaGoblin shell! +---------------------- +Available vars: + - mgoblin_app: instantiated mediagoblin application + - mgoblin_globals: mediagoblin.globals + - db: database instance +""" + + +def shell(args): + """ + """ + # Duplicated from from_celery.py, remove when we have the generic util + parser = NicerConfigParser(args.conf_file) + parser.read(args.conf_file) + parser._defaults.setdefault( + 'here', os.path.dirname(os.path.abspath(args.conf_file))) + parser._defaults.setdefault( + '__file__', os.path.abspath(args.conf_file)) + + mgoblin_section = dict(parser.items(args.app_section)) + mgoblin_conf = dict( + [(section_name, dict(parser.items(section_name))) + for section_name in parser.sections()]) + + mgoblin_app = app.paste_app_factory( + mgoblin_conf, **mgoblin_section) + + code.interact( + banner=SHELL_BANNER, + local={ + 'mgoblin_app': mgoblin_app, + 'mgoblin_globals': mgoblin_globals, + 'db': mgoblin_globals.database}) + + +def main_cli(): + parser = argparse.ArgumentParser( + description='GNU MediaGoblin utilities.') + + subparsers = parser.add_subparsers(help='sub-command help') + for command_name, command_struct in SUBCOMMAND_MAP.iteritems(): + if command_struct.has_key('help'): + subparser = subparsers.add_parser( + command_name, help=command_struct['help']) + else: + subparser = subparsers.add_parser(command_name) + + setup_func = util.import_component(command_struct['setup']) + exec_func = util.import_component(command_struct['func']) + + setup_func(subparser) + + subparser.set_defaults(func=exec_func) + + args = parser.parse_args() + args.func(args) + + +if __name__ == '__main__': + main_cli() diff --git a/setup.py b/setup.py index 08887dee..752f1b57 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ setup( 'PIL', 'Babel', 'translitcodec', + 'argparse', ], test_suite='nose.collector', @@ -47,6 +48,9 @@ setup( author = 'Christopher Webber', author_email = 'cwebber@gnu.org', entry_points = """\ + [console_scripts] + gmg = mediagoblin.gmg_commands:main_cli + [paste.app_factory] app = mediagoblin.app:paste_app_factory -- cgit v1.2.3 From 400125148f82e0e67c70a25724d940d331063b44 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 07:46:26 -0500 Subject: Properly linking to the background image --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 6c50377f..3a8d3cdc 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,6 +1,6 @@ body { background-color: #272727; - background-image: url('back.png'); + background-image: url('../images/back.png'); color: #f7f7f7; font-family: sans; padding:none; -- cgit v1.2.3 From 1ab8467320db7083bd651a26191cbecbdaa0f38d Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Mon, 16 May 2011 14:55:05 +0200 Subject: Show images in reverse submit order Fixes bug #327. Just do a .sort('created', DESCENDING) on Media when showing them to show the latest first. Signed-off-by: Sebastian Spaeth --- mediagoblin/user_pages/views.py | 3 ++- mediagoblin/views.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2c9792fa..c99556c2 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -15,6 +15,7 @@ # along with this program. If not, see . from webob import Response, exc +from pymongo import DESCENDING from mongokit import ObjectId import wtforms @@ -29,7 +30,7 @@ def user_home(request): medias = request.db.MediaEntry.find({ 'uploader': user, - 'state': 'processed'}) + 'state': 'processed'}).sort('created', DESCENDING) template = request.template_env.get_template( 'mediagoblin/user_pages/user.html') diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 7f925bb7..602f1098 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -18,13 +18,14 @@ import datetime from webob import Response, exc import wtforms +from pymongo import DESCENDING from mongokit import ObjectId from mediagoblin import models import gettext def root_view(request): media_entries = request.db.MediaEntry.find( - {u'state': u'processed'}) + {u'state': u'processed'}).sort('created', DESCENDING) template = request.template_env.get_template( 'mediagoblin/root.html') -- cgit v1.2.3 From 3e4a2f2be7c4740f7192c18cf9d8c9cd9dfedad1 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 17:35:56 -0500 Subject: ./bin/gmg shell documented in the hackinghowto --- docs/hackinghowto.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index b34ce93a..bf5278b3 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -249,6 +249,21 @@ If you did virtualenv, run:: nosetests +Running a shell +=============== + +If you want a shell with your database pre-setup and an instantiated +application ready and at your fingertips... + +If you did buildout, run:: + + ./bin/gmg shell + +If you did virtualenv, run:: + + gmg shell + + Troubleshooting =============== -- cgit v1.2.3 From 18cf34d4701f86f5c8951ae0d340824b4b4f19ac Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 18:20:50 -0500 Subject: Adding the is_admin field now per Elrond's sane request / advice. ;) --- mediagoblin/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 4a867323..edb1d46d 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -42,7 +42,8 @@ class User(Document): 'pw_hash': unicode, 'email_verified': bool, 'status': unicode, - 'verification_key': unicode + 'verification_key': unicode, + 'is_admin': bool, } required_fields = ['username', 'created', 'pw_hash', 'email'] @@ -51,7 +52,8 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, 'status': u'needs_email_verification', - 'verification_key': lambda: unicode( uuid.uuid4() ) } + 'verification_key': lambda: unicode(uuid.uuid4()), + 'is_admin': False} def check_login(self, password): """ -- cgit v1.2.3 From 37af09a2e51394c630bf7efd1718b77a574b272d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 18:22:13 -0500 Subject: Require that the slug field have only unique values. --- mediagoblin/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index edb1d46d..cdb06a35 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -99,6 +99,10 @@ class MediaEntry(Document): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} + indexes = [ + {'fields': 'slug', + 'unique': True}] + def main_mediafile(self): pass -- cgit v1.2.3 From f0545ddebd1a313249f6b39fdf96ba879a78e8b2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 18:23:27 -0500 Subject: My name's Chris Webber and I'm pedantic about lines not going over 80 characters. --- mediagoblin/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index cdb06a35..7cacc519 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -109,7 +109,8 @@ class MediaEntry(Document): def generate_slug(self): self['slug'] = util.slugify(self['title']) - duplicate = mediagoblin_globals.database.media_entries.find_one({'slug': self['slug']}) + duplicate = mediagoblin_globals.database.media_entries.find_one( + {'slug': self['slug']}) if duplicate: self['slug'] = "%s-%s" % (self['_id'], self['slug']) -- cgit v1.2.3 From 931f318cbc571419510b1ad37298c981df2f16b0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 May 2011 18:28:49 -0500 Subject: Actually we only need unique slugs per uploader. But I want to fix http://bugs.foocorp.net/issues/340 first. --- mediagoblin/models.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediagoblin/models.py b/mediagoblin/models.py index 7cacc519..1bc1da60 100644 --- a/mediagoblin/models.py +++ b/mediagoblin/models.py @@ -99,9 +99,11 @@ class MediaEntry(Document): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} - indexes = [ - {'fields': 'slug', - 'unique': True}] + # Actually we should referene uniqueness by uploader, but we + # should fix http://bugs.foocorp.net/issues/340 first. + # indexes = [ + # {'fields': ['uploader', 'slug'], + # 'unique': True}] def main_mediafile(self): pass -- cgit v1.2.3 From 0f18ed8f5e179326721221df93734864074bc185 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 18 May 2011 00:44:10 +0200 Subject: Move models into new db/ directory The database is a central point of interest/discussion. Represent that by its own directory. This will surely become more interesting when we have migrations for example. --- mediagoblin/app.py | 3 +- mediagoblin/celery_setup/from_celery.py | 3 +- mediagoblin/db/__init__.py | 0 mediagoblin/db/models.py | 128 ++++++++++++++++++++++++++++++++ mediagoblin/models.py | 128 -------------------------------- mediagoblin/views.py | 2 +- 6 files changed, 133 insertions(+), 131 deletions(-) create mode 100644 mediagoblin/db/__init__.py create mode 100644 mediagoblin/db/models.py delete mode 100644 mediagoblin/models.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index d124558d..908bb19c 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -21,7 +21,8 @@ import mongokit from paste.deploy.converters import asbool, asint from webob import Request, exc -from mediagoblin import routing, util, models, storage, staticdirect +from mediagoblin import routing, util, storage, staticdirect +from mediagoblin.db import models from mediagoblin.globals import setup_globals from mediagoblin.celery_setup import setup_celery_from_config diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 55e638b9..65dcca40 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -20,7 +20,8 @@ import mongokit from paste.deploy.loadwsgi import NicerConfigParser from paste.deploy.converters import asint, asbool -from mediagoblin import storage, models +from mediagoblin import storage +from mediagoblin.db import models from mediagoblin.celery_setup import setup_celery_from_config from mediagoblin.globals import setup_globals from mediagoblin import globals as mgoblin_globals diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py new file mode 100644 index 00000000..1bc1da60 --- /dev/null +++ b/mediagoblin/db/models.py @@ -0,0 +1,128 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import datetime, uuid + +from mongokit import Document, Set + +from mediagoblin import util +from mediagoblin.auth import lib as auth_lib +from mediagoblin import globals as mediagoblin_globals + +################### +# Custom validators +################### + +######## +# Models +######## + + +class User(Document): + __collection__ = 'users' + + structure = { + 'username': unicode, + 'email': unicode, + 'created': datetime.datetime, + 'plugin_data': dict, # plugins can dump stuff here. + 'pw_hash': unicode, + 'email_verified': bool, + 'status': unicode, + 'verification_key': unicode, + 'is_admin': bool, + } + + required_fields = ['username', 'created', 'pw_hash', 'email'] + + default_values = { + 'created': datetime.datetime.utcnow, + 'email_verified': False, + 'status': u'needs_email_verification', + 'verification_key': lambda: unicode(uuid.uuid4()), + 'is_admin': False} + + def check_login(self, password): + """ + See if a user can login with this password + """ + return auth_lib.bcrypt_check_password( + password, self['pw_hash']) + + +class MediaEntry(Document): + __collection__ = 'media_entries' + + structure = { + 'uploader': User, + 'title': unicode, + 'slug': unicode, + 'created': datetime.datetime, + 'description': unicode, + 'media_type': unicode, + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. + 'tags': [unicode], + 'state': unicode, + + # For now let's assume there can only be one main file queued + # at a time + 'queued_media_file': [unicode], + + # A dictionary of logical names to filepaths + 'media_files': dict, + + # The following should be lists of lists, in appropriate file + # record form + 'attachment_files': list, + + # This one should just be a single file record + 'thumbnail_file': [unicode]} + + required_fields = [ + 'uploader', 'created', 'media_type'] + + default_values = { + 'created': datetime.datetime.utcnow, + 'state': u'unprocessed'} + + # Actually we should referene uniqueness by uploader, but we + # should fix http://bugs.foocorp.net/issues/340 first. + # indexes = [ + # {'fields': ['uploader', 'slug'], + # 'unique': True}] + + def main_mediafile(self): + pass + + def generate_slug(self): + self['slug'] = util.slugify(self['title']) + + duplicate = mediagoblin_globals.database.media_entries.find_one( + {'slug': self['slug']}) + + if duplicate: + self['slug'] = "%s-%s" % (self['_id'], self['slug']) + +REGISTER_MODELS = [MediaEntry, User] + + +def register_models(connection): + """ + Register all models in REGISTER_MODELS with this connection. + """ + connection.register(REGISTER_MODELS) + diff --git a/mediagoblin/models.py b/mediagoblin/models.py deleted file mode 100644 index 1bc1da60..00000000 --- a/mediagoblin/models.py +++ /dev/null @@ -1,128 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import datetime, uuid - -from mongokit import Document, Set - -from mediagoblin import util -from mediagoblin.auth import lib as auth_lib -from mediagoblin import globals as mediagoblin_globals - -################### -# Custom validators -################### - -######## -# Models -######## - - -class User(Document): - __collection__ = 'users' - - structure = { - 'username': unicode, - 'email': unicode, - 'created': datetime.datetime, - 'plugin_data': dict, # plugins can dump stuff here. - 'pw_hash': unicode, - 'email_verified': bool, - 'status': unicode, - 'verification_key': unicode, - 'is_admin': bool, - } - - required_fields = ['username', 'created', 'pw_hash', 'email'] - - default_values = { - 'created': datetime.datetime.utcnow, - 'email_verified': False, - 'status': u'needs_email_verification', - 'verification_key': lambda: unicode(uuid.uuid4()), - 'is_admin': False} - - def check_login(self, password): - """ - See if a user can login with this password - """ - return auth_lib.bcrypt_check_password( - password, self['pw_hash']) - - -class MediaEntry(Document): - __collection__ = 'media_entries' - - structure = { - 'uploader': User, - 'title': unicode, - 'slug': unicode, - 'created': datetime.datetime, - 'description': unicode, - 'media_type': unicode, - 'media_data': dict, # extra data relevant to this media_type - 'plugin_data': dict, # plugins can dump stuff here. - 'tags': [unicode], - 'state': unicode, - - # For now let's assume there can only be one main file queued - # at a time - 'queued_media_file': [unicode], - - # A dictionary of logical names to filepaths - 'media_files': dict, - - # The following should be lists of lists, in appropriate file - # record form - 'attachment_files': list, - - # This one should just be a single file record - 'thumbnail_file': [unicode]} - - required_fields = [ - 'uploader', 'created', 'media_type'] - - default_values = { - 'created': datetime.datetime.utcnow, - 'state': u'unprocessed'} - - # Actually we should referene uniqueness by uploader, but we - # should fix http://bugs.foocorp.net/issues/340 first. - # indexes = [ - # {'fields': ['uploader', 'slug'], - # 'unique': True}] - - def main_mediafile(self): - pass - - def generate_slug(self): - self['slug'] = util.slugify(self['title']) - - duplicate = mediagoblin_globals.database.media_entries.find_one( - {'slug': self['slug']}) - - if duplicate: - self['slug'] = "%s-%s" % (self['_id'], self['slug']) - -REGISTER_MODELS = [MediaEntry, User] - - -def register_models(connection): - """ - Register all models in REGISTER_MODELS with this connection. - """ - connection.register(REGISTER_MODELS) - diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 602f1098..60d34908 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -20,7 +20,7 @@ from webob import Response, exc import wtforms from pymongo import DESCENDING from mongokit import ObjectId -from mediagoblin import models +from mediagoblin.db import models import gettext def root_view(request): -- cgit v1.2.3 From a4bae8700e2186adb91d5c0a5198e7a8923143c6 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 18 May 2011 01:03:40 +0200 Subject: Move "connect to database" into db/util.py --- mediagoblin/app.py | 8 ++------ mediagoblin/db/util.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 mediagoblin/db/util.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 908bb19c..c94b5f6d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -17,12 +17,12 @@ import urllib import routes -import mongokit from paste.deploy.converters import asbool, asint from webob import Request, exc from mediagoblin import routing, util, storage, staticdirect from mediagoblin.db import models +from mediagoblin.db.util import connect_database from mediagoblin.globals import setup_globals from mediagoblin.celery_setup import setup_celery_from_config @@ -118,11 +118,7 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **app_config): # Get the database connection - port = app_config.get('db_port') - if port: - port = asint(port) - connection = mongokit.Connection( - app_config.get('db_host'), port) + connection = connect_database(app_config) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py new file mode 100644 index 00000000..89e0dbef --- /dev/null +++ b/mediagoblin/db/util.py @@ -0,0 +1,11 @@ +import mongokit + + +def connect_database(app_config): + """Connect to the main database, take config from app_config""" + port = app_config.get('db_port') + if port: + port = asint(port) + connection = mongokit.Connection( + app_config.get('db_host'), port) + return connection -- cgit v1.2.3 From 254bc43174ecad984ce895c10e6be7926c52cc22 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 18 May 2011 11:32:29 +0200 Subject: Move ObjectId, DESCENDING to db.util We used to import those from pymongo and mongokit directly. We should import them from a single place. So let's try db.util for this. --- mediagoblin/db/util.py | 2 ++ mediagoblin/process_media/__init__.py | 4 ++-- mediagoblin/user_pages/views.py | 3 +-- mediagoblin/util.py | 4 ++-- mediagoblin/views.py | 3 +-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 89e0dbef..56f22d7e 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -1,4 +1,6 @@ import mongokit +from pymongo import DESCENDING +from mongokit import ObjectId def connect_database(app_config): diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 3c4d0ca1..4f06a686 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -15,7 +15,7 @@ # along with this program. If not, see . import Image -import mongokit +from mediagoblin.db.util import ObjectId from celery.task import task from mediagoblin.globals import database, queue_store, public_store @@ -27,7 +27,7 @@ THUMB_SIZE = 200, 200 @task def process_media_initial(media_id): entry = database.MediaEntry.one( - {'_id': mongokit.ObjectId(media_id)}) + {'_id': ObjectId(media_id)}) queued_filepath = entry['queued_media_file'] queued_file = queue_store.get_file(queued_filepath, 'r') diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index c99556c2..1ab3c8ef 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -15,8 +15,7 @@ # along with this program. If not, see . from webob import Response, exc -from pymongo import DESCENDING -from mongokit import ObjectId +from mediagoblin.db.util import ObjectId, DESCENDING import wtforms diff --git a/mediagoblin/util.py b/mediagoblin/util.py index a66e2ba5..680ff62e 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -21,7 +21,7 @@ import smtplib import sys import re import jinja2 -import mongokit +from mediagoblin.db.util import ObjectId import translitcodec from mediagoblin import globals as mgoblin_globals @@ -83,7 +83,7 @@ def setup_user_in_request(request): user = None user = request.app.db.User.one( - {'_id': mongokit.ObjectId(request.session['user_id'])}) + {'_id': ObjectId(request.session['user_id'])}) if not user: # Something's wrong... this user doesn't exist? Invalidate diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 60d34908..5bc04b66 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -18,9 +18,8 @@ import datetime from webob import Response, exc import wtforms -from pymongo import DESCENDING -from mongokit import ObjectId from mediagoblin.db import models +from mediagoblin.db.util import ObjectId, DESCENDING import gettext def root_view(request): -- cgit v1.2.3 From 1815f5ce2e1a12c04e9521dfe798c28b5186e458 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 18 May 2011 08:37:48 -0500 Subject: Adding copyright headers and explaining why these unused imports are here --- mediagoblin/db/__init__.py | 15 +++++++++++++++ mediagoblin/db/util.py | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py index e69de29b..c129cbf8 100644 --- a/mediagoblin/db/__init__.py +++ b/mediagoblin/db/__init__.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 56f22d7e..4828e3d7 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -1,4 +1,22 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + import mongokit + +# Imports that other modules might use from pymongo import DESCENDING from mongokit import ObjectId -- cgit v1.2.3 From 468bc8afce0eab35ca3d403708a27187f65e96ac Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 18 May 2011 08:39:09 -0500 Subject: Need to import asint for users who specify ports via config file --- mediagoblin/db/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 4828e3d7..f70a5826 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -16,6 +16,8 @@ import mongokit +from paste.deploy.converters import asint + # Imports that other modules might use from pymongo import DESCENDING from mongokit import ObjectId -- cgit v1.2.3 From 3262ad1dbbc1919de2393e11900f5a47ac5dcd75 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 18 May 2011 08:44:57 -0500 Subject: Renaming connect_database to connect_database_from_config and using in from_celery --- mediagoblin/app.py | 4 ++-- mediagoblin/celery_setup/from_celery.py | 8 +++----- mediagoblin/db/util.py | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index c94b5f6d..60adba56 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -22,7 +22,7 @@ from webob import Request, exc from mediagoblin import routing, util, storage, staticdirect from mediagoblin.db import models -from mediagoblin.db.util import connect_database +from mediagoblin.db.util import connect_database_from_config from mediagoblin.globals import setup_globals from mediagoblin.celery_setup import setup_celery_from_config @@ -118,7 +118,7 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **app_config): # Get the database connection - connection = connect_database(app_config) + connection = connect_database_from_config(app_config) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 65dcca40..57b52f56 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -22,6 +22,7 @@ from paste.deploy.converters import asint, asbool from mediagoblin import storage from mediagoblin.db import models +from mediagoblin.db.util import connect_database_from_config from mediagoblin.celery_setup import setup_celery_from_config from mediagoblin.globals import setup_globals from mediagoblin import globals as mgoblin_globals @@ -69,11 +70,8 @@ def setup_self(setup_globals_func=setup_globals): settings_module=OUR_MODULENAME, set_environ=False) - port = mgoblin_section.get('db_port') - if port: - port = asint(port) - connection = mongokit.Connection( - mgoblin_section.get('db_host'), port) + connection = connect_database_from_config(mgoblin_section) + db = connection[mgoblin_section.get('db_name', 'mediagoblin')] models.register_models(connection) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index f70a5826..407caf05 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -23,7 +23,7 @@ from pymongo import DESCENDING from mongokit import ObjectId -def connect_database(app_config): +def connect_database_from_config(app_config): """Connect to the main database, take config from app_config""" port = app_config.get('db_port') if port: -- cgit v1.2.3 From ae85ed0f971147ce7cee9ce02b498f909d21ce79 Mon Sep 17 00:00:00 2001 From: Bernhard Keller Date: Wed, 18 May 2011 17:32:49 +0200 Subject: added Pagination class, usage description in Pagination,__call__ added pagination.html, object_gallery.html as templates --- mediagoblin/templates/mediagoblin/root.html | 2 +- .../templates/mediagoblin/user_pages/user.html | 11 +-- .../mediagoblin/utils/object_gallery.html | 36 +++++++++ .../templates/mediagoblin/utils/pagination.html | 41 +++++++++++ mediagoblin/user_pages/views.py | 23 ++++-- mediagoblin/util.py | 86 ++++++++++++++++++++++ 6 files changed, 183 insertions(+), 16 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/utils/object_gallery.html create mode 100644 mediagoblin/templates/mediagoblin/utils/pagination.html diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index e2b2730a..a93a7c75 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -53,4 +53,4 @@

-{% endblock %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 5c8692fc..48516679 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -23,14 +23,9 @@ {#- Should we outsource such a media 'gallery' view to it's own file? It could be useful for the home page and other views too -#}
    - {%- for entry in media_entries %} -
  • - - -
  • - {%- endfor %} + + {% include "mediagoblin/utils/object_gallery.html" %} +
{% else %} {# This *should* not occur as the view makes sure we pass in a user. #} diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html new file mode 100644 index 00000000..6e59c380 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -0,0 +1,36 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + + +
+ {% if media_entries %} +
    + {% for entry in media_entries %} +
  • + + +
  • + {% endfor %} +
+ + {% import 'mediagoblin/utils/pagination.html' as paginationmacro %} + {{ paginationmacro.render_pagination(pagination) }} + {% endif %} +
diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html new file mode 100644 index 00000000..80b4b820 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -0,0 +1,41 @@ +{# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + + +{% macro render_pagination(pagination) %} + +{# only display if {{pagination}} is defined #} + +{% if pagination %} + +{% endif %} +{% endmacro %} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index c99556c2..55d60c6b 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,7 +18,7 @@ from webob import Response, exc from pymongo import DESCENDING from mongokit import ObjectId import wtforms - +from ..util import Pagination def user_home(request): """'Homepage' of a User()""" @@ -28,18 +28,26 @@ def user_home(request): if not user: return exc.HTTPNotFound() - medias = request.db.MediaEntry.find({ - 'uploader': user, - 'state': 'processed'}).sort('created', DESCENDING) - + pagination = Pagination() + media_entries = pagination( + { 'per_page': 2, + 'request': request, + 'collection':'MediaEntry', + 'query': { 'uploader':user, 'state':'processed'} } ) + + #if no data is available, return NotFound + if media_entries == None: + return exc.HTTPNotFound() + template = request.template_env.get_template( 'mediagoblin/user_pages/user.html') + return Response( template.render( {'request': request, 'user': user, - 'media_entries': medias})) - + 'media_entries': media_entries, + 'pagination': pagination})) def media_home(request): """'Homepage' of a MediaEntry()""" @@ -58,3 +66,4 @@ def media_home(request): template.render( {'request': request, 'media': media})) + diff --git a/mediagoblin/util.py b/mediagoblin/util.py index a66e2ba5..0f28dd79 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -26,6 +26,10 @@ import translitcodec from mediagoblin import globals as mgoblin_globals +import urllib +from pymongo import ASCENDING, DESCENDING +from math import ceil + TESTS_ENABLED = False def _activate_testing(): @@ -290,3 +294,85 @@ def setup_gettext(locale): mgoblin_globals.setup_globals( translations=this_gettext) + + +class Pagination(object): + """ + Pagination class + """ + def __init__(self): + pass + + def __call__(self, args): + """ + input values: + {'page': ..., --- requested page + 'per_page': ..., --- objects per page + 'request': ..., --- webob request object for url generation + 'collection' ... --- db collection, thats to be queried + 'query': {'user': xxx}, query restrictions, db.collection.find(query) + } + + add: + option for sorting attribute + ascending, descending option + range based pagination + """ + self.per_page = args['per_page'] + self.request = args['request'] + + try: + self.page = abs(int(args['request'].str_GET['page'])) + # set default page, if page value is not set + except KeyError: + self.page = 1 + # return None(404 Error) if page is set, but has no value or has an invalid value + except ValueError: + return None + + ###################################################### + # + # db queries should be changed into range based pagination + # save count and current page in some user session data + # + ###################################################### + + collection = getattr(self.request.db, args['collection']) + + self.total_count = collection.find(args['query']).count() + + #check if requested page is valid, not larger than available number of pages + if self.page > self.pages: + return None + + return collection.find(args['query']).sort('created',DESCENDING) \ + .skip((self.page-1)*self.per_page).limit(self.per_page) + + @property + def pages(self): + return int(ceil(self.total_count / float(self.per_page))) + + @property + def has_prev(self): + return self.page > 1 + + @property + def has_next(self): + return self.page < self.pages + + def iter_pages(self, left_edge=2, left_current=2, + right_current=5, right_edge=2): + last = 0 + for num in xrange(1, self.pages + 1): + if num <= left_edge or \ + (num > self.page - left_current - 1 and \ + num < self.page + right_current) or \ + num > self.pages - right_edge: + if last + 1 != num: + yield None + yield num + last = num + + def url_generator(self, page): + return '%s?%s' % (self.request.path_info, \ + urllib.urlencode({'page':str(page)})) -- cgit v1.2.3 From 86f9b473877434e5a811d057e192c91a70d67ef5 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 18 May 2011 22:03:52 +0200 Subject: Clean unused imports (found by pyflakes). --- mediagoblin/app.py | 2 +- mediagoblin/celery_setup/from_celery.py | 3 +-- mediagoblin/user_pages/views.py | 1 - mediagoblin/views.py | 9 ++------- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 60adba56..25a6f541 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -17,7 +17,7 @@ import urllib import routes -from paste.deploy.converters import asbool, asint +from paste.deploy.converters import asbool from webob import Request, exc from mediagoblin import routing, util, storage, staticdirect diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index 57b52f56..d35009cb 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -16,9 +16,8 @@ import os -import mongokit from paste.deploy.loadwsgi import NicerConfigParser -from paste.deploy.converters import asint, asbool +from paste.deploy.converters import asbool from mediagoblin import storage from mediagoblin.db import models diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 1ab3c8ef..9e9e3f51 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -16,7 +16,6 @@ from webob import Response, exc from mediagoblin.db.util import ObjectId, DESCENDING -import wtforms def user_home(request): diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 5bc04b66..dd722c63 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -14,13 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import datetime - -from webob import Response, exc -import wtforms -from mediagoblin.db import models -from mediagoblin.db.util import ObjectId, DESCENDING -import gettext +from webob import Response +from mediagoblin.db.util import DESCENDING def root_view(request): media_entries = request.db.MediaEntry.find( -- cgit v1.2.3 From a67fec8177c09c4e74ce7f4301b88f4e7ea6e658 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 19 May 2011 01:35:02 +0200 Subject: Factor out most of the database connection into db/open.py I needed to split the db connection/opening into open.py, due to an import loop: - util.py needs db/util.py:ObjectId - db/util.py would need db/models.py - db/models.py needs util.py:slugify --- mediagoblin/app.py | 12 +++++------ mediagoblin/celery_setup/from_celery.py | 8 ++----- mediagoblin/db/open.py | 37 +++++++++++++++++++++++++++++++++ mediagoblin/db/util.py | 13 ------------ 4 files changed, 44 insertions(+), 26 deletions(-) create mode 100644 mediagoblin/db/open.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 25a6f541..640ffc45 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -21,8 +21,7 @@ from paste.deploy.converters import asbool from webob import Request, exc from mediagoblin import routing, util, storage, staticdirect -from mediagoblin.db import models -from mediagoblin.db.util import connect_database_from_config +from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.globals import setup_globals from mediagoblin.celery_setup import setup_celery_from_config @@ -35,7 +34,7 @@ class MediaGoblinApp(object): """ Really basic wsgi app using routes and WebOb. """ - def __init__(self, connection, database_path, + def __init__(self, connection, db, public_store, queue_store, staticdirector, email_sender_address, email_debug_mode, @@ -49,8 +48,7 @@ class MediaGoblinApp(object): # Set up database self.connection = connection - self.db = connection[database_path] - models.register_models(connection) + self.db = db # set up routing self.routing = routing.get_mapper() @@ -118,7 +116,7 @@ class MediaGoblinApp(object): def paste_app_factory(global_config, **app_config): # Get the database connection - connection = connect_database_from_config(app_config) + connection, db = setup_connection_and_db_from_config(app_config) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( @@ -143,7 +141,7 @@ def paste_app_factory(global_config, **app_config): setup_celery_from_config(app_config, global_config) mgoblin_app = MediaGoblinApp( - connection, app_config.get('db_name', 'mediagoblin'), + connection, db, public_store=public_store, queue_store=queue_store, staticdirector=staticdirector, email_sender_address=app_config.get( diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/celery_setup/from_celery.py index d35009cb..0669e80c 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/celery_setup/from_celery.py @@ -20,8 +20,7 @@ from paste.deploy.loadwsgi import NicerConfigParser from paste.deploy.converters import asbool from mediagoblin import storage -from mediagoblin.db import models -from mediagoblin.db.util import connect_database_from_config +from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.celery_setup import setup_celery_from_config from mediagoblin.globals import setup_globals from mediagoblin import globals as mgoblin_globals @@ -69,10 +68,7 @@ def setup_self(setup_globals_func=setup_globals): settings_module=OUR_MODULENAME, set_environ=False) - connection = connect_database_from_config(mgoblin_section) - - db = connection[mgoblin_section.get('db_name', 'mediagoblin')] - models.register_models(connection) + connection, db = setup_connection_and_db_from_config(mgoblin_section) # Set up the storage systems. public_store = storage.storage_system_from_paste_config( diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py new file mode 100644 index 00000000..cae33394 --- /dev/null +++ b/mediagoblin/db/open.py @@ -0,0 +1,37 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import mongokit +from paste.deploy.converters import asint +from mediagoblin.db import models + + +def connect_database_from_config(app_config): + """Connect to the main database, take config from app_config""" + port = app_config.get('db_port') + if port: + port = asint(port) + connection = mongokit.Connection( + app_config.get('db_host'), port) + return connection + +def setup_connection_and_db_from_config(app_config): + connection = connect_database_from_config(app_config) + database_path = app_config.get('db_name', 'mediagoblin') + db = connection[database_path] + models.register_models(connection) + # Could configure indexes here on db + return (connection, db) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 407caf05..30615fca 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -14,20 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import mongokit - -from paste.deploy.converters import asint # Imports that other modules might use from pymongo import DESCENDING from mongokit import ObjectId - - -def connect_database_from_config(app_config): - """Connect to the main database, take config from app_config""" - port = app_config.get('db_port') - if port: - port = asint(port) - connection = mongokit.Connection( - app_config.get('db_host'), port) - return connection -- cgit v1.2.3 From ca3ca51c5a1fa4c10b88c851c9bd04ae7978cb41 Mon Sep 17 00:00:00 2001 From: Bernhard Keller Date: Thu, 19 May 2011 17:24:31 +0200 Subject: changed some coding styles and changed the interface for pagination from __call__ to the __init__, also getting a cursor as input, instead of the query details --- .../mediagoblin/utils/object_gallery.html | 35 +++++++------- .../templates/mediagoblin/utils/pagination.html | 43 ++++++++++------- mediagoblin/user_pages/views.py | 15 +++--- mediagoblin/util.py | 56 +++++----------------- 4 files changed, 62 insertions(+), 87 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 6e59c380..9e8c1875 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -16,21 +16,22 @@ # along with this program. If not, see . #} +{% import 'mediagoblin/utils/pagination.html' as paginationmacro %} -
- {% if media_entries %} -
    - {% for entry in media_entries %} -
  • - - -
  • - {% endfor %} -
- - {% import 'mediagoblin/utils/pagination.html' as paginationmacro %} - {{ paginationmacro.render_pagination(pagination) }} - {% endif %} -
+
+ {% if media_entries %} +
    + {% for entry in media_entries %} +
  • + + +
  • + {% endfor %} +
+ + {{ paginationmacro.render_pagination(pagination) }} + + {% endif %} +
diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 80b4b820..685a1bb9 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -18,24 +18,31 @@ {% macro render_pagination(pagination) %} -{# only display if {{pagination}} is defined #} - -{% if pagination %} - -{% endif %} + {% endmacro %} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 55d60c6b..26c67425 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,7 +18,8 @@ from webob import Response, exc from pymongo import DESCENDING from mongokit import ObjectId import wtforms -from ..util import Pagination +from mediagoblin.util import Pagination +from pymongo import ASCENDING, DESCENDING def user_home(request): """'Homepage' of a User()""" @@ -28,12 +29,12 @@ def user_home(request): if not user: return exc.HTTPNotFound() - pagination = Pagination() - media_entries = pagination( - { 'per_page': 2, - 'request': request, - 'collection':'MediaEntry', - 'query': { 'uploader':user, 'state':'processed'} } ) + cursor = request.db.MediaEntry \ + .find({'uploader': user, 'state': 'processed'}) \ + .sort('created', DESCENDING) + + pagination = Pagination(2, cursor, request) + media_entries = pagination() #if no data is available, return NotFound if media_entries == None: diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 0f28dd79..b79d6b05 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -27,7 +27,6 @@ import translitcodec from mediagoblin import globals as mgoblin_globals import urllib -from pymongo import ASCENDING, DESCENDING from math import ceil @@ -300,53 +299,20 @@ class Pagination(object): """ Pagination class """ - def __init__(self): - pass - - def __call__(self, args): - """ - input values: - {'page': ..., --- requested page - 'per_page': ..., --- objects per page - 'request': ..., --- webob request object for url generation - 'collection' ... --- db collection, thats to be queried - 'query': {'user': xxx}, query restrictions, db.collection.find(query) - } - - add: - option for sorting attribute - ascending, descending option - range based pagination - """ - self.per_page = args['per_page'] - self.request = args['request'] - + def __init__(self, per_page, cursor, request): try: - self.page = abs(int(args['request'].str_GET['page'])) - # set default page, if page value is not set + self.page = int(request.str_GET['page']) except KeyError: self.page = 1 - # return None(404 Error) if page is set, but has no value or has an invalid value - except ValueError: - return None - - ###################################################### - # - # db queries should be changed into range based pagination - # save count and current page in some user session data - # - ###################################################### - - collection = getattr(self.request.db, args['collection']) - - self.total_count = collection.find(args['query']).count() - - #check if requested page is valid, not larger than available number of pages - if self.page > self.pages: - return None - - return collection.find(args['query']).sort('created',DESCENDING) \ - .skip((self.page-1)*self.per_page).limit(self.per_page) + + self.per_page = per_page + self.cursor = cursor + self.request = request + self.total_count = self.cursor.count() + + def __call__(self): + return self.cursor.skip((self.page-1)*self.per_page) \ + .limit(self.per_page) @property def pages(self): -- cgit v1.2.3 From 44e3e917fbfc89409bac08d500c5a9246e0dc5f4 Mon Sep 17 00:00:00 2001 From: Bernhard Keller Date: Thu, 19 May 2011 20:37:04 +0200 Subject: removed request arg from Pagination class added get_page_url() in Pagination class, to generate proper urls without losing other get arguments --- .../templates/mediagoblin/user_pages/user.html | 2 -- .../mediagoblin/utils/object_gallery.html | 35 ++++++++++---------- .../templates/mediagoblin/utils/pagination.html | 23 +++++++------ mediagoblin/user_pages/views.py | 9 +++-- mediagoblin/util.py | 38 +++++++++++++++------- 5 files changed, 61 insertions(+), 46 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 48516679..d1809e80 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -20,8 +20,6 @@ {% if user %}

User page for '{{ user.username }}'

- {#- Should we outsource such a media 'gallery' view to it's own file? - It could be useful for the home page and other views too -#}
    {% include "mediagoblin/utils/object_gallery.html" %} diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 9e8c1875..8ae337f5 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -16,22 +16,21 @@ # along with this program. If not, see . #} -{% import 'mediagoblin/utils/pagination.html' as paginationmacro %} +{% block object_gallery_content -%} +
    + {% if media_entries %} +
      + {% for entry in media_entries %} +
    • + + +
    • + {% endfor %} +
    + {% include "mediagoblin/utils/pagination.html" %} + {% endif %} -
    - {% if media_entries %} -
      - {% for entry in media_entries %} -
    • - - -
    • - {% endfor %} -
    - - {{ paginationmacro.render_pagination(pagination) }} - - {% endif %} -
    +
    +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 685a1bb9..b74cbfcf 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -15,22 +15,21 @@ # along with this program. If not, see . #} +{# only display if {{pagination}} is defined #} -{% macro render_pagination(pagination) %} - - {# only display if {{pagination}} is defined #} - - {% if pagination %} - +{% endif %} -{% endmacro %} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 26c67425..76f96cf9 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -33,9 +33,14 @@ def user_home(request): .find({'uploader': user, 'state': 'processed'}) \ .sort('created', DESCENDING) - pagination = Pagination(2, cursor, request) + try: + page = int(request.str_GET['page']) + except KeyError: + page = 1 + + pagination = Pagination(cursor, page) media_entries = pagination() - + #if no data is available, return NotFound if media_entries == None: return exc.HTTPNotFound() diff --git a/mediagoblin/util.py b/mediagoblin/util.py index b79d6b05..9247ac19 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -28,7 +28,7 @@ from mediagoblin import globals as mgoblin_globals import urllib from math import ceil - +import copy TESTS_ENABLED = False def _activate_testing(): @@ -297,20 +297,27 @@ def setup_gettext(locale): class Pagination(object): """ - Pagination class + Pagination class, + initialization through __init__(self, page=1, per_page=2, cursor) + get actual data slice through __call__() """ - def __init__(self, per_page, cursor, request): - try: - self.page = int(request.str_GET['page']) - except KeyError: - self.page = 1 + def __init__(self, cursor, page=1, per_page=2): + """ + initializes Pagination + -- page, requested page + -- per_page, number of objects per page + -- cursor, db cursor + """ + self.page = page self.per_page = per_page self.cursor = cursor - self.request = request self.total_count = self.cursor.count() def __call__(self): + """ + returns slice of objects for the requested page + """ return self.cursor.skip((self.page-1)*self.per_page) \ .limit(self.per_page) @@ -338,7 +345,14 @@ class Pagination(object): yield None yield num last = num - - def url_generator(self, page): - return '%s?%s' % (self.request.path_info, \ - urllib.urlencode({'page':str(page)})) + + def get_page_url(self, path_info, page_no, get_params=None): + """ + Get a new page based of the path_info, the new page number, + and existing get parameters. + """ + new_get_params = copy.copy(get_params or {}) + new_get_params['page'] = page_no + return "%s?%s" % ( + path_info, urllib.urlencode(new_get_params)) + -- cgit v1.2.3 From 3eb6fc4f2f2b0a41677ab88bdd941b79e3e87b39 Mon Sep 17 00:00:00 2001 From: Bernhard Keller Date: Thu, 19 May 2011 22:52:18 +0200 Subject: moved check for correct page values into decorator for view function --- mediagoblin/decorators.py | 19 +++++++++++++++++++ mediagoblin/user_pages/views.py | 11 +++++------ mediagoblin/util.py | 6 ++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 1774ce4e..161d99ff 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -44,3 +44,22 @@ def require_active_login(controller): return controller(request, *args, **kwargs) return _make_safe(new_controller_func, controller) + + +def uses_pagination(controller): + """ + Check request GET 'page' key for wrong values + """ + def wrapper(request, *args, **kwargs): + try: + page = int(request.str_GET['page']) + if page < 0: + return exc.HTTPNotFound() + except ValueError: + return exc.HTTPNotFound() + except KeyError: + request.str_GET['page'] = 1 + + return controller(request, *args, **kwargs) + + return _make_safe(wrapper,controller) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 76f96cf9..cb2c5875 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -21,6 +21,9 @@ import wtforms from mediagoblin.util import Pagination from pymongo import ASCENDING, DESCENDING +from mediagoblin.decorators import uses_pagination + +@uses_pagination def user_home(request): """'Homepage' of a User()""" user = request.db.User.find_one({ @@ -32,13 +35,9 @@ def user_home(request): cursor = request.db.MediaEntry \ .find({'uploader': user, 'state': 'processed'}) \ .sort('created', DESCENDING) + - try: - page = int(request.str_GET['page']) - except KeyError: - page = 1 - - pagination = Pagination(cursor, page) + pagination = Pagination( int(request.str_GET['page']), cursor) media_entries = pagination() #if no data is available, return NotFound diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 9247ac19..5f5c59fb 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -29,6 +29,8 @@ from mediagoblin import globals as mgoblin_globals import urllib from math import ceil import copy +import decorators +from webob import exc TESTS_ENABLED = False def _activate_testing(): @@ -298,11 +300,11 @@ def setup_gettext(locale): class Pagination(object): """ Pagination class, - initialization through __init__(self, page=1, per_page=2, cursor) + initialization through __init__(self, cursor, page=1, per_page=2): get actual data slice through __call__() """ - def __init__(self, cursor, page=1, per_page=2): + def __init__(self, page, cursor, per_page=2): """ initializes Pagination -- page, requested page -- cgit v1.2.3 From 1301a8ad57672ae48afddf31d4951222ef8b5ff0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:39:15 -0500 Subject: Reorganizing the uses_pagination decorator a little and having it pass in the page number to the view --- mediagoblin/decorators.py | 6 ++---- mediagoblin/user_pages/views.py | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 161d99ff..8f107b6f 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -52,14 +52,12 @@ def uses_pagination(controller): """ def wrapper(request, *args, **kwargs): try: - page = int(request.str_GET['page']) + page = int(request.GET.get('page', 1)) if page < 0: return exc.HTTPNotFound() except ValueError: return exc.HTTPNotFound() - except KeyError: - request.str_GET['page'] = 1 - return controller(request, *args, **kwargs) + return controller(request, page, *args, **kwargs) return _make_safe(wrapper,controller) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index d8665915..f50f11af 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -20,8 +20,9 @@ from mediagoblin.util import Pagination from mediagoblin.decorators import uses_pagination + @uses_pagination -def user_home(request): +def user_home(request, page): """'Homepage' of a User()""" user = request.db.User.find_one({ 'username': request.matchdict['user'], @@ -32,9 +33,8 @@ def user_home(request): cursor = request.db.MediaEntry \ .find({'uploader': user, 'state': 'processed'}) \ .sort('created', DESCENDING) - - pagination = Pagination( int(request.str_GET['page']), cursor) + pagination = Pagination(page, cursor) media_entries = pagination() #if no data is available, return NotFound -- cgit v1.2.3 From a98d5254cbf0ed753678292cbd0eaefa284bc8c9 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:40:49 -0500 Subject: Adjusting docstrings a bit to my taste. --- mediagoblin/util.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index b05aad1d..67847de6 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -306,10 +306,12 @@ class Pagination(object): def __init__(self, page, cursor, per_page=2): """ - initializes Pagination - -- page, requested page - -- per_page, number of objects per page - -- cursor, db cursor + Initializes Pagination + + Args: + - page: requested page + - per_page: number of objects per page + - cursor: db cursor """ self.page = page self.per_page = per_page @@ -318,7 +320,7 @@ class Pagination(object): def __call__(self): """ - returns slice of objects for the requested page + Returns slice of objects for the requested page """ return self.cursor.skip((self.page-1)*self.per_page) \ .limit(self.per_page) -- cgit v1.2.3 From 140e21028b565cf4c13d05962658ad010c81dccf Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:41:27 -0500 Subject: We don't really need to use a \ here so let's not do so. --- mediagoblin/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 67847de6..867c4380 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -322,8 +322,8 @@ class Pagination(object): """ Returns slice of objects for the requested page """ - return self.cursor.skip((self.page-1)*self.per_page) \ - .limit(self.per_page) + return self.cursor.skip( + (self.page - 1) * self.per_page).limit(self.per_page) @property def pages(self): -- cgit v1.2.3 From 434b32214711c1a0920ed7d4d890c67defcbd731 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:42:38 -0500 Subject: One more mild styling tweak --- mediagoblin/user_pages/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index f50f11af..03f9907d 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -30,9 +30,9 @@ def user_home(request, page): if not user: return exc.HTTPNotFound() - cursor = request.db.MediaEntry \ - .find({'uploader': user, 'state': 'processed'}) \ - .sort('created', DESCENDING) + cursor = request.db.MediaEntry.find( + {'uploader': user, + 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) media_entries = pagination() @@ -51,6 +51,7 @@ def user_home(request, page): 'media_entries': media_entries, 'pagination': pagination})) + def media_home(request): """'Homepage' of a MediaEntry()""" media = request.db.MediaEntry.find_one({ -- cgit v1.2.3 From dffa0b0983f971f19be62d69b1759168da82477d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:44:57 -0500 Subject: Another minor formatting change. --- mediagoblin/util.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 867c4380..254245df 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -299,9 +299,10 @@ def setup_gettext(locale): class Pagination(object): """ - Pagination class, - initialization through __init__(self, cursor, page=1, per_page=2): - get actual data slice through __call__() + Pagination class for mongodb queries. + + Initialization through __init__(self, cursor, page=1, per_page=2), + get actual data slice through __call__(). """ def __init__(self, page, cursor, per_page=2): -- cgit v1.2.3 From b9e9610bfe613a421ac0c12148368dc8844e8366 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 May 2011 22:46:18 -0500 Subject: I think 30 is a good default number of items per page. --- mediagoblin/util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 254245df..d37d160e 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -297,6 +297,8 @@ def setup_gettext(locale): translations=this_gettext) +PAGINATION_DEFAULT_PER_PAGE = 30 + class Pagination(object): """ Pagination class for mongodb queries. @@ -305,7 +307,7 @@ class Pagination(object): get actual data slice through __call__(). """ - def __init__(self, page, cursor, per_page=2): + def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE): """ Initializes Pagination -- cgit v1.2.3 From 90bdf3428f5943ba091e5c1e96c9bd00afca21a2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 17:36:29 -0500 Subject: pass in page number in uses_pagination view via keyword argument so ordering doesn't matter. --- mediagoblin/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 8f107b6f..c594f445 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -58,6 +58,6 @@ def uses_pagination(controller): except ValueError: return exc.HTTPNotFound() - return controller(request, page, *args, **kwargs) + return controller(request, page=page, *args, **kwargs) return _make_safe(wrapper,controller) -- cgit v1.2.3 From 3c2567ac7605f996dc7619f890ceb044fd7fe77c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 17:37:50 -0500 Subject: Adjusting spacing a little bit --- mediagoblin/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index c594f445..156a745f 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -60,4 +60,4 @@ def uses_pagination(controller): return controller(request, page=page, *args, **kwargs) - return _make_safe(wrapper,controller) + return _make_safe(wrapper, controller) -- cgit v1.2.3 From 724933b154c23c8b1df23686f0d47220940aabd3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 17:47:36 -0500 Subject: MediaEntry slugs usable in URLs, & decorator that grabs media from the request --- mediagoblin/decorators.py | 26 ++++++++++++++++++++++++++ mediagoblin/user_pages/routing.py | 2 +- mediagoblin/user_pages/views.py | 13 ++++--------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 156a745f..07140831 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -17,6 +17,8 @@ from webob import exc +from mediagoblin.db.util import ObjectId + def _make_safe(decorator, original): """ @@ -61,3 +63,27 @@ def uses_pagination(controller): return controller(request, page=page, *args, **kwargs) return _make_safe(wrapper, controller) + + +def get_media_entry(controller): + """ + Pass in a MediaEntry based off of a url component + """ + def wrapper(request, *args, **kwargs): + media = request.db.MediaEntry.find_one( + {'slug': request.matchdict['media'], + 'state': 'processed'}) + + # no media via slug? Grab it via ObjectId + if not media: + media = request.db.MediaEntry.find_one( + {'_id': ObjectId(request.matchdict['media']), + 'state': 'processed'}) + + # Still no media? Okay, 404. + if not media: + return exc.HTTPNotFound() + + return controller(request, media=media, *args, **kwargs) + + return _make_safe(wrapper, controller) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 304f805f..8b535d13 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -19,6 +19,6 @@ from routes.route import Route user_routes = [ Route('mediagoblin.user_pages.user_home', "/{user}/", controller="mediagoblin.user_pages.views:user_home"), - Route('mediagoblin.user_pages.media_home', '/{user}/m/{m_id}/', + Route('mediagoblin.user_pages.media_home', '/{user}/m/{media}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), controller="mediagoblin.user_pages.views:media_home")] diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 03f9907d..87fd2ce9 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,7 +18,7 @@ from webob import Response, exc from mediagoblin.db.util import ObjectId, DESCENDING from mediagoblin.util import Pagination -from mediagoblin.decorators import uses_pagination +from mediagoblin.decorators import uses_pagination, get_media_entry @uses_pagination @@ -52,15 +52,11 @@ def user_home(request, page): 'pagination': pagination})) -def media_home(request): +@get_media_entry +def media_home(request, media): """'Homepage' of a MediaEntry()""" - media = request.db.MediaEntry.find_one({ - '_id': ObjectId(request.matchdict['m_id']), - 'state': 'processed'}) - # Check that media uploader and user correspond. - if not media or \ - media['uploader'].get('username') != request.matchdict['user']: + if media['uploader'].get('username') != request.matchdict['user']: return exc.HTTPNotFound() template = request.template_env.get_template( @@ -69,4 +65,3 @@ def media_home(request): template.render( {'request': request, 'media': media})) - -- cgit v1.2.3 From 439e37f73287efbbef8ef60492d7a8c4970a9907 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 17:48:43 -0500 Subject: Cosmetic changes: removed an unused import, stripped some trailing whitespace. --- mediagoblin/decorators.py | 2 +- mediagoblin/user_pages/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 07140831..2e7ad386 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -60,7 +60,7 @@ def uses_pagination(controller): except ValueError: return exc.HTTPNotFound() - return controller(request, page=page, *args, **kwargs) + return controller(request, page=page, *args, **kwargs) return _make_safe(wrapper, controller) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 87fd2ce9..0803749a 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -15,7 +15,7 @@ # along with this program. If not, see . from webob import Response, exc -from mediagoblin.db.util import ObjectId, DESCENDING +from mediagoblin.db.util import DESCENDING from mediagoblin.util import Pagination from mediagoblin.decorators import uses_pagination, get_media_entry -- cgit v1.2.3 From 6926b23d43323bbc214aa285948ad2850c5ad22e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 18:16:10 -0500 Subject: Added a url_for_self method for generating mediaentry links This allows for optionally making the url based off of slugs or ids --- mediagoblin/db/models.py | 18 ++++++++++++++++++ mediagoblin/templates/mediagoblin/root.html | 3 +-- .../templates/mediagoblin/utils/object_gallery.html | 3 +-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 1bc1da60..8e7889eb 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -117,6 +117,24 @@ class MediaEntry(Document): if duplicate: self['slug'] = "%s-%s" % (self['_id'], self['slug']) + def url_for_self(self, urlgen): + """ + Generate an appropriate url for ourselves + + Use a slug if we have one, else use our '_id'. + """ + if self.get('slug'): + return urlgen( + 'mediagoblin.user_pages.media_home', + user=self['uploader']['username'], + media=self['slug']) + else: + return urlgen( + 'mediagoblin.user_pages.media_home', + user=self['uploader']['username'], + media=unicode(self['_id'])) + + REGISTER_MODELS = [MediaEntry, User] diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index a93a7c75..05926687 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -44,8 +44,7 @@
      {% for entry in media_entries %}
    • - +
    • diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 8ae337f5..30497f47 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -22,8 +22,7 @@
        {% for entry in media_entries %}
      • - +
      • -- cgit v1.2.3 From 571198c938d66d2cc4d7d7a0d261633d51061968 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 18:49:04 -0500 Subject: Now you can set CELERY_ALWAYS_EAGER environment variable so that you don't have to run celeryd at the same time. This should make Elrond happy ;) --- mediagoblin/app.py | 8 +++++++- mediagoblin/celery_setup/__init__.py | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 640ffc45..714404de 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import os import urllib import routes @@ -138,7 +139,12 @@ def paste_app_factory(global_config, **app_config): raise ImproperlyConfigured( "One of direct_remote_path or direct_remote_paths must be provided") - setup_celery_from_config(app_config, global_config) + if asbool(os.environ.get('CELERY_ALWAYS_EAGER')): + setup_celery_from_config( + app_config, global_config, + force_celery_always_eager=True) + else: + setup_celery_from_config(app_config, global_config) mgoblin_app = MediaGoblinApp( connection, db, diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/celery_setup/__init__.py index 551b2741..1a77cc62 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/celery_setup/__init__.py @@ -76,6 +76,7 @@ DEFAULT_SETTINGS_MODULE = 'mediagoblin.celery_setup.dummy_settings_module' def setup_celery_from_config(app_config, global_config, settings_module=DEFAULT_SETTINGS_MODULE, + force_celery_always_eager=False, set_environ=True): """ Take a mediagoblin app config and the global config from a paste @@ -85,6 +86,7 @@ def setup_celery_from_config(app_config, global_config, - app_config: the application config section - global_config: the entire paste config, all sections - settings_module: the module to populate, as a string + - - set_environ: if set, this will CELERY_CONFIG_MODULE to the settings_module """ @@ -136,6 +138,9 @@ def setup_celery_from_config(app_config, global_config, celery_imports = celery_settings.setdefault('CELERY_IMPORTS', []) celery_imports.extend(MANDATORY_CELERY_IMPORTS) + if force_celery_always_eager: + celery_settings['CELERY_ALWAYS_EAGER'] = True + __import__(settings_module) this_module = sys.modules[settings_module] -- cgit v1.2.3 From 01674e105c4269d53453257f69f7512e8b5d40a8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 19:12:32 -0500 Subject: Make sure that a MediaEntry does belong to this appropriate user in the decorator. (Thanks Elrond) --- mediagoblin/decorators.py | 22 +++++++++++++++++----- mediagoblin/user_pages/views.py | 4 ++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 2e7ad386..34a471cb 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -15,6 +15,7 @@ # along with this program. If not, see . +from bson.errors import InvalidId from webob import exc from mediagoblin.db.util import ObjectId @@ -65,20 +66,31 @@ def uses_pagination(controller): return _make_safe(wrapper, controller) -def get_media_entry(controller): +def get_user_media_entry(controller): """ Pass in a MediaEntry based off of a url component """ def wrapper(request, *args, **kwargs): + user = request.db.User.find_one( + {'username': request.matchdict['user']}) + + if not user: + return exc.HTTPNotFound() + media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], - 'state': 'processed'}) + 'state': 'processed', + 'uploader._id': user['_id']}) # no media via slug? Grab it via ObjectId if not media: - media = request.db.MediaEntry.find_one( - {'_id': ObjectId(request.matchdict['media']), - 'state': 'processed'}) + try: + media = request.db.MediaEntry.find_one( + {'_id': ObjectId(request.matchdict['media']), + 'state': 'processed', + 'uploader._id': user['_id']}) + except InvalidId: + return exc.HTTPNotFound() # Still no media? Okay, 404. if not media: diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 0803749a..4a570579 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,7 +18,7 @@ from webob import Response, exc from mediagoblin.db.util import DESCENDING from mediagoblin.util import Pagination -from mediagoblin.decorators import uses_pagination, get_media_entry +from mediagoblin.decorators import uses_pagination, get_user_media_entry @uses_pagination @@ -52,7 +52,7 @@ def user_home(request, page): 'pagination': pagination})) -@get_media_entry +@get_user_media_entry def media_home(request, media): """'Homepage' of a MediaEntry()""" # Check that media uploader and user correspond. -- cgit v1.2.3 From 5487efc4016da577796579797812f1753c55a6de Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 19:12:44 -0500 Subject: This check is redundant now that it's handled by the decorator. --- mediagoblin/user_pages/views.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 4a570579..0d9833cd 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -55,10 +55,6 @@ def user_home(request, page): @get_user_media_entry def media_home(request, media): """'Homepage' of a MediaEntry()""" - # Check that media uploader and user correspond. - if media['uploader'].get('username') != request.matchdict['user']: - return exc.HTTPNotFound() - template = request.template_env.get_template( 'mediagoblin/user_pages/media.html') return Response( -- cgit v1.2.3 From 2aa3bb1154758f7c5445985de2f0d4a00c6d78dc Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 20 May 2011 20:20:33 -0400 Subject: Moves virtualenv instructions to a place far far away But seriously, moved them to the stop-gap wiki: https://gitorious.org/mediagoblin/pages/HackingWithVirtualenv --- docs/hackinghowto.rst | 136 ++++++-------------------------------------------- 1 file changed, 15 insertions(+), 121 deletions(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index bf5278b3..939c9510 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -4,7 +4,6 @@ Hacking HOWTO =============== - So you want to hack on GNU MediaGoblin? ======================================= @@ -26,12 +25,9 @@ new things. Third you'll need to :ref:`get the requirements `. -Fourth, you'll need to build a development environment. For this step, there are two options: - -1. :ref:`buildout and bootstrap ` (easier) OR -2. :ref:`virtualenv ` (more flexible, but harder) - -Pick one---don't do both! +Fourth, you'll need to build a development environment. We use buildout, +but if you want to use virtualenv, there's a set of mediocre not-very-supported +steps in the `wiki `_. .. _get-requirements-section: @@ -65,15 +61,10 @@ requirements:: .. _hacking-with-buildout: + How to set up and maintain an environment for hacking with buildout =================================================================== -.. Note:: - - Either follow the instructions in this section OR follow the ones - in :ref:`hacking-with-virtualenv`. But don't do both! - - **Requirements** No additional requirements. @@ -124,104 +115,14 @@ To do this, do:: rm -rf bin develop-eggs eggs mediagoblin.egg-info parts user_dev -Usually buildout works pretty great and is super easy, but if you get -problems with python-dateutil conflicts on your system, you may need -to use virtualenv instead. - - -.. _hacking-with-virtualenv: - -How to set up and maintain an environment for hacking with virtualenv -===================================================================== - -.. Note:: - - Either follow the instructions in this section OR follow the ones - in :ref:`hacking-with-buildout`. But don't do both! - - -**Requirements** - -* virtualenv: http://pypi.python.org/pypi/virtualenv -* virtualenv wrapper: - http://www.doughellmann.com/projects/virtualenvwrapper/ (be sure to - read the `install instructions - `_) - - -**Create a development environment** - -1. Clone the repository:: - - git clone http://git.gitorious.org/mediagoblin/mediagoblin.git - -2. Create a virtual environment:: - - mkvirtualenv --no-site-packages mediagoblin - -3. If that doesn't put you in the virutal environment you just - created, then do:: - - workon mediagoblin - -4. Run:: - - python setup.py develop - -That's it! - - -**Activating a virtual environment** - -When you want to work on GNU MediaGoblin, you need to activate the -virtual environment like this:: - - workon mediagoblin - - -**Deactivating a virtual environment** - -If you want to deactivate it, you can do this:: - - deactivate - - -**Updating a virtual environment with dependency changes** - -1. Enter the virtual environment. - -2. Run:: - - python setup.py develop - - -**Updating a virtual environment with code changes** - -You don't need to do anything---code changes are automatically -available. - - -**Deleting a virtual environment** - -At some point you may want to delete your virtual environment. -Perhaps it's to start over. Perhaps it's so you can test building -development environments with virtualenv. - -To do this, do:: - - rmvirtualenv mediagoblin - Running the server ================== -If you did buildout, run:: +Run:: ./bin/paster serve mediagoblin.ini --reload -If you did virtualenv, run:: - - paster serve mediagoblin.ini --reload Running celeryd =============== @@ -230,39 +131,29 @@ You need to do this if you want your media to process and actually show up. It's probably a good idea in development to have the web server (above) running in one terminal and celeryd in another window. -If you did buildout, run:: +Run:: CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd -If you did virtualenv, run:: - - CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery celeryd Running the test suite ====================== -If you did buildout, run:: +Run:: ./bin/nosetests -If you did virtualenv, run:: - - nosetests Running a shell =============== If you want a shell with your database pre-setup and an instantiated -application ready and at your fingertips... +application ready and at your fingertips.... -If you did buildout, run:: +Run:: ./bin/gmg shell -If you did virtualenv, run:: - - gmg shell - Troubleshooting =============== @@ -276,7 +167,8 @@ If you see this:: then make sure mongodb is installed and running. -If it's installed, check the mongodb log. On my machine, that's ``/var/log/mongodb/mongodb.log``. If you see something like:: +If it's installed, check the mongodb log. On my machine, that's +``/var/log/mongodb/mongodb.log``. If you see something like:: old lock file: /var/lib/mongodb/mongod.lock. probably means... @@ -398,6 +290,8 @@ getting the hang of it: it easier to get the hang of git if you're coming from other version control systems +There's also a git mission at `OpenHatch `_. + Learning other utilities ------------------------ @@ -406,5 +300,5 @@ The `OpenHatch `_ site has a series of `training missions `_ which are designed to help you learn how to use these tools. -If you're new to tar, diff and patch, we highly recommend you sign up -with OpenHatch and do the missions. +If you're new to tar, diff, patch and git, we highly recommend you sign +up with OpenHatch and do the missions. -- cgit v1.2.3 From 693b674ce094b27a8f562bf55d7695302257cc82 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 19:34:28 -0500 Subject: Added some stuff on how to run CELERY_ALWAYS_EAGER --- docs/hackinghowto.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 939c9510..8974b31d 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -136,6 +136,16 @@ Run:: CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd +Too much work? Don't want to run an http server and celeryd at the +same time? For development purposes there's a shortcut:: + + CELERY_ALWAYS_EAGER=true ./bin/paster serve mediagoblin.ini --reload + +This way the web server will block on processing items until they are +done, but you don't need to run celery separately (which is probably +good enough for development purposes). + + Running the test suite ====================== -- cgit v1.2.3 From c0bf3c807b1e5a88238e551eaa1491b51af3914d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 20 May 2011 19:35:11 -0500 Subject: Clarified: don't do this in production! --- docs/hackinghowto.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 8974b31d..3544ec92 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -143,7 +143,8 @@ same time? For development purposes there's a shortcut:: This way the web server will block on processing items until they are done, but you don't need to run celery separately (which is probably -good enough for development purposes). +good enough for development purposes, but something you almost +certainly shouldn't do in production). Running the test suite -- cgit v1.2.3 From 0e84c707cb57b864fff4bdd438644c4313677893 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 21 May 2011 16:38:34 +0200 Subject: Give Pagination.get_page_url() a request instead of path and GET Makes calling Pagination.get_page_url() much simpler. --- mediagoblin/templates/mediagoblin/utils/pagination.html | 9 +++------ mediagoblin/util.py | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index b74cbfcf..5ca5e09b 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -21,15 +21,13 @@ {% endif %} diff --git a/mediagoblin/util.py b/mediagoblin/util.py index d37d160e..a1af7bd0 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -29,8 +29,6 @@ from mediagoblin import globals as mgoblin_globals import urllib from math import ceil import copy -import decorators -from webob import exc TESTS_ENABLED = False def _activate_testing(): @@ -353,11 +351,13 @@ class Pagination(object): yield num last = num - def get_page_url(self, path_info, page_no, get_params=None): + def get_page_url(self, request, page_no): """ - Get a new page based of the path_info, the new page number, + Get a new page based of the request, the new page number, and existing get parameters. """ + path_info = request.path_info + get_params = request.GET new_get_params = copy.copy(get_params or {}) new_get_params['page'] = page_no return "%s?%s" % ( -- cgit v1.2.3 From 538a06e986a4ebebf5f670dd3d5af9ddb9501649 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 21 May 2011 17:02:49 +0200 Subject: Fix doc string of get_page_url() --- mediagoblin/util.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index a1af7bd0..f56bea43 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -353,8 +353,7 @@ class Pagination(object): def get_page_url(self, request, page_no): """ - Get a new page based of the request, the new page number, - and existing get parameters. + Get a new page url based of the request, and the new page number. """ path_info = request.path_info get_params = request.GET @@ -362,4 +361,3 @@ class Pagination(object): new_get_params['page'] = page_no return "%s?%s" % ( path_info, urllib.urlencode(new_get_params)) - -- cgit v1.2.3 From dbb92c602075c768d88d0c21b774d75203af3fc1 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 09:25:51 -0500 Subject: Move the ./bin/gmg shell command into its own module. --- mediagoblin/gmg_commands/__init__.py | 58 ++---------------------------- mediagoblin/gmg_commands/shell.py | 70 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 55 deletions(-) create mode 100644 mediagoblin/gmg_commands/shell.py diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 04e2ab6c..e585785c 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -14,71 +14,19 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import code import argparse -import os -from paste.deploy.loadwsgi import NicerConfigParser - -from mediagoblin.celery_setup import setup_celery_from_config -from mediagoblin import app, util -from mediagoblin import globals as mgoblin_globals +from mediagoblin import util SUBCOMMAND_MAP = { 'shell': { - 'setup': 'mediagoblin.gmg_commands:shell_parser_setup', - 'func': 'mediagoblin.gmg_commands:shell', + 'setup': 'mediagoblin.gmg_commands.shell:shell_parser_setup', + 'func': 'mediagoblin.gmg_commands.shell:shell', 'help': 'Run a shell with some tools pre-setup'}, } -def shell_parser_setup(subparser): - subparser.add_argument( - '-cf', '--conf_file', default='mediagoblin.ini', - help="Config file used to set up environment") - subparser.add_argument( - '-cs', '--app_section', default='app:mediagoblin', - help="Section of the config file where the app config is stored.") - - -SHELL_BANNER = """\ -GNU MediaGoblin shell! ----------------------- -Available vars: - - mgoblin_app: instantiated mediagoblin application - - mgoblin_globals: mediagoblin.globals - - db: database instance -""" - - -def shell(args): - """ - """ - # Duplicated from from_celery.py, remove when we have the generic util - parser = NicerConfigParser(args.conf_file) - parser.read(args.conf_file) - parser._defaults.setdefault( - 'here', os.path.dirname(os.path.abspath(args.conf_file))) - parser._defaults.setdefault( - '__file__', os.path.abspath(args.conf_file)) - - mgoblin_section = dict(parser.items(args.app_section)) - mgoblin_conf = dict( - [(section_name, dict(parser.items(section_name))) - for section_name in parser.sections()]) - - mgoblin_app = app.paste_app_factory( - mgoblin_conf, **mgoblin_section) - - code.interact( - banner=SHELL_BANNER, - local={ - 'mgoblin_app': mgoblin_app, - 'mgoblin_globals': mgoblin_globals, - 'db': mgoblin_globals.database}) - - def main_cli(): parser = argparse.ArgumentParser( description='GNU MediaGoblin utilities.') diff --git a/mediagoblin/gmg_commands/shell.py b/mediagoblin/gmg_commands/shell.py new file mode 100644 index 00000000..5e70d556 --- /dev/null +++ b/mediagoblin/gmg_commands/shell.py @@ -0,0 +1,70 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import code +import os + +from paste.deploy.loadwsgi import NicerConfigParser + +from mediagoblin import app +from mediagoblin import globals as mgoblin_globals + + +def shell_parser_setup(subparser): + subparser.add_argument( + '-cf', '--conf_file', default='mediagoblin.ini', + help="Config file used to set up environment") + subparser.add_argument( + '-cs', '--app_section', default='app:mediagoblin', + help="Section of the config file where the app config is stored.") + + +SHELL_BANNER = """\ +GNU MediaGoblin shell! +---------------------- +Available vars: + - mgoblin_app: instantiated mediagoblin application + - mgoblin_globals: mediagoblin.globals + - db: database instance +""" + + +def shell(args): + """ + """ + # Duplicated from from_celery.py, remove when we have the generic util + parser = NicerConfigParser(args.conf_file) + parser.read(args.conf_file) + parser._defaults.setdefault( + 'here', os.path.dirname(os.path.abspath(args.conf_file))) + parser._defaults.setdefault( + '__file__', os.path.abspath(args.conf_file)) + + mgoblin_section = dict(parser.items(args.app_section)) + mgoblin_conf = dict( + [(section_name, dict(parser.items(section_name))) + for section_name in parser.sections()]) + + mgoblin_app = app.paste_app_factory( + mgoblin_conf, **mgoblin_section) + + code.interact( + banner=SHELL_BANNER, + local={ + 'mgoblin_app': mgoblin_app, + 'mgoblin_globals': mgoblin_globals, + 'db': mgoblin_globals.database}) -- cgit v1.2.3 From 8820121ad125728613477f3dec098aa2df5f47ac Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 09:56:33 -0500 Subject: Move the general applicaiton setup commands to a utility module --- mediagoblin/gmg_commands/__init__.py | 6 ++--- mediagoblin/gmg_commands/shell.py | 22 +++--------------- mediagoblin/gmg_commands/util.py | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 22 deletions(-) create mode 100644 mediagoblin/gmg_commands/util.py diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index e585785c..9ece2ec5 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -16,7 +16,7 @@ import argparse -from mediagoblin import util +from mediagoblin import util as mg_util SUBCOMMAND_MAP = { @@ -39,8 +39,8 @@ def main_cli(): else: subparser = subparsers.add_parser(command_name) - setup_func = util.import_component(command_struct['setup']) - exec_func = util.import_component(command_struct['func']) + setup_func = mg_util.import_component(command_struct['setup']) + exec_func = mg_util.import_component(command_struct['func']) setup_func(subparser) diff --git a/mediagoblin/gmg_commands/shell.py b/mediagoblin/gmg_commands/shell.py index 5e70d556..9c0259de 100644 --- a/mediagoblin/gmg_commands/shell.py +++ b/mediagoblin/gmg_commands/shell.py @@ -16,12 +16,9 @@ import code -import os -from paste.deploy.loadwsgi import NicerConfigParser - -from mediagoblin import app from mediagoblin import globals as mgoblin_globals +from mediagoblin.gmg_commands import util as commands_util def shell_parser_setup(subparser): @@ -45,22 +42,9 @@ Available vars: def shell(args): """ + Setup a shell for the user """ - # Duplicated from from_celery.py, remove when we have the generic util - parser = NicerConfigParser(args.conf_file) - parser.read(args.conf_file) - parser._defaults.setdefault( - 'here', os.path.dirname(os.path.abspath(args.conf_file))) - parser._defaults.setdefault( - '__file__', os.path.abspath(args.conf_file)) - - mgoblin_section = dict(parser.items(args.app_section)) - mgoblin_conf = dict( - [(section_name, dict(parser.items(section_name))) - for section_name in parser.sections()]) - - mgoblin_app = app.paste_app_factory( - mgoblin_conf, **mgoblin_section) + mgoblin_app = commands_util.setup_app(args) code.interact( banner=SHELL_BANNER, diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py new file mode 100644 index 00000000..41a21a1e --- /dev/null +++ b/mediagoblin/gmg_commands/util.py @@ -0,0 +1,45 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import os + +from paste.deploy.loadwsgi import NicerConfigParser + +from mediagoblin import app + + +def setup_app(args): + """ + Setup the application after reading the mediagoblin config files + """ + # Duplicated from from_celery.py, remove when we have the generic util + parser = NicerConfigParser(args.conf_file) + parser.read(args.conf_file) + parser._defaults.setdefault( + 'here', os.path.dirname(os.path.abspath(args.conf_file))) + parser._defaults.setdefault( + '__file__', os.path.abspath(args.conf_file)) + + mgoblin_section = dict(parser.items(args.app_section)) + mgoblin_conf = dict( + [(section_name, dict(parser.items(section_name))) + for section_name in parser.sections()]) + + mgoblin_app = app.paste_app_factory( + mgoblin_conf, **mgoblin_section) + + return mgoblin_app -- cgit v1.2.3 From 757f37a52d7854ed752d56c66498383125a05a9f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 10:52:53 -0500 Subject: User migration works (but the rest of the system isn't updated for new user setup yet) --- mediagoblin/db/migrations.py | 39 +++++++++++++++++++++++++++++++ mediagoblin/db/models.py | 6 ++++- mediagoblin/gmg_commands/__init__.py | 4 ++++ mediagoblin/gmg_commands/migrate.py | 45 ++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 mediagoblin/db/migrations.py create mode 100644 mediagoblin/gmg_commands/migrate.py diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py new file mode 100644 index 00000000..d035b15b --- /dev/null +++ b/mediagoblin/db/migrations.py @@ -0,0 +1,39 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mongokit import DocumentMigration + +from mediagoblin import globals as mediagoblin_globals + + +class MediaEntryMigration(DocumentMigration): + def allmigration01_uploader_to_reference(self): + """ + Old MediaEntry['uploader'] accidentally embedded the User instead + of referencing it. Fix that! + """ + # uploader is an associative array + self.target = {'uploader': {'$type': 3}} + if not self.status: + for doc in self.collection.find(self.target): + self.update = { + '$set': { + 'uploader': doc['uploader']['_id']}} + self.collection.update( + self.target, self.update, multi=True, safe=True) + + +MIGRATE_CLASSES = ['MediaEntry'] diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 8e7889eb..3fc8d9e8 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -21,6 +21,8 @@ from mongokit import Document, Set from mediagoblin import util from mediagoblin.auth import lib as auth_lib from mediagoblin import globals as mediagoblin_globals +from mediagoblin.db import migrations +from mediagoblin.db.util import ObjectId ################### # Custom validators @@ -67,7 +69,7 @@ class MediaEntry(Document): __collection__ = 'media_entries' structure = { - 'uploader': User, + 'uploader': ObjectId, 'title': unicode, 'slug': unicode, 'created': datetime.datetime, @@ -99,6 +101,8 @@ class MediaEntry(Document): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} + migration_handler = migrations.MediaEntryMigration + # Actually we should referene uniqueness by uploader, but we # should fix http://bugs.foocorp.net/issues/340 first. # indexes = [ diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 9ece2ec5..d1f7bfc1 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -24,6 +24,10 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.shell:shell_parser_setup', 'func': 'mediagoblin.gmg_commands.shell:shell', 'help': 'Run a shell with some tools pre-setup'}, + 'migrate': { + 'setup': 'mediagoblin.gmg_commands.migrate:migrate_parser_setup', + 'func': 'mediagoblin.gmg_commands.migrate:migrate', + 'help': 'Apply all unapplied bulk migrations to the database'}, } diff --git a/mediagoblin/gmg_commands/migrate.py b/mediagoblin/gmg_commands/migrate.py new file mode 100644 index 00000000..e04fb343 --- /dev/null +++ b/mediagoblin/gmg_commands/migrate.py @@ -0,0 +1,45 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from mediagoblin.db import migrations +from mediagoblin.gmg_commands import util as commands_util +from mediagoblin import globals as mgoblin_globals + + +def migrate_parser_setup(subparser): + subparser.add_argument( + '-cf', '--conf_file', default='mediagoblin.ini', + help="Config file used to set up environment") + subparser.add_argument( + '-cs', '--app_section', default='app:mediagoblin', + help="Section of the config file where the app config is stored.") + + +def migrate(args): + mgoblin_app = commands_util.setup_app(args) + print "Applying migrations..." + + for model_name in migrations.MIGRATE_CLASSES: + model = getattr(mgoblin_app.db, model_name) + + if not hasattr(model, 'migration_handler') or not model.collection: + continue + + migration = model.migration_handler(model) + migration.migrate_all(collection=model.collection) + + print "... done." -- cgit v1.2.3 From 16509be160470202147d3b711126c7928790777d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 16:06:45 -0500 Subject: Update all the views so that they use the uploader reference instead of uploader embedding --- mediagoblin/db/models.py | 9 +++++++-- mediagoblin/decorators.py | 4 ++-- mediagoblin/submit/views.py | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- mediagoblin/user_pages/views.py | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 3fc8d9e8..37420834 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -127,17 +127,22 @@ class MediaEntry(Document): Use a slug if we have one, else use our '_id'. """ + uploader = self.uploader() + if self.get('slug'): return urlgen( 'mediagoblin.user_pages.media_home', - user=self['uploader']['username'], + user=uploader['username'], media=self['slug']) else: return urlgen( 'mediagoblin.user_pages.media_home', - user=self['uploader']['username'], + user=uploader['username'], media=unicode(self['_id'])) + def uploader(self): + return self.db.User.find_one({'_id': self['uploader']}) + REGISTER_MODELS = [MediaEntry, User] diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 34a471cb..ff3f0b5e 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -80,7 +80,7 @@ def get_user_media_entry(controller): media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], 'state': 'processed', - 'uploader._id': user['_id']}) + 'uploader': user['_id']}) # no media via slug? Grab it via ObjectId if not media: @@ -88,7 +88,7 @@ def get_user_media_entry(controller): media = request.db.MediaEntry.find_one( {'_id': ObjectId(request.matchdict['media']), 'state': 'processed', - 'uploader._id': user['_id']}) + 'uploader': user['_id']}) except InvalidId: return exc.HTTPNotFound() diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 95a416e2..262f2b12 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -46,7 +46,7 @@ def submit_start(request): entry['title'] = request.POST['title'] or unicode(splitext(filename)[0]) entry['description'] = request.POST.get('description') entry['media_type'] = u'image' # heh - entry['uploader'] = request.user + entry['uploader'] = request.user['_id'] # Save, just so we can get the entry id for the sake of using # it to generate the file path diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index e07cee44..5ccd7299 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -22,7 +22,7 @@ {% if media %}

        Media details for {{media.uploader.username}} + user= media.uploader().username) }}">{{media.uploader.username}} / {{media.title}}

        @@ -32,7 +32,7 @@
        Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, media.created.month,media.created.day)}} by {{media.uploader.username}} + user= media.uploader().username) }}">{{media.uploader.username}}
        Description: {{media.description}}
        {% else %} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 0d9833cd..41bdb402 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -31,7 +31,7 @@ def user_home(request, page): return exc.HTTPNotFound() cursor = request.db.MediaEntry.find( - {'uploader': user, + {'uploader': user['_id'], 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) -- cgit v1.2.3 From 4194b05d987d8a0dffc1c29d4d3fc706be15b386 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 16:37:58 -0500 Subject: Forgot switch to media.uploader() in the same way on two lines :P --- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 5ccd7299..3c781006 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -22,7 +22,7 @@ {% if media %}

        Media details for {{media.uploader.username}} + user= media.uploader().username) }}">{{media.uploader().username}} / {{media.title}}

        @@ -32,7 +32,7 @@
        Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, media.created.month,media.created.day)}} by {{media.uploader.username}} + user= media.uploader().username) }}">{{media.uploader().username}}
        Description: {{media.description}}
        {% else %} -- cgit v1.2.3 From cf0cc3358b2de523013a27af2ce6787e86b3932c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 16:40:31 -0500 Subject: Slightly better spacing in media.html --- .../templates/mediagoblin/user_pages/media.html | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 3c781006..036bf726 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -20,20 +20,27 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

        Media details for {{media.uploader().username}} - / {{media.title}} +

        + Media details for + + {{- media.uploader().username }} + / {{media.title}}

        - -
        Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, - media.created.month,media.created.day)}} by {{media.uploader().username}} -
        Description: {{media.description}} +
        + Uploaded on + {{ "%4d-%02d-%02d"|format(media.created.year, + media.created.month, media.created.day) }} + by + + {{- media.uploader().username }} +
        + Description: {{ media.description }}
        {% else %}

        Sorry, no such media found.

        -- cgit v1.2.3 From 50c880ac0f0d9fa90244aa8165b53a8968ae3a1a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 17:06:11 -0500 Subject: A more explicit version of get_page_url that doesn't use the request is still an option now ;) --- mediagoblin/util.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index f56bea43..2865cf11 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -351,13 +351,20 @@ class Pagination(object): yield num last = num - def get_page_url(self, request, page_no): + def get_page_url_explicit(self, base_url, get_params, page_no): """ - Get a new page url based of the request, and the new page number. + Get a page url by adding a page= parameter to the base url """ - path_info = request.path_info - get_params = request.GET new_get_params = copy.copy(get_params or {}) new_get_params['page'] = page_no return "%s?%s" % ( - path_info, urllib.urlencode(new_get_params)) + base_url, urllib.urlencode(new_get_params)) + + def get_page_url(self, request, page_no): + """ + Get a new page url based of the request, and the new page number. + + This is a nice wrapper around get_page_url_explicit() + """ + return self.get_page_url_explicit( + request.path_info, request.GET, page_no) -- cgit v1.2.3 From f4cfb4e9c8bdfdb3662417048cd6caf2fa4bcd02 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 22 May 2011 17:11:59 -0500 Subject: Encourage users to run migrations every time they buildout. --- docs/hackinghowto.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 3544ec92..a56498bb 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -96,7 +96,7 @@ While hacking on GNU MediaGoblin over time, you'll eventually have to update your development environment because the dependencies have changed. To do that, run:: - ./bin/buildout + ./bin/buildout && ./bin/gmg migrate **Updating for code changes** -- cgit v1.2.3 From 00c39256145127b9a0f34f4fdc525412065f9426 Mon Sep 17 00:00:00 2001 From: Bernhard Keller Date: Mon, 23 May 2011 19:00:46 +0200 Subject: modified atomfeed feature, corrected spacing, url generation, routing id --- mediagoblin/templates/mediagoblin/base.html | 2 ++ .../templates/mediagoblin/user_pages/user.html | 11 +++++++ mediagoblin/user_pages/routing.py | 4 ++- mediagoblin/user_pages/views.py | 34 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 4b634cf1..c4bc1364 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -20,6 +20,8 @@ {% block title %}MediaGoblin{% endblock title %} + {% block mediagoblin_head %} + {% endblock mediagoblin_head %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index d1809e80..2d09f685 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -16,6 +16,14 @@ # along with this program. If not, see . #} {% extends "mediagoblin/base.html" %} + +{% block mediagoblin_head %} + +{% endblock mediagoblin_head %} + {% block mediagoblin_content -%} {% if user %}

        User page for '{{ user.username }}'

        @@ -25,6 +33,9 @@ {% include "mediagoblin/utils/object_gallery.html" %}
      + atom feed {% else %} {# This *should* not occur as the view makes sure we pass in a user. #}

      Sorry, no such user found.

      diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 8b535d13..96f97427 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -21,4 +21,6 @@ user_routes = [ controller="mediagoblin.user_pages.views:user_home"), Route('mediagoblin.user_pages.media_home', '/{user}/m/{media}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), - controller="mediagoblin.user_pages.views:media_home")] + controller="mediagoblin.user_pages.views:media_home"), + Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/', + controller="mediagoblin.user_pages.views:atom_feed")] diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 41bdb402..cc9c7b21 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -20,6 +20,7 @@ from mediagoblin.util import Pagination from mediagoblin.decorators import uses_pagination, get_user_media_entry +from werkzeug.contrib.atom import AtomFeed @uses_pagination def user_home(request, page): @@ -61,3 +62,36 @@ def media_home(request, media): template.render( {'request': request, 'media': media})) + +ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 5 + +def atom_feed(request): + """ + generates the atom feed with the newest images + """ + + user = request.db.User.find_one({ + 'username': request.matchdict['user'], + 'status': 'active'}) + if not user: + return exc.HTTPNotFound() + + cursor = request.db.MediaEntry.find({ + 'uploader': user['_id'], + 'state': 'processed'}) \ + .sort('created', DESCENDING) \ + .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) + + feed = AtomFeed(request.matchdict['user'], + feed_url=request.url, + url=request.host_url) + + for entry in cursor: + feed.add(entry.get('title'), + entry.get('description'), + content_type='html', + author=request.matchdict['user'], + updated=entry.get('created'), + url=entry.url_for_self(request.urlgen)) + + return feed.get_response() -- cgit v1.2.3 From 76c8e34d5cf4db516becee89fbfbcde38690561a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 20 May 2011 01:26:52 +0200 Subject: Removed background images and logo, won't need those for a while --- mediagoblin/static/images/back.png | Bin 26165 -> 0 bytes mediagoblin/static/images/header_back.png | Bin 26226 -> 0 bytes mediagoblin/static/images/logo.png | Bin 58408 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mediagoblin/static/images/back.png delete mode 100644 mediagoblin/static/images/header_back.png delete mode 100644 mediagoblin/static/images/logo.png diff --git a/mediagoblin/static/images/back.png b/mediagoblin/static/images/back.png deleted file mode 100644 index 3d7fe844..00000000 Binary files a/mediagoblin/static/images/back.png and /dev/null differ diff --git a/mediagoblin/static/images/header_back.png b/mediagoblin/static/images/header_back.png deleted file mode 100644 index 3647b99d..00000000 Binary files a/mediagoblin/static/images/header_back.png and /dev/null differ diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png deleted file mode 100644 index 8d2f6272..00000000 Binary files a/mediagoblin/static/images/logo.png and /dev/null differ -- cgit v1.2.3 From a7b9c65ed52475d872f398ac8f19753cec32a69e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 23 May 2011 17:39:44 -0500 Subject: Expanded page width to 960px Conflicts: mediagoblin/static/css/base.css --- mediagoblin/static/css/base.css | 3 +- mediagoblin/static/css/base.css~ | 85 ---------------------------------------- 2 files changed, 1 insertion(+), 87 deletions(-) delete mode 100644 mediagoblin/static/css/base.css~ diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 3a8d3cdc..c66b4526 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,6 +1,5 @@ body { background-color: #272727; - background-image: url('../images/back.png'); color: #f7f7f7; font-family: sans; padding:none; @@ -45,7 +44,7 @@ label { } .mediagoblin_content { - width: 800px; + width: 960px; margin-left: auto; margin-right: auto; } diff --git a/mediagoblin/static/css/base.css~ b/mediagoblin/static/css/base.css~ deleted file mode 100644 index 4c5ae9ab..00000000 --- a/mediagoblin/static/css/base.css~ +++ /dev/null @@ -1,85 +0,0 @@ -body { - background-color: #272727; - background-image: url('back.png'); - color: #f7f7f7; - font-family: sans; - padding:none; - margin:0px; -} - -/* Carter One font */ - -@font-face { - font-family: 'Carter One'; - font-style: normal; - font-weight: normal; - src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=VjW2qt1pkqVtO22ObxgEBRsxEYwM7FgeyaSgU71cLG0') format('woff'); -} - -/* text styles */ - -h1 { - font-family: 'Carter One', arial, serif; - margin-bottom: 20px; - margin-top:50px; -} - -.dotted_line { - width:100%; - height:0px; - border-bottom: dotted 1px #5f5f5f; - position:absolute; - left:0px; - margin-top:-20px; -} - -a { - color: #d12929; - border-bottom: 1px dotted; - text-decoration: none; -} - -label { - font-weight: normal; -} - -.mediagoblin_header { - width:100%; - height:60px; - background-image:url('../images/header_back.png'); - padding-top:40px; - margin-bottom:80px; -} - -.mediagoblin_content { - width: 800px; - margin-left: auto; - margin-right: auto; -} - -.button_red, .button_green { - font-family: 'Carter One', arial, serif; - height: 28px; - min-width: 99px; - box-shadow: 0px 0px 5px #000; - border-radius: 5px; - border: none; - color: #272727; - margin: 10px; - font-size: 1em; - float: left; - display: block; - text-align: center; - padding-top: 4px; - padding-left:11px; - padding-right:11px; -} - -.button_red { - background-image: url('../images/button_red.png'); -} - -.button_green { - background-image: url('../images/button_green.png'); -} - -- cgit v1.2.3 From 265c19ae338001f718161f2fc812258ba7ff03e5 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 20 May 2011 01:31:45 +0200 Subject: Changed background colors to plain colors --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index c66b4526..523be74c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -38,7 +38,7 @@ label { .mediagoblin_header { width:100%; height:60px; - background-image:url('../images/header_back.png'); + background-color:#393939; padding-top:40px; margin-bottom:80px; } -- cgit v1.2.3 From 7e199c9c87de8feeb51287cd5770f6e830257a79 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 20 May 2011 01:33:28 +0200 Subject: Changed link color and underline --- mediagoblin/static/css/base.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 523be74c..5daab9bb 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -24,9 +24,7 @@ h1 { } a { - color: #d12929; - border-bottom: 1px dotted; - text-decoration: none; + color: #86D4B1; } label { -- cgit v1.2.3 From e83f8b3c196e04f99a6a179eda898f2f10648f7c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 25 May 2011 23:57:51 +0200 Subject: Removed clever subtitle --- mediagoblin/templates/mediagoblin/base.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index c4bc1364..d2885a5b 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -32,9 +32,6 @@ {% block mediagoblin_logo %} MediaGoblin {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} - {% block mediagoblin_header_subtitle %} - Clever subtitle here! - {% endblock %} {% if request.user %} Welcome {{ request.user['username'] }}! -- -- cgit v1.2.3 From 2f4d0584d1768f28d6031d19c44fa611250e89be Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 00:04:40 +0200 Subject: Added header icon link --- mediagoblin/static/css/base.css | 5 +++++ mediagoblin/templates/mediagoblin/base.html | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 5daab9bb..995840f8 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -41,6 +41,11 @@ label { margin-bottom:80px; } +.icon { + vertical-align:middle; + margin-right:10px; +} + .mediagoblin_content { width: 960px; margin-left: auto; diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index d2885a5b..80a63424 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -30,7 +30,7 @@

      {% block mediagoblin_logo %} - MediaGoblin + {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} {% if request.user %} Welcome {{ request.user['username'] }}! -- -- cgit v1.2.3 From d89d1bb9450c32d802fc7bead20fcb02217c5e14 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 00:05:08 +0200 Subject: Added actual image --- mediagoblin/static/images/icon.png | Bin 0 -> 960 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mediagoblin/static/images/icon.png diff --git a/mediagoblin/static/images/icon.png b/mediagoblin/static/images/icon.png new file mode 100644 index 00000000..47f07b9a Binary files /dev/null and b/mediagoblin/static/images/icon.png differ -- cgit v1.2.3 From 207219b5614c68917e0a98250cc25f048aae7af9 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 00:12:23 +0200 Subject: Changed mediagoblin_content name to mediagoblin_container --- mediagoblin/static/css/base.css | 2 +- mediagoblin/templates/mediagoblin/base.html | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 995840f8..7ce71789 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -46,7 +46,7 @@ label { margin-right:10px; } -.mediagoblin_content { +.mediagoblin_container { width: 960px; margin-left: auto; margin-right: auto; diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 80a63424..e785cfcc 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -28,10 +28,11 @@ {% block mediagoblin_body %} {% block mediagoblin_header %} {% endblock %} -- cgit v1.2.3 From 4fdd1021759bd41565fd5aba22320dd8ade72a20 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 00:41:13 +0200 Subject: We now have only one button style --- mediagoblin/static/css/base.css | 37 ++++++++------------- mediagoblin/static/images/button_green.png | Bin 2054 -> 0 bytes mediagoblin/static/images/button_red.png | Bin 1737 -> 0 bytes mediagoblin/templates/mediagoblin/auth/login.html | 4 +-- .../templates/mediagoblin/auth/register.html | 2 +- .../templates/mediagoblin/submit/start.html | 2 +- mediagoblin/templates/mediagoblin/test_submit.html | 2 +- 7 files changed, 19 insertions(+), 28 deletions(-) delete mode 100644 mediagoblin/static/images/button_green.png delete mode 100644 mediagoblin/static/images/button_red.png diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 9e5fdcce..d2bc92a0 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -56,20 +56,20 @@ label { float:right; } -.button_red, .button_green { - font-family: 'Carter One', arial, serif; - height: 28px; - min-width: 99px; - box-shadow: 0px 0px 5px #000; - border-radius: 5px; - border: none; - color: #272727; - margin: 10px; - font-size: 1em; - float: left; - display: block; - text-align: center; - padding-top: 4px; +.button { + font-family:'Carter One', arial, serif; + height:32px; + min-width:99px; + background-color:#86d4b1; + box-shadow:0px 0px 4px #000; + border-radius:5px; + border:none; + color:#272727; + margin:10px; + font-size:1em; + float:left; + display:block; + text-align:center; padding-left:11px; padding-right:11px; } @@ -84,12 +84,3 @@ label { left:0px; margin-top:-20px; } - -.button_red { - background-image: url('../images/button_red.png'); -} - -.button_green { - background-image: url('../images/button_green.png'); -} - diff --git a/mediagoblin/static/images/button_green.png b/mediagoblin/static/images/button_green.png deleted file mode 100644 index 0fc234d4..00000000 Binary files a/mediagoblin/static/images/button_green.png and /dev/null differ diff --git a/mediagoblin/static/images/button_red.png b/mediagoblin/static/images/button_red.png deleted file mode 100644 index b0f7dcad..00000000 Binary files a/mediagoblin/static/images/button_red.png and /dev/null differ diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 47b8393d..02bfb91f 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -33,12 +33,12 @@ {{ wtforms_util.render_table(login_form) }} - + {% if next %} - + {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index ee2f425b..610c7cc4 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -26,7 +26,7 @@ {{ wtforms_util.render_table(register_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 8b446417..8fdbe4ed 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -28,7 +28,7 @@ {{ wtforms_util.render_table(submit_form) }} - + diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 86cf4655..5bf8c317 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -25,7 +25,7 @@ {{ wtforms_util.render_table(image_form) }} - + -- cgit v1.2.3 From 3f139dd2595c63c01e184824c536d97aa68ee259 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 00:45:17 +0200 Subject: Changed header size --- mediagoblin/static/css/base.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d2bc92a0..c7d3d4ad 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -20,7 +20,7 @@ body { h1 { font-family: 'Carter One', arial, serif; margin-bottom: 20px; - margin-top:50px; + margin-top:40px; } a { @@ -35,10 +35,10 @@ label { .mediagoblin_header { width:100%; - height:60px; + height:36px; background-color:#393939; - padding-top:40px; - margin-bottom:80px; + padding-top:14px; + margin-bottom:40px; } .icon { -- cgit v1.2.3 From 04d7c55fc65407adbf7fee1bd2b0867c7ce99ccb Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 26 May 2011 01:24:13 +0200 Subject: Changed logout/account text --- mediagoblin/templates/mediagoblin/base.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index a0e0730d..9894f27a 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -34,9 +34,8 @@ {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %}
      {% if request.user %} - Welcome {{ request.user['username'] }}! -- - - Logout + {{ request.user['username'] }}'s account + (logout) {% else %} Login -- cgit v1.2.3 From e698dedad5a3baa73a6bc0025a77a64c384e5bd4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 26 May 2011 10:14:46 -0500 Subject: *GNU* MediaGoblin home ;) --- mediagoblin/templates/mediagoblin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index a0e0730d..b0c88a13 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -31,7 +31,7 @@
      {% block mediagoblin_logo %} - {% endblock %}{% block mediagoblin_header_title %}MediaGoblin Home{% endblock %} + {% endblock %}{% block mediagoblin_header_title %}GNU MediaGoblin Home{% endblock %}
      {% if request.user %} Welcome {{ request.user['username'] }}! -- -- cgit v1.2.3 From aba81c9f20acd0fa3fd1a31db678fccfba8777d1 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 26 May 2011 23:09:33 +0200 Subject: Starting "edit" functionality. This adds a link to the "edit" form, the form, the view for displaying the form and that's about it. --- mediagoblin/decorators.py | 20 ++++++++++++ mediagoblin/edit/__init__.py | 0 mediagoblin/edit/forms.py | 27 +++++++++++++++ mediagoblin/edit/routing.py | 22 +++++++++++++ mediagoblin/edit/views.py | 23 +++++++++++++ mediagoblin/routing.py | 2 ++ mediagoblin/templates/mediagoblin/edit/edit.html | 38 ++++++++++++++++++++++ .../templates/mediagoblin/user_pages/media.html | 3 ++ 8 files changed, 135 insertions(+) create mode 100644 mediagoblin/edit/__init__.py create mode 100644 mediagoblin/edit/forms.py create mode 100644 mediagoblin/edit/routing.py create mode 100644 mediagoblin/edit/views.py create mode 100644 mediagoblin/templates/mediagoblin/edit/edit.html diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index ff3f0b5e..fe631112 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -99,3 +99,23 @@ def get_user_media_entry(controller): return controller(request, media=media, *args, **kwargs) return _make_safe(wrapper, controller) + +def get_media_entry_by_id(controller): + """ + Pass in a MediaEntry based off of a url component + """ + def wrapper(request, *args, **kwargs): + try: + media = request.db.MediaEntry.find_one( + {'_id': ObjectId(request.matchdict['media']), + 'state': 'processed'}) + except InvalidId: + return exc.HTTPNotFound() + + # Still no media? Okay, 404. + if not media: + return exc.HTTPNotFound() + + return controller(request, media=media, *args, **kwargs) + + return _make_safe(wrapper, controller) diff --git a/mediagoblin/edit/__init__.py b/mediagoblin/edit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py new file mode 100644 index 00000000..ea25141d --- /dev/null +++ b/mediagoblin/edit/forms.py @@ -0,0 +1,27 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import wtforms + + +class EditForm(wtforms.Form): + title = wtforms.TextField( + 'Title', + [wtforms.validators.Length(min=0, max=500)]) + slug = wtforms.TextField( + 'Slug') + description = wtforms.TextAreaField('Description of this work') diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py new file mode 100644 index 00000000..d7396a60 --- /dev/null +++ b/mediagoblin/edit/routing.py @@ -0,0 +1,22 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from routes.route import Route + +edit_routes = [ + Route('mediagoblin.edit.edit_media', "/{media}/", + controller="mediagoblin.edit.views:edit_media"), +] diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py new file mode 100644 index 00000000..11dd58be --- /dev/null +++ b/mediagoblin/edit/views.py @@ -0,0 +1,23 @@ + + +from webob import Response + +from mediagoblin.edit import forms +from mediagoblin.decorators import require_active_login, get_media_entry_by_id + +@get_media_entry_by_id +@require_active_login +def edit_media(request, media): + form = forms.EditForm(request.POST, + title = media['title'], + slug = media['slug'], + description = media['description']) + + # render + template = request.template_env.get_template( + 'mediagoblin/edit/edit.html') + return Response( + template.render( + {'request': request, + 'media': media, + 'form': form})) diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index 356ef678..b854c85a 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -19,6 +19,7 @@ from routes import Mapper from mediagoblin.auth.routing import auth_routes from mediagoblin.submit.routing import submit_routes from mediagoblin.user_pages.routing import user_routes +from mediagoblin.edit.routing import edit_routes def get_mapper(): mapping = Mapper() @@ -31,5 +32,6 @@ def get_mapper(): mapping.extend(auth_routes, '/auth') mapping.extend(submit_routes, '/submit') mapping.extend(user_routes, '/u') + mapping.extend(edit_routes, '/edit') return mapping diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html new file mode 100644 index 00000000..72773cb5 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -0,0 +1,38 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} +

      Edit details for {{ media.title }}

      + +
      + + {{ wtforms_util.render_table(form) }} + + + + +
      +
      + +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 036bf726..f13c32e3 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -41,6 +41,9 @@ {{- media.uploader().username }}
      Description: {{ media.description }} +
      + Edit
      {% else %}

      Sorry, no such media found.

      -- cgit v1.2.3 From 8782001bf0002143f412e9612e97939f57d63ffe Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 26 May 2011 23:17:41 +0200 Subject: Use new button style --- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index 72773cb5..bd85f361 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -29,7 +29,7 @@ {{ wtforms_util.render_table(form) }} - + -- cgit v1.2.3 From 98857207ccb432117709f64137ca20f81635f288 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 27 May 2011 00:17:30 +0200 Subject: "edit": Finally implement saving. Currently no checks. Probably not so good. And especially, every logged in user currently can edit the data for any other user's media. --- mediagoblin/edit/views.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 11dd58be..050ece4e 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -1,6 +1,6 @@ -from webob import Response +from webob import Response, exc from mediagoblin.edit import forms from mediagoblin.decorators import require_active_login, get_media_entry_by_id @@ -13,6 +13,17 @@ def edit_media(request, media): slug = media['slug'], description = media['description']) + if request.method == 'POST' and form.validate(): + media['title'] = request.POST['title'] + media['description'] = request.POST['description'] + media['slug'] = request.POST['slug'] + media.save() + + # redirect + return exc.HTTPFound( + location=request.urlgen("mediagoblin.user_pages.media_home", + user=media.uploader()['username'], media=media['_id'])) + # render template = request.template_env.get_template( 'mediagoblin/edit/edit.html') -- cgit v1.2.3 From 8566cdda713566ef632b78388fa9016a704f6e55 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 28 May 2011 09:54:09 -0500 Subject: Added a new form rendering system, render_divs, and using it for registration --- .../templates/mediagoblin/auth/register.html | 15 +++++++------- .../templates/mediagoblin/utils/wtforms.html | 24 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index 610c7cc4..31c3d23e 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -20,14 +20,15 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} +

      Create an account!

      +
      - - {{ wtforms_util.render_table(register_form) }} - - - - -
      +
      + {{ wtforms_util.render_divs(register_form) }} +
      + +
      +
      {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 15556936..4a37ab33 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -15,6 +15,30 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . #} + +{# Auto-render a form as a series of divs #} +{% macro render_divs(form) -%} + {% for field in form %} +
      +
      {{ field.label }}
      + {% if field.description -%} +
      {{ field.description }}
      + {%- endif %} +
      {{ field }}
      + {%- if field.errors -%} +
      +
        + {% for error in field.errors %} +
      • {{ error }}
      • + {% endfor %} +
      +
      + {%- endif %} +
      + {% endfor %} +{%- endmacro %} + +{# Auto-render a form as a table #} {% macro render_table(form) -%} {% for field in form %} -- cgit v1.2.3 From 491b9109f368f06aa4032cba14518638b6b7cb5c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 18:32:43 +0200 Subject: Styled forms --- mediagoblin/static/css/base.css | 25 ++++++++++++++++++++++ .../templates/mediagoblin/auth/register.html | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index c7d3d4ad..48331554 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -84,3 +84,28 @@ label { left:0px; margin-top:-20px; } + +/* forms */ + +.form_box { + width:300px; + margin-left:auto; + margin-right:auto; + background-color:#393939; + padding:50px 83px 83px; + border-top:5px solid #d49086; + font-size:18px; +} + +.form_field_input input { + width:300px; + font-size:18px; +} + +.form_field_box { + margin-bottom:20px; +} + +.form_field_label { + margin-bottom:4px; +} diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index 31c3d23e..2ebe99ec 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -20,7 +20,7 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

      Create an account!

      +

      Create an account!

      -- cgit v1.2.3 From 9ef7c0f7376ef18e9703722b6730021c95bbdb33 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 20:43:57 +0200 Subject: Fixed form header --- mediagoblin/static/css/base.css | 8 +++++++- mediagoblin/templates/mediagoblin/auth/register.html | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 48331554..26bf8bd9 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -23,6 +23,8 @@ h1 { margin-top:40px; } +28px + a { color: #86D4B1; } @@ -92,11 +94,15 @@ label { margin-left:auto; margin-right:auto; background-color:#393939; - padding:50px 83px 83px; + padding:0px 83px 83px; border-top:5px solid #d49086; font-size:18px; } +.form_box h1 { + font-size:28px; +} + .form_field_input input { width:300px; font-size:18px; diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index 2ebe99ec..730d684d 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -20,11 +20,11 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

      Create an account!

      +

      Create an account!

      {{ wtforms_util.render_divs(register_form) }}
      -- cgit v1.2.3 From 716a0ac3f156459e9c6f6bcaab4769d2c64b4171 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 21:02:34 +0200 Subject: Styled error messages --- mediagoblin/static/css/base.css | 118 +++++++++++---------- .../templates/mediagoblin/utils/wtforms.html | 12 +-- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 26bf8bd9..618aaee0 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,9 +1,9 @@ body { - background-color: #272727; - color: #f7f7f7; - font-family: sans; - padding:none; - margin:0px; + background-color: #272727; + color: #f7f7f7; + font-family: sans; + padding:none; + margin:0px; } /* Carter One font */ @@ -18,15 +18,13 @@ body { /* text styles */ h1 { - font-family: 'Carter One', arial, serif; - margin-bottom: 20px; - margin-top:40px; + font-family: 'Carter One', arial, serif; + margin-bottom: 20px; + margin-top:40px; } -28px - a { - color: #86D4B1; + color: #86D4B1; } label { @@ -36,82 +34,90 @@ label { /* website structure */ .mediagoblin_header { - width:100%; - height:36px; - background-color:#393939; - padding-top:14px; - margin-bottom:40px; + width:100%; + height:36px; + background-color:#393939; + padding-top:14px; + margin-bottom:40px; } .icon { - vertical-align:middle; - margin-right:10px; + vertical-align:middle; + margin-right:10px; } .mediagoblin_container { - width: 960px; - margin-left: auto; - margin-right: auto; + width: 960px; + margin-left: auto; + margin-right: auto; } .mediagoblin_header_right { - float:right; + float:right; } .button { - font-family:'Carter One', arial, serif; - height:32px; - min-width:99px; - background-color:#86d4b1; - box-shadow:0px 0px 4px #000; - border-radius:5px; - border:none; - color:#272727; - margin:10px; - font-size:1em; - float:left; - display:block; - text-align:center; - padding-left:11px; - padding-right:11px; + font-family:'Carter One', arial, serif; + height:32px; + min-width:99px; + background-color:#86d4b1; + box-shadow:0px 0px 4px #000; + border-radius:5px; + border:none; + color:#272727; + margin:10px; + font-size:1em; + float:left; + display:block; + text-align:center; + padding-left:11px; + padding-right:11px; } /* common website elements */ .dotted_line { - width:100%; - height:0px; - border-bottom: dotted 1px #5f5f5f; - position:absolute; - left:0px; - margin-top:-20px; + width:100%; + height:0px; + border-bottom: dotted 1px #5f5f5f; + position:absolute; + left:0px; + margin-top:-20px; } /* forms */ .form_box { - width:300px; - margin-left:auto; - margin-right:auto; - background-color:#393939; - padding:0px 83px 83px; - border-top:5px solid #d49086; - font-size:18px; + width:300px; + margin-left:auto; + margin-right:auto; + background-color:#393939; + padding:0px 83px 83px; + border-top:5px solid #d49086; + font-size:18px; } .form_box h1 { - font-size:28px; + font-size:28px; } .form_field_input input { - width:300px; - font-size:18px; + width:300px; + font-size:18px; } .form_field_box { - margin-bottom:20px; + margin-bottom:24px; +} + +.form_field_label,.form_field_input { + margin-bottom:4px; } -.form_field_label { - margin-bottom:4px; +.form_field_error { + background-color:#87453b; + border:none; + font-size:16px; + padding:9px; + margin-top:8px; } diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 4a37ab33..9adf8e53 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -26,13 +26,11 @@ {%- endif %}
      {{ field }}
      {%- if field.errors -%} -
      -
        - {% for error in field.errors %} -
      • {{ error }}
      • - {% endfor %} -
      -
      + {% for error in field.errors %} +
      + {{ error }} +
      + {% endfor %} {%- endif %}
      {% endfor %} -- cgit v1.2.3 From b0ff25c82cdf424a54b388bb084cfd6849683662 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 21:10:54 +0200 Subject: Changed login forms to use divs instead of tables --- mediagoblin/templates/mediagoblin/auth/login.html | 30 ++++++++++------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 02bfb91f..27a3e52a 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -20,25 +20,21 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

      Login:

      - - {% if login_failed %} -

      Login failed!

      - {% endif %} - - - {{ wtforms_util.render_table(login_form) }} - - - - -
      - - {% if next %} - - {% endif %} + {% endblock %} -- cgit v1.2.3 From 7c2005b6e2fdc9665ffc5b443f6450f9d5b34b16 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 21:15:15 +0200 Subject: Forgot a bottom-margin for the error div --- mediagoblin/static/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 618aaee0..fbe84c9c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -120,4 +120,5 @@ label { font-size:16px; padding:9px; margin-top:8px; + margin-bottom:8px; } -- cgit v1.2.3 From b5cc7afea210cb1fc2e607f75d4922136ba4ecb5 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 28 May 2011 21:32:12 +0200 Subject: Fixed submit button style, added create-account notice to log in page --- mediagoblin/static/css/base.css | 8 ++++++-- mediagoblin/templates/mediagoblin/auth/login.html | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index fbe84c9c..672cc04c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -23,6 +23,11 @@ h1 { margin-top:40px; } +p { + font-family: sans; + font-size:16px; +} + a { color: #86D4B1; } @@ -67,7 +72,6 @@ label { color:#272727; margin:10px; font-size:1em; - float:left; display:block; text-align:center; padding-left:11px; @@ -92,7 +96,7 @@ label { margin-left:auto; margin-right:auto; background-color:#393939; - padding:0px 83px 83px; + padding:0px 83px 30px 83px; border-top:5px solid #d49086; font-size:18px; } diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 27a3e52a..22a57b70 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -35,6 +35,7 @@ {% if next %} {% endif %} +

      Don't have an account yet? Create one here!

      {% endblock %} -- cgit v1.2.3 From 491dd3ff47826b419764f6379474dcb859e6dcb1 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 May 2011 23:19:44 +0200 Subject: *GNU* MediaGoblin on --- mediagoblin/templates/mediagoblin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b0c88a13..3306448d 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -17,7 +17,7 @@ #} <html> <head> - <title>{% block title %}MediaGoblin{% endblock title %} + {% block title %}GNU MediaGoblin{% endblock title %} {% block mediagoblin_head %} -- cgit v1.2.3 From 00cc5cb7455e1430e5bc060d3fb2a230b5b5c562 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 May 2011 23:54:15 +0200 Subject: Changed font from 'sans' to 'sans-serif' --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 672cc04c..c62086fa 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,7 +1,7 @@ body { background-color: #272727; color: #f7f7f7; - font-family: sans; + font-family: sans-serif; padding:none; margin:0px; } -- cgit v1.2.3 From df901af738b6be18b7e8049e308f6797c21fbd92 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 May 2011 23:56:29 +0200 Subject: Changed

      font from 'sans' to 'sans-serif' --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index c62086fa..cc60d7c9 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -24,7 +24,7 @@ h1 { } p { - font-family: sans; + font-family: sans-serif; font-size:16px; } -- cgit v1.2.3 From f0e621c8f564f70517600c96880f8ca3fc60f7ff Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 29 May 2011 01:14:48 +0200 Subject: Changed submit form to divs --- mediagoblin/static/css/base.css | 4 ++++ mediagoblin/templates/mediagoblin/submit/start.html | 15 +++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index cc60d7c9..55e5a02e 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -101,6 +101,10 @@ label { font-size:18px; } +.submit_box { + width:600px; +} + .form_box h1 { font-size:28px; } diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 8fdbe4ed..75c31df4 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -20,16 +20,15 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} -

      Submit yer media

      - - {{ wtforms_util.render_table(submit_form) }} - - - - -
      +
      +

      Submit yer media

      + {{ wtforms_util.render_divs(submit_form) }} +
      + +
      +
      {% endblock %} -- cgit v1.2.3 From 722d6a970568019b8be09129f2d5b65382bccabf Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 29 May 2011 01:43:12 +0200 Subject: Modified logo to change on :hover --- mediagoblin/static/css/base.css | 12 ++++++++++-- mediagoblin/static/images/icon.png | Bin 960 -> 1670 bytes mediagoblin/templates/mediagoblin/base.html | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 55e5a02e..53efd079 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -46,9 +46,17 @@ label { margin-bottom:40px; } -.icon { - vertical-align:middle; +a.mediagoblin_logo { + width:34px; + height:25px; margin-right:10px; + background-image:url('../images/icon.png'); + background-position:0px 0px; + display:inline-block; +} + +a.mediagoblin_logo:hover { + background-position:0px -28px; } .mediagoblin_container { diff --git a/mediagoblin/static/images/icon.png b/mediagoblin/static/images/icon.png index 47f07b9a..4f4f3e9c 100644 Binary files a/mediagoblin/static/images/icon.png and b/mediagoblin/static/images/icon.png differ diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 0ba09646..704e5aa7 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -30,8 +30,8 @@
      {% block mediagoblin_logo %} - - {% endblock %}{% block mediagoblin_header_title %}GNU MediaGoblin Home{% endblock %} + + {% endblock %}{% block mediagoblin_header_title %}{% endblock %}
      {% if request.user %} {{ request.user['username'] }}'s account -- cgit v1.2.3 From 37a00748264bc47b5ceb3971622eea4858aef9dd Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 29 May 2011 01:47:12 +0200 Subject: Centered image on media page --- mediagoblin/static/css/base.css | 8 ++++++++ .../templates/mediagoblin/user_pages/media.html | 20 +++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 53efd079..5d2189c7 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -138,3 +138,11 @@ a.mediagoblin_logo:hover { margin-top:8px; margin-bottom:8px; } + +/* media pages */ + +img.media_image { + display:block; + margin-left:auto; + margin-right:auto; +} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 036bf726..475a15ff 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -20,18 +20,17 @@ {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} -

      - Media details for - - {{- media.uploader().username }} - / {{media.title}} -

      -
      -
      +

      + Media details for + + {{- media.uploader().username }} + / {{media.title}} +

      Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, media.created.month, media.created.day) }} @@ -41,7 +40,6 @@ {{- media.uploader().username }}
      Description: {{ media.description }} -
      {% else %}

      Sorry, no such media found.

      {% endif %} -- cgit v1.2.3 From d3060210bc47f0647500c3a8298ea311bf5bac32 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 29 May 2011 01:53:41 +0200 Subject: Slightly modified text on media page --- mediagoblin/templates/mediagoblin/user_pages/media.html | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 475a15ff..886962d1 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -22,25 +22,18 @@ {% if media %} -

      - Media details for - - {{- media.uploader().username }} - / {{media.title}} + {{media.title}}

      - Uploaded on +

      {{ media.description }}

      +

      Uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, media.created.month, media.created.day) }} by - {{- media.uploader().username }} -
      - Description: {{ media.description }} + {{- media.uploader().username }}

      {% else %}

      Sorry, no such media found.

      {% endif %} -{% endblock %} +{% endblock %} -- cgit v1.2.3 From dfd18edadcae821a5b6dc0bb48310e24caa796ec Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 29 May 2011 02:02:26 +0200 Subject: First changes to media gallery view --- mediagoblin/static/css/base.css | 12 ++++++++++++ mediagoblin/templates/mediagoblin/utils/object_gallery.html | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 5d2189c7..5d928b9a 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -146,3 +146,15 @@ img.media_image { margin-left:auto; margin-right:auto; } + +li.media_thumbnail { + width: 200px; + min-height: 250px; + display: -moz-inline-stack; + display: inline-block; + vertical-align: top; + margin: 5px; + zoom: 1; + *display: inline; + _height: 250px; +} diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 30497f47..c9c3e0db 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -21,7 +21,7 @@ {% if media_entries %}

        {% for entry in media_entries %} -
      • +
      • -- cgit v1.2.3 From ce72a1bb15f421725696cc3eea28b94de098f8f2 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 29 May 2011 19:15:46 +0200 Subject: this should fix #354 --- mediagoblin/auth/views.py | 13 +++++++++---- mediagoblin/db/models.py | 3 ++- mediagoblin/templates/mediagoblin/base.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index c3d24c74..8775d4c4 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import re from webob import Response, exc @@ -31,8 +32,11 @@ def register(request): if request.method == 'POST' and register_form.validate(): # TODO: Make sure the user doesn't exist already + users_with_username = \ - request.db.User.find({'username': request.POST['username']}).count() + request.db.User.find({ + 'username': request.POST['username'].lower() + }).count() if users_with_username: register_form.username.errors.append( @@ -41,7 +45,8 @@ def register(request): else: # Create the user entry = request.db.User() - entry['username'] = request.POST['username'] + entry['username'] = request.POST['username'].lower() + entry['username_repr'] = request.POST['username'] entry['email'] = request.POST['email'] entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) @@ -61,7 +66,7 @@ def register(request): # example "GNU MediaGoblin @ Wandborg - [...]". 'GNU MediaGoblin - Verify email', email_template.render( - username=entry['username'], + username=entry['username_repr'], verification_url='http://{host}{uri}?userid={userid}&token={verification_key}'.format( host=request.host, uri=request.urlgen('mediagoblin.auth.verify_email'), @@ -101,7 +106,7 @@ def login(request): if request.method == 'POST' and login_form.validate(): user = request.db.User.one( - {'username': request.POST['username']}) + {'username': request.POST['username'].lower()}) if user and user.check_login(request.POST['password']): # set up login in session diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 37420834..0b4390d7 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -38,6 +38,7 @@ class User(Document): structure = { 'username': unicode, + 'username_repr': unicode, 'email': unicode, 'created': datetime.datetime, 'plugin_data': dict, # plugins can dump stuff here. @@ -48,7 +49,7 @@ class User(Document): 'is_admin': bool, } - required_fields = ['username', 'created', 'pw_hash', 'email'] + required_fields = ['username', 'username_repr', 'created', 'pw_hash', 'email'] default_values = { 'created': datetime.datetime.utcnow, diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 704e5aa7..df803196 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -34,7 +34,7 @@ {% endblock %}{% block mediagoblin_header_title %}{% endblock %}
        {% if request.user %} - {{ request.user['username'] }}'s account + {{ request.user['username_repr'] }}'s account (logout) {% else %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 2d09f685..b9c98568 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -26,7 +26,7 @@ {% block mediagoblin_content -%} {% if user %} -

        User page for '{{ user.username }}'

        +

        User page for '{{ user.username_repr }}'

        -- cgit v1.2.3 From 03b058b78e1c27bac3dc61d8bd60801025ec0e7c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 20 Aug 2011 22:16:48 +0200 Subject: Missed one thing for Bug #464 --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 243b299c..51a855be 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -74,7 +74,7 @@ label { font-weight: normal; } -input { +input, textarea { font-size:1em; font-family:'Lato', sans-serif; } -- cgit v1.2.3 From 2ff37624ff0d19b5b0dd779e2ec1214d928554b7 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 20 Aug 2011 22:24:30 +0200 Subject: Logout -> log out --- mediagoblin/templates/mediagoblin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index e147a34b..6e54c31d 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -64,7 +64,7 @@ user= request.user['username']) }}"> {{ request.user['username'] }} - (logout) + (log out) {% else %} {% trans %}Log in{% endtrans %} -- cgit v1.2.3 From a7c641d11ed9d161648dbd4472991d5a5d06afd3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 15:43:58 -0500 Subject: Allow a user to pass in a status to render_to_response --- mediagoblin/util.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index cc426228..b588fa72 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -138,9 +138,11 @@ def clear_test_template_context(): TEMPLATE_TEST_CONTEXT = {} -def render_to_response(request, template, context): +def render_to_response(request, template, context, status=200): """Much like Django's shortcut.render()""" - return Response(render_template(request, template, context)) + return Response( + render_template(request, template, context), + status=status) def redirect(request, *args, **kwargs): -- cgit v1.2.3 From bae8f3d8c20b5724abf5ac99776ae582d0a94689 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 15:55:08 -0500 Subject: Adding and making use of the new 404 error page :) --- mediagoblin/app.py | 2 +- mediagoblin/util.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 96a7ad61..1a115a22 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -133,7 +133,7 @@ class MediaGoblinApp(object): return request.get_response(redirect)(environ, start_response) # Okay, no matches. 404 time! - return exc.HTTPNotFound()(environ, start_response) + return util.render_404(request)(environ, start_response) controller = util.import_component(route_match['controller']) request.start_response = start_response diff --git a/mediagoblin/util.py b/mediagoblin/util.py index b588fa72..0b6428da 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -348,8 +348,10 @@ def get_locale_from_request(request): accept_lang_matches = request.accept_language.best_matches() # Your routing can explicitly specify a target language - if request.matchdict.has_key('locale'): - target_lang = request.matchdict['locale'] + matchdict = request.matchdict or {} + + if matchdict.has_key('locale'): + target_lang = matchdict['locale'] elif request.session.has_key('target_lang'): target_lang = request.session['target_lang'] # Pull the first acceptable language @@ -662,3 +664,11 @@ def gridify_cursor(this_cursor, num_cols=5): the number of columns in the list """ return gridify_list(list(this_cursor), num_cols) + + +def render_404(request): + """ + Render a 404. + """ + return render_to_response( + request, 'mediagoblin/404.html', {}, status=400) -- cgit v1.2.3 From 3807e8e29c68a44140044ae7711f229dfef5af51 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 15:55:34 -0500 Subject: Tacking on an empty matchdict when 404'ing just in case a template expects it --- mediagoblin/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 1a115a22..3030929d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -133,6 +133,7 @@ class MediaGoblinApp(object): return request.get_response(redirect)(environ, start_response) # Okay, no matches. 404 time! + request.matchdict = {} # in case our template expects it return util.render_404(request)(environ, start_response) controller = util.import_component(route_match['controller']) -- cgit v1.2.3 From de12b4e77358a496bced68cbdc23bf50f95c7ee0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 15:57:24 -0500 Subject: Use render_404 EVERYWHERE! --- mediagoblin/auth/views.py | 4 ++-- mediagoblin/decorators.py | 16 ++++++++-------- mediagoblin/user_pages/views.py | 15 ++++++++------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 9120196f..4c4a34fd 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -20,7 +20,7 @@ from webob import exc from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.util import render_to_response, redirect +from mediagoblin.util import render_to_response, redirect, render_404 from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.db.util import ObjectId from mediagoblin.auth import lib as auth_lib @@ -144,7 +144,7 @@ def verify_email(request): """ # If we don't have userid and token parameters, we can't do anything; 404 if not request.GET.has_key('userid') or not request.GET.has_key('token'): - return exc.HTTPNotFound() + return render_404(request) user = request.db.User.find_one( {'_id': ObjectId(unicode(request.GET['userid']))}) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 2e90274e..c66049ca 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -17,7 +17,7 @@ from webob import exc -from mediagoblin.util import redirect +from mediagoblin.util import redirect, render_404 from mediagoblin.db.util import ObjectId, InvalidId @@ -60,9 +60,9 @@ def uses_pagination(controller): try: page = int(request.GET.get('page', 1)) if page < 0: - return exc.HTTPNotFound() + return render_404(request) except ValueError: - return exc.HTTPNotFound() + return render_404(request) return controller(request, page=page, *args, **kwargs) @@ -78,7 +78,7 @@ def get_user_media_entry(controller): {'username': request.matchdict['user']}) if not user: - return exc.HTTPNotFound() + return render_404(request) media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], @@ -93,11 +93,11 @@ def get_user_media_entry(controller): 'state': 'processed', 'uploader': user['_id']}) except InvalidId: - return exc.HTTPNotFound() + return render_404(request) # Still no media? Okay, 404. if not media: - return exc.HTTPNotFound() + return render_404(request) return controller(request, media=media, *args, **kwargs) @@ -113,11 +113,11 @@ def get_media_entry_by_id(controller): {'_id': ObjectId(request.matchdict['media']), 'state': 'processed'}) except InvalidId: - return exc.HTTPNotFound() + return render_404(request) # Still no media? Okay, 404. if not media: - return exc.HTTPNotFound() + return render_404(request) return controller(request, media=media, *args, **kwargs) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index d4ff1fce..3677c134 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -19,7 +19,8 @@ from webob import exc from mediagoblin import messages from mediagoblin.db.util import DESCENDING, ObjectId from mediagoblin.util import ( - Pagination, render_to_response, redirect, cleaned_markdown_conversion) + Pagination, render_to_response, redirect, cleaned_markdown_conversion, + render_404) from mediagoblin.user_pages import forms as user_forms from mediagoblin.decorators import (uses_pagination, get_user_media_entry, @@ -34,7 +35,7 @@ def user_home(request, page): user = request.db.User.find_one({ 'username': request.matchdict['user']}) if not user: - return exc.HTTPNotFound() + return render_404(request) elif user['status'] != u'active': return render_to_response( request, @@ -50,7 +51,7 @@ def user_home(request, page): #if no data is available, return NotFound if media_entries == None: - return exc.HTTPNotFound() + return render_404(request) user_gallery_url = request.urlgen( 'mediagoblin.user_pages.user_gallery', @@ -71,7 +72,7 @@ def user_gallery(request, page): 'username': request.matchdict['user'], 'status': 'active'}) if not user: - return exc.HTTPNotFound() + return render_404(request) cursor = request.db.MediaEntry.find( {'uploader': user['_id'], @@ -82,7 +83,7 @@ def user_gallery(request, page): #if no data is available, return NotFound if media_entries == None: - return exc.HTTPNotFound() + return render_404(request) return render_to_response( request, @@ -154,7 +155,7 @@ def atom_feed(request): 'username': request.matchdict['user'], 'status': 'active'}) if not user: - return exc.HTTPNotFound() + return render_404(request) cursor = request.db.MediaEntry.find({ 'uploader': user['_id'], @@ -190,7 +191,7 @@ def processing_panel(request): # Make sure the user exists and is active if not user: - return exc.HTTPNotFound() + return render_404(request) elif user['status'] != u'active': return render_to_response( request, -- cgit v1.2.3 From 9a91a1e7b42e1decb788ca71f5046bb835babe48 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 20 Aug 2011 23:15:00 +0200 Subject: Add 500.html page --- mediagoblin/templates/mediagoblin/500.html | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/500.html diff --git a/mediagoblin/templates/mediagoblin/500.html b/mediagoblin/templates/mediagoblin/500.html new file mode 100644 index 00000000..464630a7 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/500.html @@ -0,0 +1,49 @@ + + + + + + 500 error! GNU MediaGoblin is sorry... + + +

        YEOWCH... that's an error!

        +

        + .-------------------------.
        + |     __            _     |
        + |    -, \_,------,_//     |
        + |     <\  ,--   --.\      |
        + |      / (  X) (X  )      |
        + |      '  '--, ,--'\      |
        + |     / \ -v-v-u-v /      |
        + |     .  '.__.--__'.\     |
        + |    / ',___/ / \__/'     |
        + |    | |   ,'\_'/, ||     |
        + |    \_|   | | | | ||     |
        + |     W',_ ||| |||_''     |
        + |      |  '------'|       |
        + |      |__|     |_|_      |
        + |     ,,,-'     '-,,,     |
        + '-------------------------'
        +

        +

        Something bad happened, and things broke.

        +

        If this is not your website, you may want to alert the owner.

        +

        +

        Powered... er broken... by MediaGoblin, a GNU Project.

        + + -- cgit v1.2.3 From a01afc9a7c050d891209931c934385b68eb533d1 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 16:34:06 -0500 Subject: Changing the welcome text based on IRC conversations and marking for translation. --- mediagoblin/templates/mediagoblin/root.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 764609b6..08155c17 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -26,21 +26,25 @@

        {% trans %}Hi there, media lover! MediaGoblin is...{% endtrans %}

          -
        • The perfect place for your media! No, seriously.
        • -
        • This is just placeholder text though. In the future this will all make sense, trust me.
        • -
        • It might talk about all the awesome features we've got. Or about how great federation is.
        • -
        • Or that it's free software and a GNU project, so anyone can help improve and share it.
        • -
        • No matter what, it's probably good to have a link here. You never know.
        • +
        • {% trans %}The perfect place for your media!{% endtrans %}
        • +
        • {% trans %}A place for people to collaborate and show off original and derived creations!{% endtrans %}
        • +
        • {% trans %}Free, as in freedom. (We’re a GNU project in the making, after all.){% endtrans %}
        • +
        • {% trans %}Aiming to make the world a better place through decentralization and (eventually, coming soon!) federation!{% endtrans %}
        • +
        • {% trans %}Built for extensibility. (Multiple media types coming soon to the software, including video support!){% endtrans %}
        • +
        • {% trans %}Powered by people like you. (You can help us improve this software!){% endtrans %}
        + {% if allow_registration %}

        Excited to join us? To add your own media, make collections and save favorites...

        Create a free account or Set up MediaGoblin on your own server {% endif %}

        +
        +
        {% endif %}

        Most recent media

        -- cgit v1.2.3 From 8955ed0c599900aed144f52a1f1a9f6b5cbc018a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 16:34:18 -0500 Subject: Marking the 404 page for translation --- mediagoblin/templates/mediagoblin/404.html | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/404.html b/mediagoblin/templates/mediagoblin/404.html index 7a86a386..5af46a87 100644 --- a/mediagoblin/templates/mediagoblin/404.html +++ b/mediagoblin/templates/mediagoblin/404.html @@ -19,11 +19,16 @@ {% block mediagoblin_content %}

        {% trans %}Oops!{% endtrans %}

        -
        -

        There doesn't seem to be a page at this address. Sorry!

        -

        If you're sure the address is correct, maybe the page you're looking for has been moved or deleted.

        -
        -
        - -
        + +
        +

        {% trans %}There doesn't seem to be a page at this address. Sorry!{% endtrans %}

        +

        + {%- trans %}If you're sure the address is correct, maybe the page you're looking for has been moved or deleted.{% endtrans -%} +

        +
        + +
        + {% trans %}Image of 404 goblin stressing out{% endtrans %} +
        {% endblock %} -- cgit v1.2.3 From cd8c65133e493730d9eb4c67f691d100c845a634 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 16:48:29 -0500 Subject: Removing unused imports --- mediagoblin/gmg_commands/import_export.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index f6651327..83d64313 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -14,22 +14,17 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.gmg_commands import util as commands_util from mediagoblin import mg_globals -from mediagoblin.db import util as db_util from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.init.config import read_mediagoblin_config -from mediagoblin import util as mg_util from mediagoblin.storage import BasicFileStorage from mediagoblin.init import setup_storage, setup_global_and_app_config -import shlex import shutil import tarfile import subprocess import os.path import os -import re import sys -- cgit v1.2.3 From c02bea6fb9a87e4cbcb8d77912a92b2226b4eceb Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 21:36:08 -0500 Subject: Use "with closing(tf)" since TarFile doesn't have .__exit__() --- mediagoblin/gmg_commands/import_export.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 83d64313..fd32136c 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -26,6 +26,7 @@ import subprocess import os.path import os import sys +from contextlib import closing def import_export_parse_setup(subparser): @@ -147,7 +148,7 @@ def _create_archive(args): args.tar_file, mode='w|gz') - with tf: + with closing(tf): tf.add(args.cache_path, 'mediagoblin-data/') print "\n== Archiving done ==\n" -- cgit v1.2.3 From cc601bbd58b76ce6ee1f7b0b1e065fcd3d6ff217 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 21:59:30 -0500 Subject: Removing some print debugging from import_export --- mediagoblin/gmg_commands/import_export.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index fd32136c..b00fb1cb 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -68,9 +68,6 @@ def _import_media(db, args): media_file.write( media_cache.get_file(path, mode='rb').read()) - print(media_file) - print(entry) - print "\n== Media imported ==\n" @@ -85,8 +82,6 @@ def _import_database(db, args): '-d', db.name, os.path.join(args._cache_path['database'], db.name)]) - print p - p.wait() print "\n== Database imported ==\n" @@ -218,9 +213,6 @@ def _export_media(db, args): mc_file.write( mg_globals.public_store.get_file(path, mode='rb').read()) - print(mc_file) - print(entry) - print "\n== Media exported ==\n" -- cgit v1.2.3 From 00e381f79499b9dc5a456a24f4f012830a4c75c2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 22:00:21 -0500 Subject: Apparently we *should* _clean(args), that was commented out for debugging :) --- mediagoblin/gmg_commands/import_export.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index b00fb1cb..46a8269b 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -115,7 +115,8 @@ def env_import(args): _import_media(db, args) - # _clean(args) + _clean(args) + def _setup_paths(args): """ -- cgit v1.2.3 From 6c6009ba65b2df22b27cb6b3d83ee8c220767316 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 22:22:54 -0500 Subject: Import / export to a temporary directory if cache_path not provided. --- mediagoblin/gmg_commands/import_export.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 46a8269b..812d1486 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -22,6 +22,7 @@ from mediagoblin.init import setup_storage, setup_global_and_app_config import shutil import tarfile +import tempfile import subprocess import os.path import os @@ -43,8 +44,8 @@ def import_export_parse_setup(subparser): '--mongorestore_path', default='mongorestore', help='mongorestore binary') subparser.add_argument( - '--cache_path', default='/tmp/mediagoblin/', - help='') + '--cache_path', + help='Temporary directory where files will be temporarily dumped') def _import_media(db, args): @@ -91,6 +92,9 @@ def env_import(args): """ Restore mongo database and media files from a tar archive """ + if not args.cache_path: + args.cache_path = tempfile.mkdtemp() + # args.cache_path += 'mediagoblin-data' setup_global_and_app_config(args.conf_file) @@ -171,12 +175,6 @@ def _export_check(args): return False - if os.path.exists(args.cache_path): - print 'The cache directory must not exist before you run this script' - print 'Cache directory: ', args.cache_path - - return False - return True @@ -221,6 +219,15 @@ def env_export(args): """ Export database and media files to a tar archive """ + if args.cache_path: + if os.path.exists(args.cache_path): + print 'The cache directory must not exist before you run this script' + print 'Cache directory: ', args.cache_path + + return False + else: + args.cache_path = tempfile.mkdtemp() + args = _setup_paths(args) if not _export_check(args): -- cgit v1.2.3 From 2db2211d96ec200471af675c55ae95c1b5f4ac0d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 20 Aug 2011 22:26:45 -0500 Subject: We should use os.path.join to concatenate directories. --- mediagoblin/gmg_commands/import_export.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 812d1486..367924a5 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -95,7 +95,6 @@ def env_import(args): if not args.cache_path: args.cache_path = tempfile.mkdtemp() - # args.cache_path += 'mediagoblin-data' setup_global_and_app_config(args.conf_file) # Creates mg_globals.public_store and mg_globals.queue_store @@ -111,7 +110,8 @@ def env_import(args): tf.extractall(args.cache_path) - args.cache_path += 'mediagoblin-data' + args.cache_path = os.path.join( + args.cache_path, 'mediagoblin-data') args = _setup_paths(args) # Import database from extracted data -- cgit v1.2.3 From e3df834a8a22a45ba77940efbd083c7d5a23764e Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Sun, 21 Aug 2011 00:09:28 -0500 Subject: Bug #503 - removes inert navigation buttons - the grey X navigation buttons indicating the first and last media entries should not appear since they do not do anything --- .../templates/mediagoblin/utils/prev_next.html | 38 ++++++++-------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 7cf8d2a4..f8a746d9 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -20,27 +20,17 @@ {% set prev_entry_url = media.url_to_prev(request.urlgen) %} {% set next_entry_url = media.url_to_next(request.urlgen) %} -
        - {# There are no previous entries for the very first media entry #} - {% if prev_entry_url %} - - Previous image - - {% else %} - {# This is the first entry. display greyed-out 'previous' image #} - - {% endif %} - {# Likewise, this could be the very last media entry #} - {% if next_entry_url %} - - Next image - - {% else %} - {# This is the last entry. display greyed-out 'next' image #} - - {% endif %} -
        +{% if prev_entry_url or next_entry_url %} +
        + {% if prev_entry_url %} + + Previous image + + {% endif %} + {% if next_entry_url %} + + Next image + + {% endif %} +
        +{% endif %} -- cgit v1.2.3 From 72ae87af4a0d5a9e30db220b3ec832721b027769 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 00:09:29 -0500 Subject: Slightly wrapping paste error middleware and turning it on Now we can show a nice "borked goblin" error :) --- mediagoblin/errormiddleware.py | 53 ++++++++++++++++++++++++++++++ mediagoblin/templates/mediagoblin/500.html | 49 --------------------------- paste.ini | 12 +++++-- setup.py | 3 ++ 4 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 mediagoblin/errormiddleware.py delete mode 100644 mediagoblin/templates/mediagoblin/500.html diff --git a/mediagoblin/errormiddleware.py b/mediagoblin/errormiddleware.py new file mode 100644 index 00000000..084b3684 --- /dev/null +++ b/mediagoblin/errormiddleware.py @@ -0,0 +1,53 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from paste.exceptions.errormiddleware import make_error_middleware + +MGOBLIN_ERROR_MESSAGE = """\ +
        +

        YEOWCH... that's an error!

        +
        +.-------------------------.
        +|     __            _     |
        +|    -, \_,------,_//     |
        +|     <\  ,--   --.\      |
        +|      / (  X) (X  )      |
        +|      '  '--, ,--'\      |
        +|     / \ -v-v-u-v /      |
        +|     .  '.__.--__'.\     |
        +|    / ',___/ / \__/'     |
        +|    | |   ,'\_'/, ||     |
        +|    \_|   | | | | ||     |
        +|     W',_ ||| |||_''     |
        +|      |  '------'|       |
        +|      |__|     |_|_      |
        +|     ,,,-'     '-,,,     |
        +'-------------------------'
        +  
        +

        Something bad happened, and things broke.

        +

        If this is not your website, you may want to alert the owner.

        +

        +

        + Powered... er broken... by + MediaGoblin, + a GNU Project. +

        +
        """ + + +def mgoblin_error_middleware(app, global_conf, **kw): + kw['error_message'] = MGOBLIN_ERROR_MESSAGE + return make_error_middleware(app, global_conf, **kw) diff --git a/mediagoblin/templates/mediagoblin/500.html b/mediagoblin/templates/mediagoblin/500.html deleted file mode 100644 index 464630a7..00000000 --- a/mediagoblin/templates/mediagoblin/500.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - 500 error! GNU MediaGoblin is sorry... - - -

        YEOWCH... that's an error!

        -

        - .-------------------------.
        - |     __            _     |
        - |    -, \_,------,_//     |
        - |     <\  ,--   --.\      |
        - |      / (  X) (X  )      |
        - |      '  '--, ,--'\      |
        - |     / \ -v-v-u-v /      |
        - |     .  '.__.--__'.\     |
        - |    / ',___/ / \__/'     |
        - |    | |   ,'\_'/, ||     |
        - |    \_|   | | | | ||     |
        - |     W',_ ||| |||_''     |
        - |      |  '------'|       |
        - |      |__|     |_|_      |
        - |     ,,,-'     '-,,,     |
        - '-------------------------'
        -

        -

        Something bad happened, and things broke.

        -

        If this is not your website, you may want to alert the owner.

        -

        -

        Powered... er broken... by MediaGoblin, a GNU Project.

        - - diff --git a/paste.ini b/paste.ini index 73fbe8e8..fc459989 100644 --- a/paste.ini +++ b/paste.ini @@ -1,7 +1,11 @@ [DEFAULT] -debug = true +# Set to true to enable web-based debugging messages and etc. +debug = false -[composite:main] +[pipeline:main] +pipeline = errors routing + +[composite:routing] use = egg:Paste#urlmap / = mediagoblin /mgoblin_media/ = publicstore_serve @@ -28,6 +32,10 @@ beaker.session.key = mediagoblin beaker.session.data_dir = %(here)s/user_dev/beaker/sessions/data beaker.session.lock_dir = %(here)s/user_dev/beaker/sessions/lock +[filter:errors] +use = egg:mediagoblin#errors +debug = false + [server:main] use = egg:Paste#http host = 127.0.0.1 diff --git a/setup.py b/setup.py index 40715dd0..d6ef584b 100644 --- a/setup.py +++ b/setup.py @@ -58,6 +58,9 @@ setup( [paste.app_factory] app = mediagoblin.app:paste_app_factory + [paste.filter_app_factory] + errors = mediagoblin.errormiddleware:mgoblin_error_middleware + [zc.buildout] make_user_dev_dirs = mediagoblin.buildout_recipes:MakeUserDevDirs -- cgit v1.2.3 From 9ac7371712c73c7b2e5d0abd2b495959745e8e2f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 00:11:54 -0500 Subject: Better derp eyes for a 500 error in the ascii art :) --- mediagoblin/errormiddleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/errormiddleware.py b/mediagoblin/errormiddleware.py index 084b3684..2f14fdd5 100644 --- a/mediagoblin/errormiddleware.py +++ b/mediagoblin/errormiddleware.py @@ -24,7 +24,7 @@ MGOBLIN_ERROR_MESSAGE = """\ | __ _ | | -, \_,------,_// | | <\ ,-- --.\ | -| / ( X) (X ) | +| / (x ) ( X ) | | ' '--, ,--'\ | | / \ -v-v-u-v / | | . '.__.--__'.\ | -- cgit v1.2.3 From ae72c6381475408d83bfcf702c8eed7d4d80c1f5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 00:24:47 -0500 Subject: Added a docstring to mgoblin_error_middleware --- mediagoblin/errormiddleware.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mediagoblin/errormiddleware.py b/mediagoblin/errormiddleware.py index 2f14fdd5..352dc891 100644 --- a/mediagoblin/errormiddleware.py +++ b/mediagoblin/errormiddleware.py @@ -49,5 +49,12 @@ MGOBLIN_ERROR_MESSAGE = """\ def mgoblin_error_middleware(app, global_conf, **kw): + """ + MediaGoblin wrapped error middleware. + + This is really just wrapping the error middleware from Paste. + It should take all of Paste's default options, so see: + http://pythonpaste.org/modules/exceptions.html + """ kw['error_message'] = MGOBLIN_ERROR_MESSAGE return make_error_middleware(app, global_conf, **kw) -- cgit v1.2.3 From 0a100476b24d81355342cae5320e1a5a6c83014d Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Sun, 21 Aug 2011 01:03:02 -0500 Subject: only remove the inert Xs when the user has one item --- mediagoblin/templates/mediagoblin/utils/prev_next.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index f8a746d9..8c0cee02 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -22,15 +22,27 @@ {% if prev_entry_url or next_entry_url %}
        + {# There are no previous entries for the very first media entry #} {% if prev_entry_url %} Previous image + {% else %} + {# This is the first entry. display greyed-out 'previous' image #} + {% endif %} + {# Likewise, this could be the very last media entry #} {% if next_entry_url %} Next image + {% else %} + {# This is the last entry. display greyed-out 'next' image #} + {% endif %}
        {% endif %} -- cgit v1.2.3 From 63c9a0c766559ddd9bea79a03499040a0f3f9853 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 15:14:45 -0500 Subject: Updating tests for new storage config code --- mediagoblin/tests/test_mgoblin_app.ini | 10 +++++++--- mediagoblin/tests/test_storage.py | 21 +++++++++------------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 7716e9ca..0109d751 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -1,7 +1,4 @@ [mediagoblin] -queuestore_base_dir = %(here)s/test_user_dev/media/queue -publicstore_base_dir = %(here)s/test_user_dev/media/public -publicstore_base_url = /mgoblin_media/ direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" email_debug_mode = true @@ -15,5 +12,12 @@ tags_max_length = 50 # mediagoblin.init.celery.from_celery celery_setup_elsewhere = true +[storage:publicstore] +base_dir = %(here)s/test_user_dev/media/public +base_url = /mgoblin_media/ + +[storage:queuestore] +queuestore_base_dir = %(here)s/test_user_dev/media/queue + [celery] celery_always_eager = true diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 1800c29d..45cb35c1 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -60,23 +60,20 @@ class FakeRemoteStorage(storage.BasicFileStorage): def test_storage_system_from_config(): this_storage = storage.storage_system_from_config( - {'somestorage_base_url': 'http://example.org/moodia/', - 'somestorage_base_dir': '/tmp/', - 'somestorage_garbage_arg': 'garbage_arg', - 'garbage_arg': 'trash'}, - 'somestorage') + {'base_url': 'http://example.org/moodia/', + 'base_dir': '/tmp/', + 'garbage_arg': 'garbage_arg', + 'garbage_arg': 'trash'}) assert this_storage.base_url == 'http://example.org/moodia/' assert this_storage.base_dir == '/tmp/' assert this_storage.__class__ is storage.BasicFileStorage this_storage = storage.storage_system_from_config( - {'somestorage_foobie': 'eiboof', - 'somestorage_blech': 'hcelb', - 'somestorage_garbage_arg': 'garbage_arg', - 'garbage_arg': 'trash', - 'somestorage_storage_class': - 'mediagoblin.tests.test_storage:FakeStorageSystem'}, - 'somestorage') + {'foobie': 'eiboof', + 'blech': 'hcelb', + 'garbage_arg': 'garbage_arg', + 'storage_class': + 'mediagoblin.tests.test_storage:FakeStorageSystem'}) assert this_storage.foobie == 'eiboof' assert this_storage.blech == 'hcelb' assert this_storage.__class__ is FakeStorageSystem -- cgit v1.2.3 From abbc6c1a550d3aa8bab11fc67561e134d65ac5e6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 21:54:54 -0500 Subject: Updating the mediagoblin manual's foreward: - Removing contributors section of the foreward... we should have a contributors list, but it doesn't belong here. - Specifying that this manual is not contributor-oriented... it's for local users/administrators - Updating issue tracker link - Adjusting the "living document" line to mention http://docs.mediagoblin.org --- docs/source/foreword.rst | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/docs/source/foreword.rst b/docs/source/foreword.rst index 1d423f08..4fd96842 100644 --- a/docs/source/foreword.rst +++ b/docs/source/foreword.rst @@ -8,26 +8,19 @@ About this manual This is the GNU MediaGoblin manual. This documentation targets the following groups of individuals: -* people who want to use the software -* people who want to deploy the software -* contributors - -This manual is a living document and is in the ``mediagoblin`` -repository in the ``docs/`` directory. +* people who want to try the software locally +* people who want to deploy and administrate the software +This manual doesn't cover contributors to the codebase. But we want +and love contributors! To join as a contributor please visit the +following pages instead: -Who wrote this documentation? -============================= +* http://mediagoblin.org/pages/join.html for general "join us" information +* http://wiki.mediagoblin.org/ for our contributor-focused wiki -In no particular order: - -* Chris -* Will -* Deb -* Greg -* Karen -* Matt -* Asheesh +If you are viewing this from http://docs.mediagoblin.org be aware that +this manual is a living document and is in the ``mediagoblin`` +repository in the ``docs/`` directory. I found an error in the docs---who do I tell? @@ -35,7 +28,7 @@ I found an error in the docs---who do I tell? There are a few ways---please pick the one most convenient to you! -1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/ . +1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/projects/mediagoblin/issues 2. Tell someone on IRC ``#mediagoblin`` on Freenode. 3. Send an email to Will ``willg at bluesock dot org``. -- cgit v1.2.3 From 26924b717efe7942593c992999a792de36dc82f4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 22:23:03 -0500 Subject: Changing the MediaGoblin Sphinx docs a bit... - Removing the git guide, and moved it to the wiki - moving mediagoblin.rst to about_mediagoblin.rst --- docs/source/about_mediagoblin.rst | 70 ++++++++++++ docs/source/git.rst | 224 -------------------------------------- docs/source/index.rst | 5 +- docs/source/mediagoblin.rst | 70 ------------ 4 files changed, 72 insertions(+), 297 deletions(-) create mode 100644 docs/source/about_mediagoblin.rst delete mode 100644 docs/source/git.rst delete mode 100644 docs/source/mediagoblin.rst diff --git a/docs/source/about_mediagoblin.rst b/docs/source/about_mediagoblin.rst new file mode 100644 index 00000000..af6658f3 --- /dev/null +++ b/docs/source/about_mediagoblin.rst @@ -0,0 +1,70 @@ +================= + GNU MediaGoblin +================= + +.. contents:: Sections + :local: + + +What is GNU MediaGoblin +======================= + +Three years ago (2008), a number of free software luminaries got +together at the FSF office to answer the question, "What should +software freedom look like on the participatory web?" Those thinkers +included Richard Stallman---founder of the free software movement and +instigator of the GNU project, Evan Prodromou---the driving force +behind Status.net, a highly sucessful federated micro-blogging +service, and FIXME. + +Since that time Identi.ca and Libre.fm have answered the +freedom-loving web-user's need for micro-blogging and music sharing. +Now, GNU MediaGoblin is building a format for users to share photos. +Later versions of MediaGoblin will include support for video and other +media as well as tools to encourage collaboration on media projects. + + +Why are we doing this? +====================== + +Centralization and proprietization of media on the internet is a +serious problem and makes the web go from a system of extreme +resilience to a system of frightening fragility. We believe people +should be able to free their data from proprietary control and that +means someone has to build the tools to make it possible. We decided +that in this case, that someone would be us! + + +Who are you? +============ + +Free software activists and folks who have worked on a variety of +other projects like Libre.fm, GNU Social, Status.net, Miro, Miro +Community, OpenHatch and other projects as well. We're admirers and +contributors. We're writers and painters. We're friendly and +dedicated to computer user freedom. + + +How can I participate? +====================== + +See `Get Involved `_ on the website.. + + +How is GNU MediaGoblin licensed? +================================ + +GNU MediaGoblin software is released under an AGPLv3 license. + +See the ``COPYING`` file in the source for details. + + +Is this an official GNU Project? What does that mean? +====================================================== + +We are! It means that we meet the GNU Project's rigourous standards +for free software. To find out more about what that means, check out +`the GNU site `_. + +Please feel free to contact us with further questions! + diff --git a/docs/source/git.rst b/docs/source/git.rst deleted file mode 100644 index ab3206b6..00000000 --- a/docs/source/git.rst +++ /dev/null @@ -1,224 +0,0 @@ -========================== - Git, Cloning and Patches -========================== - -.. contents:: Sections - :local: - - -GNU MediaGoblin uses git for all our version control and we have the -repositories hosted on `Gitorious `_. We have -two repositories: - -* MediaGoblin software: http://gitorious.org/mediagoblin/mediagoblin -* MediaGoblin website: http://gitorious.org/mediagoblin/mediagoblin-website - -It's most likely you want to look at the software repository--not the -website one. - -The rest of this chapter talks about using the software repository. - - -How to clone the project -======================== - -Do:: - - git clone git://gitorious.org/mediagoblin/mediagoblin.git - - -How to contribute changes -========================= - -Tie your changes to issues in the issue tracker ------------------------------------------------ - -All patches should be tied to issues in the `issue tracker -`_. That makes -it a lot easier for everyone to track proposed changes and make sure -your hard work doesn't get dropped on the floor! If there isn't an -issue for what you're working on, please create one. The better the -description of what it is you're trying to fix/implement, the better -everyone else is able to understand why you're doing what you're -doing. - - -Use bugfix branches to make changes ------------------------------------ - -The best way to isolate your changes is to create a branch based off -of the MediaGoblin repository master branch, do the changes related to -that one issue there, and then let us know how to get it. - -It's much easier on us if you isolate your changes to a branch focused -on the issue. Then we don't have to sift through things. - -It's much easier on you if you isolate your changes to a branch -focused on the issue. Then when we merge your changes in, you just -have to do a ``git fetch`` and that's it. This is especially true if -we reject some of your changes, but accept others or otherwise tweak -your changes. - -Further, if you isolate your changes to a branch, then you can work on -multiple issues at the same time and they don't conflict with one -another. - -Name your branches using the isue number and something that makes it clear -what it's about. For example, if you were working on tagging, you -might name your branch ``360_tagging``. - - -Properly document your changes ------------------------------- - -Include comments in the code. - -Write comprehensive commit messages. The better your commit message -is at describing what you did and why, the easier it is for us to -quickly accept your patch. - -Write comprehensive comments in the issue tracker about what you're -doing and why. - - -How to send us your changes ---------------------------- - -There are two ways to let us know how to get it: - -1. *(preferred)* **push changes to publicly available git clone and - let us know where to find it** - - Push your feature/bugfix/issue branch to your publicly available - git clone and add a comment to the issue with the url for your - clone and the branch to look at. - -2. **attaching the patch files to the issue** - - Run:: - - git format-patch --stdout /master > issue_.patch - - ``format-patch`` creates a patch of all the commits that are in - your branch that aren't in ``/master``. The ``--stdout`` - flag causes all this output to go to stdout where it's redirected - to a file named ``issue_.patch``. That file should be - based on the issue you're working with. For example, - ``issue_42.patch`` is a good filename and ``issue_42_rev2.patch`` - is good if you did a revision of it. - - Having said all that, the filename isn't wildly important. - - -Example workflow -================ - -Here's an example workflow. - - -Contributing changes --------------------- - -Slartibartfast from the planet Magrathea far off in the universe has -decided that he is bored with fjords and wants to fix issue 42 (the -meaning of life bug) and send us the changes. - -Slartibartfast has cloned the MediaGoblin repository and his clone -lives on gitorious. - -Slartibartfast works locally. The remote named ``origin`` points to -his clone on gitorious. The remote named ``gmg`` points to the -MediaGoblin repository. - -Slartibartfast does the following: - -1. Fetches the latest from the MediaGoblin repository:: - - git fetch --all -p - - This tells ``git fetch`` to fetch all the recent data from all of - the remotes (``--all``) and prune any branches that have been - deleted in the remotes (``-p``). - -2. Creates a branch from the tip of the MediaGoblin repository (the - remote is named ``gmg``) master branch called ``bug42_meaning_of_life``:: - - git checkout -b bug42_meaning_of_life gmg/master - - This creates a new branch (``-b``) named ``bug42_meaning_of_life`` based - on the tip of the ``master`` branch of the remote named ``gmg`` and checks - it out. - -3. Slartibartfast works hard on his changes in the ``bug42_meaning_of_life`` - branch. When done, he wants to notify us that he has made changes - he wants us to see. - -4. Slartibartfast pushes his changes to his clone:: - - git push origin bug42_meaning_of_life --set-upstream - - This pushes the changes in the ``bug42_meaning_of_life`` branch to the - remote named ``origin``. - -5. Slartibartfast adds a comment to issue 42 with the url for his - repository and the name of the branch he put the code in. He also - explains what he did and why it addresses the issue. - - -Updating a contribution ------------------------ - -Slartibartfast brushes his hands off with the sense of accomplishment -that comes with the knowledge of a job well done. He stands, wanders -over to get a cup of water, then realizes that he forgot to run the -unit tests! - -He runs the unit tests and discovers there's a bug in the code! - -Then he does this: - -1. He checks out the ``bug42_meaning_of_life`` branch:: - - git checkout bug42_meaning_of_life - -2. He fixes the bug and checks it into the ``bug42_meaning_of_life`` branch. - -3. He pushes his changes to his clone (the remote is named ``origin``):: - - git push origin bug42_meaning_of_life - -4. He adds another comment to issue 42 explaining about the mistake - and how he fixed it and that he's pushed the new change to the - ``bug42_meaning_of_life`` branch of his publicly available clone. - - -What happens next ------------------ - -Slartibartfast is once again happy with his work. He finds issue 42 -in the issue tracker and adds a comment saying he submitted a merge -request with his changes and explains what they are. - -Later, someone checks out his code and finds a problem with it. He -adds a comment to the issue tracker specifying the problem and asks -Slartibartfast to fix it. Slartibartfst goes through the above steps -again, fixes the issue, pushes it to his ``bug42_meaning_of_life`` branch and adds -another comment to the issue tracker about how he fixed it. - -Later, someone checks out his code and is happy with it. Someone -pulls it into the master branch of the MediaGoblin repository and adds -another comment to the issue and probably closes the issue out. - -Slartibartfast is notified of this. Slartibartfast does a:: - - git fetch --all - -The changes show up in the ``master`` branch of the ``gmg`` remote. -Slartibartfast now deletes his ``bug42_meaning_of_life`` branch -because he doesn't need it anymore. - - -How to learn git -================ - -Check out `the wiki `_. diff --git a/docs/source/index.rst b/docs/source/index.rst index 8c00869a..79f2653e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,11 +12,10 @@ Table of Contents: :maxdepth: 2 foreword - mediagoblin - contributinghowto + about_mediagoblin deploymenthowto theminghowto - git + contributinghowto codebase vision diff --git a/docs/source/mediagoblin.rst b/docs/source/mediagoblin.rst deleted file mode 100644 index af6658f3..00000000 --- a/docs/source/mediagoblin.rst +++ /dev/null @@ -1,70 +0,0 @@ -================= - GNU MediaGoblin -================= - -.. contents:: Sections - :local: - - -What is GNU MediaGoblin -======================= - -Three years ago (2008), a number of free software luminaries got -together at the FSF office to answer the question, "What should -software freedom look like on the participatory web?" Those thinkers -included Richard Stallman---founder of the free software movement and -instigator of the GNU project, Evan Prodromou---the driving force -behind Status.net, a highly sucessful federated micro-blogging -service, and FIXME. - -Since that time Identi.ca and Libre.fm have answered the -freedom-loving web-user's need for micro-blogging and music sharing. -Now, GNU MediaGoblin is building a format for users to share photos. -Later versions of MediaGoblin will include support for video and other -media as well as tools to encourage collaboration on media projects. - - -Why are we doing this? -====================== - -Centralization and proprietization of media on the internet is a -serious problem and makes the web go from a system of extreme -resilience to a system of frightening fragility. We believe people -should be able to free their data from proprietary control and that -means someone has to build the tools to make it possible. We decided -that in this case, that someone would be us! - - -Who are you? -============ - -Free software activists and folks who have worked on a variety of -other projects like Libre.fm, GNU Social, Status.net, Miro, Miro -Community, OpenHatch and other projects as well. We're admirers and -contributors. We're writers and painters. We're friendly and -dedicated to computer user freedom. - - -How can I participate? -====================== - -See `Get Involved `_ on the website.. - - -How is GNU MediaGoblin licensed? -================================ - -GNU MediaGoblin software is released under an AGPLv3 license. - -See the ``COPYING`` file in the source for details. - - -Is this an official GNU Project? What does that mean? -====================================================== - -We are! It means that we meet the GNU Project's rigourous standards -for free software. To find out more about what that means, check out -`the GNU site `_. - -Please feel free to contact us with further questions! - -- cgit v1.2.3 From 7a8ad8187c22f96604fda3a9a63f2b0e70d3aca0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 23:02:21 -0500 Subject: MediaGoblin favicon by Alex Camelio!!! OMG. --- mediagoblin/static/images/goblin.ico | Bin 0 -> 318 bytes mediagoblin/static/images/goblin.png | Bin 0 -> 413 bytes mediagoblin/templates/mediagoblin/base.html | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 mediagoblin/static/images/goblin.ico create mode 100644 mediagoblin/static/images/goblin.png diff --git a/mediagoblin/static/images/goblin.ico b/mediagoblin/static/images/goblin.ico new file mode 100644 index 00000000..f2e7152f Binary files /dev/null and b/mediagoblin/static/images/goblin.ico differ diff --git a/mediagoblin/static/images/goblin.png b/mediagoblin/static/images/goblin.png new file mode 100644 index 00000000..0a3ad22e Binary files /dev/null and b/mediagoblin/static/images/goblin.png differ diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 6e54c31d..91b434c1 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -28,6 +28,8 @@ href="{{ request.staticdirect('/css/extlib/960_16_col.css') }}"/> + {% block mediagoblin_head %} {% endblock mediagoblin_head %} -- cgit v1.2.3 From ec451724ccd436f758fabb67e1e872f002acf4d5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 23:10:12 -0500 Subject: Add titles to media entries in galleries --- mediagoblin/static/css/base.css | 5 +++++ mediagoblin/templates/mediagoblin/utils/object_gallery.html | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 51a855be..af8f7763 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -244,6 +244,11 @@ text-align: center; text-align: center; } +.media_thumbnail a { + color: #eee; + text-decoration: none; +} + /* media detail */ h2.media_title{ diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index b451946d..34eb7dbc 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -25,13 +25,18 @@ {%- if loop.first %} thumb_row_first {%- elif loop.last %} thumb_row_last{% endif %}"> {% for entry in row %} + {% set entry_url = entry.url_for_self(request.urlgen) %} - + + {% if entry['title'] %} +
        + {{ entry['title'] }} + {% endif %} {% endfor %} -- cgit v1.2.3 From 970cea18dcdbfd68ad5506843504decd6826122b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 23:39:35 -0500 Subject: I think the media entries' titles look nicer if they're a bit smaller. --- mediagoblin/static/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index af8f7763..1852b70c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -242,6 +242,7 @@ text-align: center; float: left; margin: 0px 4px 10px 4px; text-align: center; + font-size: 0.875em; } .media_thumbnail a { -- cgit v1.2.3 From 9b424b17ccb6b6c034755925b14f9cfda23ad29a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 21 Aug 2011 23:39:59 -0500 Subject: Feature #506: link to original sized image if we scaled the image down. --- .../templates/mediagoblin/user_pages/media.html | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 2086d3d6..6747fddc 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -24,9 +24,24 @@ {% if media %}
        - + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} + + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media['media_files'].has_key('medium') %} + + Image for {{ media.title }} + + {% else %} + Image for {{ media.title }} + {% endif %}

        -- cgit v1.2.3 From a8327519ebcb9ea7b3b8362cda989a130a5813d1 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 22 Aug 2011 00:33:33 -0500 Subject: Experimentally putting logo in place Combining MediaGoblin eared-M logo with Thorsten's handwritten text. Well... looking nice to me :) --- mediagoblin/static/images/logo.png | Bin 0 -> 3340 bytes mediagoblin/templates/mediagoblin/base.html | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 mediagoblin/static/images/logo.png diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png new file mode 100644 index 00000000..019ec5ec Binary files /dev/null and b/mediagoblin/static/images/logo.png differ diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 91b434c1..370ec6ef 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -42,8 +42,9 @@
        {% block mediagoblin_logo %} + {% trans %}MediaGoblin logo{% endtrans %} + {% endblock %} {% if request.user and request.user['status'] == 'active' %} Date: Mon, 22 Aug 2011 02:57:40 -0700 Subject: + 'confirm' section for confirmation dialogues + implemented delete functionality * fixed several instances of 'must be an instance of unicode, not str' --- mediagoblin/auth/views.py | 11 ++++++----- mediagoblin/edit/views.py | 13 ++++++++----- mediagoblin/routing.py | 2 ++ mediagoblin/submit/views.py | 4 ++-- mediagoblin/templates/mediagoblin/user_pages/media.html | 7 +++++-- mediagoblin/user_pages/routing.py | 2 ++ mediagoblin/user_pages/views.py | 2 +- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 4c4a34fd..48c5937c 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -44,11 +44,12 @@ def register(request): if request.method == 'POST' and register_form.validate(): # TODO: Make sure the user doesn't exist already - + username = unicode(request.POST['username'].lower()) + email = unicode(request.POST['email'].lower()) users_with_username = request.db.User.find( - {'username': request.POST['username'].lower()}).count() + {'username': username}).count() users_with_email = request.db.User.find( - {'email': request.POST['email'].lower()}).count() + {'email': email}).count() extra_validation_passes = True @@ -64,8 +65,8 @@ def register(request): if extra_validation_passes: # Create the user user = request.db.User() - user['username'] = request.POST['username'].lower() - user['email'] = request.POST['email'].lower() + user['username'] = username + user['email'] = email user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) user.save(validate=True) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 0b1a98f1..2a835816 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import uuid from webob import exc from string import split @@ -53,15 +54,17 @@ def edit_media(request, media): form.slug.errors.append( _(u'An entry with that slug already exists for this user.')) else: - media['title'] = request.POST['title'] - media['description'] = request.POST.get('description') + media['title'] = unicode(request.POST['title']) + media['description'] = unicode(request.POST.get('description')) media['tags'] = convert_to_tag_list_of_dicts( request.POST.get('tags')) media['description_html'] = cleaned_markdown_conversion( media['description']) - media['slug'] = request.POST['slug'] + media['slug'] = unicode(request.POST['slug']) + task_id = unicode(uuid.uuid4()) + media['queued_task_id'] = task_id media.save() return redirect(request, "mediagoblin.user_pages.media_home", @@ -102,8 +105,8 @@ def edit_profile(request): bio = user.get('bio')) if request.method == 'POST' and form.validate(): - user['url'] = request.POST['url'] - user['bio'] = request.POST['bio'] + user['url'] = unicode(request.POST['url']) + user['bio'] = unicode(request.POST['bio']) user['bio_html'] = cleaned_markdown_conversion(user['bio']) diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index 1340da60..125f7270 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -21,6 +21,7 @@ from mediagoblin.submit.routing import submit_routes from mediagoblin.user_pages.routing import user_routes from mediagoblin.edit.routing import edit_routes from mediagoblin.listings.routing import tag_routes +from mediagoblin.confirm.routing import confirm_routes def get_mapper(): @@ -36,5 +37,6 @@ def get_mapper(): mapping.extend(user_routes, '/u') mapping.extend(edit_routes, '/edit') mapping.extend(tag_routes, '/tag') + mapping.extend(confirm_routes, '/confirm') return mapping diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1ba17954..5bcc5393 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -55,10 +55,10 @@ def submit_start(request): entry = request.db.MediaEntry() entry['_id'] = ObjectId() entry['title'] = ( - request.POST['title'] + unicode(request.POST['title']) or unicode(splitext(filename)[0])) - entry['description'] = request.POST.get('description') + entry['description'] = unicode(request.POST.get('description')) entry['description_html'] = cleaned_markdown_conversion( entry['description']) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 6747fddc..c80144aa 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -127,8 +127,11 @@ class="media_icon" />edit

        - {% trans %}delete{% endtrans %} + {% trans %}delete{% endtrans %}

        {% endif %} diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index bf9f12ab..1283355a 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -29,6 +29,8 @@ user_routes = [ controller="mediagoblin.user_pages.views:media_home"), Route('mediagoblin.edit.edit_media', "/{user}/m/{media}/edit/", controller="mediagoblin.edit.views:edit_media"), + Route('mediagoblin.confirm.confirm_delete', "/{user}/m/{media}/confirm/", + controller="mediagoblin.confirm.views:confirm_delete"), Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/', controller="mediagoblin.user_pages.views:atom_feed"), Route('mediagoblin.user_pages.media_post_comment', diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 3677c134..bb789f42 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -129,7 +129,7 @@ def media_post_comment(request): comment = request.db.MediaComment() comment['media_entry'] = ObjectId(request.matchdict['media']) comment['author'] = request.user['_id'] - comment['content'] = request.POST['comment_content'] + comment['content'] = unicode(request.POST['comment_content']) comment['content_html'] = cleaned_markdown_conversion(comment['content']) -- cgit v1.2.3 From ae4feecfc20b6c7daf54e7822dc85dba6ac0f2eb Mon Sep 17 00:00:00 2001 From: Mark Holmquist Date: Mon, 22 Aug 2011 03:35:44 -0700 Subject: * Fix bad commit (oops!) * Delete works now --- mediagoblin/confirm/__init__.py | 17 +++++++ mediagoblin/confirm/forms.py | 26 ++++++++++ mediagoblin/confirm/lib.py | 24 ++++++++++ mediagoblin/confirm/routing.py | 21 ++++++++ mediagoblin/confirm/views.py | 56 ++++++++++++++++++++++ .../mediagoblin/confirm/confirm_delete.html | 40 ++++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 mediagoblin/confirm/__init__.py create mode 100644 mediagoblin/confirm/forms.py create mode 100644 mediagoblin/confirm/lib.py create mode 100644 mediagoblin/confirm/routing.py create mode 100644 mediagoblin/confirm/views.py create mode 100644 mediagoblin/templates/mediagoblin/confirm/confirm_delete.html diff --git a/mediagoblin/confirm/__init__.py b/mediagoblin/confirm/__init__.py new file mode 100644 index 00000000..a8eeb5ed --- /dev/null +++ b/mediagoblin/confirm/__init__.py @@ -0,0 +1,17 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + diff --git a/mediagoblin/confirm/forms.py b/mediagoblin/confirm/forms.py new file mode 100644 index 00000000..4529528b --- /dev/null +++ b/mediagoblin/confirm/forms.py @@ -0,0 +1,26 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +import wtforms + +from mediagoblin.util import fake_ugettext_passthrough as _ + +class ConfirmDeleteForm(wtforms.Form): + confirm = wtforms.RadioField('Confirm', + default='False', + choices=[('False', 'No, I made a mistake!'), + ('True', 'Yes, delete it!')]) diff --git a/mediagoblin/confirm/lib.py b/mediagoblin/confirm/lib.py new file mode 100644 index 00000000..2efc3735 --- /dev/null +++ b/mediagoblin/confirm/lib.py @@ -0,0 +1,24 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +def may_delete_media(request, media): + """Check, if the request's user may edit the media details""" + if media['uploader'] == request.user['_id']: + return True + if request.user['is_admin']: + return True + return False diff --git a/mediagoblin/confirm/routing.py b/mediagoblin/confirm/routing.py new file mode 100644 index 00000000..d8c1ef22 --- /dev/null +++ b/mediagoblin/confirm/routing.py @@ -0,0 +1,21 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from routes.route import Route + +confirm_routes = [ +] diff --git a/mediagoblin/confirm/views.py b/mediagoblin/confirm/views.py new file mode 100644 index 00000000..a4a63582 --- /dev/null +++ b/mediagoblin/confirm/views.py @@ -0,0 +1,56 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import uuid + +from webob import exc +from string import split + +from mediagoblin import messages +from mediagoblin import mg_globals +from mediagoblin.util import ( + render_to_response, redirect, clean_html, convert_to_tag_list_of_dicts, + media_tags_as_string, cleaned_markdown_conversion) +from mediagoblin.util import pass_to_ugettext as _ +from mediagoblin.confirm import forms +from mediagoblin.confirm.lib import may_delete_media +from mediagoblin.decorators import require_active_login, get_user_media_entry + + +@get_user_media_entry +@require_active_login +def confirm_delete(request, media): + if not may_delete_media(request, media): + return exc.HTTPForbidden() + + form = forms.ConfirmDeleteForm(request.POST) + + if request.method == 'POST' and form.validate(): + if request.POST.get('confirm') == 'True': + username = media.uploader()['username'] + media.delete() + return redirect(request, "mediagoblin.user_pages.user_home", + user=username) + else: + return redirect(request, "mediagoblin.user_pages.media_home", + user=media.uploader()['username'], + media=media['slug']) + + return render_to_response( + request, + 'mediagoblin/confirm/confirm_delete.html', + {'media': media, + 'form': form}) diff --git a/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html b/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html new file mode 100644 index 00000000..ada89d5d --- /dev/null +++ b/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html @@ -0,0 +1,40 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} + +
        +
        +

        + {%- trans title=media['title'] -%} + Really delete {{ title }}? + {%- endtrans %} +

        + {{ wtforms_util.render_divs(form) }} +
        + +
        +
        +
        +{% endblock %} -- cgit v1.2.3 From 132aa9d97a32abfe86bc5de3ea4e2fa62ddc3793 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 22 Aug 2011 08:01:20 -0500 Subject: Removing any chance of spaces in the logo link --- mediagoblin/templates/mediagoblin/base.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 370ec6ef..32d5a5d2 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -41,10 +41,10 @@
        {% block mediagoblin_logo %} - + {% endblock %} {% if request.user and request.user['status'] == 'active' %} Date: Mon, 22 Aug 2011 18:06:28 +0200 Subject: Feature #482 - Media attachments - * Moved attachment uploading to separate view * Support for multiple attachments! --- mediagoblin/edit/forms.py | 10 ++- mediagoblin/edit/views.py | 92 +++++++++++++++++----- mediagoblin/submit/forms.py | 3 - mediagoblin/submit/views.py | 25 ------ .../templates/mediagoblin/edit/attachments.html | 55 +++++++++++++ mediagoblin/templates/mediagoblin/edit/edit.html | 9 +-- .../templates/mediagoblin/submit/start.html | 3 - .../templates/mediagoblin/user_pages/media.html | 36 +++++---- mediagoblin/user_pages/routing.py | 5 +- mediagoblin/user_pages/views.py | 5 +- 10 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/edit/attachments.html diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 37e2349c..3969e509 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -30,10 +30,6 @@ class EditForm(wtforms.Form): tags = wtforms.TextField( 'Tags', [tag_length_validator]) - attachment_name = wtforms.TextField( - 'Attachment title') - attachment_delete = wtforms.BooleanField( - 'Delete attachment') class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField('Bio', @@ -42,3 +38,9 @@ class EditProfileForm(wtforms.Form): 'Website', [wtforms.validators.Optional(), wtforms.validators.URL(message='Improperly formed URL')]) + +class EditAttachmentsForm(wtforms.Form): + attachment_name = wtforms.TextField( + 'Title') + attachment_file = wtforms.FileField( + 'File') diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 09aee48b..c4d503b7 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -17,6 +17,10 @@ from webob import exc from string import split +from cgi import FieldStorage +from datetime import datetime + +from werkzeug.utils import secure_filename from mediagoblin import messages from mediagoblin import mg_globals @@ -34,17 +38,15 @@ def edit_media(request, media): if not may_edit_media(request, media): return exc.HTTPForbidden() - defaults = dict( - title = media['title'], - slug = media['slug'], - description = media['description'], - tags = media_tags_as_string(media['tags'])) + title=media['title'], + slug=media['slug'], + description=media['description'], + tags=media_tags_as_string(media['tags'])) if len(media['attachment_files']): defaults['attachment_name'] = media['attachment_files'][0]['name'] - form = forms.EditForm( request.POST, **defaults) @@ -56,7 +58,7 @@ def edit_media(request, media): {'slug': request.POST['slug'], 'uploader': media['uploader'], '_id': {'$ne': media['_id']}}).count() - + if existing_user_slug_entries: form.slug.errors.append( u'An entry with that slug already exists for this user.') @@ -65,14 +67,16 @@ def edit_media(request, media): media['description'] = request.POST.get('description') media['tags'] = convert_to_tag_list_of_dicts( request.POST.get('tags')) - + media['description_html'] = cleaned_markdown_conversion( media['description']) if 'attachment_name' in request.POST: - media['attachment_files'][0]['name'] = request.POST['attachment_name'] + media['attachment_files'][0]['name'] = \ + request.POST['attachment_name'] - if 'attachment_delete' in request.POST and 'y' == request.POST['attachment_delete']: + if 'attachment_delete' in request.POST \ + and 'y' == request.POST['attachment_delete']: del media['attachment_files'][0] media['slug'] = request.POST['slug'] @@ -87,18 +91,68 @@ def edit_media(request, media): messages.add_message( request, messages.WARNING, "You are editing another user's media. Proceed with caution.") - return render_to_response( request, 'mediagoblin/edit/edit.html', {'media': media, 'form': form}) - + +@get_user_media_entry @require_active_login -def edit_profile(request): +def edit_attachments(request, media): + if mg_globals.app_config['allow_attachments']: + form = forms.EditAttachmentsForm() + + # Add any attachements + if ('attachment_file' in request.POST + and isinstance(request.POST['attachment_file'], FieldStorage) + and request.POST['attachment_file'].file): + + attachment_public_filepath \ + = mg_globals.public_store.get_unique_filepath( + ['media_entries', unicode(media['_id']), 'attachment', + secure_filename(request.POST['attachment_file'].filename)]) + + attachment_public_file = mg_globals.public_store.get_file( + attachment_public_filepath, 'wb') + + try: + attachment_public_file.write( + request.POST['attachment_file'].file.read()) + finally: + request.POST['attachment_file'].file.close() + + media['attachment_files'].append(dict( + name=request.POST['attachment_name'] \ + or request.POST['attachment_file'].filename, + filepath=attachment_public_filepath, + created=datetime.utcnow() + )) + media.save() + + messages.add_message( + request, messages.SUCCESS, + "You added the attachment %s!" \ + % (request.POST['attachment_name'] + or request.POST['attachment_file'].filename)) + + return redirect(request, 'mediagoblin.user_pages.media_home', + user=media.uploader()['username'], + media=media['slug']) + return render_to_response( + request, + 'mediagoblin/edit/attachments.html', + {'media': media, + 'form': form}) + else: + return exc.HTTPForbidden() + + +@require_active_login +def edit_profile(request): # admins may edit any user profile given a username in the querystring edit_username = request.GET.get('username') if request.user['is_admin'] and request.user['username'] != edit_username: @@ -112,8 +166,8 @@ def edit_profile(request): user = request.user form = forms.EditProfileForm(request.POST, - url = user.get('url'), - bio = user.get('bio')) + url=user.get('url'), + bio=user.get('bio')) if request.method == 'POST' and form.validate(): user['url'] = request.POST['url'] @@ -123,12 +177,12 @@ def edit_profile(request): user.save() - messages.add_message(request, - messages.SUCCESS, - 'Profile edited!') + messages.add_message(request, + messages.SUCCESS, + 'Profile edited!') return redirect(request, 'mediagoblin.user_pages.user_home', - user=edit_username) + user=edit_username) return render_to_response( request, diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 9b35a8c3..f02c95a6 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -28,6 +28,3 @@ class SubmitStartForm(wtforms.Form): tags = wtforms.TextField( 'Tags', [tag_length_validator]) - attachment = wtforms.FileField( - 'Attachment', - [wtforms.validators.Optional()]) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 213b2494..126cf3a8 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -76,31 +76,6 @@ def submit_start(request): # Generate a slug from the title entry.generate_slug() - # Add any attachements - if (mg_globals.app_config['allow_attachments'] - and request.POST.has_key('attachment') - and isinstance(request.POST['attachment'], FieldStorage) - and request.POST['attachment'].file): - - attachment_public_filepath = mg_globals.public_store.get_unique_filepath( - ['media_entries', - unicode('attachment-%s' % entry['_id']), - secure_filename(request.POST['attachment'].filename)]) - - attachment_public_file = mg_globals.public_store.get_file( - attachment_public_filepath, 'wb') - - try: - attachment_public_file.write(request.POST['attachment'].file.read()) - finally: - request.POST['attachment'].file.close() - - entry['attachment_files'] = [dict( - name=request.POST['attachment'].filename, - filepath=attachment_public_filepath, - created=datetime.utcnow() - )] - # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html new file mode 100644 index 00000000..2f319dbb --- /dev/null +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -0,0 +1,55 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} +{% block mediagoblin_content %} +
        + +
        +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index c834918e..d19034cb 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -31,14 +31,7 @@
        - {{ wtforms_util.render_field_div(form.title) }} - {{ wtforms_util.render_field_div(form.slug) }} - {{ wtforms_util.render_field_div(form.description) }} - {{ wtforms_util.render_field_div(form.tags) }} - {% if media.attachment_files %} - {{ wtforms_util.render_field_div(form.attachment_name) }} - {{ wtforms_util.render_field_div(form.attachment_delete) }} - {% endif %} + {{ wtforms_util.render_divs(form) }}
        Cancel diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 42bbf724..6d00510c 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -28,9 +28,6 @@ {{ wtforms_util.render_field_div(submit_form.title) }} {{ wtforms_util.render_textarea_div(submit_form.description) }} {{ wtforms_util.render_field_div(submit_form.tags) }} - {% if app_config.allow_attachments %} - {{ wtforms_util.render_field_div(submit_form.attachment) }} - {% endif %}
        diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index cc4c3350..1a5eed1f 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -104,20 +104,8 @@
        {% include "mediagoblin/utils/prev_next.html" %}

        Sidebar content here!

        - - {% if media.attachment_files %} -
        -
        Attachments
        - {% for attachment in media.attachment_files %} -
        - - {{ attachment.name }} - -
        - {% endfor %} -
        - {% endif %} + {% if media.attachment_files or media['uploader'] == request.user['_id'] or + request.user['is_admin'] %}

        {% if media['uploader'] == request.user['_id'] or @@ -136,6 +124,26 @@ {% endif %}

        + {% if media.attachment_files|count %} +

        Attachments

        + + {% endif %} + {% if app_config['allow_attachments'] %} + Add attachment + {% endif %} + {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 3be0617d..81bb80c2 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -28,7 +28,10 @@ user_routes = [ '/{user}/m/{media}/c/{comment}/', controller="mediagoblin.user_pages.views:media_home"), Route('mediagoblin.edit.edit_media', "/{user}/m/{media}/edit/", - controller="mediagoblin.edit.views:edit_media"), + controller="mediagoblin.edit.views:edit_media"), + Route('mediagoblin.edit.attachments', + '/{user}/m/{media}/attachments/', + controller="mediagoblin.edit.views:edit_attachments"), Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/', controller="mediagoblin.user_pages.views:atom_feed"), Route('mediagoblin.user_pages.media_post_comment', diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 85a84db6..8b9d94e5 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -16,7 +16,7 @@ from webob import exc -from mediagoblin import messages +from mediagoblin import messages, mg_globals from mediagoblin.db.util import DESCENDING, ObjectId from mediagoblin.util import ( Pagination, render_to_response, redirect, cleaned_markdown_conversion) @@ -117,7 +117,8 @@ def media_home(request, media, page, **kwargs): {'media': media, 'comments': comments, 'pagination': pagination, - 'comment_form': comment_form}) + 'comment_form': comment_form, + 'app_config': mg_globals.app_config}) @require_active_login -- cgit v1.2.3 From a28f072615ce420172d709823f5839a461e84655 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 22 Aug 2011 21:55:06 -0500 Subject: Wrap "add attachment" in a paragraph for proper spacing. --- mediagoblin/templates/mediagoblin/user_pages/media.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 08d5dbe9..0425500e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -149,9 +149,11 @@ {% if app_config['allow_attachments'] and (media['uploader'] == request.user['_id'] or request.user['is_admin']) %} - Add attachment +

        + Add attachment +

        {% endif %} {% if media.tags %} -- cgit v1.2.3 From f955a2bccc0fce01b2156aa2883d9b9b99a23443 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 22 Aug 2011 22:00:30 -0500 Subject: We're no longer a GNU project in the making... we're a straight up GNU project! --- mediagoblin/templates/mediagoblin/root.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 08155c17..4ea3fe2a 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -28,7 +28,7 @@
        • {% trans %}The perfect place for your media!{% endtrans %}
        • {% trans %}A place for people to collaborate and show off original and derived creations!{% endtrans %}
        • -
        • {% trans %}Free, as in freedom. (We’re a GNU project in the making, after all.){% endtrans %}
        • +
        • {% trans %}Free, as in freedom. (We’re a GNU project, after all.){% endtrans %}
        • {% trans %}Aiming to make the world a better place through decentralization and (eventually, coming soon!) federation!{% endtrans %}
        • {% trans %}Built for extensibility. (Multiple media types coming soon to the software, including video support!){% endtrans %}
        • {% trans %}Powered by people like you. (You can help us improve this software!){% endtrans %}
        • -- cgit v1.2.3 From ba880861c3cc95c76d240d4233b8381f2daaf56d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 23 Aug 2011 22:56:22 -0500 Subject: Must switch queuestore_base_dir -> base_dir in test_mgoblin_app.ini --- mediagoblin/tests/test_mgoblin_app.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 0109d751..9d938b4f 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -17,7 +17,7 @@ base_dir = %(here)s/test_user_dev/media/public base_url = /mgoblin_media/ [storage:queuestore] -queuestore_base_dir = %(here)s/test_user_dev/media/queue +base_dir = %(here)s/test_user_dev/media/queue [celery] celery_always_eager = true -- cgit v1.2.3 From 12c340fc07bdf576ffb6da6b5e3b525119131b3b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 23 Aug 2011 23:20:20 -0500 Subject: Static serving in test_paste.ini wasn't pointing at test_user_dev either Not that it matters too much, but... should point it to the right place :) --- mediagoblin/tests/test_paste.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_paste.ini b/mediagoblin/tests/test_paste.ini index 929a1ccf..e7574b7a 100644 --- a/mediagoblin/tests/test_paste.ini +++ b/mediagoblin/tests/test_paste.ini @@ -14,7 +14,7 @@ config = %(here)s/test_mgoblin_app.ini [app:publicstore_serve] use = egg:Paste#static -document_root = %(here)s/user_dev/media/public +document_root = %(here)s/test_user_dev/media/public [app:mediagoblin_static] use = egg:Paste#static -- cgit v1.2.3 From 0533f117a9ecadbe640281e9721a6e85c9ae1fec Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 23 Aug 2011 23:22:17 -0500 Subject: Basic beaker caching functionality added to the application. --- mediagoblin/app.py | 5 ++++- mediagoblin/config_spec.ini | 6 ++++++ mediagoblin/init/__init__.py | 16 ++++++++++++++++ mediagoblin/mg_globals.py | 3 +++ mediagoblin/tests/test_mgoblin_app.ini | 3 +++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 3030929d..113bcb8d 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -25,7 +25,7 @@ from mediagoblin.mg_globals import setup_globals from mediagoblin.init.celery import setup_celery_from_config from mediagoblin.init import (get_jinja_loader, get_staticdirector, setup_global_and_app_config, setup_workbench, setup_database, - setup_storage) + setup_storage, setup_beaker_cache) class MediaGoblinApp(object): @@ -71,6 +71,9 @@ class MediaGoblinApp(object): # set up staticdirector tool self.staticdirector = get_staticdirector(app_config) + # set up caching + self.cache = setup_beaker_cache() + # Setup celery, if appropriate if setup_celery and not app_config.get('celery_setup_elsewhere'): if os.environ.get('CELERY_ALWAYS_EAGER'): diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 11badc1f..3f99b497 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -46,6 +46,12 @@ base_url = string(default="/mgoblin_media/") base_dir = string(default="%(here)s/user_dev/media/queue") +[beaker.cache] +type = string(default="file") +data_dir = string(default="%(here)s/user_dev/beaker/cache/data") +lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock") + + [celery] # known booleans celery_result_persistent = boolean() diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index 44f604b1..4fe5df35 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -14,7 +14,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from beaker.cache import CacheManager +from beaker.util import parse_cache_config_options import jinja2 + from mediagoblin import staticdirect from mediagoblin.init.config import ( read_mediagoblin_config, generate_validation_report) @@ -135,3 +138,16 @@ def setup_workbench(): workbench_manager = WorkbenchManager(app_config['workbench_path']) setup_globals(workbench_manager = workbench_manager) + + +def setup_beaker_cache(): + """ + Setup the Beaker Cache manager. + """ + cache_config = mg_globals.global_config['beaker.cache'] + cache_config = dict( + [(u'cache.%s' % key, value) + for key, value in cache_config.iteritems()]) + cache = CacheManager(**parse_cache_config_options(cache_config)) + setup_globals(cache=cache) + return cache diff --git a/mediagoblin/mg_globals.py b/mediagoblin/mg_globals.py index 80ff5ead..8df5606e 100644 --- a/mediagoblin/mg_globals.py +++ b/mediagoblin/mg_globals.py @@ -31,6 +31,9 @@ db_connection = None # mongokit.Connection database = None +# beaker's cache manager +cache = None + # should be the same as the public_store = None queue_store = None diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 9d938b4f..986f793b 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -19,5 +19,8 @@ base_url = /mgoblin_media/ [storage:queuestore] base_dir = %(here)s/test_user_dev/media/queue +[beaker.cache] +enabled = false + [celery] celery_always_eager = true -- cgit v1.2.3 From 026074af1e85217fbcd0b5b58c931b106d0b15bd Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 25 Aug 2011 01:05:49 +0200 Subject: Feature/Bug #519 - CloudFilesStorage.get_file() performance issue - Fix * `CloudFilesStorage.get_file()` now guesses the filepath without connecting to cloudfiles. Huge profits for xDSL-hosted or slow net machines. --- mediagoblin/storage.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index d484be1f..7ada95e1 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -254,6 +254,8 @@ class CloudFilesStorage(StorageInterface): self.container = self.connection.get_container( self.param_container) + self.container_uri = self.container.public_uri() + def _resolve_filepath(self, filepath): return '/'.join( clean_listy_filepath(filepath)) @@ -282,7 +284,9 @@ class CloudFilesStorage(StorageInterface): self.container.delete_object(filepath) def file_url(self, filepath): - return self.get_file(filepath).public_uri() + return '/'.join([ + self.container_uri, + self._resolve_filepath(filepath)]) class MountStorage(StorageInterface): -- cgit v1.2.3 From fb91ef0f69a354dddf11a6983d5d41789dc09fec Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 24 Aug 2011 20:17:06 -0500 Subject: Changing account "verified" to account "activated" in some points for clarity. --- mediagoblin/templates/mediagoblin/user_pages/user.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 0214082c..88f6803d 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -40,7 +40,7 @@

          {% trans -%} - Almost done! Your account still needs to be verified. + Almost done! Your account still needs to be activated. {%- endtrans %}

          @@ -60,7 +60,7 @@

          {% trans -%} - Someone has registered an account with this username, but it still has to be verified. + Someone has registered an account with this username, but it still has to be activated. {%- endtrans %}

          -- cgit v1.2.3 From 9cecbe4e35bd75d9a6d56fc6cf44e5281fbce8f3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 24 Aug 2011 20:20:38 -0500 Subject: Also changing "Verification needed!" to "Email verification needed!" --- mediagoblin/templates/mediagoblin/user_pages/user.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 88f6803d..e7fd9692 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -36,7 +36,7 @@ {% if user == request.user %} {# this should only be visible when you are this user #}
          -

          {% trans %}Verification needed{% endtrans %}

          +

          {% trans %}Email verification needed{% endtrans %}

          {% trans -%} @@ -56,7 +56,7 @@ {% else %} {# if the user is not you, but still needs to verify their email #}

          -

          {% trans %}Verification needed{% endtrans %}

          +

          {% trans %}Email verification needed{% endtrans %}

          {% trans -%} -- cgit v1.2.3 From e39039dcbf8ab0141d2f88c861c51346101583ca Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 24 Aug 2011 20:21:23 -0500 Subject: Updating extracted translation template --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 182 ++++++++++++++++++------- 1 file changed, 132 insertions(+), 50 deletions(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 9c46ebe8..cbc82003 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -88,97 +88,125 @@ msgstr "" msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "" +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for " +"has been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." +"Free, as in freedom. (We’re a GNU project," +" after all.)" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the " +"software, including video support!)" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve " +"this software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 @@ -193,6 +221,10 @@ msgstr "" msgid "Create an account!" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -214,6 +246,7 @@ msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "" @@ -226,33 +259,51 @@ msgstr "" msgid "Media tagged with:" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" +msgid "Email verification needed" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." +msgid "Almost done! Your account still needs to be activated." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 @@ -270,7 +321,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to" -" be verified." +" be activated." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 @@ -285,15 +336,46 @@ msgstr "" msgid "%(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" -- cgit v1.2.3 From 39f115edabf0830e852ae5d9ea65d43d06f837b6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 24 Aug 2011 20:24:44 -0500 Subject: Pulling down new translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 386 +++++++++++++++++++++ mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 274 ++++++++++----- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 253 +++++++++----- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 291 ++++++++++------ mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 218 ++++++++---- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 207 +++++++---- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 399 ++++++++++++++++++++++ mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 251 +++++++++----- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 251 +++++++++----- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 251 +++++++++----- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 387 +++++++++++++++++++++ mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 251 +++++++++----- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 227 ++++++++---- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 208 +++++++---- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 207 +++++++---- 15 files changed, 3127 insertions(+), 934 deletions(-) create mode 100644 mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po create mode 100644 mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po create mode 100644 mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..4aff740e --- /dev/null +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,386 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: ar\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "" + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "" + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "الوسوم" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "" + +#: mediagoblin/edit/views.py:65 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:94 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:165 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "" + +#: mediagoblin/submit/views.py:47 +msgid "You must provide a file." +msgstr "" + +#: mediagoblin/submit/views.py:50 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:122 +msgid "Woohoo! Submitted!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "غنو ميدياغوبلن" + +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:52 +msgid "Submit media" +msgstr "أرسل وسائط" + +#: mediagoblin/templates/mediagoblin/base.html:63 +msgid "verify your email!" +msgstr "أكد بريدك" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "لُج" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "" +"Powered by MediaGoblin, a GNU project" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "ألا تملك حسابا؟" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "أنشئ حسابا هنا!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "أنشئ حسابا!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "ألغِ" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +msgid "Save changes" +msgstr "احفظ التغييرات" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "تعديل ملف %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "الوسائط الموسومة بـ:" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "أرسل" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can log in and resend it." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +msgid "Edit profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#, python-format +msgid "View all of %(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + + diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 30c55e21..1b6c2684 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -3,16 +3,18 @@ # This file is distributed under the same license as the PROJECT project. # # Rafael Maguiña , 2011. +# , 2011. # , 2011. +# Elrond , 2011. # , 2011. # Jan-Christoph Borchardt , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 23:20+0000\n" -"Last-Translator: JanCBorchardt \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -45,28 +47,32 @@ msgstr "Email-Adresse" msgid "Sorry, registration is disabled on this instance." msgstr "Registrierung ist auf dieser Instanz leider deaktiviert." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "Tut und Leid, aber diese E-Mail Adresse wird bereits verwendet." + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Deine Email-Adresse wurde bestätigt. Du kannst dich nun anmelden, dein " +"Deine Email-Adresse wurde bestätigt. Du kannst dich nun anmelden, Dein " "Profil bearbeiten und Bilder hochladen!" -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "Der Bestätigungssschlüssel oder die Nutzernummer ist falsch." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." -msgstr "Bestätigungs-Email noch Mal senden." +msgstr "Bestätigungs-Email wurde erneut versand." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" @@ -90,104 +96,128 @@ msgstr "Biographie" msgid "Website" msgstr "Webseite" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Adresse fehlerhaft" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Diesen Kurztitel hast du bereits vergeben." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Datei" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du musst eine Datei angeben." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Diese Datei scheint kein Bild zu sein!" -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Yeeeaaah! Geschafft!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Mediagoblin-Logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Medien hochladen" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Bitte bestätige deine Email-Adresse!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Anmelden" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Läüft mit MediaGoblin, einem MediaGoblin, einem GNU-Projekt" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Willkommen bei GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" -msgstr "Eintrag hochladen" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Falls du ein Konto hast, kannst du dich anmelden." -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -"Wenn du noch kein Konto hast, registriere " -"dich." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Anmelden" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Anmeldung fehlgeschlagen!" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Bestätigen" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -201,6 +231,10 @@ msgstr "Registriere dich!" msgid "Create an account!" msgstr "Neues Konto registrieren!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -227,91 +261,145 @@ msgid "Cancel" msgstr "Abbrechen" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Änderungen speichern" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" -msgstr "%(username)s’s Profil barbeiten" +msgstr "%(username)ss Profil barbeiten" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "Medien markiert mit:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "Atom-Feed" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Medien hochladen" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Bestätigen" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "%(username)s’s Medien" +msgstr "%(username)ss Medien" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Dieser Benutzer wurde leider nicht gefunden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Überprüfung notwendig" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Fast geschafft! Dein Konto muss nur noch bestätigt werden." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -"Gleich solltest du eine Email bekommen, die dir sagt was du noch machen " +"Gleich solltest du eine Email bekommen, die dir sagt, was du noch machen " "musst." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "Wenn sie nicht ankommt:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" -msgstr "Bestätigung noch Mal senden" +msgstr "Bestätigung erneut senden" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Jemand hat schon ein Konto mit diesem Nutzernamen registriert, aber es muss " -"noch bestätigt werden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Wenn dir dieses Konto gehört und die Bestätigungsmail weg ist, kannst du " -"dich anmelden und sie erneut senden." +"Wenn dir dieses Konto gehört und die Bestätigungsmail verloren gegangen ist," +" kannst du dich anmelden und sie erneut " +"senden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" -msgstr "%(username)s’s Profil" +msgstr "%(username)ss Profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Profil bearbeiten" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Alle Medien von %(username)s anschauen" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Kommentar" + diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index ea19af01..6ee8b85f 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -2,15 +2,16 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# , 2011. # , 2011. # Fernando Inocencio , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" -"PO-Revision-Date: 2011-08-15 20:33+0000\n" -"Last-Translator: fajro \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,7 +26,7 @@ msgstr "Uzantnomo" #: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 msgid "Password" -msgstr "Pasvorton" +msgstr "Pasvorto" #: mediagoblin/auth/forms.py:34 msgid "Passwords must match." @@ -37,11 +38,11 @@ msgstr "Retajpu pasvorton" #: mediagoblin/auth/forms.py:39 msgid "Email address" -msgstr "Retadreso" +msgstr "Retpoŝtadreso" #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." -msgstr "Bedaŭrinde, registrado estas malaktivita en tiu ĉi instanco." +msgstr "Bedaŭrinde, registrado estas malaktivigita en tiu ĉi instalaĵo." #: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." @@ -49,14 +50,14 @@ msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." #: mediagoblin/auth/views.py:61 msgid "Sorry, that email address has already been taken." -msgstr "" +msgstr "Tiu retpoŝtadreso jam estas uzata." #: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Vian retadreson estas kontrolita. Vi povas nun ensaluti, redakti vian " +"Via retpoŝtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian " "profilon, kaj alŝuti bildojn!" #: mediagoblin/auth/views.py:165 @@ -74,11 +75,11 @@ msgstr "Titolo" #: mediagoblin/edit/forms.py:29 msgid "Slug" -msgstr "" +msgstr "La distingiga adresparto" #: mediagoblin/edit/forms.py:30 msgid "The slug can't be empty" -msgstr "" +msgstr "La distingiga adresparto ne povas esti malplena" #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 msgid "Tags" @@ -92,101 +93,128 @@ msgstr "Bio" msgid "Website" msgstr "Retejo" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." -msgstr "" +msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." -msgstr "" +msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." +msgstr "Vi redaktas profilon de uzanto. Agu singardeme." + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Dosiero" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Vi devas provizi dosieron." -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" -msgstr "" +msgstr "La dosiero ŝajnas ne esti bildo!" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" +msgstr "Hura! Alŝutitas!" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" msgstr "" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr " Logogramo de Mediagoblin" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Alŝuti aŭd-vid-dosieron" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" -msgstr "kontrolu vian retpoŝton! " +msgstr "konfirmu vian retpoŝtadreson! " -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Ensaluti" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Provizita de MediaGoblin, unu el la " -"GNU projectoj" +"Funkciigata per MediaGoblin, unu el " +"la projektoj de GNU" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Bonvenon al GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" -msgstr "Alŝuti dosieron" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." -msgstr "Se vi havas konton, vi povas Ensaluti." +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Se vi ne havas konton, bonvolu Registriĝi." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Ensaluti" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Ensalutado malsukcesis!" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" -msgstr "Alŝuti" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -194,12 +222,16 @@ msgstr "Ĉu ankoraŭ sen konto?" #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Create one here!" -msgstr "Kreu unu ĉi tie!" +msgstr "Kreu ĝin ĉi tie!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Kreu konton!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -226,52 +258,72 @@ msgid "Cancel" msgstr "Nuligi" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Konservi ŝanĝojn" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" -msgstr "Redaktanta profilon de %(username)s'" +msgstr "Redaktado de l’profilo de %(username)s'" #: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" -msgstr "Dosiero markita kiel:" - -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "Atom-a informfluado" +msgstr "Dosieroj markitaj per:" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Alŝutu vian aŭd-vid-dosieron" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Alŝuti" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "%(username)s-a aŭd-vid-dosiero" +msgstr "Dosieroj de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Uzanto ne trovita." +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" -msgstr "Kontrolon bezonata" +msgid "Email verification needed" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." -msgstr "Preskaŭ farite! Via konto ankoraŭ devas esti kontrolita." +msgid "Almost done! Your account still needs to be activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -"Retmesaĝo alvenos post kelkaj momentoj kun instrukcioj pri kiel tion fari." +"Post kelkaj momentoj devas veni retletero kun instrukcio pri kiel tion fari." #: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" @@ -279,15 +331,13 @@ msgstr "Se tio ne okazas:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" -msgstr "Resendu kontrolmesaĝon" +msgstr "Resendi kontrolmesaĝon" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti " -"kontrolita." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -301,16 +351,47 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" -msgstr "%(username)s'-a profilo" +msgstr "Profilo de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" -msgstr "Redakti profilo" +msgstr "Redakti profilon" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "Rigardu ĉiuj aŭd-vid-dosierojn de %(username)s'" +msgstr "Rigardi ĉiujn dosierojn de %(username)s'" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 0a12586c..d35e3b47 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -2,14 +2,15 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# , 2011. # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 20:30+0000\n" -"Last-Translator: nvjacobo \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -40,31 +41,35 @@ msgstr "Dirección de correo electrónico" #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." -msgstr "Lo sentimos, el registro está deshabilitado en este momento." +msgstr "Lo sentimos, la registración está deshabilitado en este momento." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." -msgstr "Lo sentimos, un usuario con ese nombre ya existe." +msgstr "Lo sentimos, ya existe un usuario con ese nombre." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "Lo sentimos, su dirección de correo electrónico ya ha sido tomada." + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Su dirección de correo electrónico ha sido verificada. Ahora puede ingresar," -" editar su perfil, y enviar las imágenes!" +"Su dirección de correo electrónico ha sido verificada. ¡Ahora puede " +"ingresar, editar su perfil, y enviar imágenes!" -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "" -"La clave de la verificación o la identificación del usuario es incorrecta" +"La clave de verificación o la identificación de usuario son incorrectas" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." -msgstr "Reenvíe su correo electrónico de verificación" +msgstr "Reenvíe su correo electrónico de verificación." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Título" @@ -74,7 +79,7 @@ msgstr "Ficha" #: mediagoblin/edit/forms.py:30 msgid "The slug can't be empty" -msgstr "La ficha no puede estar vacia" +msgstr "La ficha no puede estar vacía" #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 msgid "Tags" @@ -88,60 +93,80 @@ msgstr "Bio" msgid "Website" msgstr "Sitio web" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "URL de forma incorrecta" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Una entrada con esa ficha ya existe para este usuario." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Usted está editando el contenido de otro usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." -msgstr "Usted está editando un perfil de usuario. Proceder con precaucións." +msgstr "Usted está editando un perfil de usuario. Proceder con precaución." -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Archivo" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Usted debe proporcionar un archivo." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" -msgstr "El archivo no parece ser una imagen!" +msgstr "¡El archivo no parece ser una imagen!" -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" -msgstr "Woohoo! Enviado!" +msgstr "¡Woohoo! ¡Enviado!" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Mediagoblin logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Enviar contenido" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Verifique su correo electrónico" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Conectarse" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -149,44 +174,48 @@ msgstr "" "Potenciado por MediaGoblin, a GNU project" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "¡Bienvenido a GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" -msgstr "Enviar un item" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Si tiene una cuenta, puede iniciar sesión Login." -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -"Si no tienes una cuenta, por favor, Regístrese ." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Conectarse" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "El inicio de sesión fallo" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Enviar" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -194,11 +223,15 @@ msgstr "¿No tienes una cuenta?" #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Create one here!" -msgstr "Crea una aquí" +msgstr "¡Crea una aquí!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" -msgstr "Crea una cuenta!" +msgstr "¡Crea una cuenta!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -210,7 +243,7 @@ msgid "" "\n" "%(verification_url)s" msgstr "" -"Hola %(username)s , para activar su cuenta MediaGoblin GNU, abra ls " +"Hola %(username)s , para activar su cuenta GNU MediaGoblin, abra la " "siguiente URL en su navegador: %(verification_url)s " #: mediagoblin/templates/mediagoblin/edit/edit.html:29 @@ -223,90 +256,144 @@ msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salvar cambios" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" -msgstr "Edición %(username)s de perfil" +msgstr "Editando el perfil de %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" -msgstr "El contenido con la etiqueta:" - -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "feed Atom" +msgstr "Contenido etiquetado con:" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Envíe su contenido" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Enviar" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "Contenido de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." -msgstr "Lo sentimos, no se ha encontrado el usuario." +msgstr "Lo sentimos, no se ha encontrado ese usuario." + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Verificación necesaria" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Ya está casi hecho! Su cuenta tiene que ser verificada." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -"Un e-mail debe llegar en unos momentos con las instrucciones para hacerlo." +"Un e-mail debería llegar en unos momentos con las instrucciones para " +"hacerlo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "En caso de que no:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "Reenviar correo electrónico de verificación" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Alguien ha registrado una cuenta con este nombre de usuario, pero todavía " -"tiene que ser verificado." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Si usted es esa persona, pero usted ha perdido su correo electrónico de " -"verificación, usted puede reenviarlo acceder." +"Si usted es esa persona, pero ha perdido su correo electrónico de " +"verificación, puede acceder y reenviarlo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "Perfil de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Ver todo el contenido de %(username)s's " +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Comentario" + diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 5afe7091..81151d94 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -2,6 +2,7 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# , 2011. # , 2011. # Valentin Villenave , 2011. # , 2011. @@ -9,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" -"PO-Revision-Date: 2011-08-16 13:22+0000\n" -"Last-Translator: joar \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -50,7 +51,7 @@ msgstr "Un utilisateur existe déjà avec ce nom, désolé." #: mediagoblin/auth/views.py:61 msgid "Sorry, that email address has already been taken." -msgstr "" +msgstr "Désolé, cette adresse courriel a déjà été prise." #: mediagoblin/auth/views.py:159 msgid "" @@ -93,63 +94,83 @@ msgstr "Bio" msgid "Website" msgstr "Site web" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Adresse web mal formée" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Une entrée existe déjà pour cet utilisateur avec la même légende." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " "prendre garde." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " "garde." +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fichier" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Il vous faut fournir un fichier." -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Ce fichier ne semble pas être une image !" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Youhou, c'est envoyé !" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "logo de MediaGoblin" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Soumettre un média" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" -msgstr "vérifier son adresse e-mail" +msgstr "vérifiez votre adresse e-mail !" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" -msgstr "Identification" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "S'identifier" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -157,44 +178,48 @@ msgstr "" "Propulsé par MediaGoblin, un projet " "de GNU" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Bienvenue sur GNU MediaGoblin !" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" -msgstr "Soumettre un fichier" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" msgstr "" -"Si vous avez un compte, vous pouvez vous identifier." -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Si vous n'avez pas de compte, veuillez vous inscrire." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "S'identifier" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "L'identification a échoué !" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" -msgstr "Soumettre" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -208,6 +233,10 @@ msgstr "Créez-en un ici !" msgid "Create an account!" msgstr "Créer un compte !" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -234,6 +263,7 @@ msgid "Cancel" msgstr "Annuler" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Enregistrer les modifications" @@ -246,34 +276,53 @@ msgstr "Modification du profil de %(username)s" msgid "Media tagged with:" msgstr "Média comportant les tags suivants :" -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "flux Atom" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Soumettez ce média" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Soumettre" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "Médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Impossible de trouver cet utilisateur, désolé." +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" -msgstr "Vérification requise" +msgid "Email verification needed" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." -msgstr "C'est presque fini ! Il vous faut encore vérifier votre compte." +msgid "Almost done! Your account still needs to be activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -293,10 +342,8 @@ msgstr "Renvoyer l'e-mail de vérification" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Quelqu'un a créé un compte à ce nom, mais le compte n'a pas encore été " -"vérifié." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -313,17 +360,48 @@ msgstr "" msgid "%(username)s's profile" msgstr "profil de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Modifier le profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Voir tous les médias de %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" -msgstr "" +msgstr "Commentaire" diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 0aba5755..6472b6fa 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" -"PO-Revision-Date: 2011-08-14 00:47+0000\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -89,59 +89,79 @@ msgstr "自己紹介" msgid "Website" msgstr "URL" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "不適切な形式のURL" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "そのスラグを持つエントリは、このユーザーは既に存在します。" -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "ファイル" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "ファイルを提供する必要があります。" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "ファイルが画像ではないようです!" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "投稿終了!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "MediaGoblinロゴ" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "コンテンツを投稿" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "メアドを確認してください!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "ログイン" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -149,40 +169,48 @@ msgstr "" "Powered by MediaGoblin, a GNU project" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" -msgstr "GNU MediaGoblinへようこそ!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" -msgstr "アイテムを投稿" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." -msgstr "もしアカウントが持ったら、ログインできます。" +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." -msgstr "アカウントが持っていなければ、登録してお願いします。" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "ログイン" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "ログイン失敗!" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" -msgstr "送信" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -196,6 +224,10 @@ msgstr "ここで作成!" msgid "Create an account!" msgstr "アカウントを作成!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -222,6 +254,7 @@ msgid "Cancel" msgstr "キャンセル" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "投稿する" @@ -234,34 +267,53 @@ msgstr "%(username)sさんのプロフィールを編集中" msgid "Media tagged with:" msgstr "タグ付けされたコンテンツ:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "Atomフィード" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "コンテンツを投稿" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "送信" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "申し訳ありませんが、そのユーザーは見つかりませんでした。" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" -msgstr "確認必要" +msgid "Email verification needed" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." -msgstr "ほぼ完了!アカウントを検証する必要があります。" +msgid "Almost done! Your account still needs to be activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -279,8 +331,8 @@ msgstr "確認メールを再送信" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." -msgstr "誰かがこのユーザ名でアカウントを登録しているが、まだ検証する必要があります。" +" activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -294,15 +346,46 @@ msgstr "あなたの確認メールを紛失した場合、, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: nl\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Gebruikersnaam" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Wachtwoord" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Wachtwoorden moeten overeenkomen." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Bevestig wachtwoord" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "E-mail adres" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "Sorry, registratie is uitgeschakeld op deze instantie." + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "Sorry, er bestaat al een gebruiker met die naam." + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "Sorry, dat e-mailadres is al ingenomen." + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Uw e-mailadres is geverifieerd. U kunt nu inloggen, uw profiel bewerken, en " +"afbeeldingen toevoegen!" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "De verificatie sleutel of gebruikers-ID is onjuist" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "Verificatie e-mail opnieuw opgestuurd." + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Titel" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Etiket" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "Bio" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Website" + +#: mediagoblin/edit/views.py:65 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:94 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" +"U bent de media van een andere gebruiker aan het aanpassen. Ga voorzichtig " +"te werk." + +#: mediagoblin/edit/views.py:165 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" +"U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk." + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Bestand" + +#: mediagoblin/submit/views.py:47 +msgid "You must provide a file." +msgstr "U moet een bestand aangeven." + +#: mediagoblin/submit/views.py:50 +msgid "The file doesn't seem to be an image!" +msgstr "Het lijkt erop dat dit bestand geen afbeelding is!" + +#: mediagoblin/submit/views.py:122 +msgid "Woohoo! Submitted!" +msgstr "Mooizo! Toegevoegd!" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:52 +msgid "Submit media" +msgstr "Voeg media toe" + +#: mediagoblin/templates/mediagoblin/base.html:63 +msgid "verify your email!" +msgstr "Controleer uw e-mail!" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "Inloggen" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "" +"Powered by MediaGoblin, a GNU project" +msgstr "" +"Aangedreven door MediaGoblin , een GNU-project" + +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Heeft u nog geen account?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Maak er hier een!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Maak een account aan!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "" +"Hallo %(username)s , open de volgende URL in uw webbrowser om uw GNU " +"MediaGoblin account te activeren: %(verification_url)s " + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "%(media_title)s aanpassen" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Annuleren" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +msgid "Save changes" +msgstr "Wijzigingen opslaan" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Het profiel aanpassen van %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Media met het etiket:" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Voeg media toe" + +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Voeg toe" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "%(username)s's media" +msgstr "Media van %(username)s " + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "Sorry, die gebruiker kon niet worden gevonden." + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"Een e-mail zou in een paar ogenblikken aan moeten komen met instructies " +"hiertoe." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "Zoniet:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "Stuur de verificatie e-mail opnieuw op." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can log in and resend it." +msgstr "" +"Als u die persoon bent, maar de verificatie e-mail verloren hebt, kunt u inloggen en hem nogmaals verzenden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "Profiel van %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +msgid "Edit profile" +msgstr "Profiel aanpassen." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Bekijk alle media van %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Commentaar" + + diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index bd00fd1f..2e9ad8a2 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 21:23+0000\n" -"Last-Translator: velmont \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,11 +42,15 @@ msgstr "E-postadresse" msgid "Sorry, registration is disabled on this instance." msgstr "Registrering er slege av. Orsak." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "Ein konto med dette brukarnamnet finst allereide." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -54,16 +58,16 @@ msgstr "" "E-postadressa di, og dimed kontoen din er stadfesta. Du kan no logga inn, " "endra profilen din og lasta opp filer." -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." msgstr "Send ein ny stadfestingsepost." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Tittel" @@ -87,59 +91,79 @@ msgstr "Presentasjon" msgid "Website" msgstr "Heimeside" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Ugyldeg URL" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Eit innlegg med denne adressetittelen finst allereie." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sitt innlegg." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sin profil." -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fil" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du må velja ei fil." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Fila verkar ikkje å vera ei gyldig biletefil." -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Johoo! Opplasta!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "MediaGoblin-logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Last opp" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Stadfest epostadressa di" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Logg inn" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -147,40 +171,48 @@ msgstr "" "Driven av MediaGoblin, eit GNU-prosjekt" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Velkomen til GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" -msgstr "Last opp" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." -msgstr "Har du ein konto? Logg inn." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." -msgstr "Har du ingen konto? Registrer deg." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Logg inn" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Innlogging feila!" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Send" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -194,6 +226,10 @@ msgstr "Lag ein!" msgid "Create an account!" msgstr "Lag ein konto." +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -220,6 +256,7 @@ msgid "Cancel" msgstr "Avbryt" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Lagra" @@ -228,61 +265,78 @@ msgstr "Lagra" msgid "Editing %(username)s's profile" msgstr "Redigerar profilen til %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "Merkelappar:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "atom-feed" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Last opp" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Send" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "%(username)s sin mediafiler" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Fann ingen slik brukar" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Treng stadfesting" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Nesten klart. Du treng berre stadfesta kontoen din." +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Ein epost med instruksjonar kjem straks." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "I tilfelle det ikkje skjer:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "Send ein ny epost" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Det finst allereie ein konto med det brukarnamnet, men den kontoen treng " -"stadfesting." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can logga inn for å få " "tilsendt ny epost med stadfestingslenkje." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "%(username)s sin profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Endra profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Sjå all media frå %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 43f65af6..7ea81f3b 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 23:16+0000\n" -"Last-Translator: osc \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,11 +42,15 @@ msgstr "Endereço de email" msgid "Sorry, registration is disabled on this instance." msgstr "Desculpa, o registro está desativado neste momento." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "Desculpe, um usuário com este nome já existe." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -54,16 +58,16 @@ msgstr "" "O seu endereço de e-mail foi verificado. Você pode agora fazer login, editar" " seu perfil, e enviar imagens!" -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "A chave de verificação ou nome usuário estão incorretos." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." msgstr "O email de verificação foi reenviado." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Título" @@ -87,59 +91,79 @@ msgstr "Biográfia" msgid "Website" msgstr "Website" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Arquivo" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Você deve fornecer um arquivo." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "O arquivo não parece ser uma imagem!" -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Eba! Enviado!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Logo de Mediagoblin" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Enviar mídia" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Verifique seu email!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" -msgstr "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "Entrar" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -147,42 +171,48 @@ msgstr "" "Powered by MediaGoblin, a GNU project" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Bemvindo a GNU Mediagoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." -msgstr "Se você tem conta, você pode Entrar ." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -"Se você não tem conta, por favor Registrar " -"." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Entrar" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Login falhou!" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Enviar" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -196,6 +226,10 @@ msgstr "Crie uma aqui!" msgid "Create an account!" msgstr "Criar uma conta!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -222,6 +256,7 @@ msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salvar mudanças" @@ -230,61 +265,78 @@ msgstr "Salvar mudanças" msgid "Editing %(username)s's profile" msgstr "Editando perfil de %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "atom feed" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Envie sua mídia" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Enviar" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Desculpe, tal usuário não encontrado." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Verificação necessária" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Quase pronto! Sua conta precisa de verificação." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Receberá um email com instruções de como fazer." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "Caso contrário:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "Reenviar email de verificação" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Alguém já registrou uma conta com este nome, mas ainda tem que ser " -"verificada." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can efetuar login e reenviá-la." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "Perfil de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index feb261c8..6a671468 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 21:52+0000\n" -"Last-Translator: gap \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,11 +42,15 @@ msgstr "Adresa de e-mail" msgid "Sorry, registration is disabled on this instance." msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe această instanță." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "Ne pare rău, există deja un utilizator cu același nume." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "Ne pare rău, această adresă de e-mail este deja rezervată." + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -54,16 +58,16 @@ msgstr "" "Adresa dvs. de e-mail a fost confirmată. Puteți să vă autentificați, să vă " "modificați profilul și să trimiteți imagini!" -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "Cheie de verificare sau user ID incorect." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." msgstr "E-mail-ul de verificare a fost retrimis." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titlu" @@ -87,60 +91,80 @@ msgstr "Biografie" msgid "Website" msgstr "Sit Web" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Adresă URL incorectă" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" "Există deja un entry cu același identificator pentru acest utilizator." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "Editați fișierul unui alt utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "Editați profilul unui utilizator. Se recomandă prudență." -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fișier" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Trebuie să selectați un fișier." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Fișierul nu pare a fi o imagine!" -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Gata, trimis!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Logo MediaGoblin" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Transmiteți fișier" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "verificați e-mail-ul!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Autentificare" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -148,44 +172,48 @@ msgstr "" "Construit cu MediaGoblin, un proiect GNU" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Bun venit la GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" -msgstr "Trimite un fișier" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Dacă aveți deja un cont, vă puteți autentifica." -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -"Dacă nu aveți cont, vă rugăm să vă înregistrați." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Autentificare" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Autentificare nereușită!" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Trimite" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -199,6 +227,10 @@ msgstr "Creați-l aici!" msgid "Create an account!" msgstr "Creați un cont!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -225,6 +257,7 @@ msgid "Cancel" msgstr "Anulare" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salvează modificările" @@ -233,61 +266,78 @@ msgstr "Salvează modificările" msgid "Editing %(username)s's profile" msgstr "Editare profil %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "Etichete:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "flux atom" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Trimite fișierele tale" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Trimite" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "Fișierele lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Ne pare rău, nu am găsit utilizatorul căutat." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Confirmare necesară" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Aproape gata! Este necesară confirmarea contului dvs." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Veți primi în scurt timp un mesaj prin e-mail cu instrucțiuni." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "Dacă nu primiți mesajul:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "Retrimite mesajul de verificare" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Cineva s-a înscris pe site cu acest nume de utilizator, dar nu a fost " -"confirmat încă." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can autentificați pentru " "a-l retrimite." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "Profil %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Editare profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Toate fișierele lui %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Scrie un comentariu" + diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..cedd5a2e --- /dev/null +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,387 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: ru\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 +msgid "Username" +msgstr "Логин" + +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 +msgid "Password" +msgstr "Пароль" + +#: mediagoblin/auth/forms.py:34 +msgid "Passwords must match." +msgstr "Пароли должны совпадать." + +#: mediagoblin/auth/forms.py:36 +msgid "Confirm password" +msgstr "Подтвердите пароль" + +#: mediagoblin/auth/forms.py:39 +msgid "Email address" +msgstr "Адрес электронной почты" + +#: mediagoblin/auth/views.py:40 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:57 +msgid "Sorry, a user with that name already exists." +msgstr "" + +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" + +#: mediagoblin/auth/views.py:165 +msgid "The verification key or user id is incorrect" +msgstr "" + +#: mediagoblin/auth/views.py:186 +#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +msgid "Resent your verification email." +msgstr "" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Название" + +#: mediagoblin/edit/forms.py:29 +msgid "Slug" +msgstr "Отличительная часть адреса" + +#: mediagoblin/edit/forms.py:30 +msgid "The slug can't be empty" +msgstr "Отличительная часть адреса необходима" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 +msgid "Tags" +msgstr "Метки" + +#: mediagoblin/edit/forms.py:38 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:41 +msgid "Website" +msgstr "Сайт" + +#: mediagoblin/edit/views.py:65 +msgid "An entry with that slug already exists for this user." +msgstr "" +"У этого пользователя уже есть файл с такой отличительной частью адреса." + +#: mediagoblin/edit/views.py:94 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:165 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Файл" + +#: mediagoblin/submit/views.py:47 +msgid "You must provide a file." +msgstr "" + +#: mediagoblin/submit/views.py:50 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:122 +msgid "Woohoo! Submitted!" +msgstr "Ура! Файл загружен!" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:52 +msgid "Submit media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:63 +msgid "verify your email!" +msgstr "подтвердите ваш адрес электронной почты!" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "" +"Powered by MediaGoblin, a GNU project" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Ещё нет учётной записи?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Создайте её здесь!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Создаём учётную запись!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Редактирование %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +msgid "Cancel" +msgstr "Отменить" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +msgid "Save changes" +msgstr "Сохранить изменения" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Редактирование профиля %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Файлы с меткой:" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can log in and resend it." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "Профиль пользователя %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +msgid "Edit profile" +msgstr "Изменить профиль" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Смотреть все файлы %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + + diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index bf2dd4fa..7302ce6e 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-10 21:28+0000\n" -"Last-Translator: JLP \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,11 +42,15 @@ msgstr "E-poštni naslov" msgid "Sorry, registration is disabled on this instance." msgstr "Oprostite, prijava za ta izvod ni omogočena." -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "Oprostite, uporabnik s tem imenom že obstaja." -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -54,16 +58,16 @@ msgstr "" "Vaš e-poštni naslov je bil potrjen. Sedaj se lahko prijavite, uredite svoj " "profil in pošljete slike." -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "Potrditveni ključ ali uporabniška identifikacija je napačna" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." msgstr "Ponovno pošiljanje potrditvene e-pošte." -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Naslov" @@ -87,59 +91,79 @@ msgstr "Biografija" msgid "Website" msgstr "Spletna stran" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Napačno oblikovan URL" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Vnos s to oznako za tega uporabnika že obstaja." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Datoteka" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Podati morate datoteko." -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Kot kaže datoteka ni slika." -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Juhej! Poslano." +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Logotip MediaGoblin" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Pošlji vsebino" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Preverite svojo e-pošto." -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Prijava" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -147,40 +171,48 @@ msgstr "" "Stran poganja MediaGoblin, del projekta GNU" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Dobrodošli v GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" -msgstr "Pošljite datoteko" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." -msgstr "Če imate račun, se lahko Prijavite." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." -msgstr "Če računa še nimate, se Registrirajte." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Prijava" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Neuspešna prijava." +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" -msgstr "Pošlji" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -194,6 +226,10 @@ msgstr "Ustvarite si ga." msgid "Create an account!" msgstr "Ustvarite račun." +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -221,6 +257,7 @@ msgid "Cancel" msgstr "Prekliči" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Shrani spremembe" @@ -229,61 +266,78 @@ msgstr "Shrani spremembe" msgid "Editing %(username)s's profile" msgstr "Urejanje profila – %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "Vsebina označena z:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "Vir Atom" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Pošljite svojo vsebino" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Pošlji" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Oprostite, tega uporabnika ni bilo moč najti." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" -msgstr "Potrebna je potrditev" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." -msgstr "Skoraj ste zaključili. Račun je potrebno le še potrditi." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "V kratkem bi morali prejeti e-pošto z navodili, kako to storiti." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "Če je ne prejmete:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "Ponovno pošlji potrditveno e-pošto" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Nekdo je s tem uporabniškim imenom že registriral račun, vendar mora biti še" -" potrjen." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can prijavite in jo ponovno pošljete." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "Profil – %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Uredi profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Prikaži vso vsebino uporabnika %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index ec8611ee..ddb5d44b 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-08 22:53-0500\n" -"PO-Revision-Date: 2011-08-09 03:57+0000\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -41,26 +41,30 @@ msgstr "" msgid "Sorry, registration is disabled on this instance." msgstr "" -#: mediagoblin/auth/views.py:55 +#: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:152 +#: mediagoblin/auth/views.py:61 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -#: mediagoblin/auth/views.py:158 +#: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." msgstr "" -#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:26 +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "" @@ -84,97 +88,125 @@ msgstr "" msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/submit/forms.py:29 +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:45 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:48 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "" -#: mediagoblin/submit/views.py:96 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:21 -msgid "Welcome to GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:26 -msgid "Submit an item" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -#, python-format -msgid "If you have an account, you can Login." +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:37 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:32 msgid "" -"If you don't have an account, please Register." +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:32 -msgid "Submit" +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 @@ -189,6 +221,10 @@ msgstr "" msgid "Create an account!" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -210,6 +246,7 @@ msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "" @@ -218,77 +255,131 @@ msgstr "" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:29 +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:40 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:46 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -msgid "atom feed" -msgstr "" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:51 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:30 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:37 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:57 -msgid "Verification needed" +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:40 -msgid "Almost done! Your account still needs to be verified." +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:45 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:49 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:66 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:76 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:84 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:95 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "" + diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index 23605892..ede78f0d 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" -"PO-Revision-Date: 2011-08-16 13:22+0000\n" -"Last-Translator: joar \n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -91,59 +91,79 @@ msgstr "Presentation" msgid "Website" msgstr "Hemsida" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "Ogiltig URL" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Ett inlägg med det sökvägsnamnet existerar redan." -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "Var försiktig, du redigerar någon annans inlägg." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fil" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du måste ange en fil" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "Filen verkar inte vara en giltig bildfil!" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "Tjohoo! Upladdat!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "MediaGoblin logo" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "Ladda upp" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "Verifiera din e-postadress!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "Logga in" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -151,41 +171,48 @@ msgstr "" "Drivs av MediaGoblin, ett GNU-projekt" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" -msgstr "Välkommen till GNU MediaGoblin!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" -msgstr "Ladda upp" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." -msgstr "Har du ett konto? Logga in." +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." +"Free, as in freedom. (We’re a GNU project, " +"after all.)" msgstr "" -"Har du inget konto? Registrera ett konto." -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "Logga in" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "Inloggning misslyckades!" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" -msgstr "Skicka" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -199,6 +226,10 @@ msgstr "Skapa ett!" msgid "Create an account!" msgstr "Skapa ett konto!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -225,6 +256,7 @@ msgid "Cancel" msgstr "Avbryt" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Spara" @@ -237,34 +269,53 @@ msgstr "Redigerar %(username)ss profil" msgid "Media tagged with:" msgstr "Taggat med:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "atom-feed" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Ladda upp" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Skicka" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "%(username)ss media" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "Finns ingen sådan användare ännu." +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" -msgstr "Verifiering krävs" +msgid "Email verification needed" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." -msgstr "Nästan klart! Nu behöver du bara verifiera ditt konto." +msgid "Almost done! Your account still needs to be activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -283,10 +334,8 @@ msgstr "Skicka ett nytt e-postmeddelande" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." +" activated." msgstr "" -"Det finns redan ett konto med det här användarnamnet, men det behöver " -"verifieras." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -303,15 +352,46 @@ msgstr "" msgid "%(username)s's profile" msgstr "%(username)ss profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" msgstr "Redigera profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:98 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" msgstr "Se all media från %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Kommentar" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index d8f8c98d..500b1946 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-13 19:47-0500\n" -"PO-Revision-Date: 2011-08-14 00:47+0000\n" +"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"PO-Revision-Date: 2011-08-25 01:22+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -89,59 +89,79 @@ msgstr "自傳" msgid "Website" msgstr "網站" -#: mediagoblin/edit/forms.py:43 -msgid "Improperly formed URL" -msgstr "部正確的網址" - -#: mediagoblin/edit/views.py:54 +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "這個自訂字串已經被其他人用了" -#: mediagoblin/edit/views.py:75 +#: mediagoblin/edit/views.py:94 msgid "You are editing another user's media. Proceed with caution." msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:96 +#: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." msgstr "你正在編輯他人的檔案. 請謹慎處理." +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "檔案" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "你必須提供一個檔案" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" msgstr "檔案看起來不像是一個圖片喔!" -#: mediagoblin/submit/views.py:94 +#: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" msgstr "喔耶! 送出去了!" +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" msgstr "GNU MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:45 -msgid "Mediagoblin logo" -msgstr "Mediagoblin 標誌" +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" msgstr "送出媒體" -#: mediagoblin/templates/mediagoblin/base.html:62 +#: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" msgstr "確認您的電子郵件!" -#: mediagoblin/templates/mediagoblin/base.html:72 -msgid "Login" +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" msgstr "登入" -#: mediagoblin/templates/mediagoblin/base.html:88 +#: mediagoblin/templates/mediagoblin/base.html:89 msgid "" "Powered by MediaGoblin, a GNU project" @@ -149,40 +169,48 @@ msgstr "" "由 MediaGoblin 製作, 她是一個 GNU project" -#: mediagoblin/templates/mediagoblin/root.html:23 -msgid "Welcome to GNU MediaGoblin!" -msgstr "GNU MediaGoblin 歡迎您!" +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Submit an item" -msgstr "送出一個項目" +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -#, python-format -msgid "If you have an account, you can Login." -msgstr "如果您有帳號了, 你可以直接 登入." +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 -#, python-format +#: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"If you don't have an account, please Register." -msgstr "如果您尚未取得帳號, 請 註冊." +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:26 -msgid "Log in" -msgstr "登入" +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:29 -msgid "Login failed!" -msgstr "登入錯誤" +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:34 -#: mediagoblin/templates/mediagoblin/auth/register.html:30 -#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/submit/start.html:29 -msgid "Submit" -msgstr "送出" +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -196,6 +224,10 @@ msgstr "在這裡建立一個吧!" msgid "Create an account!" msgstr "建立一個帳號!" +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format msgid "" @@ -222,6 +254,7 @@ msgid "Cancel" msgstr "取消" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "儲存變更" @@ -234,34 +267,53 @@ msgstr "編輯 %(username)s'的檔案中" msgid "Media tagged with:" msgstr "媒體被標籤為:" -#: mediagoblin/templates/mediagoblin/listings/tag.html:42 -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:48 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:104 -msgid "atom feed" -msgstr "atom feed" - #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "送出你的媒體檔案" +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "送出" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" msgstr "%(username)s的媒體" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." msgstr "抱歉, 找不到這個使用者." +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 -msgid "Verification needed" -msgstr "需要驗證" +msgid "Email verification needed" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 -msgid "Almost done! Your account still needs to be verified." -msgstr "快要完成了! 你的帳號仍需要驗證." +msgid "Almost done! Your account still needs to be activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -279,8 +331,8 @@ msgstr "重送認證郵件 " #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" -" verified." -msgstr "有人已經註冊了這個帳號, 但此帳號仍需要驗證." +" activated." +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -294,15 +346,46 @@ msgstr "如果你就是那個人, 但是遺失了認證信, 你可以 Date: Thu, 25 Aug 2011 07:41:07 -0500 Subject: 'GNU project' to 'GNU project' --- mediagoblin/templates/mediagoblin/root.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 4ea3fe2a..086c99c4 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -28,7 +28,7 @@

          • {% trans %}The perfect place for your media!{% endtrans %}
          • {% trans %}A place for people to collaborate and show off original and derived creations!{% endtrans %}
          • -
          • {% trans %}Free, as in freedom. (We’re a GNU project, after all.){% endtrans %}
          • +
          • {% trans %}Free, as in freedom. (We’re a GNU project, after all.){% endtrans %}
          • {% trans %}Aiming to make the world a better place through decentralization and (eventually, coming soon!) federation!{% endtrans %}
          • {% trans %}Built for extensibility. (Multiple media types coming soon to the software, including video support!){% endtrans %}
          • {% trans %}Powered by people like you. (You can help us improve this software!){% endtrans %}
          • -- cgit v1.2.3 From 2bbee946bce7a198499f6a5bd3bfe9bad627b861 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 25 Aug 2011 07:41:42 -0500 Subject: Updating extracted translations --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index cbc82003..3f5539c6 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -182,7 +182,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project," +"Free, as in freedom. (We’re a GNU project," " after all.)" msgstr "" -- cgit v1.2.3 From 7d6a9058ddb36798f59c7506703c53ba780f0b62 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 25 Aug 2011 07:43:31 -0500 Subject: Pulling down new translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 8634 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 95 ++++++++++++---------- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 5641 -> 8090 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 5561 -> 7946 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 24 +++--- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 5708 -> 8315 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 65 +++++++++------ mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 5983 -> 8263 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 6281 -> 8482 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 7962 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 5217 -> 7739 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 5414 -> 7906 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 5629 -> 8238 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 69 ++++++++++------ mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 8393 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 5487 -> 8028 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 69 +++++++++------- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 5401 -> 7885 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 5597 -> 8114 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 29 ++++--- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 5387 -> 7758 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 6 +- 30 files changed, 237 insertions(+), 168 deletions(-) create mode 100644 mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo create mode 100644 mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo create mode 100644 mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..aa0cd03b Binary files /dev/null and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index 4aff740e..201f2611 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,15 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Majid Al-Dharrab , 2011. # , 2011. +# , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,54 +22,55 @@ msgstr "" #: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:46 msgid "Username" -msgstr "" +msgstr "اسم المستخدم" #: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:50 msgid "Password" -msgstr "" +msgstr "كلمة المرور" #: mediagoblin/auth/forms.py:34 msgid "Passwords must match." -msgstr "" +msgstr "يجب أن تتطابق كلمتا المرور." #: mediagoblin/auth/forms.py:36 msgid "Confirm password" -msgstr "" +msgstr "تأكيد كلمة المرور" #: mediagoblin/auth/forms.py:39 msgid "Email address" -msgstr "" +msgstr "عنوان البريد الإلكتروني" #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." -msgstr "" +msgstr "عفوًا، التسجيل غير متاح هنا." #: mediagoblin/auth/views.py:57 msgid "Sorry, a user with that name already exists." -msgstr "" +msgstr "عذرا، مستخدم بهذا الاسم موجود فعلا." #: mediagoblin/auth/views.py:61 msgid "Sorry, that email address has already been taken." -msgstr "" +msgstr "عفوًا، هذا العنوان البريدي مستخدم." #: mediagoblin/auth/views.py:159 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" +"تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، تحرير ملفك، وإرسال الصور!" #: mediagoblin/auth/views.py:165 msgid "The verification key or user id is incorrect" -msgstr "" +msgstr "مفتاح التحقق أو معرف المستخدم خاطئ" #: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." -msgstr "" +msgstr "أعيد إرسال رسالة التحقق." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" -msgstr "" +msgstr "العنوان" #: mediagoblin/edit/forms.py:29 msgid "Slug" @@ -83,11 +86,11 @@ msgstr "الوسوم" #: mediagoblin/edit/forms.py:38 msgid "Bio" -msgstr "" +msgstr "السيرة" #: mediagoblin/edit/forms.py:41 msgid "Website" -msgstr "" +msgstr "الموقع الإلكتروني" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -115,7 +118,7 @@ msgstr "" #: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" -msgstr "" +msgstr "لا يبدو أن هذا الملف صورة!" #: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" @@ -145,7 +148,7 @@ msgstr "غنو ميدياغوبلن" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "شعار ميدياغوبلن" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -166,24 +169,26 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"مدعوم بواسطة ميدياغوبلن، مشروع غنو" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "مرحبا بكم يا محبوا الوسائط! ميدياغوبلن هو..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "المكان الأنسب لوسائطك!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" -msgstr "" +msgstr "مكان يجتمع فيه الناس ليتعاونوا ويعرضوا إبداعاتهم الأصلية والمقتبسة!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -208,7 +213,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "فشل الولوج!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -224,7 +229,7 @@ msgstr "أنشئ حسابا!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "أنشئ" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -236,11 +241,17 @@ msgid "" "\n" "%(verification_url)s" msgstr "" +"أهلا %(username)s،\n" +"\n" +"لتفعيل حسابك في غنو ميدياغوبلن، افتح الرابط التالي\n" +"في متصفحك:\n" +"\n" +"%(verification_url)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format msgid "Editing %(media_title)s" -msgstr "" +msgstr "تعديل %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 msgid "Cancel" @@ -262,7 +273,7 @@ msgstr "الوسائط الموسومة بـ:" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" -msgstr "" +msgstr "انشر وسائطك" #: mediagoblin/templates/mediagoblin/submit/start.html:29 msgid "Submit" @@ -271,16 +282,16 @@ msgstr "أرسل" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "وسائط %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." -msgstr "" +msgstr "عذرا، لا يوجد مستخدم مماثل" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "لوحة معالجة الوسائط" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" @@ -302,30 +313,30 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "يجب التحقق من البريد الإلكتروني" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "انتهينا تقريبا! لا زال حسابك يحتاج إلى التفعيل." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." -msgstr "" +msgstr "ستصلك رسالة إلكترونية خلال لحظات بها التعليمات." #: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" -msgstr "" +msgstr "إن لم تصل." #: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" -msgstr "" +msgstr "أعد إرسال رسالة التحقق" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." -msgstr "" +msgstr "سجّل أحدهم حسابًا بهذا الاسم، ولكننا بانتظار التفعيل حتى الآن." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -333,20 +344,22 @@ msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" +"إن كنت أنت ذلك الشخص لكنك فقدت رسالة التحقق، يمكنك الولوج وإعادة إرسالها." #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" -msgstr "" +msgstr "ملف %(username)s's" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "هذه زاوية لتخبر الآخرين فيها عن نفسك." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" -msgstr "" +msgstr "عدل الملف" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." @@ -355,21 +368,21 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "" +msgstr "اعرض كل وسائط %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:135 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "" +msgstr "هنا ستظهر وسائطك، ولكن يبدو أنك لم تضف شيئًا بعد." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "أضف وسائط" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "لا يبدو أنه يوجد أي وسائط هنا حتى الآن..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 6bb69ce9..47b24367 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 1b6c2684..fa8a9b45 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -192,7 +192,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 114ab7c0..72347f29 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 6ee8b85f..ab15f0af 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -30,7 +30,7 @@ msgstr "Pasvorto" #: mediagoblin/auth/forms.py:34 msgid "Passwords must match." -msgstr "Pasvortoj devas koincidi. " +msgstr "Pasvortoj devas esti egalaj." #: mediagoblin/auth/forms.py:36 msgid "Confirm password" @@ -103,7 +103,7 @@ msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." #: mediagoblin/edit/views.py:165 msgid "You are editing a user's profile. Proceed with caution." -msgstr "Vi redaktas profilon de uzanto. Agu singardeme." +msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." @@ -138,6 +138,8 @@ msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Se vi estas certa, ke la adreso estas ĝusta, eble la serĉata de vi paĝo " +"estis movita aŭ forigita." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" @@ -149,7 +151,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "Emblemo de MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -170,8 +172,8 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Funkciigata per MediaGoblin, unu el " -"la projektoj de GNU" +"Funkcias per MediaGoblin, unu el la " +"projektoj de GNU" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -179,7 +181,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "La perfekta loko por viaj aŭd-vid-dosieroj!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" @@ -189,7 +191,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -214,7 +216,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Ensaluto malsukcesis!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -251,7 +253,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format msgid "Editing %(media_title)s" -msgstr "Editing %(media_title)s" +msgstr "Priredaktado de %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 msgid "Cancel" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index dfd3a1bc..f107ac62 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index d35e3b47..d8627710 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -2,14 +2,15 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# , 2011. # , 2011. # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -108,7 +109,7 @@ msgstr "Usted está editando un perfil de usuario. Proceder con precaución." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Archivo inálido para el formato seleccionado." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -128,21 +129,23 @@ msgstr "¡Woohoo! ¡Enviado!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Ups!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Parece no haber una página en esta dirección. ¡Lo siento!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Si estas seguro que la dirección es correcta, puede ser que la pagina halla " +"sido movida o borrada." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "404 el goblin esta estresado" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -150,7 +153,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "Logo de MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -176,21 +179,22 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Hola, amante de los medios de comunicación! MediaGoblin es ..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "El lugar ideal para tus cosas!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Un lugar para colaborar y exhibir tus creaciones orignales y derivadas" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -199,12 +203,16 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Queriendo hacer del mundo un mejor lugar a través de la descentralización y " +"(eventualmente!) la federalización!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Pensado para la ser extensible. (Prontamente soporte para multiples " +"formatos, incluyendo video!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -212,10 +220,13 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Impulsado por gente como vos. ( Vos podés ayudarnos a " +"mejorar este programa)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Fallo el inicio de sesión!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -231,7 +242,7 @@ msgstr "¡Crea una cuenta!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Crear" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -289,33 +300,35 @@ msgstr "Lo sentimos, no se ha encontrado ese usuario." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Panel de procesamiento de contenido" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." msgstr "" +"Puedes hacer un seguimiento del estado de tu contenido siendo procesado " +"aquí." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Contenido siendo procesado" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "No hay contenido siendo procesado." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Estos archivos no pudieron ser procesados:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Correo electrónico de verificación necesario" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Casi terminas! Solo falta activar la cuenta." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -337,6 +350,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Alguien ya registró una cuenta con ese nombre de usuario, pero todavía no " +"fué activada." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -354,7 +369,7 @@ msgstr "Perfil de %(username)s's" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Aquí hay un lugar para que le cuentes a los demás sobre tí" #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -363,7 +378,7 @@ msgstr "Editar perfil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Este usuario (todavia) no ha completado su perfil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -375,22 +390,24 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"Aquí es donde tú contenido estará, pero parece que no haz agregado contenido" +" todavia." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Añadir contenido" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Parece que no hay ningún contenido aquí todavia..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "ícono feed" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "Atom feed" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index f8854734..871d2a42 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 81151d94..91da5fc7 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -194,7 +194,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 78455ad2..0e0e240d 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 6472b6fa..611bae32 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -185,7 +185,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..931d51b9 Binary files /dev/null and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index cd193b97..1a8fb631 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -190,7 +190,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index 8911785f..8bdb4a92 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index 2e9ad8a2..f4c97b12 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -187,7 +187,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 4dc4ab5f..b2e1161e 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 7ea81f3b..438af907 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -187,7 +187,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 361846d4..23d205cf 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 6a671468..e0727b69 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -106,7 +106,7 @@ msgstr "Editați profilul unui utilizator. Se recomandă prudență." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Formatul fișierului nu corespunde cu tipul selectat." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -126,21 +126,23 @@ msgstr "Gata, trimis!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Oops!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Ne pare rău, nu există nicio pagină la această adresă." #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Dacă sunteți sigur că adresa este coresctă, poate că pagina pe care o " +"căutați a fost mutată sau ștearsă." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Imagine cu elful 404 stresat." #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -148,7 +150,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "logo MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -174,21 +176,23 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Bună! MediaGoblin este..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "Locul perfect pentru fișierele tale media!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Un loc unde oamenii colaborează și își expun creațiile originale și " +"derivate!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -197,12 +201,16 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Un pas spre o lume mai bună prin descentralizare și (în curând) " +"federalizare!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Proiectat să fie extensibil. (Software-ul va avea în curând suport pentru " +"multiple formate de media, inclusiv pentru video!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -210,10 +218,13 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Animat de oameni ca tine. (Ne poți ajuta să îmbunătățim" +" acest software!)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Autentificare eșuată!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -229,7 +240,7 @@ msgstr "Creați un cont!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Creează" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -272,7 +283,7 @@ msgstr "Etichete:" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" -msgstr "Trimite fișierele tale" +msgstr "Trimite fișierele tale media" #: mediagoblin/templates/mediagoblin/submit/start.html:29 msgid "Submit" @@ -281,7 +292,7 @@ msgstr "Trimite" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "Fișierele lui %(username)s" +msgstr "Fișierele media ale lui %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 @@ -290,33 +301,33 @@ msgstr "Ne pare rău, nu am găsit utilizatorul căutat." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Panou de procesare media" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" +msgstr "Aici poți urmări stadiul procesării fișierelor media din galeria ta." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Fișiere în curs de procesare" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Niciun fișier în curs de procesare" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Aceste fișiere nu au putut fi procesate:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Este necesară verificarea adresei de e-mail" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Aproape gata! Mai trebuie doar să activezi contul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -336,6 +347,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Cineva a înregistrat un cont cu acest nume de utilizator, dar contul nu a " +"fost încă activat." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -354,7 +367,7 @@ msgstr "Profil %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Aici poți spune altora ceva despre tine." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -363,7 +376,7 @@ msgstr "Editare profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Acest utilizator nu și-a completat (încă) profilul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -375,22 +388,24 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"Aici vor apărea fișierele tale media, dar se pare că încă nu ai trimis " +"nimic." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Trimite fișier" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Nu pare să existe niciun fișier media deocamdată..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "icon feed" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "feed Atom" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..55f611d5 Binary files /dev/null and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index cedd5a2e..53222a97 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -184,7 +184,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index a70b1fef..aaeec466 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index 7302ce6e..3db6ed4a 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -48,7 +48,7 @@ msgstr "Oprostite, uporabnik s tem imenom že obstaja." #: mediagoblin/auth/views.py:61 msgid "Sorry, that email address has already been taken." -msgstr "" +msgstr "Oprostite, ta e-poštni naslov je že v uporabi." #: mediagoblin/auth/views.py:159 msgid "" @@ -105,7 +105,7 @@ msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Za vrsto vsebine je bila podana napačna datoteka." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -125,21 +125,23 @@ msgstr "Juhej! Poslano." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Opa!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Oprostite. Videti je, da na tem naslovu ni nobene strani." #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Če ste v točnost naslova prepričani, je bila iskana stran morda premaknjena " +"ali pa izbrisana." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Slika napake 404 s paničnim škratom" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -147,7 +149,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "Logotip MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -173,21 +175,23 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Pozdravljen, ljubitelj večpredstavnostnih vsebin! MediaGoblin je ..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "Popolno mesto za vaše večpredstavnostne vsebine." #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Mesto, kjer ljudje lahko sodelujejo in razkazujejo originalne in predelane " +"stvaritve." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -196,12 +200,16 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Ustvarjen z namenom izboljšati svet, s pomočjo decentralizacije in (kmalu) " +"federacije." #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Zgrajen za razširjanje. (Kmalu bodo na voljo dodatne vrste vsebin, vključno " +"podpora za video)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -209,10 +217,13 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Sad dela ljudi, kot ste vi. (Pri izboljševanju nam lahko " +"pomagate tudi vi.)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Prijava ni uspela." #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -228,7 +239,7 @@ msgstr "Ustvarite račun." #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Ustvari" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -290,33 +301,33 @@ msgstr "Oprostite, tega uporabnika ni bilo moč najti." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Podokno obdelovanja vsebine" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" +msgstr "Tu lahko spremljate stanje vsebin, ki so v obdelavi za vašo galerijo." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Vsebina v obdelavi" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "V obdelavi ni nobene vsebine" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Teh vsebin ni bilo moč obdelati:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Potrebna je potrditev prek e-pošte" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Skoraj ste zaključili. Svoj račun morate le še aktivirati." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -336,6 +347,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Nekdo je s tem uporabniškim imenom že registriral račun, vendar mora biti še" +" aktiviran." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -353,7 +366,7 @@ msgstr "Profil – %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Na tem mestu lahko drugim poveste nekaj o sebi." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -362,7 +375,7 @@ msgstr "Uredi profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Ta uporabnik še ni izpolnil svojega profila." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -373,26 +386,26 @@ msgstr "Prikaži vso vsebino uporabnika %(username)s" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "" +msgstr "Tu bo prikazana vaša vsebina, a trenutno še niste dodali nič." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Dodaj vsebino" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Videti je, da tu še ni nobene vsebine ..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "Ikona vira" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "Ikona Atom" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" -msgstr "" +msgstr "Komentar" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index 153584d3..2f9de271 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index ddb5d44b..51c2e443 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -182,7 +182,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index 0d4b463c..e209556f 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index ede78f0d..e4183c18 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -105,7 +105,7 @@ msgstr "Var försiktig, du redigerar en annan användares profil." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Ogiltig fil för mediatypen." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -125,21 +125,23 @@ msgstr "Tjohoo! Upladdat!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Ojoj!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Ledsen, det verkar inte vara någonting här." #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Om du är säker på att adressen stämmer så kanske sidan du letar efter har " +"flyttats eller tagits bort." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Bild av stressat 404-troll." #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -147,7 +149,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "MediaGoblin-logotyp" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -173,21 +175,23 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Hej där mediaentusiast, MediaGoblin..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "Är ett perfekt ställe för din media!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Är ett ställe för människor att samarbeta och visa upp originella och " +"härrörande verk." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" @@ -196,6 +200,11 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Arbetar för att göra världen till ett bättre ställe genom decentralisering " +"och (så småningom, kommer snart!) -- Google Translate säger " +"\"sammanslutning\", en: federation" +" " #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index 9615e44c..ce7240fc 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 500b1946..44670ab2 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-24 20:20-0500\n" -"PO-Revision-Date: 2011-08-25 01:22+0000\n" +"POT-Creation-Date: 2011-08-25 07:41-0500\n" +"PO-Revision-Date: 2011-08-25 12:41+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -185,7 +185,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" -"Free, as in freedom. (We’re a GNU project, " +"Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" -- cgit v1.2.3 From d71170ad0abea7768c425a6011816cd8cdadf9df Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 25 Aug 2011 19:38:13 +0200 Subject: Feature #489 - SMTP configuration options - Acts on feedback from cwebber. http://bugs.foocorp.net/issues/489#note-2 --- mediagoblin/config_spec.ini | 2 +- mediagoblin/util.py | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index bc6f00d9..0bc7d6ad 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -20,7 +20,7 @@ direct_remote_path = string(default="/mgoblin_static/") # set to false to enable sending notices email_debug_mode = boolean(default=True) email_sender_address = string(default="notice@mediagoblin.example.org") -email_smtp_host = string(default=None) +email_smtp_host = string(default='') email_smtp_port = integer(default=25) email_smtp_user = string(default=None) email_smtp_pass = string(default=None) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 6dced54e..60ba8800 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -237,10 +237,7 @@ class FakeMhost(object): Just a fake mail host so we can capture and test messages from send_email """ - def connect(self): - pass - - def login(self): + def login(self, *args, **kwargs): pass def sendmail(self, from_addr, to_addrs, message): @@ -273,14 +270,16 @@ def send_email(from_addr, to_addrs, subject, message_body): if TESTS_ENABLED or mg_globals.app_config['email_debug_mode']: mhost = FakeMhost() elif not mg_globals.app_config['email_debug_mode']: - if not mg_globals.app_config['email_smtp_host']: - mhost = smtplib.SMTP() - else: - mhost = smtplib.SMTP( - mg_globals.app_config['email_smtp_host'], - mg_globals.app_config['email_smtp_port']) - - if mg_globals.app_config['email_smtp_user']: + mhost = smtplib.SMTP( + mg_globals.app_config['email_smtp_host'], + mg_globals.app_config['email_smtp_port']) + + # SMTP.__init__ Issues SMTP.connect implicitly if host + if not mg_globals.app_config['email_smtp_host']: # e.g. host = '' + mhost.connect() # We SMTP.connect explicitly + + if mg_globals.app_config['email_smtp_user'] \ + or mg_globals.app_config['email_smtp_pass']: mhost.login( mg_globals.app_config['email_smtp_user'], mg_globals.app_config['email_smtp_pass']) -- cgit v1.2.3 From 6503d66c98765802836b09fb9f6a5f2ad47ad47a Mon Sep 17 00:00:00 2001 From: tycho garen Date: Sat, 27 Aug 2011 17:43:14 -0400 Subject: Documentation Revision, clarification, and editing. - a line in the .gitignore file to ignore the built documentation tree. - a complete revision/editorial pass of all non-technical documents that outline process, project fundamentals, and background. These edits clarified the text, unified the style, and elaborated on stubs. --- .gitignore | 1 + docs/source/about_mediagoblin.rst | 95 +++++++------- docs/source/contributinghowto.rst | 262 +++++++++++++++++++++----------------- docs/source/foreword.rst | 51 ++++---- docs/source/index.rst | 5 +- 5 files changed, 231 insertions(+), 183 deletions(-) diff --git a/.gitignore b/.gitignore index 9da56bab..5f16bd74 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ mediagoblin.egg-info *.pyc *.pyo docs/_build/ +docs/build user_dev/ paste_local.ini mediagoblin_local.ini diff --git a/docs/source/about_mediagoblin.rst b/docs/source/about_mediagoblin.rst index af6658f3..71d8b89c 100644 --- a/docs/source/about_mediagoblin.rst +++ b/docs/source/about_mediagoblin.rst @@ -9,43 +9,52 @@ What is GNU MediaGoblin ======================= -Three years ago (2008), a number of free software luminaries got -together at the FSF office to answer the question, "What should -software freedom look like on the participatory web?" Those thinkers -included Richard Stallman---founder of the free software movement and -instigator of the GNU project, Evan Prodromou---the driving force -behind Status.net, a highly sucessful federated micro-blogging -service, and FIXME. - -Since that time Identi.ca and Libre.fm have answered the -freedom-loving web-user's need for micro-blogging and music sharing. -Now, GNU MediaGoblin is building a format for users to share photos. -Later versions of MediaGoblin will include support for video and other -media as well as tools to encourage collaboration on media projects. - - -Why are we doing this? -====================== - -Centralization and proprietization of media on the internet is a -serious problem and makes the web go from a system of extreme -resilience to a system of frightening fragility. We believe people -should be able to free their data from proprietary control and that -means someone has to build the tools to make it possible. We decided -that in this case, that someone would be us! - - -Who are you? -============ - -Free software activists and folks who have worked on a variety of -other projects like Libre.fm, GNU Social, Status.net, Miro, Miro -Community, OpenHatch and other projects as well. We're admirers and -contributors. We're writers and painters. We're friendly and -dedicated to computer user freedom. - - -How can I participate? +In 2008 a number of free software developers and activists gathered at +the FSF to attempt to answer the question "What should software +freedom look like on the participatory web?" Their answer, the +`Franklin Street Statement `_, +has lead to the development of `autonomo.us `_ +community, and free software projects including `Identi.ca `_ +and `Libre.fm `_. + +Identi.ca and Libre.fm address the need for micro-blogging and music +sharing services and software that respect users' freedom and +autonomy. GNU MediaGoblin emerges from this milieu to create a +platform for us to share photos in an environment that respects our +freedom and independence. In the future MediaGoblin will include +support other media, like video, and provide tools to facilitate +collaboration on media projects. + +Why Build GNU MediaGoblin +========================= + +The Internet is designed--and works best--as a complex and endlessly +resilient network. When key services and media outlets are +concentrated in centralized platforms, the network becomes less useful +and increasingly fragile. As always, the proprietary nature of these +systems, hinders users ability to develop, extend, and understand +their software; however, in the case of network services it also means +that users must forfeit control of their data to the service +providers. + +Therefore, we believe that network services must be federated to avoid +centralization and that everyone ought to have control over their +data. In support of this, we've decided to help build the tools to +make these kinds of services possible. We hope you'll join us, both as +users and as contributors. + +Who Contributes to the Project +============================== + +You do! + +We are free software activists and folks who have worked on a variety +of other projects including: Libre.fm, GNU Social, Status.net, Miro, +Miro Community, and OpenHatch among others. We're programmers, +musicians, writers, and painters. We're friendly and dedicated to +software and network freedom. + +How Can I Participate? ====================== See `Get Involved `_ on the website.. @@ -56,15 +65,15 @@ How is GNU MediaGoblin licensed? GNU MediaGoblin software is released under an AGPLv3 license. -See the ``COPYING`` file in the source for details. +See the ``COPYING`` file in the source repository for details. -Is this an official GNU Project? What does that mean? -====================================================== +Is MedaGobilin an official GNU project? What does that mean? +============================================================= -We are! It means that we meet the GNU Project's rigourous standards -for free software. To find out more about what that means, check out -`the GNU site `_. +MediaGoblin is an official GNU project! This status means that we the +meet the GNU Project's rigorous standards for free software. To find +out more about what that means, check out `the GNU site `_. Please feel free to contact us with further questions! diff --git a/docs/source/contributinghowto.rst b/docs/source/contributinghowto.rst index a4f5771a..8eaff5e4 100644 --- a/docs/source/contributinghowto.rst +++ b/docs/source/contributinghowto.rst @@ -1,185 +1,215 @@ .. _contributing-howto-chapter: -==================== - Contributing HOWTO -==================== +=================================== +HOWTO Contribute to GNU MediaGoblin +=================================== .. contents:: Sections :local: - .. _join-the-community-section: Join the community! =================== -We're super glad you want to join our community! - -See `the join page on the website `_ for -where we hang out. - -There are a variety of ways you can help us and become part of the -team. We're not just looking for coders! We're also looking for -documentation writers, users, testers, evangelists, user-interface -designers, graphics designers, user-experience designers, system -administrators, friends, painters, bakers, candle-stick makers... - -Here are some things you can do today: - +We're **really** glad that you want to join the MediaGoblin community! - **Hang out with us** +There are a variety of ways to help and support MediaGoblin and to +join the team. If you want to code, great, if not, even better! +MediaGoblin interested contributors in many different roles: users, +system administrators, technical writers, testers, evangelists, +UI/UX and graphics designers, cheerleaders, and dreamers. - You should hang out with us! We like people like you! +This document provides an overview of different ways you can get +involved with MediaGoblin along with instructions for getting +started. There is some obvious overlap with `the "join" page on +mediagoblin.org `_ at present. - At a bare minimum, join the `mailing list - `_ and say, "Hi!" +Hang out with the MediaGoblin folk +---------------------------------- - We also hang out on IRC in ``#mediagoblin`` on Freenode.net. +MediaGoblin has a `discussion listserv `_, +and an IRC (``#mediagoblin``) channel on `freenode.net `_. +Don't be afraid to drop by and say "Hi!" And, if you're looking for +something to do, just ask: there's always work to be done. - **File bugs** +File Bugs / Triage Bugs +----------------------- - Filing bugs is a critical part of any project. For more - information on filing bugs, see :ref:`filing-bugs`. +Issue reports are critical for all projects. Identified bugs give +developers a basis for beginning work, and providing an idea of what +features and issues are most important to users and the overall +usability of the software. If you identify errors, flaws, unexpected +behaviors, or deficits that impede use, file a bug. +See the section on `filing bugs <#filing-bugs>`_ for more information on how to file the best +and most useful bug reports. - **Write/Fix some code** +If you want to contribute to MediaGoblin and don't know where to +start, look at the `bug database `_ +as a starting point. - If you are a coder and you're looking to code, check out the - `wiki `_ for suggestions on how +to most effectively triage and approach the issue queue. +Write/Fix Code +-------------- - **Send encouragement** +If you are a coder and you would like to write code, the `repository `_ +is hosted on `gitorious `_. Clone or fork the +repository and start poking around. Become familiar with this `manual `_ +for an overview of how the software works and is used. Consider the +`contributor wiki `_ for more +information about the project, our preferred methods, and guides for +developing MediaGoblin. We even have tips on *becoming* a coder and +we're willing to help! - A nice word from you could send someone into a tizzy of - productive work. Ten nice words could complete a feature. - One hundred nice words could get us to the next milestone. +Send Encouragement, Spread the Word +----------------------------------- - Send it to the `mailing list `_ - or hop into ``#mediagoblin`` on Freenode.net and let us know. +Sometimes, a nice word, simple encouragement, and interest in the work +we're doing is enough to inspire a tizzy of productive work. Just a +bit more interest and encouragement can even make the difference +between a complete feature and limited functionality; between a +completed milestone and lost momentum. +Similarly, MediaGoblin, and the movement for free network services, is +always in need of encouragement. Use free network services, understand +the `principals `_ +behind the movement, be able to articulate the benefits of free +network services and the problems with psudo-free applications that +don't respect the users' freedom. - **Spread the word** - - The seductive call of Free Software services is a powerful - one, but many cannot hear it because it's drowned out by the - rush hour traffic honking of proprietary walled gardens and - faux free services. Yuck! Be the sweet chirrup of the bird - amidst the din! Tell others that there is a better way to - live! - - FIXME - do we want to talk about ways to spread the word? - - FIXME - how can people notify us that they're spreading the - word? +Write a blog post, post a status update, drop by the `listserv `_ +or join ``#mediagoblin`` on freenode.net and let us know. +Participate in MediaGoblin +========================== We're still working on project infrastructure. We hope to have the bits in place for these additional things to do in the coming months: - **Become a user** - - We're building GNU MediaGoblin for us and for you but really - you're one of us and I am you and we are we and GNU - MediaGoblin is the walrus. - - Sign up for an account. Use the service. Relish in the - thought that this service comes with a heaping side of Freedom - and you can salt and pepper it to your liking. +Become a User +------------- +We're building GNU MediaGoblin for us and for you but really +you're one of us and I am you and we are we and GNU +MediaGoblin is the walrus. - **Help other users** +Sign up for an account. Use the service. Relish in the +thought that this service comes with a heaping side of Freedom +and you can salt and pepper it to your liking. - Have you spent time with GNU MediaGoblin? If so, your - experience and wisdom are invaluable and you're the best - person we can think of to help other users with their - questions. +Help Others +----------- - **Run your own instance** +Have you spent time with GNU MediaGoblin? If so, your +experience and wisdom are invaluable and you're the best +person we can think of to help other users with their +questions. - Are there things about our instance you want to change? Are - there things about other instances you wish were different? - Want to test upcoming changes? Want to create patches to - implement things you need? That's great---you can run your - own instance! - - For more information on deploying your own instance, see - :ref:`deployment-howto`. +Run your own MediaGoblin Instance +--------------------------------- - **Translate GNU MediaGoblin** +Are there things about our instance you want to change? Are +there things about other instances you wish were different? +Want to test upcoming changes? Want to create patches to +implement things you need? That's great---you can run your +own instance! - Knowing more than one language is an important skill. If you - are multi-lingual and are interested in translating GNU - MediaGoblin, see :ref:`translating`. - - - **Create a theme** - - As people deploy their own GNU MediaGoblin instances, good - themes are a must have! For more information on theming, see - :ref:`theming-howto`. +For more information on deploying your own instance, see +the `Deployment HOWTO `_ +.. _translating: -Contributing thank you drawings / copyright assignment -====================================================== +Translate MediaGoblin +--------------------- -Copyright assignment with GNU MediaGoblin to the `FSF -`_ is highly encouraged but not mandatory. To -incentivize both this and people to make cool contributions to our -project, if you make useful contributions to GNU MediaGoblin *and* do -a copyright assignment to the Free Software Foundation, the founder of -the project, Chris Webber, will make a custom drawing of a goblin -dedicated specifically to you. +If you know English and another language and feel comfortable +translating elements of the interface or even the documentation, +we'd love to have help translating the software and resources. -For why we're doing copyright assignment, see the -`wiki `_. +Create a Theme +-------------- +MedaGoblin development is premised on the idea that the entire +interface for the platform be completely theme-able. If you have a +design or theming background, consider developing themes for +MediaGoblin. New themes help test the theming system, provide +attractive and appealing interfaces for prospective users. If you want +to start a new theme but don't know where to start, touch base with +the development community on the list or in the IRC channel for more +information. .. _filing-bugs: -File bugs +File Bugs ========= -GNU MediaGoblin uses a bug tracker called `Redmine -`_. +MediaGoblin uses a bug tracker called `Redmine `_. -The bug tracker is at ``_. +Our instance is located at ``_. -A good bug report has the following things in it: +The most useful bug reports have the following components: 1. A short summary that's 60 characters or less. 2. A description that describes the issue (bug, feature request, ...) - as well as the context. + as well as the context. Consider: - * If it's a bug, can you reproduce it? Is the issue specific to a - browser, computer, image, ...? + * If you think you've found a bug, can you reproduce it in a + controlled environment? Is the issue specific to a browser, + computer, image, media type, or other dimension? All data helps. - * If it's a feature request, are there related links on the Internet - for more information? Would you be willing to help implement or - test the feature? + * If you're submitting a feature request, are there related links + on the Internet for more information? Would you be willing to + help implement or test the feature? -That's it! When someone looks into the issue and has questions, -they'll contact you! +That's it! -If you don't hear from anyone in a couple of weeks, find someone on -IRC. +The better the issue report, the easier it is to address the bug, and +the more likely that the developers will be able to resolve the +issue. If someone has questions about the bug report, they may reach +out to the reporter directly. +If you get a response after a couple of weeks, find someone on IRC. -.. _translating: +.. _triage-bugs: + +Triage Bugs +=========== + +The triage process involves reviewing bugs, removing duplicates, +validating that the issues described are reproducible, ensuring that +the exact behavior is properly documented, diagnosing the cause of +each issue, and working with developers to ensure that critical bugs +get addressed. In many cases, developers do this kind of work as a +matter of course, but one need not be able to code in order to help +working with bugs. + +To triage bugs, go to the `bug tracker `_ +and begin reviewing the open issues. If you are able, attempt to: -Translate GNU MediaGoblin -========================= +- ensure that one or two people in addition to the initial reporter + have been able to reproduce the issue. -Coming soon when we set up translation infrastructure. +- document the issue more clearly. If you had any trouble reproducing + the issue, provide any elucidating information that you can to help + others solve the problem more effectively. + +- find a way to resolve the problem or provide a workaround. +For help, instructions, and suggestions be in touch with the +development community on the list or in the IRC channel for more +information. With many eyes, all bugs are shallow. -Where to go when you get stuck -============================== +How to Get Help with MediaGoblin +================================ -Go to `our Web site `_ where we list the -various places we hang out and how to get a hold of us. +The usual channels, the IRC channel, the listserv, the bug tracker, +are all great ways to be in touch with us. Check the `web site `_ +for more specific contact information. diff --git a/docs/source/foreword.rst b/docs/source/foreword.rst index 4fd96842..c525d002 100644 --- a/docs/source/foreword.rst +++ b/docs/source/foreword.rst @@ -1,39 +1,46 @@ -========== - Foreword -========== +======== +Foreword +======== -About this manual -================= +About the MediaGoblin Manual +============================ -This is the GNU MediaGoblin manual. This documentation targets the -following groups of individuals: +Welcome to the GNU MediaGoblin manual. This document targets several +classes of users, including: -* people who want to try the software locally -* people who want to deploy and administrate the software +* users who would like to try the software locally, +* systems administrators who want to deploy and administer the + software in "production environments," and +* anyone who wants to learn how MediaGoblin works. -This manual doesn't cover contributors to the codebase. But we want -and love contributors! To join as a contributor please visit the -following pages instead: +Some information relevant to the MediaGoblin community members, +including how to get involved (We want and love contributors!) To join +as a contributor please see the following pages: * http://mediagoblin.org/pages/join.html for general "join us" information * http://wiki.mediagoblin.org/ for our contributor-focused wiki -If you are viewing this from http://docs.mediagoblin.org be aware that -this manual is a living document and is in the ``mediagoblin`` -repository in the ``docs/`` directory. +If you suspect that documentation on http://docs.mediagoblin.org is +out of date, it might be. The documentation is updated regularly and +the "living" version of this resource resides in the ``mediagoblin`` +repository with the project's source code the ``docs/`` directory. +Improving the MediaGobiin Manual +================================ -I found an error in the docs---who do I tell? -============================================= - -There are a few ways---please pick the one most convenient to you! +There are a few ways---please pick whichever method is convenient for +you! 1. Write up a bug report in the bug tracker at http://bugs.foocorp.net/projects/mediagoblin/issues 2. Tell someone on IRC ``#mediagoblin`` on Freenode. -3. Send an email to Will ``willg at bluesock dot org``. +3. Send an email to Will ``willg at bluesock dot org``, or Sam at + ``sam@cyborginstitute.com`` When you tell us about your issue, please let us know: * where you are looking (in git? url of the web-page?) -* what the issue is -* your thoughts on how to resolve it +* what the issue is, and +* your thoughts on how to resolve it. + +We hope these materials are useful and we look forward to any and all +feedback. diff --git a/docs/source/index.rst b/docs/source/index.rst index 79f2653e..93b2a942 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,7 +23,8 @@ Table of Contents: Indices and tables ================== -* :ref:`genindex` -* :ref:`modindex` * :ref:`search` +* :ref:`genindex` + +.. * :ref:`modindex` -- cgit v1.2.3 From c35b8426f922cf49e4f495c6a8e7ce87eff71c69 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 28 Aug 2011 09:42:46 -0500 Subject: Pulling down latest translations --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 8090 -> 8220 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 71 +++++++++++++++---------- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 7946 -> 7968 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 18 ++++--- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 8315 -> 8328 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 6 ++- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 8238 -> 8249 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 11 ++-- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 8393 -> 8585 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 21 +++++--- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 8114 -> 8142 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 45 ++++++++++------ 12 files changed, 105 insertions(+), 67 deletions(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 47b24367..898d5f0f 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index fa8a9b45..f8ee1ea8 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -13,8 +13,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 19:13+0000\n" +"Last-Translator: piratenpanda \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -53,7 +53,7 @@ msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." #: mediagoblin/auth/views.py:61 msgid "Sorry, that email address has already been taken." -msgstr "Tut und Leid, aber diese E-Mail Adresse wird bereits verwendet." +msgstr "Tut und Leid, aber diese Email-Adresse wird bereits verwendet." #: mediagoblin/auth/views.py:159 msgid "" @@ -70,7 +70,7 @@ msgstr "Der Bestätigungssschlüssel oder die Nutzernummer ist falsch." #: mediagoblin/auth/views.py:186 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." -msgstr "Bestätigungs-Email wurde erneut versand." +msgstr "Bestätigungs-Email wurde erneut versandt." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" @@ -110,7 +110,7 @@ msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -130,21 +130,23 @@ msgstr "Yeeeaaah! Geschafft!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Hoppla!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Tut uns Leid, aber unter der angegebenen Adresse gibt es keine Seite!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Wenn du sicher bist, dass die Adresse stimmt, wurde die Seite eventuell " +"verschoben oder gelöscht." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Bild eines angespannten Goblins" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -152,7 +154,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "MediaGoblin-Logo" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -178,35 +180,43 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Hallo Medien-Liebhaber! MediaGoblin ist …" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "Der perfekte Platz für deine Medien!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Ein Platz für Zusammenarbeit und um Originale und abgeleitete Werke zu " +"präsentieren!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Frei, wie in Freiheit. (Wir sind schließlich ein GNU-Projekt.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Weltverbesserer durch Dezentralisierung und (hoffentlich bald!) unabhängige " +"Kommunikation!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Gebaut für Erweiterungen. (Bald mit Unterstützung für verschiedene " +"Medientypen inklusive Videos!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -214,10 +224,13 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Betrieben von Leuten wie dir. (Du kannst uns dabei helfen, " +"die Software zu verbessern!)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Anmeldevorgang fehlgeschlagen!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -233,7 +246,7 @@ msgstr "Neues Konto registrieren!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Erstellen" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -245,7 +258,7 @@ msgid "" "\n" "%(verification_url)s" msgstr "" -"Hi %(username)s,\n" +"Hallo %(username)s,\n" "\n" "um dein Konto bei GNU MediaGoblin zu aktivieren, musst du folgende Adresse in einem Webbrowser öffnen:\n" "\n" @@ -294,33 +307,35 @@ msgstr "Dieser Benutzer wurde leider nicht gefunden." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Medienverarbeitung" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." msgstr "" +"Du kannst den Status der gerade in Bearbeitung befindlichen Medien hier " +"betrachten." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Medien in Bearbeitung" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Keine Medien in Bearbeitung" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Die folgenden Uploads sind fehlgeschlagen" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Email-Bestätigung benötigt" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Fast fertig! Dein Konto muss noch freigeschaltet werden." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -342,6 +357,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Jemand hat bereits ein Konto mit diesem Benutzernamen registriert, aber es " +"muss noch aktiviert werden." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -360,7 +377,7 @@ msgstr "%(username)ss Profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Hier kannst du Anderen etwas über dich zu erzählen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -369,7 +386,7 @@ msgstr "Profil bearbeiten" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Dieser Benutzer hat (noch) keine Daten in seinem Profil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -380,23 +397,23 @@ msgstr "Alle Medien von %(username)s anschauen" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "" +msgstr "Hier erscheinen deine Medien. Sobald du etwas hochgeladen hast." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Medien hinzufügen" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Scheinbar gibt es hier noch nichts …" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "Feed-Symbol" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "Atom-Feed" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 72347f29..63a3294f 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index ab15f0af..f2a1b78b 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 14:28+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -194,6 +194,8 @@ msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Libera verko. (Ni ja estas projekto de <a " +"href=\"http://gnu.org\">GNU</a>.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" @@ -232,7 +234,7 @@ msgstr "Kreu konton!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Krei" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -315,7 +317,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Necesas konfirmo de retpoŝtadreso" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." @@ -357,7 +359,7 @@ msgstr "Profilo de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Jen estas spaceto por rakonti pri vi al aliaj." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -381,15 +383,15 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Aldoni dosieron" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Ĉi tie ŝajne estas ankoraŭ neniuj dosieroj…" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "flusimbolo" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index f107ac62..6adf5526 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index d8627710..d2e8f662 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 20:22+0000\n" +"Last-Translator: nvjacobo \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -197,6 +197,8 @@ msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Libre, como en la libertad. (Somos parte del proyecto GNU después de todo.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 23d205cf..a3f48cd7 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index e0727b69..4ae3290c 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 17:38+0000\n" +"Last-Translator: gap \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -106,7 +106,7 @@ msgstr "Editați profilul unui utilizator. Se recomandă prudență." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "Formatul fișierului nu corespunde cu tipul selectat." +msgstr "Formatul fișierului nu corespunde cu tipul de media selectat." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -154,7 +154,7 @@ msgstr "logo MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" -msgstr "Transmiteți fișier" +msgstr "Transmiteți un fișier media" #: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" @@ -195,6 +195,7 @@ msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Liber. (Suntem un proiect GNU, până la urmă.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" @@ -381,7 +382,7 @@ msgstr "Acest utilizator nu și-a completat (încă) profilul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "Toate fișierele lui %(username)s" +msgstr "Toate fișierele media ale lui %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:135 msgid "" diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 55f611d5..49aa9ccb 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 53222a97..9adc9b83 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 14:35+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -116,7 +116,7 @@ msgstr "" #: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" -msgstr "" +msgstr "Файл, похоже, не является картинкой!" #: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" @@ -124,7 +124,7 @@ msgstr "Ура! Файл загружен!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Ой!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" @@ -142,11 +142,11 @@ msgstr "" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" -msgstr "" +msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "Символ MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -160,7 +160,7 @@ msgstr "подтвердите ваш адрес электронной почт #: mediagoblin/templates/mediagoblin/auth/login.html:26 #: mediagoblin/templates/mediagoblin/auth/login.html:34 msgid "Log in" -msgstr "" +msgstr "Представиться" #: mediagoblin/templates/mediagoblin/base.html:89 msgid "" @@ -237,6 +237,11 @@ msgid "" "\n" "%(verification_url)s" msgstr "" +"Привет, %(username)s!\n" +"\n" +"Чтобы активировать свою учётную запись в GNU MediaGoblin, откройте в своём веб‐браузере следующую ссылку:\n" +"\n" +"%(verification_url)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format @@ -378,7 +383,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "лента в формате Atom" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index e209556f..2136e0a3 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index e4183c18..dd30371a 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-08-25 07:41-0500\n" -"PO-Revision-Date: 2011-08-25 12:41+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-08-25 13:07+0000\n" +"Last-Translator: joar \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -194,6 +194,8 @@ msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Är fritt som i frihet. (Vi är ju ett GNU-projekt.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" @@ -211,6 +213,8 @@ msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Byggd för utbyggbarhet. (Flera mediatyper kommer snart till MediaGoblin, " +"bland annat video!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -218,10 +222,13 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Drivs av människor som du. (Du kan hjälpa os forbättra " +"MediaGoblin!)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Inloggning misslyckades!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -237,7 +244,7 @@ msgstr "Skapa ett konto!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Skapa" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -298,33 +305,33 @@ msgstr "Finns ingen sådan användare ännu." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Mediabehandlingspanel" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" +msgstr "Här kan du se status för mediabehandling av bilder i ditt galleri." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Media under behandling" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Ingen media under behandling" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "De här behandlingarna misslyckades:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "E-postadressverifiering krävs." #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Nästan klar! Ditt konto behöver bara aktiveras." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -345,6 +352,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Någon har redan registrerat ett konto med det här användarnamnet men det har" +" inte aktiverats." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -363,7 +372,7 @@ msgstr "%(username)ss profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Här kan du berätta för andra om dig själv." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -372,7 +381,7 @@ msgstr "Redigera profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Den här användaren har inte fyllt i sin profilsida ännu." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -384,22 +393,24 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"Här kommer din media att dyka upp, du verkar inte ha lagt till någonting " +"ännu." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Lägg till media" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Det verkar inte finnas någon media här ännu." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "feed-ikon" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "Atom-feed" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" -- cgit v1.2.3 From ad56a4826b987a0fa8f65849d3611f61cc1f50d6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 28 Aug 2011 17:30:45 -0500 Subject: Testing logo without logo --- mediagoblin/static/images/logo.png | Bin 3340 -> 2479 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png index 019ec5ec..1c08a2fb 100644 Binary files a/mediagoblin/static/images/logo.png and b/mediagoblin/static/images/logo.png differ -- cgit v1.2.3 From 46df0297e029c075a2c28b0c31490c560c99158c Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 29 Aug 2011 00:42:55 +0200 Subject: Added notice that deletion of a media entry is *permanent* --- mediagoblin/templates/mediagoblin/confirm/confirm_delete.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html b/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html index ada89d5d..67d45811 100644 --- a/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/confirm/confirm_delete.html @@ -31,6 +31,14 @@ Really delete {{ title }}? {%- endtrans %}

        +

        + + {%- trans -%} + If you choose yes, the media entry will be deleted permanently. + {%- endtrans %} + +

        + {{ wtforms_util.render_divs(form) }}
        -- cgit v1.2.3 From 25ba955e20e9262f2599a21d234511b724569717 Mon Sep 17 00:00:00 2001 From: Alejandro Villanueva Date: Thu, 21 Jul 2011 11:55:41 -0500 Subject: Adding fotgot password functionality --- mediagoblin/auth/forms.py | 32 ++++++++ mediagoblin/auth/lib.py | 40 +++++++-- mediagoblin/auth/routing.py | 12 +++ mediagoblin/auth/views.py | 96 +++++++++++++++++++++- mediagoblin/db/migrations.py | 15 ++++ mediagoblin/db/models.py | 2 + .../templates/mediagoblin/auth/change_fp.html | 37 +++++++++ .../mediagoblin/auth/forgot_password.html | 37 +++++++++ .../mediagoblin/auth/fp_changed_success.html | 25 ++++++ .../templates/mediagoblin/auth/fp_email_sent.html | 26 ++++++ .../mediagoblin/auth/fp_verification_email.txt | 25 ++++++ mediagoblin/templates/mediagoblin/auth/login.html | 6 ++ 12 files changed, 346 insertions(+), 7 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/auth/change_fp.html create mode 100644 mediagoblin/templates/mediagoblin/auth/forgot_password.html create mode 100644 mediagoblin/templates/mediagoblin/auth/fp_changed_success.html create mode 100644 mediagoblin/templates/mediagoblin/auth/fp_email_sent.html create mode 100644 mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 917909c5..1be74aa6 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import wtforms +import re from mediagoblin.util import fake_ugettext_passthrough as _ @@ -49,3 +50,34 @@ class LoginForm(wtforms.Form): password = wtforms.PasswordField( _('Password'), [wtforms.validators.Required()]) + + +class ForgotPassForm(wtforms.Form): + username = wtforms.TextField( + 'Username or email', + [wtforms.validators.Required()]) + + def validate_username(form,field): + if not (re.match(r'^\w+$',field.data) or + re.match(r'^.+@[^.].*\.[a-z]{2,10}$',field.data, re.IGNORECASE)): + raise wtforms.ValidationError(u'Incorrect input') + + +class ChangePassForm(wtforms.Form): + password = wtforms.PasswordField( + 'Password', + [wtforms.validators.Required(), + wtforms.validators.Length(min=6, max=30), + wtforms.validators.EqualTo( + 'confirm_password', + 'Passwords must match.')]) + confirm_password = wtforms.PasswordField( + 'Confirm password', + [wtforms.validators.Required()]) + userid = wtforms.HiddenField( + '', + [wtforms.validators.Required()]) + token = wtforms.HiddenField( + '', + [wtforms.validators.Required()]) + diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 6d1aec49..df93b666 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -47,7 +47,7 @@ def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None): # number (thx to zooko on this advice, which I hopefully # incorporated right.) # - # See also: + # See also: rand_salt = bcrypt.gensalt(5) randplus_stored_hash = bcrypt.hashpw(stored_hash, rand_salt) randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt) @@ -99,7 +99,7 @@ def send_verification_email(user, request): Args: - user: a user object - - request: the request + - request: the request """ rendered_email = render_template( request, 'mediagoblin/auth/verification_email.txt', @@ -116,8 +116,38 @@ def send_verification_email(user, request): [user['email']], # TODO # Due to the distributed nature of GNU MediaGoblin, we should - # find a way to send some additional information about the - # specific GNU MediaGoblin instance in the subject line. For - # example "GNU MediaGoblin @ Wandborg - [...]". + # find a way to send some additional information about the + # specific GNU MediaGoblin instance in the subject line. For + # example "GNU MediaGoblin @ Wandborg - [...]". 'GNU MediaGoblin - Verify your email!', rendered_email) + + +EMAIL_FP_VERIFICATION_TEMPLATE = ( + u"http://{host}{uri}?" + u"userid={userid}&token={fp_verification_key}") + +def send_fp_verification_email(user,request): + """ + Send the verification email to users to change their password. + + Args: + - user: a user object + - request: the request + """ + rendered_email = render_template( + request, 'mediagoblin/auth/fp_verification_email.txt', + {'username': user['username'], + 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( + host=request.host, + uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), + userid=unicode(user['_id']), + fp_verification_key=user['fp_verification_key'])}) + + # TODO: There is no error handling in place + send_email( + mg_globals.email_sender_address, + [user['email']], + 'GNU MediaGoblin - Change forgotten password!', + rendered_email) + diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 9547b3ea..14e87133 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -30,4 +30,16 @@ auth_routes = [ Route('mediagoblin.auth.resend_verification_success', '/resend_verification_success/', template='mediagoblin/auth/resent_verification_email.html', + controller='mediagoblin.views:simple_template_render'), + Route('mediagoblin.auth.forgot_password', '/forgotpass/', + controller='mediagoblin.auth.views:forgot_password'), + Route('mediagoblin.auth.verify_forgot_password', '/verifyforgotpass/', + controller='mediagoblin.auth.views:verify_forgot_password'), + Route('mediagoblin.auth.fp_changed_success', + '/fp_changed_success/', + template='mediagoblin/auth/fp_changed_success.html', + controller='mediagoblin.views:simple_template_render'), + Route('mediagoblin.auth.fp_email_sent', + '/fp_email_sent/', + template='mediagoblin/auth/fp_email_sent.html', controller='mediagoblin.views:simple_template_render')] diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 4c4a34fd..50276442 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import uuid +import datetime from webob import exc @@ -22,10 +23,11 @@ from mediagoblin import messages from mediagoblin import mg_globals from mediagoblin.util import render_to_response, redirect, render_404 from mediagoblin.util import pass_to_ugettext as _ -from mediagoblin.db.util import ObjectId +from mediagoblin.db.util import ObjectId, InvalidId from mediagoblin.auth import lib as auth_lib from mediagoblin.auth import forms as auth_forms -from mediagoblin.auth.lib import send_verification_email +from mediagoblin.auth.lib import send_verification_email, \ + send_fp_verification_email def register(request): @@ -187,3 +189,93 @@ def resend_activation(request): return redirect( request, 'mediagoblin.user_pages.user_home', user=request.user['username']) + + +def forgot_password(request): + """ + Forgot password view + + Sends an email whit an url to renew forgoten password + """ + fp_form = auth_forms.ForgotPassForm(request.POST) + + if request.method == 'POST' and fp_form.validate(): + user = request.db.User.one( + {'$or': [{'username': request.POST['username']}, + {'email': request.POST['username']}]}) + + if not user: + fp_form.username.errors.append( + u"Sorry, the username doesn't exists") + else: + user['fp_verification_key'] = unicode(uuid.uuid4()) + user['fp_token_expire'] = datetime.datetime.now() + \ + datetime.timedelta(days=10) + user.save() + + send_fp_verification_email(user, request) + + return redirect(request, 'mediagoblin.auth.fp_email_sent') + + return render_to_response( + request, + 'mediagoblin/auth/forgot_password.html', + {'fp_form': fp_form}) + + +def verify_forgot_password(request): + if request.method == 'GET': + # If we don't have userid and token parameters, we can't do anything;404 + if (not request.GET.has_key('userid') or + not request.GET.has_key('token')): + return exc.HTTPNotFound('You must provide userid and token') + + # check if it's a valid Id + try: + user = request.db.User.find_one( + {'_id': ObjectId(unicode(request.GET['userid']))}) + except InvalidId: + return exc.HTTPNotFound('Invalid id') + + # check if we have a real user and correct token + if (user and + user['fp_verification_key'] == unicode(request.GET['token'])): + cp_form = auth_forms.ChangePassForm(request.GET) + + return render_to_response( + request, + 'mediagoblin/auth/change_fp.html', + {'cp_form': cp_form}) + # in case there is a valid id but no user whit that id in the db + else: + return exc.HTTPNotFound('User not found') + if request.method == 'POST': + # verification doing here to prevent POST values modification + try: + user = request.db.User.find_one( + {'_id': ObjectId(unicode(request.POST['userid']))}) + except InvalidId: + return exc.HTTPNotFound('Invalid id') + + cp_form = auth_forms.ChangePassForm(request.POST) + + # verification doing here to prevent POST values modification + # if token and id are correct they are able to change their password + if (user and + user['fp_verification_key'] == unicode(request.POST['token'])): + + if cp_form.validate(): + user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + request.POST['password']) + user['fp_verification_key'] = None + user.save() + + return redirect(request, + 'mediagoblin.auth.fp_changed_success') + else: + return render_to_response( + request, + 'mediagoblin/auth/change_fp.html', + {'cp_form': cp_form}) + else: + return exc.HTTPNotFound('User not found') diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 5456b248..b0cb6965 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -92,3 +92,18 @@ def mediaentry_add_fail_error_and_metadata(database): {'fail_metadata': {'$exists': False}}, {'$set': {'fail_metadata': {}}}, multi=True) + + +@RegisterMigration(6) +def user_add_forgot_password_token_and_expires(database): + """ + Add token and expiration fields to help recover forgotten passwords + """ + database['users'].update( + {'fp_token': {'$exists': False}}, + {'$set': {'fp_token': ''}}, + multi=True) + database['users'].update( + {'fp_token_expire': {'$exists': False}}, + {'$set': {'fp_token_expire': ''}}, + multi=True) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index b6e52441..a626937d 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -78,6 +78,8 @@ class User(Document): 'url' : unicode, 'bio' : unicode, # May contain markdown 'bio_html': unicode, # May contain plaintext, or HTML + 'fp_token': unicode, # forgotten password verification key + 'fp_token_expire': datetime.datetime } required_fields = ['username', 'created', 'pw_hash', 'email'] diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html new file mode 100644 index 00000000..0a3c76f6 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -0,0 +1,37 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} + +
        + +
        +{% endblock %} + diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html new file mode 100644 index 00000000..1708874f --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html @@ -0,0 +1,37 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_content %} + +
        + +
        +{% endblock %} + diff --git a/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html b/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html new file mode 100644 index 00000000..dfce1423 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html @@ -0,0 +1,25 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} +

        + Your password have been changed. Now you can Login +

        +{% endblock %} + diff --git a/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html b/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html new file mode 100644 index 00000000..d7fad722 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html @@ -0,0 +1,26 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% block mediagoblin_content %} +

        + Please check your email. We send an email whit an url to change your password. +

        + +{% endblock %} + diff --git a/mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt b/mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt new file mode 100644 index 00000000..1b2dbe2f --- /dev/null +++ b/mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt @@ -0,0 +1,25 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +Hi {{ username }}, + +to change your GNU MediaGoblin password, open the following URL in your web browser + +{{ verification_url|safe }} + +If you think this is an error, just ignore this email and continue being a happy goblin! + diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index afbecf20..75e6eed1 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -44,6 +44,12 @@ {%- trans %}Create one here!{% endtrans %}

        +

        + {% trans %}Forgot your password?{% endtrans %} +
        + + {%- trans %}Send a reminder!{% endtrans %} +

        {% endif %}
        -- cgit v1.2.3 From 65030735085782be067c8c97e288e9baf3dbdbf4 Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Sun, 28 Aug 2011 21:13:07 -0500 Subject: oops, uses Alejandro's fp_verification_key. my bad. --- mediagoblin/db/migrations.py | 4 ++-- mediagoblin/db/models.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index b0cb6965..cf09e817 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -100,8 +100,8 @@ def user_add_forgot_password_token_and_expires(database): Add token and expiration fields to help recover forgotten passwords """ database['users'].update( - {'fp_token': {'$exists': False}}, - {'$set': {'fp_token': ''}}, + {'fp_verification_key': {'$exists': False}}, + {'$set': {'fp_verification_key': ''}}, multi=True) database['users'].update( {'fp_token_expire': {'$exists': False}}, diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index a626937d..ad989f81 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -78,7 +78,7 @@ class User(Document): 'url' : unicode, 'bio' : unicode, # May contain markdown 'bio_html': unicode, # May contain plaintext, or HTML - 'fp_token': unicode, # forgotten password verification key + 'fp_verification_key': unicode, # forgotten password verification key 'fp_token_expire': datetime.datetime } -- cgit v1.2.3 From f85909c061a6cff211cf27f46879ad096ae7852f Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Sun, 28 Aug 2011 21:41:42 -0500 Subject: needed to access email_sender_address through mg_globals.app_config instead of mg_globals.email_sender_address. --- mediagoblin/auth/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index df93b666..31dc4b7f 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -146,7 +146,7 @@ def send_fp_verification_email(user,request): # TODO: There is no error handling in place send_email( - mg_globals.email_sender_address, + mg_globals.app_config['email_sender_address'], [user['email']], 'GNU MediaGoblin - Change forgotten password!', rendered_email) -- cgit v1.2.3 From fac7b8c9b160db7c6c85f9677acfb7bc7650c23f Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Sun, 28 Aug 2011 22:46:21 -0500 Subject: Changed phrasing, spelling, and added translations --- mediagoblin/templates/mediagoblin/auth/change_fp.html | 4 ++-- mediagoblin/templates/mediagoblin/auth/forgot_password.html | 4 ++-- .../templates/mediagoblin/auth/fp_changed_success.html | 4 +++- mediagoblin/templates/mediagoblin/auth/fp_email_sent.html | 4 +++- .../templates/mediagoblin/auth/fp_verification_email.txt | 11 ++++++++--- mediagoblin/templates/mediagoblin/auth/login.html | 2 +- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 0a3c76f6..4be7e065 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -23,8 +23,8 @@
        -
      {% if allow_registration %} -

      Excited to join us? To add your own media, make collections and save favorites...

      +

      Excited to join us?

      Create a free account or Set up MediaGoblin on your own server {% endif %} -- cgit v1.2.3 From 8775f68d33279347f7bc72258d9133f20b192149 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Sep 2011 16:37:38 -0500 Subject: Make "newer" and "older" arrows not have underlined gap between image / text --- mediagoblin/templates/mediagoblin/utils/pagination.html | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index cdac01c8..7a99880a 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -33,15 +33,18 @@

      diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 78b88ae8..190b9ac3 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -26,6 +26,7 @@ + {{ csrf_token }} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 442bef6d..433f74dc 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -72,6 +72,7 @@ {{ wtforms_util.render_divs(comment_form) }}
      + {{ csrf_token }}
      {% endif %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 48fbc3b0..3acf802b 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -42,6 +42,7 @@ {{ wtforms_util.render_divs(form) }}
      + {{ csrf_token }}
      -- cgit v1.2.3 From 6be33a778098e38b4951dd358c5016e9fcd280e6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Sep 2011 22:26:57 -0500 Subject: Removing description field cruft that mostly existed for testing purposes. :) --- mediagoblin/auth/forms.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index daf7b993..1dfaf095 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -24,18 +24,14 @@ class RegistrationForm(wtforms.Form): _('Username'), [wtforms.validators.Required(), wtforms.validators.Length(min=3, max=30), - wtforms.validators.Regexp(r'^\w+$')], - description=_( - u"This is the name other users will identify you with.")) + wtforms.validators.Regexp(r'^\w+$')]) password = wtforms.PasswordField( _('Password'), [wtforms.validators.Required(), wtforms.validators.Length(min=6, max=30), wtforms.validators.EqualTo( 'confirm_password', - _('Passwords must match.'))], - description=_( - u"Try to use a strong password!")) + _('Passwords must match.'))]) confirm_password = wtforms.PasswordField( _('Confirm password'), [wtforms.validators.Required()], @@ -44,9 +40,7 @@ class RegistrationForm(wtforms.Form): email = wtforms.TextField( _('Email address'), [wtforms.validators.Required(), - wtforms.validators.Email()], - description=_( - u"Your email will never be published.")) + wtforms.validators.Email()]) class LoginForm(wtforms.Form): -- cgit v1.2.3 From 7b80685ac544886cb6cfa00424c785e1d5fb5c9c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Sep 2011 23:05:06 -0500 Subject: Added a description to the slug field on the media entry form. --- mediagoblin/edit/forms.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 7bf3c6a8..f81d58b2 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -25,13 +25,17 @@ class EditForm(wtforms.Form): title = wtforms.TextField( _('Title'), [wtforms.validators.Length(min=0, max=500)]) - slug = wtforms.TextField( - _('Slug'), - [wtforms.validators.Required(message=_("The slug can't be empty"))]) description = wtforms.TextAreaField('Description of this work') tags = wtforms.TextField( _('Tags'), [tag_length_validator]) + slug = wtforms.TextField( + _('Slug'), + [wtforms.validators.Required(message=_("The slug can't be empty"))], + description=_( + "The title part of this media's URL. " + "You usually don't need to change this.")) + class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField( @@ -42,6 +46,7 @@ class EditProfileForm(wtforms.Form): [wtforms.validators.Optional(), wtforms.validators.URL(message='Improperly formed URL')]) + class EditAttachmentsForm(wtforms.Form): attachment_name = wtforms.TextField( 'Title') -- cgit v1.2.3 From 8d1c9863b6541e811b0168cca29c3dc33f8b6cf1 Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Mon, 5 Sep 2011 14:02:23 -0500 Subject: refactors verify_forgot_password --- mediagoblin/auth/views.py | 113 ++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 589d87cf..7ffa7416 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -222,62 +222,59 @@ def forgot_password(request): def verify_forgot_password(request): - if request.method == 'GET': - # If we don't have userid and token parameters, we can't do anything;404 - if (not request.GET.has_key('userid') or - not request.GET.has_key('token')): - return render_404(request) - - # check if it's a valid Id - try: - user = request.db.User.find_one( - {'_id': ObjectId(unicode(request.GET['userid']))}) - except InvalidId: - return render_404(request) - - # check if we have a real user and correct token - if (user and - user['fp_verification_key'] == unicode(request.GET['token']) and - datetime.datetime.now() < user['fp_token_expire']): - cp_form = auth_forms.ChangePassForm(request.GET) - - return render_to_response( - request, - 'mediagoblin/auth/change_fp.html', - {'cp_form': cp_form}) - # in case there is a valid id but no user whit that id in the db - # or the token expired - else: - return render_404(request) - if request.method == 'POST': - # verification doing here to prevent POST values modification - try: - user = request.db.User.find_one( - {'_id': ObjectId(unicode(request.POST['userid']))}) - except InvalidId: - return render_404(request) - - cp_form = auth_forms.ChangePassForm(request.POST) - - # verification doing here to prevent POST values modification - # if token and id are correct they are able to change their password - if (user and - user['fp_verification_key'] == unicode(request.POST['token']) and - datetime.datetime.now() < user['fp_token_expire']): - - if cp_form.validate(): - user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( - request.POST['password']) - user['fp_verification_key'] = None - user['fp_token_expire'] = None - user.save() - - return redirect(request, - 'mediagoblin.auth.fp_changed_success') - else: - return render_to_response( - request, - 'mediagoblin/auth/change_fp.html', - {'cp_form': cp_form}) + # get session variables, and specifically check for presence of token + mysession = _process_for_token(request) + if not mysession['token_complete']: + return render_404(request) + + session_token = mysession['vars']['token'] + session_userid = mysession['vars']['userid'] + session_vars = mysession['vars'] + + # check if it's a valid Id + try: + user = request.db.User.find_one( + {'_id': ObjectId(unicode(session_userid))}) + except InvalidId: + return render_404(request) + + # check if we have a real user and correct token + if (user and user['fp_verification_key'] == unicode(session_token) and + datetime.datetime.now() < user['fp_token_expire']): + cp_form = auth_forms.ChangePassForm(session_vars) + + if request.method == 'POST' and cp_form.validate(): + user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + request.POST['password']) + user['fp_verification_key'] = None + user['fp_token_expire'] = None + user.save() + + return redirect(request, 'mediagoblin.auth.fp_changed_success') else: - return render_404(request) + return render_to_response(request, + 'mediagoblin/auth/change_fp.html', + {'cp_form': cp_form}) + # in case there is a valid id but no user whit that id in the db + # or the token expired + else: + return render_404(request) + + +def _process_for_token(request): + """ + Checks for tokens in session without prior knowledge of request method + + For now, returns whether the userid and token session variables exist, and + the session variables in a hash. Perhaps an object is warranted? + """ + # retrieve the session variables + if request.method == 'GET': + session_vars = request.GET + else: + session_vars = request.POST + + mysession = {'vars': session_vars, + 'token_complete': session_vars.has_key('userid') and + session_vars.has_key('token')} + return mysession -- cgit v1.2.3 From c2b862d1349b5ecc6d787000edb209525b719751 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 5 Sep 2011 22:06:47 +0200 Subject: Feature #571 - Closing storage objects - Removed closing(), renamed StorageObjectWrapper, added with-support to CloudFilesStorageWrapper * Removed custom `closing()` method * Removed usage of `closing()` in process_media/__init__.py * Renamed StorageObjectWrapper -> CloudFilesStorageObject wrapper In my first version of the StorageOjbectWrapper it was located inside the CloudFilesStorage object, things have changed since then but there has been no renaming, thank you Elrond for the good point. * CloudFilesStorageObjectWrapper now supports context manager methods such as `__enter__()` and `__exit__()` (and `close()`) --- mediagoblin/process_media/__init__.py | 19 +++++-------------- mediagoblin/storage.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index db913f5f..2b9eed6e 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -16,7 +16,6 @@ import Image -from contextlib import contextmanager from celery.task import Task from celery import registry @@ -36,14 +35,6 @@ def create_pub_filepath(entry, filename): filename]) -@contextmanager -def closing(callback): - try: - yield callback - finally: - pass - - ################################ # Media processing initial steps ################################ @@ -66,7 +57,7 @@ class ProcessMedia(Task): except BaseProcessingFail, exc: mark_entry_failed(entry[u'_id'], exc) return - + entry['state'] = u'processed' entry.save() @@ -144,7 +135,7 @@ def process_image(entry): thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with closing(thumb_file): + with thumb_file: thumb.save(thumb_file, "JPEG", quality=90) # If the size of the original file exceeds the specified size of a `medium` @@ -162,7 +153,7 @@ def process_image(entry): medium_filepath = create_pub_filepath(entry, 'medium.jpg') medium_file = mgg.public_store.get_file(medium_filepath, 'w') - with closing(medium_file): + with medium_file: medium.save(medium_file, "JPEG", quality=90) medium_processed = True @@ -172,8 +163,8 @@ def process_image(entry): with queued_file: original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - - with closing(mgg.public_store.get_file(original_filepath, 'wb')) as original_file: + + with mgg.public_store.get_file(original_filepath, 'wb') as original_file: original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index e3df72be..b376ead0 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -291,7 +291,7 @@ class CloudFilesStorage(StorageInterface): if mimetype: obj.content_type = mimetype[0] - return StorageObjectWrapper(obj, *args, **kwargs) + return CloudFilesStorageObjectWrapper(obj, *args, **kwargs) def delete_file(self, filepath): # TODO: Also delete unused directories if empty (safely, with @@ -305,7 +305,7 @@ class CloudFilesStorage(StorageInterface): self._resolve_filepath(filepath)]) -class StorageObjectWrapper(): +class CloudFilesStorageObjectWrapper(): """ Wrapper for python-cloudfiles's cloudfiles.storage_object.Object used to circumvent the mystic `medium.jpg` corruption issue, where @@ -322,11 +322,38 @@ class StorageObjectWrapper(): return self.storage_object.read(*args, **kwargs) def write(self, data, *args, **kwargs): + """ + write data to the cloudfiles storage object + + The original motivation for this wrapper is to ensure + that buffered writing to a cloudfiles storage object does not overwrite + any preexisting data. + + Currently this method does not support any write modes except "append". + However if we should need it it would be easy implement. + """ if self.storage_object.size and type(data) == str: data = self.read() + data self.storage_object.write(data, *args, **kwargs) + def close(self): + pass + + def __enter__(self): + """ + Context Manager API implementation + http://docs.python.org/library/stdtypes.html#context-manager-types + """ + return self + + def __exit__(self, *args): + """ + Context Manger API implementation + see self.__enter__() + """ + self.close() + # ------------ # MountStorage -- cgit v1.2.3 From 213285cd856359ad4429af8b2b93614eb6709558 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 5 Sep 2011 22:33:27 +0200 Subject: Changed `*args` => `*exc_info` in CloudFilesStorageObjectWrapper --- mediagoblin/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index b376ead0..f9563031 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -347,7 +347,7 @@ class CloudFilesStorageObjectWrapper(): """ return self - def __exit__(self, *args): + def __exit__(self, *exc_info): """ Context Manger API implementation see self.__enter__() -- cgit v1.2.3 From 65a8304794f5ad694799454c0337675708b10906 Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Mon, 5 Sep 2011 17:33:01 -0500 Subject: added unit tests for lost password code --- mediagoblin/tests/test_auth.py | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 4781dd9b..a8e2d123 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import urlparse +import datetime from nose.tools import assert_equal @@ -237,6 +238,81 @@ def test_register_views(test_app): ## TODO: Also check for double instances of an email address? + ### Oops, forgot the password + # ------------------- + util.clear_test_template_context() + response = test_app.post('/auth/forgotpass/', {'username': 'happygirl'}) + response.follow() + + ## Did we redirect to the proper page? Use the right template? + assert_equal( + urlparse.urlsplit(response.location)[2], + '/auth/fp_email_sent/') + assert util.TEMPLATE_TEST_CONTEXT.has_key( + 'mediagoblin/auth/fp_email_sent.html') + + ## Make sure link to change password is sent by email + assert len(util.EMAIL_TEST_INBOX) == 1 + message = util.EMAIL_TEST_INBOX.pop() + assert message['To'] == 'happygrrl@example.org' + email_context = util.TEMPLATE_TEST_CONTEXT[ + 'mediagoblin/auth/fp_verification_email.txt'] + #TODO - change the name of verification_url to something forgot-password-ish + assert email_context['verification_url'] in message.get_payload(decode=True) + + path = urlparse.urlsplit(email_context['verification_url'])[2] + get_params = urlparse.urlsplit(email_context['verification_url'])[3] + assert path == u'/auth/verifyforgotpass/' + parsed_get_params = urlparse.parse_qs(get_params) + + # user should have matching parameters + new_user = mg_globals.database.User.find_one({'username': 'happygirl'}) + assert parsed_get_params['userid'] == [unicode(new_user['_id'])] + assert parsed_get_params['token'] == [new_user['fp_verification_key']] + + ### The forgotten password token should be set to expire in ~ 10 days + # A few ticks have expired so there are only 9 full days left... + assert (new_user['fp_token_expire'] - datetime.datetime.now()).days == 9 + + ## Try using a bs password-changing verification key, shouldn't work + util.clear_test_template_context() + response = test_app.get( + "/auth/verifyforgotpass/?userid=%s&token=total_bs" % unicode( + new_user['_id']), status=400) + assert response.status == '400 Bad Request' + + ## Verify step 1 of password-change works -- can see form to change password + util.clear_test_template_context() + response = test_app.get("%s?%s" % (path, get_params)) + assert util.TEMPLATE_TEST_CONTEXT.has_key('mediagoblin/auth/change_fp.html') + + ## Verify step 2.1 of password-change works -- report success to user + util.clear_test_template_context() + response = test_app.post( + '/auth/verifyforgotpass/', { + 'userid': parsed_get_params['userid'], + 'password': 'iamveryveryhappy', + 'confirm_password': 'iamveryveryhappy', + 'token': parsed_get_params['token']}) + response.follow() + assert util.TEMPLATE_TEST_CONTEXT.has_key( + 'mediagoblin/auth/fp_changed_success.html') + + ## Verify step 2.2 of password-change works -- login w/ new password success + util.clear_test_template_context() + response = test_app.post( + '/auth/login/', { + 'username': u'happygirl', + 'password': 'iamveryveryhappy'}) + + # User should be redirected + response.follow() + assert_equal( + urlparse.urlsplit(response.location)[2], + '/') + assert util.TEMPLATE_TEST_CONTEXT.has_key( + 'mediagoblin/root.html') + @setup_fresh_app def test_authentication_views(test_app): -- cgit v1.2.3 From a237735a70fb7d4a4ffabbf09fdb8f104a24698d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 18:19:24 -0500 Subject: Mark description field's label for translation --- mediagoblin/submit/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 17df6be6..a999c714 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -26,7 +26,8 @@ class SubmitStartForm(wtforms.Form): title = wtforms.TextField( _('Title'), [wtforms.validators.Length(min=0, max=500)]) - description = wtforms.TextAreaField('Description of this work') + description = wtforms.TextAreaField( + _('Description of this work')) tags = wtforms.TextField( _('Tags'), [tag_length_validator]) -- cgit v1.2.3 From 4bcaf9f32ab7e125a8db8deece4f292fed71e291 Mon Sep 17 00:00:00 2001 From: Caleb Forbes Davis V Date: Mon, 5 Sep 2011 18:57:06 -0500 Subject: for readability, and adds unit test for expired token --- mediagoblin/auth/views.py | 4 ++-- mediagoblin/tests/test_auth.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 7ffa7416..c18bfa34 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -224,7 +224,7 @@ def forgot_password(request): def verify_forgot_password(request): # get session variables, and specifically check for presence of token mysession = _process_for_token(request) - if not mysession['token_complete']: + if not mysession['has_userid_and_token']: return render_404(request) session_token = mysession['vars']['token'] @@ -275,6 +275,6 @@ def _process_for_token(request): session_vars = request.POST mysession = {'vars': session_vars, - 'token_complete': session_vars.has_key('userid') and + 'has_userid_and_token': session_vars.has_key('userid') and session_vars.has_key('token')} return mysession diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index a8e2d123..bfa66bd2 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -281,6 +281,16 @@ def test_register_views(test_app): new_user['_id']), status=400) assert response.status == '400 Bad Request' + ## Try using an expired token to change password, shouldn't work + util.clear_test_template_context() + real_token_expiration = new_user['fp_token_expire'] + new_user['fp_token_expire'] = datetime.datetime.now() + new_user.save() + response = test_app.get("%s?%s" % (path, get_params), status=400) + assert response.status == '400 Bad Request' + new_user['fp_token_expire'] = real_token_expiration + new_user.save() + ## Verify step 1 of password-change works -- can see form to change password util.clear_test_template_context() response = test_app.get("%s?%s" % (path, get_params)) -- cgit v1.2.3 From 8daef28dc75b30917d42497a5419d54ea5ab5eae Mon Sep 17 00:00:00 2001 From: Shawn Khan Date: Mon, 5 Sep 2011 19:12:53 -0400 Subject: Page Redesign to Delete confirmation page --- .../user_pages/media_confirm_delete.html | 21 ++++++++++++--------- mediagoblin/user_pages/forms.py | 6 ++---- mediagoblin/user_pages/views.py | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 48fbc3b0..1e7752cb 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -31,17 +31,20 @@ Really delete {{ title }}? {%- endtrans %} -

      - - {%- trans -%} - If you choose yes, the media entry will be deleted permanently. - {%- endtrans %} - -

      - {{ wtforms_util.render_divs(form) }} +
      + +
      + +
      + +

      + {{ form.confirm }} + {{ _(form.confirm.label.text) }} +

      - +
      diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 22dedfd9..bf456630 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -26,7 +26,5 @@ class MediaCommentForm(wtforms.Form): class ConfirmDeleteForm(wtforms.Form): - confirm = wtforms.RadioField('Confirm', - default='False', - choices=[('False', 'No, I made a mistake!'), - ('True', 'Yes, delete it!')]) + confirm = wtforms.BooleanField('I am sure I want to delete this', + [wtforms.validators.Required()]) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2c376283..f60bd186 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -154,7 +154,7 @@ def media_confirm_delete(request, media): form = user_forms.ConfirmDeleteForm(request.POST) if request.method == 'POST' and form.validate(): - if request.POST.get('confirm') == 'True': + if form.confirm.data is True: username = media.uploader()['username'] # Delete all files on the public storage -- cgit v1.2.3 From b7f7c13b6d70113857bac89c426d17dffc55bc6d Mon Sep 17 00:00:00 2001 From: Shawn Khan Date: Mon, 5 Sep 2011 19:35:25 -0400 Subject: Created a Cancel Button, if you don't want to delete Media. --- mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 1e7752cb..3fbc2862 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -44,7 +44,10 @@ {{ _(form.confirm.label.text) }}

      + + +
      -- cgit v1.2.3 From 677f55cc51c82c80005b0ff6658e9937133ef78b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 21:01:22 -0500 Subject: A couple more delete UI tweaks - Adjusting HTML indentation - Making the cancel button a link rather than a button (a bit missized though it seems... maybe a feature ;)) --- mediagoblin/static/css/base.css | 12 +++++++++++- .../mediagoblin/user_pages/media_confirm_delete.html | 16 ++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 307e2970..ea54f77f 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -141,7 +141,7 @@ background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, /* common website elements */ -.button { +.button, .cancel_link { height: 32px; min-width: 99px; background-color: #86d4b1; @@ -165,6 +165,16 @@ background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, font-weight: bold; } +.cancel_link { + background-color: #aaa; + background-image: -webkit-gradient(linear, left top, left bottom, from(##D2D2D2), to(#aaa)); + background-image: -webkit-linear-gradient(top, #D2D2D2, #aaa); + background-image: -moz-linear-gradient(top, #D2D2D2, #aaa); + background-image: -ms-linear-gradient(top, #D2D2D2, #aaa); + background-image: -o-linear-gradient(top, #D2D2D2, #aaa); + background-image: linear-gradient(top, #D2D2D2, #aaa); +} + .pagination{ text-align: center; } diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 3fbc2862..9192289e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -32,22 +32,22 @@ {%- endtrans %} -
      +
      -
      +

      - {{ form.confirm }} - {{ _(form.confirm.label.text) }} -

      + {{ form.confirm }} + {{ _(form.confirm.label.text) }} +

      +
      - - + {# TODO: This isn't a button really... might do unexpected things :) #} + {% trans %}Cancel{% endtrans %} -
      -- cgit v1.2.3 From e8b517924ea5586c3249e4fbcf8b96c4dbeba49a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 21:03:54 -0500 Subject: A couple of tweaks to the checkbox styling... pretty minor. --- mediagoblin/static/css/base.css | 8 ++++++++ .../templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index ea54f77f..d1b891ac 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -365,3 +365,11 @@ table.media_panel th { font-weight: bold; padding-bottom: 4px; } + + +/* Delete panel */ + +.delete_checkbox_box { + margin-top: 10px; + margin-left: 10px; +} \ No newline at end of file diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 9192289e..01323a6e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -39,7 +39,7 @@
      -

      +

      {{ form.confirm }} {{ _(form.confirm.label.text) }}

      -- cgit v1.2.3 From 284ebca0b217b6cca1f9484ec4871a9a72ee627e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 22:57:52 -0500 Subject: Caching test... pretty basic. --- mediagoblin/tests/test_cache.py | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 mediagoblin/tests/test_cache.py diff --git a/mediagoblin/tests/test_cache.py b/mediagoblin/tests/test_cache.py new file mode 100644 index 00000000..cbffeb84 --- /dev/null +++ b/mediagoblin/tests/test_cache.py @@ -0,0 +1,52 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin import mg_globals + + +DATA_TO_CACHE = { + 'herp': 'derp', + 'lol': 'cats'} + + +def _get_some_data(key): + """ + Stuid function that makes use of some caching. + """ + some_data_cache = mg_globals.cache.get_cache('sum_data') + if some_data_cache.has_key(key): + return some_data_cache.get(key) + + value = DATA_TO_CACHE.get(key) + some_data_cache.put(key, value) + return value + + +@setup_fresh_app +def test_cache_working(test_app): + some_data_cache = mg_globals.cache.get_cache('sum_data') + assert not some_data_cache.has_key('herp') + assert _get_some_data('herp') == 'derp' + assert some_data_cache.get('herp') == 'derp' + # should get the same value again + assert _get_some_data('herp') == 'derp' + + # now we force-change it, but the function should use the cached + # version + some_data_cache.put('herp', 'pred') + assert _get_some_data('herp') == 'pred' -- cgit v1.2.3 From 7624c641cd0f5a6d438d88dcfb48d724b09e7763 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 23:20:08 -0500 Subject: Updating the confirm delete form: checkboxes shouldn't be required, make translatable --- mediagoblin/user_pages/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index bf456630..57061d34 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -26,5 +26,5 @@ class MediaCommentForm(wtforms.Form): class ConfirmDeleteForm(wtforms.Form): - confirm = wtforms.BooleanField('I am sure I want to delete this', - [wtforms.validators.Required()]) + confirm = wtforms.BooleanField( + _('I am sure I want to delete this')) -- cgit v1.2.3 From 9a64272e483ef1e3a5ee8b10555822a3ea158053 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 23:20:50 -0500 Subject: Fixing the confirm delete unit test Now it's updated for the new checkbox-for-confirm code. --- mediagoblin/tests/test_submission.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index b7013839..007c0348 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -178,7 +178,8 @@ class TestSubmission: # No work: user=media.uploader().username, user=self.test_user['username'], media=media['_id']), - {'confirm': 'False'}) + # no value means no confirm + {}) response.follow() @@ -197,7 +198,7 @@ class TestSubmission: # No work: user=media.uploader().username, user=self.test_user['username'], media=media['_id']), - {'confirm': 'True'}) + {'confirm': 'y'}) response.follow() -- cgit v1.2.3 From fc21a55c76e9786f8ea8fdf504861c48e179a841 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 23:28:11 -0500 Subject: Turning on caching for mediagoblin testing after all? Maybe we'll add a way to toggle this. --- mediagoblin/tests/test_mgoblin_app.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 986f793b..ab32cccc 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -20,7 +20,8 @@ base_url = /mgoblin_media/ base_dir = %(here)s/test_user_dev/media/queue [beaker.cache] -enabled = false +data_dir = %(here)s/test_user_dev/beaker/cache/data +lock_dir = %(here)s/test_user_dev/beaker/cache/lock [celery] celery_always_eager = true -- cgit v1.2.3 From b0391ad94bcae4dabfc2749612038c34a47bee75 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Sep 2011 23:34:20 -0500 Subject: Updating translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 9432 -> 9631 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 140 ++++++++++---------- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 9038 -> 9020 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 92 +++++++------ mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 72 ++++++----- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 8775 -> 8804 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 113 +++++++++------- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 9157 -> 9151 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 83 ++++++------ mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 9083 -> 9314 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 151 +++++++++++++--------- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 9308 -> 9266 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 8779 -> 8737 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 8385 -> 8343 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 8732 -> 8690 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 9081 -> 9008 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 122 +++++++++-------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 11171 -> 11125 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 99 +++++++------- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 8848 -> 8806 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 8711 -> 8669 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 75 ++++++----- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 8972 -> 8930 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 77 ++++++----- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 8541 -> 8545 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 114 ++++++++-------- 31 files changed, 843 insertions(+), 680 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index dafcdb66..d02639a9 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index df47bac4..112c6973 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,49 +20,37 @@ msgstr "" "Language: ar\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "اسم المستخدم" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" -msgstr "كلمة المرور" +msgstr "كلمة السر" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." -msgstr "يجب أن تتطابق كلمتا المرور." +msgstr "يجب أن تتطابق كلمتا السر." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" -msgstr "تأكيد كلمة المرور" +msgstr "أكّد كلمة السر" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "اكتبها مرة أخرى هنا للتأكد من عدم وجود أخطاء إملائية." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "عنوان البريد الإلكتروني" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "عفوًا، التسجيل غير متاح هنا." #: mediagoblin/auth/views.py:58 msgid "Sorry, a user with that name already exists." -msgstr "عذرا، مستخدم بهذا الاسم موجود فعلا." +msgstr "عذرًا، لقد اختار مستخدم آخر هذا الاسم." #: mediagoblin/auth/views.py:62 msgid "Sorry, that email address has already been taken." @@ -73,7 +61,8 @@ msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، تحرير ملفك، وإرسال الصور!" +"تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، وتحرير ملفك الشخصي، ونشر " +"الصور!" #: mediagoblin/auth/views.py:166 msgid "The verification key or user id is incorrect" @@ -82,41 +71,46 @@ msgstr "مفتاح التحقق أو معرف المستخدم خاطئ" #: mediagoblin/auth/views.py:187 #: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 msgid "Resent your verification email." -msgstr "أعيد إرسال رسالة التحقق." +msgstr "أعدنا إرسال رسالة التحقق." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "العنوان" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "الوسوم" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "الوسوم" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "السيرة" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "الموقع الإلكتروني" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -126,11 +120,15 @@ msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" +msgstr "الملف" + +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" msgstr "" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." -msgstr "" +msgstr "يجب أن تضع ملفًا." #: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" @@ -138,7 +136,7 @@ msgstr "لا يبدو أن هذا الملف صورة!" #: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" -msgstr "" +msgstr "يا سلام! نُشرَت!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -146,13 +144,14 @@ msgstr "" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "يبدو أنه لا توجد صفحة في العنوان. عذرًا!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"إن كنت متأكدًا من صحة العنوان فربما تكون الصفحة التي تريدها نُقلت أو حُذفت." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" @@ -172,13 +171,13 @@ msgstr "أرسل وسائط" #: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" -msgstr "أكد بريدك" +msgstr "أكّد بريدك" #: mediagoblin/templates/mediagoblin/base.html:73 #: mediagoblin/templates/mediagoblin/auth/login.html:26 #: mediagoblin/templates/mediagoblin/auth/login.html:34 msgid "Log in" -msgstr "لُج" +msgstr "لِج" #: mediagoblin/templates/mediagoblin/base.html:89 msgid "" @@ -188,7 +187,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "مرحبا بكم يا محبوا الوسائط! ميدياغوبلن هو..." +msgstr "مرحبًا بكم يا محبي الوسائط! ميدياغوبلن هو..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" @@ -204,19 +203,20 @@ msgstr "مكان يجتمع فيه الناس ليتعاونوا ويعرضوا msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" -msgstr "" +msgstr "مشروع حر، فنحن أحد مشاريع غنو." #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" -msgstr "" +msgstr "مشروع يحاول جعل عالمنا أفضل عن طريق اللامركزية (قريبًا!)." #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"جاهز للتمدد. (سيُضاف دعم أنساق كثيرة من الوسائط قريبًا، كما سندعم الفيديو!)." #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -231,15 +231,15 @@ msgstr "فشل الولوج!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" -msgstr "ألا تملك حسابا؟" +msgstr "ألا تملك حسابًا بعد؟" #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Create one here!" -msgstr "أنشئ حسابا هنا!" +msgstr "أنشئ حسابًا هنا!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" -msgstr "أنشئ حسابا!" +msgstr "أنشئ حسابًا!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" @@ -255,36 +255,36 @@ msgid "" "\n" "%(verification_url)s" msgstr "" -"أهلا %(username)s،\n" +"أهلًا يا %(username)s،\n" "\n" -"لتفعيل حسابك في غنو ميدياغوبلن، افتح الرابط التالي\n" -"في متصفحك:\n" +"افتح الرابط التالي\n" +"في متصفحك لتفعيل حسابك في غنو ميدياغوبلن:\n" "\n" "%(verification_url)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format msgid "Editing %(media_title)s" -msgstr "تعديل %(media_title)s" +msgstr "تحرير %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "ألغِ" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "احفظ التغييرات" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" -msgstr "تعديل ملف %(username)s" +msgstr "تحرير ملف %(username)s الشخصي" #: mediagoblin/templates/mediagoblin/listings/tag.html:31 msgid "Media tagged with:" -msgstr "الوسائط الموسومة بـ:" +msgstr "الوسائط الموسومة ب‍" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -302,17 +302,15 @@ msgstr "وسائط %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." -msgstr "عذرا، لا يوجد مستخدم مماثل" +msgstr "عذرًا، تعذر العثور على مستخدم بهذا الاسم." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -343,7 +341,7 @@ msgstr "يجب التحقق من البريد الإلكتروني" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "انتهينا تقريبا! لا زال حسابك يحتاج إلى التفعيل." +msgstr "أوشكنا على الانتهاء! ما زال حسابك بحاجة إلى التفعيل." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -376,7 +374,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" -msgstr "ملف %(username)s's" +msgstr "ملف %(username)s الشخصي" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." @@ -385,7 +383,7 @@ msgstr "هذه زاوية لتخبر الآخرين فيها عن نفسك." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 msgid "Edit profile" -msgstr "عدل الملف" +msgstr "حرِّر الملف الشخصي" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." @@ -394,7 +392,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "اعرض كل وسائط %(username)s" +msgstr "أظهِر كل وسائط %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:135 msgid "" @@ -408,7 +406,7 @@ msgstr "أضف وسائط" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "لا يبدو أنه يوجد أي وسائط هنا حتى الآن..." +msgstr "لا يبدو أنه توجد أي وسائط هنا حتى الآن..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" @@ -418,8 +416,20 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" +msgstr "علِّق" + +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:176 diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 848ea148..d53cff8b 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 22836525..8360ee93 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -4,16 +4,17 @@ # # Rafael Maguiña , 2011. # , 2011. -# , 2011. # Elrond , 2011. +# , 2011. +# Vinzenz Vietzke , 2011. # , 2011. # Jan-Christoph Borchardt , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -23,42 +24,30 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Benutzername" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Passwort" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Passwörter müssen übereinstimmen." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Passwort wiederholen" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Hier nochmal eintragen, um Tippfehler zu verhindern." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Email-Adresse" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Registrierung ist auf dieser Instanz leider deaktiviert." @@ -92,35 +81,40 @@ msgstr "Bestätigungs-Email wurde erneut versandt." msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Markierungen" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Kurztitel" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Bitte gib einen Kurztitel ein" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Markierungen" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biographie" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Webseite" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Diesen Kurztitel hast du bereits vergeben." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." @@ -132,6 +126,10 @@ msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein." msgid "File" msgstr "Datei" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du musst eine Datei angeben." @@ -191,6 +189,8 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Läuft mit <a href=\"http://mediagoblin.org\">MediaGoblin</a>, " +"einem <a href=\"http://gnu.org/\">GNU-Projekt</a>" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -260,7 +260,7 @@ msgstr "Neues Konto registrieren!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "Erstellen" +msgstr "Registrieren" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -284,12 +284,12 @@ msgid "Editing %(media_title)s" msgstr "%(media_title)s bearbeiten" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Abbrechen" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Änderungen speichern" @@ -323,12 +323,10 @@ msgstr "Dieser Benutzer wurde leider nicht gefunden." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "%(title)s wirklich löschen?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -403,7 +401,7 @@ msgstr "%(username)ss Profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "Hier kannst du Anderen etwas über dich zu erzählen." +msgstr "Hier kannst du Anderen etwas über dich erzählen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -441,12 +439,24 @@ msgstr "Feed-Symbol" msgid "Atom feed" msgstr "Atom-Feed" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Kommentar" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "" +msgstr "Du versuchst Medien eines anderen Nutzers zu löschen. Sei vorsichtig." diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index f9022543..5818cd77 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,42 +17,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "" -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "" @@ -84,35 +72,39 @@ msgstr "" msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" +#: mediagoblin/edit/forms.py:35 +msgid "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -124,6 +116,10 @@ msgstr "" msgid "File" msgstr "" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "" @@ -258,12 +254,12 @@ msgid "Editing %(media_title)s" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "" @@ -299,10 +295,8 @@ msgstr "" msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -404,10 +398,22 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 4fb13eef..2502703b 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index c4a286e2..0b01e7b5 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,42 +20,30 @@ msgstr "" "Language: eo\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Uzantnomo" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Pasvorto" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Pasvortoj devas esti egalaj." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Retajpu pasvorton" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Retajpu ĝin por certigi, ke ne okazis mistajpoj." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Retpoŝtadreso" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Bedaŭrinde, registrado estas malaktivigita en tiu ĉi instalaĵo." @@ -89,46 +77,55 @@ msgstr "Resendi vian kontrol-mesaĝon." msgid "Title" msgstr "Titolo" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Etikedoj" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "La distingiga adresparto" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La distingiga adresparto ne povas esti malplena" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Etikedoj" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Retejo" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "La provizita dosiero ne konformas al la informtipo." #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Dosiero" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Vi devas provizi dosieron." @@ -147,7 +144,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Verŝajne ĉe ĉi tiu adreso ne estas paĝo. Ni bedaŭras!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" @@ -159,7 +156,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Bildo de 404-koboldo penŝvitanta." #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -188,10 +185,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Funkcias per <a href=\"http://mediagoblin.org\">MediaGoblin</a>," +" unu el la <a href=\"http://gnu.org/\">projektoj de GNU</a>" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Saluton, artemulo! MediaGoblin estas…" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" @@ -202,14 +201,15 @@ msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Loko, kie homoj povas kunlabori, kaj elmeti originalajn kreaĵojn kaj " +"derivaĵojn!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" -"Libera verko. (Ni ja estas projekto de <a " -"href=\"http://gnu.org\">GNU</a>.)" +"Libera verko. (Ni ja estas projekto de GNU.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" @@ -222,6 +222,8 @@ msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Kreita por etendado. (Baldaŭ en la programo aperos subteno de pluraj " +"informspecoj, inkluzive de filmoj!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -272,12 +274,12 @@ msgid "Editing %(media_title)s" msgstr "Priredaktado de %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Nuligi" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Konservi ŝanĝojn" @@ -311,34 +313,34 @@ msgstr "Uzanto ne trovita." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Ĉu efektive forigi %(title)s?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Kontrolejo pri dosierpreparado." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." msgstr "" +"Ĉi tie vi povas informiĝi pri la stato de preparado de dosieroj por via " +"galerio." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Dosieroj preparataj" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Neniu dosieroj preparatas" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Preparado de ĉi tiuj alŝutaĵoj malsukcesis:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 @@ -347,7 +349,7 @@ msgstr "Necesas konfirmo de retpoŝtadreso" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Preskaŭ finite! Restas nur validigi vian konton." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -406,6 +408,7 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"Ĝuste ĉi tie aperos viaj dosieroj, sed vi ŝajne ankoraŭ nenion alŝutis." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" @@ -421,14 +424,26 @@ msgstr "flusimbolo" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" +msgstr "Atom-a informfluo" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" msgstr "" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Komento" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "" +msgstr "Vi estas forigonta dosieron de alia uzanto. Estu singardema." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index 58531d96..a8fc04ea 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index cfe19a1e..5b16f19d 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -5,12 +5,13 @@ # , 2011. # , 2011. # , 2011. +# Mario Rodriguez , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -20,42 +21,31 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Nombre de Usuario" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Contraseña" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Las contraseñas deben coincidir." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Confirme su contraseña" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" +"Escriba de nuevo aquí para asegurarse de que no hay faltas de ortografía." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Dirección de correo electrónico" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Lo sentimos, la registración está deshabilitado en este momento." @@ -90,36 +80,41 @@ msgstr "Reenvíe su correo electrónico de verificación." msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Etiquetas" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Ficha" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La ficha no puede estar vacía" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Etiquetas" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sitio web" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Una entrada con esa ficha ya existe para este usuario." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Usted está editando el contenido de otro usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Usted está editando un perfil de usuario. Proceder con precaución." @@ -131,6 +126,10 @@ msgstr "Archivo inálido para el formato seleccionado." msgid "File" msgstr "Archivo" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Usted debe proporcionar un archivo." @@ -279,12 +278,12 @@ msgid "Editing %(media_title)s" msgstr "Edición %(media_title)s " #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Salvar cambios" @@ -318,12 +317,10 @@ msgstr "Lo sentimos, no se ha encontrado ese usuario." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Realmente desea eliminar %(title)s ?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -437,12 +434,26 @@ msgstr "ícono feed" msgid "Atom feed" msgstr "Atom feed" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Comentario" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" +"Usted está a punto de eliminar un medio de otro usuario. Proceder con " +"cautela." diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index fe006cdc..93e218e8 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index a3b0eb53..51b60aec 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -2,6 +2,7 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# , 2011. # , 2011. # , 2011. # Valentin Villenave , 2011. @@ -10,8 +11,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -21,42 +22,32 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Nom d'utilisateur" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Mot de passe" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Les mots de passe doivent correspondre." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Confirmer le mot de passe" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" +"Tapez-le à nouveau ici pour vous assurer qu'il n'ya pas de fautes " +"d'orthographe." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Adresse e-mail" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "L'inscription n'est pas activée sur ce serveur, désolé." @@ -90,37 +81,42 @@ msgstr "E-mail de vérification renvoyé." msgid "Title" msgstr "Titre" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Tags" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Légende" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La légende ne peut pas être laissée vide." -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Tags" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Site web" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Une entrée existe déjà pour cet utilisateur avec la même légende." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " "prendre garde." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " @@ -128,12 +124,16 @@ msgstr "" #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "" +msgstr "Invalide fichier donné pour le type de média." #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fichier" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Il vous faut fournir un fichier." @@ -148,21 +148,23 @@ msgstr "Youhou, c'est envoyé !" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Zut!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Il ne semble pas être une page à cette adresse. Désolé!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Si vous êtes sûr que l'adresse est correcte, peut-être la page que vous " +"recherchez a été déplacé ou supprimé." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Image de 404 gobelin stresser" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -170,7 +172,7 @@ msgstr "GNU MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:47 msgid "MediaGoblin logo" -msgstr "" +msgstr "Logo MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" @@ -191,38 +193,48 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Propulsé par MediaGoblin , un GNU de projet" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "" +msgstr "Salut à tous, amateur de médias! MediaGoblin est ..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "" +msgstr "L'endroit idéal pour vos médias!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" +"Un lieu pour les personnes de collaborer et de montrer des créations " +"originales et dérivées!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" +"Logiciel libre. (Nous sommes une GNU projet, " +"après tout.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Visant à rendre le monde meilleur grâce à la décentralisation et " +"(éventuellement, venir bientôt!) fédération!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Construit pour l'extensibilité. (Plusieurs types de médias à venir au " +"logiciel, y compris le support vidéo!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -230,26 +242,29 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Propulsé par des gens comme vous. (Vous pouvez nous aider à " +"améliorer ce logiciel!)" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "" +msgstr "Connexion a échoué!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" -msgstr "Pas encore de compte ?" +msgstr "Pas encore de compte?" #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Create one here!" -msgstr "Créez-en un ici !" +msgstr "Créez-en un ici!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" -msgstr "Créer un compte !" +msgstr "Créer un compte!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" -msgstr "" +msgstr "Créer" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -273,12 +288,12 @@ msgid "Editing %(media_title)s" msgstr "Modification de %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Annuler" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Enregistrer les modifications" @@ -312,43 +327,43 @@ msgstr "Impossible de trouver cet utilisateur, désolé." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Voulez-vous vraiment supprimer %(title)s ?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Panneau pour le traitement des médias" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." msgstr "" +"Vous pouvez suivre l'état des médias en cours de traitement pour votre " +"galerie ici." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Médias en transformation" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Aucun média en transformation" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Ces ajouts n'etaient pas processé:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "" +msgstr "Vérification d'email nécessaire" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Presque fini! Votre compte a encore besoin d'être activé." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -370,6 +385,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Quelqu'un a enregistré un compte avec ce nom, mais il doit encore être " +"activé." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -388,7 +405,7 @@ msgstr "profil de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Voici un endroit pour parler aux autres de vous-même." #: mediagoblin/templates/mediagoblin/user_pages/user.html:90 #: mediagoblin/templates/mediagoblin/user_pages/user.html:108 @@ -397,7 +414,7 @@ msgstr "Modifier le profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Cet utilisateur n'a pas rempli leur profil (encore)." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -409,29 +426,45 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"C'est là où vos médias apparaît, mais vous ne semblez pas avoir quoi que ce " +"soit encore ajouté." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "" +msgstr "Ajouter des médias" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Il ne semble pas être un média encore là ..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "icon de flux" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" +msgstr "flux Atom" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" msgstr "" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commentaire" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" +"Vous êtes sur le point de supprimer des médias d'un autre utilisateur. " +"Procédez avec prudence." diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 6308eaa6..176bcb4d 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 089a352a..7f0c4716 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: ja\n" "Plural-Forms: nplurals=1; plural=0\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "ユーザネーム" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "パスワード" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "パスワードが一致している必要があります。" -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "パスワードを確認" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "メールアドレス" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "申し訳ありませんが、このインスタンスで登録は無効になっています。" @@ -85,35 +73,40 @@ msgstr "検証メールを再送しました。" msgid "Title" msgstr "タイトル" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "タグ" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "スラグ" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "スラグは必要です。" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "タグ" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "自己紹介" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "URL" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "そのスラグを持つエントリは、このユーザーは既に存在します。" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" @@ -125,6 +118,10 @@ msgstr "" msgid "File" msgstr "ファイル" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "ファイルを提供する必要があります。" @@ -264,12 +261,12 @@ msgid "Editing %(media_title)s" msgstr "%(media_title)sを編集中" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "キャンセル" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "投稿する" @@ -305,10 +302,8 @@ msgstr "申し訳ありませんが、そのユーザーは見つかりません msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -412,10 +407,22 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index 809cd90d..e91b7235 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index 7eed6f4e..b8feb0d7 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Gebruikersnaam" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Wachtwoord" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Wachtwoorden moeten overeenkomen." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Bevestig wachtwoord" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "E-mail adres" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Sorry, registratie is uitgeschakeld op deze instantie." @@ -87,37 +75,42 @@ msgstr "Verificatie e-mail opnieuw opgestuurd." msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Etiket" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Etiket" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Website" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" "U bent de media van een andere gebruiker aan het aanpassen. Ga voorzichtig " "te werk." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk." @@ -130,6 +123,10 @@ msgstr "" msgid "File" msgstr "Bestand" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "U moet een bestand aangeven." @@ -266,12 +263,12 @@ msgid "Editing %(media_title)s" msgstr "%(media_title)s aanpassen" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Annuleren" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Wijzigingen opslaan" @@ -307,10 +304,8 @@ msgstr "Sorry, die gebruiker kon niet worden gevonden." msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -418,10 +413,22 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commentaar" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index 8c196295..1837c8da 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index c4b42d89..5bbe2180 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: nn_NO\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Brukarnamn" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Passord" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Passorda må vera like." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Gjenta passord" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "E-postadresse" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Registrering er slege av. Orsak." @@ -87,35 +75,40 @@ msgstr "Send ein ny stadfestingsepost." msgid "Title" msgstr "Tittel" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Merkelappar" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Adressetittel" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Adressetittelen kan ikkje vera tom" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Merkelappar" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Presentasjon" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Heimeside" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Eit innlegg med denne adressetittelen finst allereie." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sitt innlegg." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sin profil." @@ -127,6 +120,10 @@ msgstr "Ugyldig fil for mediatypen." msgid "File" msgstr "Fil" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du må velja ei fil." @@ -274,12 +271,12 @@ msgid "Editing %(media_title)s" msgstr "Redigerer %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Avbryt" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Lagra" @@ -315,10 +312,8 @@ msgstr "Fann ingen slik brukar" msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -424,10 +419,22 @@ msgstr " " msgid "Atom feed" msgstr "Atom-kjelde" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Innspel" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 28cf6af2..6c08c67a 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 8c5ab19e..190cab68 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Nome de Usuário" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Senha" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Senhas devem ser iguais." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Confirmar senha" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Endereço de email" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Desculpa, o registro está desativado neste momento." @@ -87,35 +75,40 @@ msgstr "O email de verificação foi reenviado." msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Tags" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Tags" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biográfia" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Website" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -127,6 +120,10 @@ msgstr "" msgid "File" msgstr "Arquivo" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Você deve fornecer um arquivo." @@ -266,12 +263,12 @@ msgid "Editing %(media_title)s" msgstr "Editando %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Salvar mudanças" @@ -307,10 +304,8 @@ msgstr "Desculpe, tal usuário não encontrado." msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -416,10 +411,22 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 4c3e785c..1fe03578 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 1c366b06..38696aa4 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: ro\n" "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1))\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Nume de utilizator" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Parolă" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Parolele trebuie să fie identice." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" -msgstr "Reintroduceți parola" +msgstr "Reintrodu parola" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Introdu parola din nou pentru verificare." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Adresa de e-mail" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe această instanță." @@ -71,8 +59,8 @@ msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Adresa dvs. de e-mail a fost confirmată. Puteți să vă autentificați, să vă " -"modificați profilul și să trimiteți imagini!" +"Adresa ta de e-mail a fost confirmată. Poți să te autentifici, să îți " +"completezi profilul și să trimiți imagini!" #: mediagoblin/auth/views.py:166 msgid "The verification key or user id is incorrect" @@ -87,38 +75,43 @@ msgstr "E-mail-ul de verificare a fost retrimis." msgid "Title" msgstr "Titlu" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Etichete" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Identificator" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Identificatorul nu poate să lipsească" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Etichete" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografie" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sit Web" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" "Există deja un entry cu același identificator pentru acest utilizator." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." -msgstr "Editați fișierul unui alt utilizator. Se recomandă prudență." +msgstr "Editezi fișierul unui alt utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." -msgstr "Editați profilul unui utilizator. Se recomandă prudență." +msgstr "Editezi profilul unui utilizator. Se recomandă prudență." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." @@ -128,9 +121,13 @@ msgstr "Formatul fișierului nu corespunde cu tipul de media selectat." msgid "File" msgstr "Fișier" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." -msgstr "Trebuie să selectați un fișier." +msgstr "Trebuie să selectezi un fișier." #: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" @@ -153,8 +150,8 @@ msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" -"Dacă sunteți sigur că adresa este coresctă, poate că pagina pe care o " -"căutați a fost mutată sau ștearsă." +"Dacă ești sigur că adresa este corectă, poate că pagina pe care o cauți a " +"fost mutată sau ștearsă." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" @@ -170,11 +167,11 @@ msgstr "logo MediaGoblin" #: mediagoblin/templates/mediagoblin/base.html:52 msgid "Submit media" -msgstr "Transmiteți un fișier media" +msgstr "Transmite un fișier media" #: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" -msgstr "verificați e-mail-ul!" +msgstr "verifică e-mail-ul!" #: mediagoblin/templates/mediagoblin/base.html:73 #: mediagoblin/templates/mediagoblin/auth/login.html:26 @@ -187,6 +184,8 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Construit cu MediaGoblin, un proiect " +"GNU" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -225,7 +224,7 @@ msgid "" " including video support!)" msgstr "" "Proiectat să fie extensibil. (Software-ul va avea în curând suport pentru " -"multiple formate de media, inclusiv pentru video!)" +"mai multe formate de media, inclusiv pentru video!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -243,15 +242,15 @@ msgstr "Autentificare eșuată!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" -msgstr "Nu aveți un cont?" +msgstr "Nu ai un cont?" #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Create one here!" -msgstr "Creați-l aici!" +msgstr "Creează-l aici!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" -msgstr "Creați un cont!" +msgstr "Creează un cont!" #: mediagoblin/templates/mediagoblin/auth/register.html:30 msgid "Create" @@ -279,12 +278,12 @@ msgid "Editing %(media_title)s" msgstr "Editare %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Anulare" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Salvează modificările" @@ -318,12 +317,10 @@ msgstr "Ne pare rău, nu am găsit utilizatorul căutat." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Sigur dorești să ștergi %(title)s?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -359,11 +356,11 @@ msgstr "Aproape gata! Mai trebuie doar să activezi contul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" "An email should arrive in a few moments with instructions on how to do so." -msgstr "Veți primi în scurt timp un mesaj prin e-mail cu instrucțiuni." +msgstr "Vei primi în scurt timp un mesaj prin e-mail cu instrucțiuni." #: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" -msgstr "Dacă nu primiți mesajul:" +msgstr "Dacă nu primești mesajul:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" @@ -383,9 +380,8 @@ msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Dacă dvs. sunteți persoana respectivă și nu mai aveți e-mail-ul de " -"verificare, puteți să vă autentificați pentru " -"a-l retrimite." +"Dacă tu ești persoana respectivă și nu mai ai e-mail-ul de verificare, poți " +"să te autentifici pentru a-l retrimite." #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format @@ -434,12 +430,26 @@ msgstr "icon feed" msgid "Atom feed" msgstr "feed Atom" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Scrie un comentariu" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" +"Urmează să ștergi fișierele media ale unui alt utilizator. Se recomandă " +"prudență." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index babdb60e..35c8ed2d 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 6fee7f3a..6fd2322e 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Логин" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Пароль" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Пароли должны совпадать." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Подтвердите пароль" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Type it again here to make sure there are no spelling mistakes." -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "Адрес электронной почты" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Извините, на этом разделе регистрация запрещена." @@ -87,36 +75,41 @@ msgstr "Переслать сообщение с подтверждением а msgid "Title" msgstr "Название" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Метки" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Отличительная часть адреса" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Отличительная часть адреса необходима" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Метки" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" -msgstr "Биограаия" +msgstr "Биография" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Сайт" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" "У этого пользователя уже есть файл с такой отличительной частью адреса." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Вы редактируете файлы другого пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Вы редактируете профиль пользователя. Будьте осторожны." @@ -128,6 +121,10 @@ msgstr "Неправильный формат файла." msgid "File" msgstr "Файл" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Вы должны загрузить файл." @@ -188,7 +185,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Привет, любитель мультимедиа! Mediagoblin это..." +msgstr "Привет, любитель мультимедиа! MediaGoblin это…" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" @@ -221,6 +218,8 @@ msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -274,12 +273,12 @@ msgid "Editing %(media_title)s" msgstr "Редактирование %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Отменить" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Сохранить изменения" @@ -315,10 +314,8 @@ msgstr "Извините, но такой пользователь не найд msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -346,11 +343,11 @@ msgstr "Обработка этих файлов вызвала ошибку:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "Нужно подтверджение почтового адреса" +msgstr "Нужно подтверждение почтового адреса" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "Почти закончили! Теперь надо активизировать ваш аккаунт." +msgstr "Почти закончили! Теперь надо активировать ваш аккаунт." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -371,7 +368,7 @@ msgstr "Повторно отправить подверждение на адр msgid "" "Someone has registered an account with this username, but it still has to be" " activated." -msgstr "Кто-то создал аккаунт с этим именем, но его еще надо активизировать." +msgstr "Кто‐то создал аккаунт с этим именем, но его еще надо активировать." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -379,8 +376,8 @@ msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Если это были вы, и если вы потеряли сообщение с подтвердлением аккаунта, то" -" вы можете войти и отпраыить его повторно." +"Если это были вы, и если вы потеряли сообщение для подтверждения аккаунта, " +"то вы можете войти и отправить его повторно." #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format @@ -409,7 +406,7 @@ msgstr "Смотреть все файлы %(username)s" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "Ваши файлы появятся здесь, кодга вы их добавите." +msgstr "Ваши файлы появятся здесь, когда вы их добавите." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" @@ -417,7 +414,7 @@ msgstr "Добавить файлы" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "Пока что тут файлов нет..." +msgstr "Пока что тут файлов нет…" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" @@ -427,10 +424,22 @@ msgstr "" msgid "Atom feed" msgstr "лента в формате Atom" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Комментарий" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 97723319..663a7e55 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index c2a28308..22c80076 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: sl\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Uporabniško ime" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Geslo" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Gesli morata biti enaki." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Potrdite geslo" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "E-poštni naslov" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Oprostite, prijava za ta izvod ni omogočena." @@ -87,35 +75,40 @@ msgstr "Ponovno pošiljanje potrditvene e-pošte." msgid "Title" msgstr "Naslov" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Oznake" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Oznaka" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Oznaka ne sme biti prazna" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Oznake" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografija" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Spletna stran" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Vnos s to oznako za tega uporabnika že obstaja." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." @@ -127,6 +120,10 @@ msgstr "Za vrsto vsebine je bila podana napačna datoteka." msgid "File" msgstr "Datoteka" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Podati morate datoteko." @@ -278,12 +275,12 @@ msgid "Editing %(media_title)s" msgstr "Urejanje %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Prekliči" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Shrani spremembe" @@ -319,10 +316,8 @@ msgstr "Oprostite, tega uporabnika ni bilo moč najti." msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -430,10 +425,22 @@ msgstr "Ikona vira" msgid "Atom feed" msgstr "Ikona Atom" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Komentar" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index d3336ad0..80608e3a 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index e37ae3c1..7a843fdc 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -17,42 +17,30 @@ msgstr "" "Language: sr\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "" -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "" @@ -84,35 +72,40 @@ msgstr "" msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -124,6 +117,10 @@ msgstr "" msgid "File" msgstr "" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "" @@ -258,12 +255,12 @@ msgid "Editing %(media_title)s" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "" @@ -299,10 +296,8 @@ msgstr "" msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -406,10 +401,22 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index f84cb70a..9086472a 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index b3883533..78a6bd41 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -18,42 +18,30 @@ msgstr "" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "Användarnamn" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "Lösenord" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "Lösenorden måste vara identiska." -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "Bekräfta lösenord" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "E-postadress" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "Vi beklagar, registreringen är avtängd på den här instansen." @@ -87,35 +75,40 @@ msgstr "Skickade ett nytt verifierings-email." msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Taggar" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Sökvägsnamn" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Sökvägsnamnet kan inte vara tomt" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "Taggar" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Presentation" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Hemsida" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "Ett inlägg med det sökvägsnamnet existerar redan." -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "Var försiktig, du redigerar någon annans inlägg." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." @@ -127,6 +120,10 @@ msgstr "Ogiltig fil för mediatypen." msgid "File" msgstr "Fil" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "Du måste ange en fil" @@ -282,12 +279,12 @@ msgid "Editing %(media_title)s" msgstr "Redigerar %(media_title)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 msgid "Cancel" msgstr "Avbryt" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:44 msgid "Save changes" msgstr "Spara" @@ -323,10 +320,8 @@ msgstr "Finns ingen sådan användare ännu." msgid "Really delete %(title)s?" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -438,10 +433,22 @@ msgstr "feed-ikon" msgid "Atom feed" msgstr "Atom-feed" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Kommentar" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index e2cdd52f..dc196210 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 3020df07..8a5fc21c 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -3,12 +3,13 @@ # This file is distributed under the same license as the PROJECT project. # # , 2011. +# Harry Chen , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-08-30 22:51-0500\n" -"PO-Revision-Date: 2011-08-31 03:51+0000\n" +"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"PO-Revision-Date: 2011-09-06 04:31+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,42 +19,30 @@ msgstr "" "Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:54 +#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 msgid "Username" msgstr "使用者名稱" -#: mediagoblin/auth/forms.py:28 -msgid "This is the name other users will identify you with." -msgstr "" - -#: mediagoblin/auth/forms.py:31 mediagoblin/auth/forms.py:58 +#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 msgid "Password" msgstr "密碼" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:34 msgid "Passwords must match." msgstr "密碼必須一致" -#: mediagoblin/auth/forms.py:37 -msgid "Try to use a strong password!" -msgstr "" - -#: mediagoblin/auth/forms.py:40 +#: mediagoblin/auth/forms.py:36 msgid "Confirm password" msgstr "確認密碼" -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:38 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "再輸入一次,確定你沒有打錯字。" -#: mediagoblin/auth/forms.py:45 +#: mediagoblin/auth/forms.py:41 msgid "Email address" msgstr "電子郵件位置" -#: mediagoblin/auth/forms.py:48 -msgid "Your email will never be published." -msgstr "" - #: mediagoblin/auth/views.py:40 msgid "Sorry, registration is disabled on this instance." msgstr "抱歉, 這個項目已經被暫停註冊." @@ -83,37 +72,42 @@ msgstr "重送認證信." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" -msgstr "稱謂" +msgstr "標題" -#: mediagoblin/edit/forms.py:29 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "標籤" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "自訂字串" -#: mediagoblin/edit/forms.py:30 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "自訂字串不能空白" -#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:31 -msgid "Tags" -msgstr "標籤" +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:42 msgid "Bio" -msgstr "自傳" +msgstr "自我介紹" -#: mediagoblin/edit/forms.py:41 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "網站" -#: mediagoblin/edit/views.py:66 +#: mediagoblin/edit/views.py:63 msgid "An entry with that slug already exists for this user." msgstr "這個自訂字串已經被其他人用了" -#: mediagoblin/edit/views.py:95 +#: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:166 +#: mediagoblin/edit/views.py:155 msgid "You are editing a user's profile. Proceed with caution." msgstr "你正在編輯一位用戶的檔案. 請謹慎處理." @@ -125,6 +119,10 @@ msgstr "指定錯誤的媒體類別!" msgid "File" msgstr "檔案" +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + #: mediagoblin/submit/views.py:47 msgid "You must provide a file." msgstr "你必須提供一個檔案" @@ -135,7 +133,7 @@ msgstr "檔案似乎不是一個圖片喔!" #: mediagoblin/submit/views.py:122 msgid "Woohoo! Submitted!" -msgstr "呼嚕! 送出去了!" +msgstr "呼呼! 送出去嚕!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -182,10 +180,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"由 MediaGoblin製作, 它是一個 GNU 專案" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "嗨!媒體愛好者!MediaGoblin是..." +msgstr "嗨!多媒體檔案愛好者!MediaGoblin是..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" @@ -195,7 +195,7 @@ msgstr "你的媒體檔案的最佳所在!" msgid "" "A place for people to collaborate and show off original and derived " "creations!" -msgstr "這是一個地方,可以讓人們協同且展示他們的創作或是衍生作品!" +msgstr "這是一個可以讓人們共同展示他們的創作、衍生作品的地方!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" @@ -207,13 +207,13 @@ msgstr "免費但是我們更重視自由 (畢竟我們是個 %(username)s's media" -msgstr "%(username)s的媒體" +msgstr "%(username)s的媒體檔案" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 @@ -305,12 +305,10 @@ msgstr "抱歉,找不到這個使用者." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "真的要刪除 %(title)s?" -#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:36 -msgid "" -"If you choose yes, the media entry will be deleted " -"permanently." +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 @@ -328,7 +326,7 @@ msgstr "媒體處理中" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "沒有媒體正在處理" +msgstr "沒有正在處理中的媒體" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" @@ -341,7 +339,7 @@ msgstr "需要認證電子郵件" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "幾乎完成了!你的帳號仍然需要被啟用。" +msgstr "幾乎完成了!但你的帳號仍然需要被啟用。" #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -396,15 +394,15 @@ msgstr "查看%(username)s的全部媒體檔案" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "這個地方是你的媒體會出現的地方,但是你似乎還沒有加入東西。" +msgstr "這個地方是你的媒體檔案會出現的地方,但是你似乎還沒有加入任何東西。" #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" -msgstr "新增媒體" +msgstr "新增媒體檔案" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "似乎還沒有任何的媒體..." +msgstr "似乎還沒有任何的媒體檔案..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" @@ -414,12 +412,24 @@ msgstr "feed圖示" msgid "Atom feed" msgstr "Atom feed" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "評論" +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + #: mediagoblin/user_pages/views.py:176 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "" +msgstr "你在刪除其他人的媒體檔案。請小心處理喔。" -- cgit v1.2.3 From 63bf10f9a635b012e07f65ca5ceccc6845551143 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 19:37:25 -0500 Subject: Adjusting spacing between function arguments --- mediagoblin/auth/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 31dc4b7f..abe8ce33 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -127,7 +127,7 @@ EMAIL_FP_VERIFICATION_TEMPLATE = ( u"http://{host}{uri}?" u"userid={userid}&token={fp_verification_key}") -def send_fp_verification_email(user,request): +def send_fp_verification_email(user, request): """ Send the verification email to users to change their password. -- cgit v1.2.3 From daa26200c7e0ef9683af641385504e6b2de403ba Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 19:40:00 -0500 Subject: Changing the forgot password urls so they all start under /auth/forgot_password/ --- mediagoblin/auth/routing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 14e87133..399ed8d2 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -31,15 +31,15 @@ auth_routes = [ '/resend_verification_success/', template='mediagoblin/auth/resent_verification_email.html', controller='mediagoblin.views:simple_template_render'), - Route('mediagoblin.auth.forgot_password', '/forgotpass/', + Route('mediagoblin.auth.forgot_password', '/forgot_password/', controller='mediagoblin.auth.views:forgot_password'), - Route('mediagoblin.auth.verify_forgot_password', '/verifyforgotpass/', + Route('mediagoblin.auth.verify_forgot_password', '/forgot_password/verify/', controller='mediagoblin.auth.views:verify_forgot_password'), Route('mediagoblin.auth.fp_changed_success', - '/fp_changed_success/', + '/forgot_password/changed_success/', template='mediagoblin/auth/fp_changed_success.html', controller='mediagoblin.views:simple_template_render'), Route('mediagoblin.auth.fp_email_sent', - '/fp_email_sent/', + '/forgot_password/email_sent/', template='mediagoblin/auth/fp_email_sent.html', controller='mediagoblin.views:simple_template_render')] -- cgit v1.2.3 From 34fddf47f0b4f7cfa9fbd865bd9eb8ae96913ce4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 19:42:56 -0500 Subject: Resent verification email template and view aren't used anymore. Removing! --- mediagoblin/auth/routing.py | 6 +----- .../auth/resent_verification_email.html | 24 ---------------------- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 mediagoblin/templates/mediagoblin/auth/resent_verification_email.html diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 76c7ceed..edd21be7 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -26,8 +26,4 @@ auth_routes = [ Route('mediagoblin.auth.verify_email', '/verify_email/', controller='mediagoblin.auth.views:verify_email'), Route('mediagoblin.auth.resend_verification', '/resend_verification/', - controller='mediagoblin.auth.views:resend_activation'), - Route('mediagoblin.auth.resend_verification_success', - '/resend_verification_success/', - template='mediagoblin/auth/resent_verification_email.html', - controller='mediagoblin.views:simple_template_render')] + controller='mediagoblin.auth.views:resend_activation')] diff --git a/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html b/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html deleted file mode 100644 index 37cd6b03..00000000 --- a/mediagoblin/templates/mediagoblin/auth/resent_verification_email.html +++ /dev/null @@ -1,24 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% block mediagoblin_content %} -

      - {% trans %}Resent your verification email.{% endtrans %} -

      -{% endblock %} -- cgit v1.2.3 From 2db31581ed597cab1d148091c1fe8975ee9d70d2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 20:18:17 -0500 Subject: user_add_forgot_password_token_and_expires migration should set new fields to None/null --- mediagoblin/db/migrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index cf09e817..3c3deee8 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -101,9 +101,9 @@ def user_add_forgot_password_token_and_expires(database): """ database['users'].update( {'fp_verification_key': {'$exists': False}}, - {'$set': {'fp_verification_key': ''}}, + {'$set': {'fp_verification_key': None}}, multi=True) database['users'].update( {'fp_token_expire': {'$exists': False}}, - {'$set': {'fp_token_expire': ''}}, + {'$set': {'fp_token_expire': None}}, multi=True) -- cgit v1.2.3 From f03fef4ea8ec106f698936e2ffce02d58105f802 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:23:26 -0500 Subject: Updating calls to recall password URLs to respect changed routing --- mediagoblin/tests/test_auth.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index bfa66bd2..ec60b259 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -241,13 +241,15 @@ def test_register_views(test_app): ### Oops, forgot the password # ------------------- util.clear_test_template_context() - response = test_app.post('/auth/forgotpass/', {'username': 'happygirl'}) + response = test_app.post( + '/auth/forgot_password/', + {'username': 'happygirl'}) response.follow() ## Did we redirect to the proper page? Use the right template? assert_equal( urlparse.urlsplit(response.location)[2], - '/auth/fp_email_sent/') + '/auth/forgot_password/email_sent/') assert util.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/auth/fp_email_sent.html') @@ -262,7 +264,7 @@ def test_register_views(test_app): path = urlparse.urlsplit(email_context['verification_url'])[2] get_params = urlparse.urlsplit(email_context['verification_url'])[3] - assert path == u'/auth/verifyforgotpass/' + assert path == u'/auth/forgot_password/verify/' parsed_get_params = urlparse.parse_qs(get_params) # user should have matching parameters @@ -277,7 +279,7 @@ def test_register_views(test_app): ## Try using a bs password-changing verification key, shouldn't work util.clear_test_template_context() response = test_app.get( - "/auth/verifyforgotpass/?userid=%s&token=total_bs" % unicode( + "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( new_user['_id']), status=400) assert response.status == '400 Bad Request' @@ -299,14 +301,14 @@ def test_register_views(test_app): ## Verify step 2.1 of password-change works -- report success to user util.clear_test_template_context() response = test_app.post( - '/auth/verifyforgotpass/', { + '/auth/forgot_password/verify/', { 'userid': parsed_get_params['userid'], 'password': 'iamveryveryhappy', 'confirm_password': 'iamveryveryhappy', 'token': parsed_get_params['token']}) response.follow() assert util.TEMPLATE_TEST_CONTEXT.has_key( - 'mediagoblin/auth/fp_changed_success.html') + 'mediagoblin/auth/fp_changed_success.html') ## Verify step 2.2 of password-change works -- login w/ new password success util.clear_test_template_context() -- cgit v1.2.3 From d1a64326456d67d43ac99f28c2c45c7e9996be07 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:23:44 -0500 Subject: Avoiding using '$or' query modifier since that's newer-mongo only. --- mediagoblin/auth/views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index c18bfa34..666426e6 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -200,9 +200,12 @@ def forgot_password(request): fp_form = auth_forms.ForgotPassForm(request.POST) if request.method == 'POST' and fp_form.validate(): - user = request.db.User.one( - {'$or': [{'username': request.POST['username']}, - {'email': request.POST['username']}]}) + # '$or' not available till mongodb 1.5.3 + user = request.db.User.find_one( + {'username': request.POST['username']}) + if not user: + user = request.db.User.find_one( + {'email': request.POST['username']}) if user: user['fp_verification_key'] = unicode(uuid.uuid4()) -- cgit v1.2.3 From 2c9e8184a44336689b8d3e0d01b17b15dfbcb791 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:25:46 -0500 Subject: Adjusting indentation a bit --- mediagoblin/auth/views.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 666426e6..098443b8 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -219,9 +219,9 @@ def forgot_password(request): return redirect(request, 'mediagoblin.auth.fp_email_sent') return render_to_response( - request, - 'mediagoblin/auth/forgot_password.html', - {'fp_form': fp_form}) + request, + 'mediagoblin/auth/forgot_password.html', + {'fp_form': fp_form}) def verify_forgot_password(request): @@ -277,7 +277,9 @@ def _process_for_token(request): else: session_vars = request.POST - mysession = {'vars': session_vars, - 'has_userid_and_token': session_vars.has_key('userid') and - session_vars.has_key('token')} + mysession = { + 'vars': session_vars, + 'has_userid_and_token': + session_vars.has_key('userid') and session_vars.has_key('token')} + return mysession -- cgit v1.2.3 From 73fffbb8b0b37d642f7dc996bbec8fdf7d4e3e8b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:32:15 -0500 Subject: Adding additional check that verification key exists, and updating indentation --- mediagoblin/auth/views.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 098443b8..dd693892 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -242,8 +242,10 @@ def verify_forgot_password(request): return render_404(request) # check if we have a real user and correct token - if (user and user['fp_verification_key'] == unicode(session_token) and - datetime.datetime.now() < user['fp_token_expire']): + if ((user and user['fp_verification_key'] and + user['fp_verification_key'] == unicode(session_token) and + datetime.datetime.now() < user['fp_token_expire'])): + cp_form = auth_forms.ChangePassForm(session_vars) if request.method == 'POST' and cp_form.validate(): @@ -255,9 +257,11 @@ def verify_forgot_password(request): return redirect(request, 'mediagoblin.auth.fp_changed_success') else: - return render_to_response(request, - 'mediagoblin/auth/change_fp.html', - {'cp_form': cp_form}) + return render_to_response( + request, + 'mediagoblin/auth/change_fp.html', + {'cp_form': cp_form}) + # in case there is a valid id but no user whit that id in the db # or the token expired else: -- cgit v1.2.3 From a85a21103bb5e3d4b5a6e454cce1d2011372c867 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:45:14 -0500 Subject: If the user hasn't verified their email or account inactive give a special warning --- mediagoblin/auth/views.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index dd693892..1c010372 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -208,12 +208,27 @@ def forgot_password(request): {'email': request.POST['username']}) if user: - user['fp_verification_key'] = unicode(uuid.uuid4()) - user['fp_token_expire'] = datetime.datetime.now() + \ - datetime.timedelta(days=10) - user.save() + if user['email_verified'] and user['status'] == 'active': + user['fp_verification_key'] = unicode(uuid.uuid4()) + user['fp_token_expire'] = datetime.datetime.now() + \ + datetime.timedelta(days=10) + user.save() + + send_fp_verification_email(user, request) + else: + # special case... we can't send the email because the + # username is inactive / hasn't verified their email + messages.add_message( + request, + messages.WARNING, + _("Could not send password recovery email as " + "your username is inactive or your account's " + "email address has not been verified.")) + + return redirect( + request, 'mediagoblin.user_pages.user_home', + user=user['username']) - send_fp_verification_email(user, request) # do not reveal whether or not there is a matching user, just move along return redirect(request, 'mediagoblin.auth.fp_email_sent') @@ -244,7 +259,8 @@ def verify_forgot_password(request): # check if we have a real user and correct token if ((user and user['fp_verification_key'] and user['fp_verification_key'] == unicode(session_token) and - datetime.datetime.now() < user['fp_token_expire'])): + datetime.datetime.now() < user['fp_token_expire'] + and user['email_verified'] and user['status'] == 'active')): cp_form = auth_forms.ChangePassForm(session_vars) -- cgit v1.2.3 From daf029646e4f56798f65748b28f6f815602dc174 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:46:41 -0500 Subject: Also nullify verification key after verifying in the email confirmation step --- mediagoblin/auth/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 1c010372..0cb3963c 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -154,7 +154,10 @@ def verify_email(request): if user and user['verification_key'] == unicode(request.GET['token']): user['status'] = u'active' user['email_verified'] = True + user[u'verification_key'] = None + user.save() + messages.add_message( request, messages.SUCCESS, -- cgit v1.2.3 From 4185e644f4209fbc21b3a066d17fefc9d68effef Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:48:10 -0500 Subject: Keys in mongodb should be unicode, here... --- mediagoblin/auth/views.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 0cb3963c..5fabf40b 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -152,8 +152,8 @@ def verify_email(request): {'_id': ObjectId(unicode(request.GET['userid']))}) if user and user['verification_key'] == unicode(request.GET['token']): - user['status'] = u'active' - user['email_verified'] = True + user[u'status'] = u'active' + user[u'email_verified'] = True user[u'verification_key'] = None user.save() @@ -180,7 +180,7 @@ def resend_activation(request): Resend the activation email. """ - request.user['verification_key'] = unicode(uuid.uuid4()) + request.user[u'verification_key'] = unicode(uuid.uuid4()) request.user.save() send_verification_email(request.user, request) @@ -212,8 +212,8 @@ def forgot_password(request): if user: if user['email_verified'] and user['status'] == 'active': - user['fp_verification_key'] = unicode(uuid.uuid4()) - user['fp_token_expire'] = datetime.datetime.now() + \ + user[u'fp_verification_key'] = unicode(uuid.uuid4()) + user[u'fp_token_expire'] = datetime.datetime.now() + \ datetime.timedelta(days=10) user.save() @@ -268,10 +268,10 @@ def verify_forgot_password(request): cp_form = auth_forms.ChangePassForm(session_vars) if request.method == 'POST' and cp_form.validate(): - user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + user[u'pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) - user['fp_verification_key'] = None - user['fp_token_expire'] = None + user[u'fp_verification_key'] = None + user[u'fp_token_expire'] = None user.save() return redirect(request, 'mediagoblin.auth.fp_changed_success') -- cgit v1.2.3 From 961fe381635d80595084428123bee2e6f29f7e62 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 7 Sep 2011 23:51:41 -0500 Subject: Adding a small docstring --- mediagoblin/auth/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 5fabf40b..ac3f621e 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -243,6 +243,10 @@ def forgot_password(request): def verify_forgot_password(request): + """ + Check the forgot-password verification and possibly let the user + change their password because of it. + """ # get session variables, and specifically check for presence of token mysession = _process_for_token(request) if not mysession['has_userid_and_token']: -- cgit v1.2.3 From f7ab66707c4d5ef5941e13131dbf9ce2a8c7a875 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 8 Sep 2011 08:10:27 -0500 Subject: Renaming request.[GET|POST] as formdata instead of session; that's more accurate. --- mediagoblin/auth/views.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index ac3f621e..000f7681 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -247,29 +247,29 @@ def verify_forgot_password(request): Check the forgot-password verification and possibly let the user change their password because of it. """ - # get session variables, and specifically check for presence of token - mysession = _process_for_token(request) - if not mysession['has_userid_and_token']: + # get form data variables, and specifically check for presence of token + formdata = _process_for_token(request) + if not formdata['has_userid_and_token']: return render_404(request) - session_token = mysession['vars']['token'] - session_userid = mysession['vars']['userid'] - session_vars = mysession['vars'] + formdata_token = formdata['vars']['token'] + formdata_userid = formdata['vars']['userid'] + formdata_vars = formdata['vars'] # check if it's a valid Id try: user = request.db.User.find_one( - {'_id': ObjectId(unicode(session_userid))}) + {'_id': ObjectId(unicode(formdata_userid))}) except InvalidId: return render_404(request) # check if we have a real user and correct token if ((user and user['fp_verification_key'] and - user['fp_verification_key'] == unicode(session_token) and + user['fp_verification_key'] == unicode(formdata_token) and datetime.datetime.now() < user['fp_token_expire'] and user['email_verified'] and user['status'] == 'active')): - cp_form = auth_forms.ChangePassForm(session_vars) + cp_form = auth_forms.ChangePassForm(formdata_vars) if request.method == 'POST' and cp_form.validate(): user[u'pw_hash'] = auth_lib.bcrypt_gen_password_hash( @@ -293,20 +293,20 @@ def verify_forgot_password(request): def _process_for_token(request): """ - Checks for tokens in session without prior knowledge of request method + Checks for tokens in formdata without prior knowledge of request method - For now, returns whether the userid and token session variables exist, and - the session variables in a hash. Perhaps an object is warranted? + For now, returns whether the userid and token formdata variables exist, and + the formdata variables in a hash. Perhaps an object is warranted? """ - # retrieve the session variables + # retrieve the formdata variables if request.method == 'GET': - session_vars = request.GET + formdata_vars = request.GET else: - session_vars = request.POST + formdata_vars = request.POST - mysession = { - 'vars': session_vars, + formdata = { + 'vars': formdata_vars, 'has_userid_and_token': - session_vars.has_key('userid') and session_vars.has_key('token')} + formdata_vars.has_key('userid') and formdata_vars.has_key('token')} - return mysession + return formdata -- cgit v1.2.3 From 8d7b549bb6d17c66ce1d3590da6e9bd0868b4403 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 9 Sep 2011 23:59:32 +0200 Subject: Use media.url_for_self() instead of generating it Some places used to generate the URL for a media entry on their own instead of calling media.url_for_self() to do that. The later handles missing slugs better. --- mediagoblin/edit/views.py | 9 ++++----- mediagoblin/user_pages/views.py | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 11bee110..15edfdd6 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -73,8 +73,8 @@ def edit_media(request, media): media['slug'] = unicode(request.POST['slug']) media.save() - return redirect(request, "mediagoblin.user_pages.media_home", - user=media.uploader()['username'], media=media['slug']) + return exc.HTTPFound( + location=media.url_for_self(request.urlgen)) if request.user['is_admin'] \ and media['uploader'] != request.user['_id'] \ @@ -130,9 +130,8 @@ def edit_attachments(request, media): % (request.POST['attachment_name'] or request.POST['attachment_file'].filename)) - return redirect(request, 'mediagoblin.user_pages.media_home', - user=media.uploader()['username'], - media=media['slug']) + return exc.HTTPFound( + location=media.url_for_self(request.urlgen)) return render_to_response( request, 'mediagoblin/edit/attachments.html', diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index f60bd186..6a82d718 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -165,9 +165,8 @@ def media_confirm_delete(request, media): return redirect(request, "mediagoblin.user_pages.user_home", user=username) else: - return redirect(request, "mediagoblin.user_pages.media_home", - user=media.uploader()['username'], - media=media['slug']) + return exc.HTTPFound( + location=media.url_for_self(request.urlgen)) if ((request.user[u'is_admin'] and request.user[u'_id'] != media.uploader()[u'_id'])): -- cgit v1.2.3 From 33d3de8e2cafbdbc50dd3fc12ddf1b4b57da2d6c Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 10 Sep 2011 10:55:53 -0500 Subject: Refractored gmg_commands.import_export --- mediagoblin/gmg_commands/import_export.py | 90 +++++++++++++++++-------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 2e227e77..fc5c88a8 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -27,8 +27,13 @@ import subprocess import os.path import os import sys +import logging from contextlib import closing +_log = logging.getLogger('gmg.import_export') +logging.basicConfig() +_log.setLevel(logging.INFO) + def import_export_parse_setup(subparser): # TODO: Add default @@ -49,12 +54,12 @@ def import_export_parse_setup(subparser): def _import_media(db, args): - """ + ''' Import media files Must be called after _import_database() - """ - print "\n== Importing media ==\n" + ''' + _log.info('-> Importing media...') media_cache = BasicFileStorage( args._cache_path['media']) @@ -65,18 +70,22 @@ def _import_media(db, args): for entry in db.media_entries.find(): for name, path in entry['media_files'].items(): + _log.info('Importing: {0} - {1}'.format( + entry['title'], + name)) + media_file = mg_globals.public_store.get_file(path, mode='wb') media_file.write( media_cache.get_file(path, mode='rb').read()) - print "\n== Media imported ==\n" + _log.info('...Media imported') def _import_database(db, args): - """ + ''' Restore mongo database from ___.bson files - """ - print "\n== Importing database ==\n" + ''' + _log.info('-> Importing database...') p = subprocess.Popen([ args.mongorestore_path, @@ -85,13 +94,13 @@ def _import_database(db, args): p.wait() - print "\n== Database imported ==\n" + _log.info('...Database imported') def env_import(args): - """ + ''' Restore mongo database and media files from a tar archive - """ + ''' if not args.cache_path: args.cache_path = tempfile.mkdtemp() @@ -100,9 +109,9 @@ def env_import(args): # Creates mg_globals.public_store and mg_globals.queue_store setup_storage() - config, validation_result = read_mediagoblin_config(args.conf_file) + global_config, app_config = setup_global_and_app_config(args.conf_file) connection, db = setup_connection_and_db_from_config( - config['mediagoblin'], use_pymongo=True) + app_config, use_pymongo=True) tf = tarfile.open( args.tar_file, @@ -123,9 +132,9 @@ def env_import(args): def _setup_paths(args): - """ + ''' Populate ``args`` variable with cache subpaths - """ + ''' args._cache_path = dict() PATH_MAP = { 'media': 'media', @@ -139,10 +148,10 @@ def _setup_paths(args): def _create_archive(args): - """ + ''' Create the tar archive - """ - print "\n== Compressing to archive ==\n" + ''' + _log.info('-> Compressing to archive') tf = tarfile.open( args.tar_file, @@ -151,27 +160,27 @@ def _create_archive(args): with closing(tf): tf.add(args.cache_path, 'mediagoblin-data/') - print "\n== Archiving done ==\n" + _log.info('...Archiving done') def _clean(args): - """ + ''' Remove cache directory - """ + ''' shutil.rmtree(args.cache_path) def _export_check(args): - """ + ''' Run security checks for export command - """ + ''' if os.path.exists(args.tar_file): overwrite = raw_input( 'The output file already exists. ' 'Are you **SURE** you want to overwrite it? ' '(yes/no)> ') if not overwrite == 'yes': - print "Aborting." + print 'Aborting.' return False @@ -179,12 +188,7 @@ def _export_check(args): def _export_database(db, args): - print "\n== Exporting database ==\n" - - command = '{mongodump_path} -d {database} -o {mongodump_cache}'.format( - mongodump_path=args.mongodump_path, - database=db.name, - mongodump_cache=args._cache_path['database']) + _log.info('-> Exporting database...') p = subprocess.Popen([ args.mongodump_path, @@ -193,11 +197,11 @@ def _export_database(db, args): p.wait() - print "\n== Database exported ==\n" + _log.info('...Database exported') def _export_media(db, args): - print "\n== Exporting media ==\n" + _log.info('-> Exporting media...') media_cache = BasicFileStorage( args._cache_path['media']) @@ -208,21 +212,25 @@ def _export_media(db, args): for entry in db.media_entries.find(): for name, path in entry['media_files'].items(): + _log.info('Exporting {0} - {1}'.format( + entry['title'], + name)) + mc_file = media_cache.get_file(path, mode='wb') mc_file.write( mg_globals.public_store.get_file(path, mode='rb').read()) - print "\n== Media exported ==\n" + _log.info('...Media exported') def env_export(args): - """ + ''' Export database and media files to a tar archive - """ + ''' if args.cache_path: if os.path.exists(args.cache_path): - print 'The cache directory must not exist before you run this script' - print 'Cache directory: ', args.cache_path + _log.error('The cache directory must not exist before you run this script') + _log.error('Cache directory: {0}'.format(args.cache_path)) return False else: @@ -231,15 +239,15 @@ def env_export(args): args = _setup_paths(args) if not _export_check(args): - print "\n== Checks did not pass, exiting ==\n" + _log.error('Checks did not pass, exiting') sys.exit(0) - setup_global_and_app_config(args.conf_file) - setup_storage() + globa_config, app_config = setup_global_and_app_config(args.conf_file) - config, validation_result = read_mediagoblin_config(args.conf_file) + setup_storage() + connection, db = setup_connection_and_db_from_config( - config['mediagoblin'], use_pymongo=True) + app_config, use_pymongo=True) _export_database(db, args) -- cgit v1.2.3 From ab613cb3c8a2bc28750dbd2827d226fbbada22c6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 10 Sep 2011 17:27:47 -0500 Subject: Using Local Fonts instead of Remote Fonts linked to Google. Thanks to Shawn Kahn for help on / original version of this patch! --- extlib/lato/Lato-Bold.ttf | Bin 0 -> 93224 bytes extlib/lato/Lato-BoldItalic.ttf | Bin 0 -> 81936 bytes extlib/lato/Lato-Italic.ttf | Bin 0 -> 83680 bytes extlib/lato/Lato-Regular.ttf | Bin 0 -> 96044 bytes extlib/lato/OFL_1.1.txt | 97 +++++++++++++++++++++++++++ mediagoblin/static/css/base.css | 10 +-- mediagoblin/static/fonts/Lato-Bold.ttf | 1 + mediagoblin/static/fonts/Lato-BoldItalic.ttf | 1 + mediagoblin/static/fonts/Lato-Italic.ttf | 1 + mediagoblin/static/fonts/Lato-Regular.ttf | 1 + 10 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 extlib/lato/Lato-Bold.ttf create mode 100644 extlib/lato/Lato-BoldItalic.ttf create mode 100644 extlib/lato/Lato-Italic.ttf create mode 100644 extlib/lato/Lato-Regular.ttf create mode 100644 extlib/lato/OFL_1.1.txt create mode 120000 mediagoblin/static/fonts/Lato-Bold.ttf create mode 120000 mediagoblin/static/fonts/Lato-BoldItalic.ttf create mode 120000 mediagoblin/static/fonts/Lato-Italic.ttf create mode 120000 mediagoblin/static/fonts/Lato-Regular.ttf diff --git a/extlib/lato/Lato-Bold.ttf b/extlib/lato/Lato-Bold.ttf new file mode 100644 index 00000000..bc3529fc Binary files /dev/null and b/extlib/lato/Lato-Bold.ttf differ diff --git a/extlib/lato/Lato-BoldItalic.ttf b/extlib/lato/Lato-BoldItalic.ttf new file mode 100644 index 00000000..2cf5ae0d Binary files /dev/null and b/extlib/lato/Lato-BoldItalic.ttf differ diff --git a/extlib/lato/Lato-Italic.ttf b/extlib/lato/Lato-Italic.ttf new file mode 100644 index 00000000..11ca3eb6 Binary files /dev/null and b/extlib/lato/Lato-Italic.ttf differ diff --git a/extlib/lato/Lato-Regular.ttf b/extlib/lato/Lato-Regular.ttf new file mode 100644 index 00000000..26ce1002 Binary files /dev/null and b/extlib/lato/Lato-Regular.ttf differ diff --git a/extlib/lato/OFL_1.1.txt b/extlib/lato/OFL_1.1.txt new file mode 100644 index 00000000..f1a20ac1 --- /dev/null +++ b/extlib/lato/OFL_1.1.txt @@ -0,0 +1,97 @@ +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d1b891ac..b108cc9e 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -4,25 +4,25 @@ font-family: 'Lato'; font-style: normal; font-weight: 700; - src: local('Lato Bold'), local('Lato-Bold'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/wkfQbvfT_02e2IWO3yYueQ.woff') format('woff'); + src: local('Lato Bold'), local('Lato-Bold'), url('../fonts/Lato-Bold.ttf') format('truetype'); } @font-face { font-family: 'Lato'; font-style: italic; font-weight: 400; - src: local('Lato Italic'), local('Lato-Italic'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/oUan5VrEkpzIazlUe5ieaA.woff') format('woff'); + src: local('Lato Italic'), local('Lato-Italic'), url('../fonts/Lato-Italic.ttf') format('truetype'); } @font-face { font-family: 'Lato'; font-style: italic; font-weight: 700; - src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/HkF_qI1x_noxlxhrhMQYED8E0i7KZn-EPnyo3HZu7kw.woff') format('woff'); + src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('../fonts/Lato-BoldItalic.ttf') format('truetype'); } @font-face { font-family: 'Lato'; font-style: normal; font-weight: 400; - src: local('Lato Regular'), local('Lato-Regular'), url('http://themes.googleusercontent.com/static/fonts/lato/v1/9k-RPmcnxYEPm8CNFsH2gg.woff') format('woff'); + src: local('Lato Regular'), local('Lato-Regular'), url('../fonts/Lato-Regular.woff') format('truetype'); } body { @@ -372,4 +372,4 @@ table.media_panel th { .delete_checkbox_box { margin-top: 10px; margin-left: 10px; -} \ No newline at end of file +} diff --git a/mediagoblin/static/fonts/Lato-Bold.ttf b/mediagoblin/static/fonts/Lato-Bold.ttf new file mode 120000 index 00000000..8b747690 --- /dev/null +++ b/mediagoblin/static/fonts/Lato-Bold.ttf @@ -0,0 +1 @@ +../../../extlib/lato/Lato-Bold.ttf \ No newline at end of file diff --git a/mediagoblin/static/fonts/Lato-BoldItalic.ttf b/mediagoblin/static/fonts/Lato-BoldItalic.ttf new file mode 120000 index 00000000..20886f02 --- /dev/null +++ b/mediagoblin/static/fonts/Lato-BoldItalic.ttf @@ -0,0 +1 @@ +../../../extlib/lato/Lato-BoldItalic.ttf \ No newline at end of file diff --git a/mediagoblin/static/fonts/Lato-Italic.ttf b/mediagoblin/static/fonts/Lato-Italic.ttf new file mode 120000 index 00000000..3e4ee80c --- /dev/null +++ b/mediagoblin/static/fonts/Lato-Italic.ttf @@ -0,0 +1 @@ +../../../extlib/lato/Lato-Italic.ttf \ No newline at end of file diff --git a/mediagoblin/static/fonts/Lato-Regular.ttf b/mediagoblin/static/fonts/Lato-Regular.ttf new file mode 120000 index 00000000..ff8e9d2c --- /dev/null +++ b/mediagoblin/static/fonts/Lato-Regular.ttf @@ -0,0 +1 @@ +../../../extlib/lato/Lato-Regular.ttf \ No newline at end of file -- cgit v1.2.3 From a7302773f64a41fdcefbb6e219b39dda4189278d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 10 Sep 2011 17:33:06 -0500 Subject: Adding Shawn to the contributor list. By the way, it's Shawn *Khan* :) --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 9653a332..8b202f58 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,6 +29,7 @@ Thank you! * Rasmus Larsson * Sam Kleinman * Sebastian Spaeth +* Shawn Khan * Will Kahn-Greene If you think your name should be on this list, let us know! -- cgit v1.2.3 From 611542034ab69c79be387b2655081af70a798b38 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 10 Sep 2011 17:33:41 -0500 Subject: Adding Nathan Yergler, another recent contributor, to the AUTHORS list. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 8b202f58..c9fc5c8e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,6 +24,7 @@ Thank you! * Karen Rustad * Mark Holmquist * Matt Lee +* Nathan Yergler * Odin Hørthe Omdal * Osama Khalid * Rasmus Larsson -- cgit v1.2.3 From 0125e5567bfa71e47d79fa02acbe7f66c0c8bec7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 10 Sep 2011 17:39:10 -0500 Subject: Adding MIT.txt to the 960.gs extlib/ checkout. Free software developers! You don't already have 80000 copies of these license texts in your distro, let's give you 50 more. --- extlib/960.gs/MIT.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 extlib/960.gs/MIT.txt diff --git a/extlib/960.gs/MIT.txt b/extlib/960.gs/MIT.txt new file mode 100644 index 00000000..5a2aeb47 --- /dev/null +++ b/extlib/960.gs/MIT.txt @@ -0,0 +1,20 @@ +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -- cgit v1.2.3 From 3d95afeb36fa9c5354de825801c0f7ac79bbea14 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 11 Sep 2011 16:13:27 -0500 Subject: Marking some things on the frontpage for translation. --- mediagoblin/templates/mediagoblin/root.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index ed4878a5..854fca51 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -21,7 +21,7 @@ {% block mediagoblin_content %} {% if request.user %} -

      Explore

      +

      {% trans %}Explore{% endtrans %}

      {% else %}

      {% trans %}Hi there, media lover! MediaGoblin is...{% endtrans %}

      @@ -35,9 +35,12 @@
    {% if allow_registration %} -

    Excited to join us?

    - Create a free account or - Set up MediaGoblin on your own server +

    {% trans %}Excited to join us?{% endtrans %}

    + {% trans register_url=request.urlgen('mediagoblin.auth.register') %} + Create a free account + or + Set up MediaGoblin on your own server + {% endtrans %} {% endif %}

@@ -47,6 +50,6 @@
{% endif %} -

Most recent media

+

{% trans %}Most recent media{% endtrans %}

{{ object_gallery(request, media_entries, pagination) }} {% endblock %} -- cgit v1.2.3 From 8c12e57b9e0db109e0fc3211ec1a8145ef3d3eb1 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 11 Sep 2011 16:20:10 -0500 Subject: Extracted, pushed, pulled, compiled translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 9631 -> 11549 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 108 ++++++++++-- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 9020 -> 10915 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 128 ++++++++++++--- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 107 ++++++++++-- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 8804 -> 10738 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 130 ++++++++++++--- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 9151 -> 11114 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 192 +++++++++++++++------- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 9314 -> 11232 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 110 ++++++++++--- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 9266 -> 11184 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 8737 -> 10655 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 8343 -> 10261 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 8690 -> 10608 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 9008 -> 10955 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 118 ++++++++++--- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 11125 -> 13306 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 126 +++++++++++--- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 8806 -> 10724 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 8669 -> 10587 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 8930 -> 10836 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 126 +++++++++++--- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 8545 -> 10463 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 106 ++++++++++-- 31 files changed, 1531 insertions(+), 356 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index d02639a9..146a588f 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index 112c6973..eb1c5f2d 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -2,15 +2,16 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # Majid Al-Dharrab , 2011. -# , 2011. # , 2011. +# , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,43 +21,43 @@ msgstr "" "Language: ar\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "اسم المستخدم" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "كلمة السر" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "يجب أن تتطابق كلمتا السر." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "أكّد كلمة السر" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "اكتبها مرة أخرى هنا للتأكد من عدم وجود أخطاء إملائية." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "عنوان البريد الإلكتروني" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "عفوًا، التسجيل غير متاح هنا." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "عذرًا، لقد اختار مستخدم آخر هذا الاسم." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "عفوًا، هذا العنوان البريدي مستخدم." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -64,15 +65,20 @@ msgstr "" "تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، وتحرير ملفك الشخصي، ونشر " "الصور!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "مفتاح التحقق أو معرف المستخدم خاطئ" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "أعدنا إرسال رسالة التحقق." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "العنوان" @@ -110,7 +116,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -185,6 +191,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "مرحبًا بكم يا محبي الوسائط! ميدياغوبلن هو..." @@ -225,6 +235,60 @@ msgid "" " software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "فشل الولوج!" @@ -237,6 +301,14 @@ msgstr "ألا تملك حسابًا بعد؟" msgid "Create one here!" msgstr "أنشئ حسابًا هنا!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "أنشئ حسابًا!" @@ -432,7 +504,7 @@ msgstr "علِّق" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index d53cff8b..bb7538c2 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 8360ee93..3aaabce0 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -2,19 +2,20 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # -# Rafael Maguiña , 2011. +# Translators: # , 2011. +# , 2011. # Elrond , 2011. +# Jan-Christoph Borchardt , 2011. # , 2011. +# Rafael Maguiña , 2011. # Vinzenz Vietzke , 2011. -# , 2011. -# Jan-Christoph Borchardt , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -24,43 +25,43 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Benutzername" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Passwort" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Passwörter müssen übereinstimmen." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Passwort wiederholen" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "Hier nochmal eintragen, um Tippfehler zu verhindern." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Email-Adresse" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Registrierung ist auf dieser Instanz leider deaktiviert." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Tut und Leid, aber diese Email-Adresse wird bereits verwendet." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -68,15 +69,20 @@ msgstr "" "Deine Email-Adresse wurde bestätigt. Du kannst dich nun anmelden, Dein " "Profil bearbeiten und Bilder hochladen!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Der Bestätigungssschlüssel oder die Nutzernummer ist falsch." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Bestätigungs-Email wurde erneut versandt." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" @@ -97,6 +103,8 @@ msgstr "Bitte gib einen Kurztitel ein" msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"Der Titelteil der Medienadresse. Normalerweise muss hier nichts geändert " +"werden." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -114,7 +122,7 @@ msgstr "Diesen Kurztitel hast du bereits vergeben." msgid "You are editing another user's media. Proceed with caution." msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." @@ -128,7 +136,7 @@ msgstr "Datei" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Beschreibung des Werkes" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." @@ -189,8 +197,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Läuft mit <a href=\"http://mediagoblin.org\">MediaGoblin</a>, " -"einem <a href=\"http://gnu.org/\">GNU-Projekt</a>" +"Läuft mit MediaGoblin, einem GNU-Projekt" + +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -242,6 +254,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Du kannst uns dabei helfen, " "die Software zu verbessern!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Anmeldevorgang fehlgeschlagen!" @@ -254,6 +320,14 @@ msgstr "Hast du noch kein Konto?" msgid "Create one here!" msgstr "Registriere dich!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Neues Konto registrieren!" @@ -327,7 +401,7 @@ msgstr "%(title)s wirklich löschen?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Dauerhaft löschen." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -441,11 +515,11 @@ msgstr "Atom-Feed" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Neuere" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Ältere" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -453,9 +527,9 @@ msgstr "Kommentar" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Ja, wirklich löschen" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Du versuchst Medien eines anderen Nutzers zu löschen. Sei vorsichtig." diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 5818cd77..6ff8e8df 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,57 +17,62 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "" -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "" -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your " "profile, and submit images!" msgstr "" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "" +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or " +"your account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "" @@ -104,7 +109,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -178,6 +183,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "" @@ -217,6 +226,64 @@ msgid "" "this software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on " +"your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your " +"password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "" @@ -229,6 +296,14 @@ msgstr "" msgid "Create one here!" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "" @@ -414,7 +489,7 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 2502703b..b260cb16 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 0b01e7b5..296f1b4b 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -2,15 +2,16 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. -# , 2011. # Fernando Inocencio , 2011. +# , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,43 +21,43 @@ msgstr "" "Language: eo\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Uzantnomo" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Pasvorto" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Pasvortoj devas esti egalaj." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Retajpu pasvorton" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "Retajpu ĝin por certigi, ke ne okazis mistajpoj." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Retpoŝtadreso" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Bedaŭrinde, registrado estas malaktivigita en tiu ĉi instalaĵo." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Tiu retpoŝtadreso jam estas uzata." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -64,15 +65,20 @@ msgstr "" "Via retpoŝtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian " "profilon, kaj alŝuti bildojn!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "La kontrol-kodo aŭ la uzantonomo ne estas korekta" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Resendi vian kontrol-mesaĝon." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titolo" @@ -93,6 +99,8 @@ msgstr "La distingiga adresparto ne povas esti malplena" msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"La parto de la dosieradreso, bazita sur la dosiertitolo. Ordinare ne necesas" +" ĝin ŝanĝi." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -110,7 +118,7 @@ msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto." msgid "You are editing another user's media. Proceed with caution." msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." @@ -124,7 +132,7 @@ msgstr "Dosiero" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Priskribo de ĉi tiu verko" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." @@ -140,7 +148,7 @@ msgstr "Hura! Alŝutitas!" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Oj!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" @@ -188,6 +196,10 @@ msgstr "" "Funkcias per <a href=\"http://mediagoblin.org\">MediaGoblin</a>," " unu el la <a href=\"http://gnu.org/\">projektoj de GNU</a>" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Saluton, artemulo! MediaGoblin estas…" @@ -216,6 +228,7 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" +"Celanta plibonigi la mondon per sencentreco kaj (iam, baldaŭ!) federateco!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" @@ -231,6 +244,63 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" +"Vivanta per homoj kiel vi. (<a " +"href=\"http://mediagoblin.org/pages/join.html\">Vi povas helpi al ni " +"plibonigi la programon!</a>)" + +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" @@ -244,6 +314,14 @@ msgstr "Ĉu ankoraŭ sen konto?" msgid "Create one here!" msgstr "Kreu ĝin ĉi tie!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Kreu konton!" @@ -317,7 +395,7 @@ msgstr "Ĉu efektive forigi %(title)s?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Forigi senrevene" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -370,6 +448,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti " +"aktivigita." #: mediagoblin/templates/mediagoblin/user_pages/user.html:68 #, python-format @@ -396,7 +476,7 @@ msgstr "Redakti profilon" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Ĉi tiu uzanto ne jam aldonis informojn pri si." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -428,11 +508,11 @@ msgstr "Atom-a informfluo" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Plinovaj" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Malplinovaj" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -440,9 +520,9 @@ msgstr "Komento" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Mi estas certa, ke mi volas forigi ĉi tion" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Vi estas forigonta dosieron de alia uzanto. Estu singardema." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index a8fc04ea..7c7dea0d 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 5b16f19d..85da5dbe 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -2,16 +2,18 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. -# , 2011. # , 2011. +# Javier Di Mauro , 2011. +# , 2011. # Mario Rodriguez , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -21,60 +23,65 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nombre de Usuario" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Contraseña" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Las contraseñas deben coincidir." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" -msgstr "Confirme su contraseña" +msgstr "Confirma tu contraseña" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" "Escriba de nuevo aquí para asegurarse de que no hay faltas de ortografía." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Dirección de correo electrónico" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Lo sentimos, la registración está deshabilitado en este momento." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Lo sentimos, ya existe un usuario con ese nombre." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." -msgstr "Lo sentimos, su dirección de correo electrónico ya ha sido tomada." +msgstr "Lo sentimos, esa dirección de correo electrónico ya ha sido tomada." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Su dirección de correo electrónico ha sido verificada. ¡Ahora puede " -"ingresar, editar su perfil, y enviar imágenes!" +"Tu dirección de correo electrónico ha sido verificada. ¡Ahora puedes " +"ingresar, editar tu perfil, y enviar imágenes!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "" "La clave de verificación o la identificación de usuario son incorrectas" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." -msgstr "Reenvíe su correo electrónico de verificación." +msgstr "Se reenvió tu correo electrónico de verificación." + +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" @@ -96,6 +103,8 @@ msgstr "La ficha no puede estar vacía" msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"La parte del título de la URL de este contenido. Normalmente no necesitas " +"cambiar esto." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -111,16 +120,15 @@ msgstr "Una entrada con esa ficha ya existe para este usuario." #: mediagoblin/edit/views.py:84 msgid "You are editing another user's media. Proceed with caution." -msgstr "" -"Usted está editando el contenido de otro usuario. Proceder con precaución." +msgstr "Estás editando el contenido de otro usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." -msgstr "Usted está editando un perfil de usuario. Proceder con precaución." +msgstr "Estás editando un perfil de usuario. Proceder con precaución." #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "Archivo inálido para el formato seleccionado." +msgstr "Archivo inválido para el formato seleccionado." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -128,11 +136,11 @@ msgstr "Archivo" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Descripción de esta obra" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." -msgstr "Usted debe proporcionar un archivo." +msgstr "Debes proporcionar un archivo." #: mediagoblin/submit/views.py:50 msgid "The file doesn't seem to be an image!" @@ -155,12 +163,12 @@ msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" -"Si estas seguro que la dirección es correcta, puede ser que la pagina halla " +"Si estás seguro que la dirección es correcta, puede ser que la pagina haya " "sido movida o borrada." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "404 el goblin esta estresado" +msgstr "Imagen de 404 goblin estresándose" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -176,7 +184,7 @@ msgstr "Enviar contenido" #: mediagoblin/templates/mediagoblin/base.html:63 msgid "verify your email!" -msgstr "Verifique su correo electrónico" +msgstr "Verifica tu correo electrónico!" #: mediagoblin/templates/mediagoblin/base.html:73 #: mediagoblin/templates/mediagoblin/auth/login.html:26 @@ -190,20 +198,24 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Hola, amante de los medios de comunicación! MediaGoblin es ..." +msgstr "Hola, amante de los contenidos! MediaGoblin es ..." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" -msgstr "El lugar ideal para tus cosas!" +msgstr "El lugar ideal para tus contenidos!" #: mediagoblin/templates/mediagoblin/root.html:30 msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" -"Un lugar para colaborar y exhibir tus creaciones orignales y derivadas" +"Un lugar para colaborar y exhibir tus creaciones orignales y derivadas!" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" @@ -219,7 +231,7 @@ msgid "" "(eventually, coming soon!) federation!" msgstr "" "Queriendo hacer del mundo un mejor lugar a través de la descentralización y " -"(eventualmente!) la federalización!" +"(eventualmente, muy pronto!) la federalización!" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" @@ -239,9 +251,63 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\"> Vos podés ayudarnos a " "mejorar este programa)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" -msgstr "Fallo el inicio de sesión!" +msgstr "Falló el inicio de sesión!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Don't have an account yet?" @@ -251,6 +317,14 @@ msgstr "¿No tienes una cuenta?" msgid "Create one here!" msgstr "¡Crea una aquí!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "¡Crea una cuenta!" @@ -269,8 +343,11 @@ msgid "" "\n" "%(verification_url)s" msgstr "" -"Hola %(username)s , para activar su cuenta GNU MediaGoblin, abra la " -"siguiente URL en su navegador: %(verification_url)s " +"Hola %(username)s,\n" +"\n" +"para activar tu cuenta de GNU MediaGoblin, abre la siguiente URL en tu navegador:\n" +"\n" +"%(verification_url)s " #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format @@ -285,7 +362,7 @@ msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" -msgstr "Salvar cambios" +msgstr "Guardar cambios" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -298,7 +375,7 @@ msgstr "Contenido etiquetado con:" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" -msgstr "Envíe su contenido" +msgstr "Envía tu contenido" #: mediagoblin/templates/mediagoblin/submit/start.html:29 msgid "Submit" @@ -312,16 +389,16 @@ msgstr "Contenido de %(username)s's" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 msgid "Sorry, no such user found." -msgstr "Lo sentimos, no se ha encontrado ese usuario." +msgstr "Lo sentimos, no se encontró ese usuario." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "Realmente desea eliminar %(title)s ?" +msgstr "Realmente deseas eliminar %(title)s ?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Eliminar permanentemente" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -359,8 +436,8 @@ msgstr "Casi terminas! Solo falta activar la cuenta." msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -"Un e-mail debería llegar en unos momentos con las instrucciones para " -"hacerlo." +"En unos momentos te debería llegar un correo electrónico con las " +"instrucciones para hacerlo." #: mediagoblin/templates/mediagoblin/user_pages/user.html:51 msgid "In case it doesn't:" @@ -384,13 +461,13 @@ msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Si usted es esa persona, pero ha perdido su correo electrónico de " -"verificación, puede acceder y reenviarlo." +"Si tú eres esa persona, pero has perdido tu correo electrónico de " +"verificación, puedes acceder y reenviarlo." #: mediagoblin/templates/mediagoblin/user_pages/user.html:78 #, python-format msgid "%(username)s's profile" -msgstr "Perfil de %(username)s's" +msgstr "Perfil de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:85 msgid "Here's a spot to tell others about yourself." @@ -408,15 +485,14 @@ msgstr "Este usuario (todavia) no ha completado su perfil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "Ver todo el contenido de %(username)s's " +msgstr "Ver todo el contenido de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:135 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -"Aquí es donde tú contenido estará, pero parece que no haz agregado contenido" -" todavia." +"Aquí es donde tú contenido estará, pero parece que aún no has agregado nada." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" @@ -424,7 +500,7 @@ msgstr "Añadir contenido" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "Parece que no hay ningún contenido aquí todavia..." +msgstr "Parece que aún no hay ningún contenido aquí..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" @@ -436,11 +512,11 @@ msgstr "Atom feed" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Recientes" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Antiguas" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -448,12 +524,12 @@ msgstr "Comentario" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Estoy seguro de que quiero borrar esto" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" -"Usted está a punto de eliminar un medio de otro usuario. Proceder con " -"cautela." +"Estás a punto de eliminar un contenido de otro usuario. Proceder con " +"precaución." diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index 93e218e8..baab45ab 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 51b60aec..032399d6 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -2,17 +2,18 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. -# , 2011. # , 2011. -# Valentin Villenave , 2011. +# , 2011. # , 2011. +# Valentin Villenave , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -22,45 +23,45 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nom d'utilisateur" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Mot de passe" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Les mots de passe doivent correspondre." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Confirmer le mot de passe" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" "Tapez-le à nouveau ici pour vous assurer qu'il n'ya pas de fautes " "d'orthographe." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Adresse e-mail" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "L'inscription n'est pas activée sur ce serveur, désolé." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Un utilisateur existe déjà avec ce nom, désolé." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Désolé, cette adresse courriel a déjà été prise." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -68,15 +69,20 @@ msgstr "" "Votre adresse e-mail a bien été vérifiée. Vous pouvez maintenant vous " "identifier, modifier votre profil, et soumettre des images !" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "La clé de vérification ou le nom d'utilisateur est incorrect." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "E-mail de vérification renvoyé." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titre" @@ -116,7 +122,7 @@ msgstr "" "Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " "prendre garde." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " @@ -196,6 +202,10 @@ msgstr "" "Propulsé par MediaGoblin , un GNU de projet" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Salut à tous, amateur de médias! MediaGoblin est ..." @@ -246,6 +256,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Vous pouvez nous aider à " "améliorer ce logiciel!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Connexion a échoué!" @@ -258,6 +322,14 @@ msgstr "Pas encore de compte?" msgid "Create one here!" msgstr "Créez-en un ici!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Créer un compte!" @@ -461,7 +533,7 @@ msgstr "Commentaire" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Vous êtes sur le point de supprimer des médias d'un autre utilisateur. " diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 176bcb4d..efd3e3f4 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 7f0c4716..79be3177 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,57 +19,62 @@ msgstr "" "Language: ja\n" "Plural-Forms: nplurals=1; plural=0\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "ユーザネーム" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "パスワード" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "パスワードが一致している必要があります。" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "パスワードを確認" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "メールアドレス" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "申し訳ありませんが、このインスタンスで登録は無効になっています。" -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "申し訳ありませんが、その名前を持つユーザーがすでに存在しています。" -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "" -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "メアドが確認されています。これで、ログインしてプロファイルを編集し、画像を提出することができます!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "検証キーまたはユーザーIDが間違っています" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "検証メールを再送しました。" +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "タイトル" @@ -106,7 +112,7 @@ msgstr "そのスラグを持つエントリは、このユーザーは既に存 msgid "You are editing another user's media. Proceed with caution." msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" @@ -180,6 +186,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "" @@ -219,6 +229,60 @@ msgid "" " software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "" @@ -231,6 +295,14 @@ msgstr "まだアカウントを持っていませんか?" msgid "Create one here!" msgstr "ここで作成!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "アカウントを作成!" @@ -423,7 +495,7 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index e91b7235..261e5e95 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index b8feb0d7..b9e0896d 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Gebruikersnaam" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Wachtwoord" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Wachtwoorden moeten overeenkomen." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Bevestig wachtwoord" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "E-mail adres" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Sorry, registratie is uitgeschakeld op deze instantie." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Sorry, er bestaat al een gebruiker met die naam." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Sorry, dat e-mailadres is al ingenomen." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "Uw e-mailadres is geverifieerd. U kunt nu inloggen, uw profiel bewerken, en " "afbeeldingen toevoegen!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "De verificatie sleutel of gebruikers-ID is onjuist" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Verificatie e-mail opnieuw opgestuurd." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" @@ -110,7 +116,7 @@ msgstr "" "U bent de media van een andere gebruiker aan het aanpassen. Ga voorzichtig " "te werk." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk." @@ -185,6 +191,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "" @@ -224,6 +234,60 @@ msgid "" " software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "" @@ -236,6 +300,14 @@ msgstr "Heeft u nog geen account?" msgid "Create one here!" msgstr "Maak er hier een!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Maak een account aan!" @@ -429,7 +501,7 @@ msgstr "Commentaar" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index 1837c8da..9e4cf80f 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index 5bbe2180..cc0e495a 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: nn_NO\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Brukarnamn" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Passord" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Passorda må vera like." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Gjenta passord" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "E-postadresse" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Registrering er slege av. Orsak." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Ein konto med dette brukarnamnet finst allereide." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Den epostadressa er allereide teken." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "E-postadressa di, og dimed kontoen din er stadfesta. Du kan no logga inn, " "endra profilen din og lasta opp filer." -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Send ein ny stadfestingsepost." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Tittel" @@ -108,7 +114,7 @@ msgstr "Eit innlegg med denne adressetittelen finst allereie." msgid "You are editing another user's media. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sitt innlegg." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Ver forsiktig, du redigerer ein annan konto sin profil." @@ -183,6 +189,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Hei der mediaentusiast, MediaGoblin..." @@ -229,6 +239,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Du kan hjelpa med å forbetra" " MediaGoblin)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Innlogging feila" @@ -241,6 +305,14 @@ msgstr "Har du ingen konto?" msgid "Create one here!" msgstr "Lag ein!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Lag ein konto." @@ -435,7 +507,7 @@ msgstr "Innspel" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 6c08c67a..686989fc 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 190cab68..02054003 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nome de Usuário" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Senha" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Senhas devem ser iguais." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Confirmar senha" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Endereço de email" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Desculpa, o registro está desativado neste momento." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Desculpe, um usuário com este nome já existe." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "" -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "O seu endereço de e-mail foi verificado. Você pode agora fazer login, editar" " seu perfil, e enviar imagens!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "A chave de verificação ou nome usuário estão incorretos." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "O email de verificação foi reenviado." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Título" @@ -108,7 +114,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -182,6 +188,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "" @@ -221,6 +231,60 @@ msgid "" " software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "" @@ -233,6 +297,14 @@ msgstr "Ainda não tem conta?" msgid "Create one here!" msgstr "Crie uma aqui!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Criar uma conta!" @@ -427,7 +499,7 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 1fe03578..994d6f30 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 38696aa4..967f7dbb 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: ro\n" "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1))\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nume de utilizator" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Parolă" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Parolele trebuie să fie identice." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Reintrodu parola" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "Introdu parola din nou pentru verificare." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Adresa de e-mail" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe această instanță." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Ne pare rău, există deja un utilizator cu același nume." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Ne pare rău, această adresă de e-mail este deja rezervată." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "Adresa ta de e-mail a fost confirmată. Poți să te autentifici, să îți " "completezi profilul și să trimiți imagini!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Cheie de verificare sau user ID incorect." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "E-mail-ul de verificare a fost retrimis." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titlu" @@ -91,6 +97,8 @@ msgstr "Identificatorul nu poate să lipsească" msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"Partea din adresa acestui fișier corespunzătoare titlului. De regulă nu " +"trebuie modificată." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -109,7 +117,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "Editezi fișierul unui alt utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Editezi profilul unui utilizator. Se recomandă prudență." @@ -123,7 +131,7 @@ msgstr "Fișier" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Descrierea acestui fișier" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." @@ -187,6 +195,10 @@ msgstr "" "Construit cu MediaGoblin, un proiect " "GNU" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Bună! MediaGoblin este..." @@ -236,6 +248,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Ne poți ajuta să îmbunătățim" " acest software!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Autentificare eșuată!" @@ -248,6 +314,14 @@ msgstr "Nu ai un cont?" msgid "Create one here!" msgstr "Creează-l aici!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Creează un cont!" @@ -321,7 +395,7 @@ msgstr "Sigur dorești să ștergi %(title)s?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Șterge definitiv" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -432,11 +506,11 @@ msgstr "feed Atom" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Mai noi" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Mai vechi" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -444,9 +518,9 @@ msgstr "Scrie un comentariu" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Sunt sigur că doresc să șterg" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Urmează să ștergi fișierele media ale unui alt utilizator. Se recomandă " diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 35c8ed2d..2b698e4d 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 6fd2322e..865f5424 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Логин" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Пароль" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Пароли должны совпадать." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Подтвердите пароль" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "Type it again here to make sure there are no spelling mistakes." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "Адрес электронной почты" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Извините, на этом разделе регистрация запрещена." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Извините, пользователь с этим именем уже зарегистрирован." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Извините, этот адрес электнонной почты уже занят." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "Адрес вашей электронной потвержден. Вы теперь можете войти и начать " "редактировать свой профиль и загружать новые изображения!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Неверный ключ проверки или идентификатор пользователя" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Переслать сообщение с подтверждением аккаунта." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Название" @@ -91,6 +97,8 @@ msgstr "Отличительная часть адреса необходима" msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"Часть адреса этого файла, производная от его названия. Её обычно не нужно " +"изменять." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -109,7 +117,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "Вы редактируете файлы другого пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Вы редактируете профиль пользователя. Будьте осторожны." @@ -123,7 +131,7 @@ msgstr "Файл" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Описание этого произведения" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." @@ -183,6 +191,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Привет, любитель мультимедиа! MediaGoblin это…" @@ -203,7 +215,7 @@ msgstr "" msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" -msgstr "" +msgstr "Свободное ПО. (Мы же проект GNU.)" #: mediagoblin/templates/mediagoblin/root.html:32 msgid "" @@ -231,6 +243,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Ты можешь помочь сделать это" " ПО лучше!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Авторизация неуспешна!" @@ -243,6 +309,14 @@ msgstr "Ещё нету аккаунта?" msgid "Create one here!" msgstr "Создайте здесь!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Создать аккаунт!" @@ -302,7 +376,7 @@ msgstr "Подтвердить" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Файлы пользователя <a href=\"%(user_url)s\">%(username)s</a>" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 @@ -312,11 +386,11 @@ msgstr "Извините, но такой пользователь не найд #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Действительно удалить %(title)s?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Удалить безвозвратно" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -418,7 +492,7 @@ msgstr "Пока что тут файлов нет…" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "значок ленты" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" @@ -426,11 +500,11 @@ msgstr "лента в формате Atom" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Более новые" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Более старые" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -438,9 +512,9 @@ msgstr "Комментарий" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Я уверен, что хочу удалить это" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 663a7e55..d1ce44b2 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index 22c80076..17ffeec0 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # Jure Repinc , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: sl\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Uporabniško ime" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Geslo" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Gesli morata biti enaki." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Potrdite geslo" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "E-poštni naslov" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Oprostite, prijava za ta izvod ni omogočena." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "Oprostite, uporabnik s tem imenom že obstaja." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Oprostite, ta e-poštni naslov je že v uporabi." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "Vaš e-poštni naslov je bil potrjen. Sedaj se lahko prijavite, uredite svoj " "profil in pošljete slike." -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Potrditveni ključ ali uporabniška identifikacija je napačna" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Ponovno pošiljanje potrditvene e-pošte." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Naslov" @@ -108,7 +114,7 @@ msgstr "Vnos s to oznako za tega uporabnika že obstaja." msgid "You are editing another user's media. Proceed with caution." msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." @@ -184,6 +190,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "Pozdravljen, ljubitelj večpredstavnostnih vsebin! MediaGoblin je ..." @@ -232,6 +242,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Pri izboljševanju nam lahko " "pomagate tudi vi.)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Prijava ni uspela." @@ -244,6 +308,14 @@ msgstr "Še nimate računa?" msgid "Create one here!" msgstr "Ustvarite si ga." +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Ustvarite račun." @@ -441,7 +513,7 @@ msgstr "Komentar" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index 80608e3a..d09aea44 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index 7a843fdc..da928da6 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -2,12 +2,13 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -17,57 +18,62 @@ msgstr "" "Language: sr\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "" -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "" -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "" +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "" @@ -105,7 +111,7 @@ msgstr "" msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "" @@ -179,6 +185,10 @@ msgid "" "href=\"http://gnu.org/\">GNU project" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "" @@ -218,6 +228,60 @@ msgid "" " software!)" msgstr "" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "" @@ -230,6 +294,14 @@ msgstr "" msgid "Create one here!" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "" @@ -417,7 +489,7 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index 9086472a..5f8ac655 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index 78a6bd41..f38166a5 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -2,13 +2,14 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -18,43 +19,43 @@ msgstr "" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Användarnamn" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "Lösenord" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "Lösenorden måste vara identiska." -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "Bekräfta lösenord" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Skriv in det igen för att undvika stavfel." -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "E-postadress" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "Vi beklagar, registreringen är avtängd på den här instansen." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "En användare med det användarnamnet finns redan." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "Den e-postadressen är redan tagen." -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -62,15 +63,20 @@ msgstr "" "Din e-postadress är verifierad. Du kan nu logga in, redigera din profil och " "ladda upp filer!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "Verifieringsnyckeln eller användar-IDt är fel." -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "Skickade ett nytt verifierings-email." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" @@ -90,7 +96,7 @@ msgstr "Sökvägsnamnet kan inte vara tomt" #: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." -msgstr "" +msgstr "Sökvägstitlen för din media. Du brukar inte behöva ändra denna." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -108,7 +114,7 @@ msgstr "Ett inlägg med det sökvägsnamnet existerar redan." msgid "You are editing another user's media. Proceed with caution." msgstr "Var försiktig, du redigerar någon annans inlägg." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." @@ -122,7 +128,7 @@ msgstr "Fil" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Beskrivning av verket" #: mediagoblin/submit/views.py:47 msgid "You must provide a file." @@ -183,6 +189,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Drivs av MediaGoblin, ett GNU-projekt" + +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -237,6 +249,60 @@ msgstr "" "href=\"http://mediagoblin.org/pages/join.html\">Du kan hjälpa os forbättra " "MediaGoblin!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "Inloggning misslyckades!" @@ -249,6 +315,14 @@ msgstr "Har du inget konto?" msgid "Create one here!" msgstr "Skapa ett!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Skapa ett konto!" @@ -318,11 +392,11 @@ msgstr "Finns ingen sådan användare ännu." #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Vill du verkligen radera %(title)s?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Radera permanent" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -435,11 +509,11 @@ msgstr "Atom-feed" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Nyare" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Äldre" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -447,10 +521,10 @@ msgstr "Kommentar" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Jag är säker på att jag vill radera detta" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "" +msgstr "Du tänker radera en annan användares media. Var försiktig." diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index dc196210..e0117391 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 8a5fc21c..9e4380c2 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -2,14 +2,15 @@ # Copyright (C) 2011 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # +# Translators: # , 2011. # Harry Chen , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-05 23:31-0500\n" -"PO-Revision-Date: 2011-09-06 04:31+0000\n" +"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"PO-Revision-Date: 2011-09-11 21:16+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,57 +20,62 @@ msgstr "" "Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0\n" -#: mediagoblin/auth/forms.py:24 mediagoblin/auth/forms.py:48 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "使用者名稱" -#: mediagoblin/auth/forms.py:29 mediagoblin/auth/forms.py:52 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 msgid "Password" msgstr "密碼" -#: mediagoblin/auth/forms.py:34 +#: mediagoblin/auth/forms.py:35 msgid "Passwords must match." msgstr "密碼必須一致" -#: mediagoblin/auth/forms.py:36 +#: mediagoblin/auth/forms.py:37 msgid "Confirm password" msgstr "確認密碼" -#: mediagoblin/auth/forms.py:38 +#: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "再輸入一次,確定你沒有打錯字。" -#: mediagoblin/auth/forms.py:41 +#: mediagoblin/auth/forms.py:42 msgid "Email address" msgstr "電子郵件位置" -#: mediagoblin/auth/views.py:40 +#: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." msgstr "抱歉, 這個項目已經被暫停註冊." -#: mediagoblin/auth/views.py:58 +#: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." msgstr "抱歉, 這個使用者名稱已經存在." -#: mediagoblin/auth/views.py:62 +#: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." msgstr "抱歉,這個電子郵件已經被其他人使用了。" -#: mediagoblin/auth/views.py:160 +#: mediagoblin/auth/views.py:165 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "你的電子郵件位址已被認證. 你現在就可以登入, 編輯你的個人檔案而且遞交照片!" -#: mediagoblin/auth/views.py:166 +#: mediagoblin/auth/views.py:171 msgid "The verification key or user id is incorrect" msgstr "認證碼或是使用者帳號錯誤" -#: mediagoblin/auth/views.py:187 -#: mediagoblin/templates/mediagoblin/auth/resent_verification_email.html:22 +#: mediagoblin/auth/views.py:192 msgid "Resent your verification email." msgstr "重送認證信." +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "標題" @@ -107,7 +113,7 @@ msgstr "這個自訂字串已經被其他人用了" msgid "You are editing another user's media. Proceed with caution." msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:154 msgid "You are editing a user's profile. Proceed with caution." msgstr "你正在編輯一位用戶的檔案. 請謹慎處理." @@ -183,6 +189,10 @@ msgstr "" "由 MediaGoblin製作, 它是一個 GNU 專案" +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." msgstr "嗨!多媒體檔案愛好者!MediaGoblin是..." @@ -224,6 +234,60 @@ msgstr "" "由像你一樣的人們製作 (你可以幫我們改進軟體!)" +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"\n" +" Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "" +"\n" +" Your password has been changed. Try to log in now.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"\n" +" Check your inbox. We sent an email with a URL for changing your password.\n" +" " +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" msgstr "登入失敗!" @@ -236,6 +300,14 @@ msgstr "還沒有帳號嗎?" msgid "Create one here!" msgstr "在這裡建立一個吧!" +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "建立一個帳號!" @@ -428,7 +500,7 @@ msgstr "評論" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:176 +#: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." msgstr "你在刪除其他人的媒體檔案。請小心處理喔。" -- cgit v1.2.3 From a2468d18ca39afed9102d707e7aea6a613ff2dab Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 12 Sep 2011 02:32:03 +0200 Subject: Feature #587 - Split storage.py into submodules * Removed storage.py * Created submodules for filestorage, cloudfiles, mountstorage * Changed test_storage to reflect the changes made in the storage module structure * Added mediagoblin.storage.filestorage.BasicFileStorage as a default for both publicstore and queuestore's `storage_class` --- mediagoblin/config_spec.ini | 2 + mediagoblin/storage.py | 568 ------------------------------------ mediagoblin/storage/__init__.py | 240 +++++++++++++++ mediagoblin/storage/cloudfiles.py | 156 ++++++++++ mediagoblin/storage/filestorage.py | 78 +++++ mediagoblin/storage/mountstorage.py | 156 ++++++++++ mediagoblin/tests/test_storage.py | 6 +- 7 files changed, 635 insertions(+), 571 deletions(-) delete mode 100644 mediagoblin/storage.py create mode 100644 mediagoblin/storage/__init__.py create mode 100644 mediagoblin/storage/cloudfiles.py create mode 100644 mediagoblin/storage/filestorage.py create mode 100644 mediagoblin/storage/mountstorage.py diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 6fefb581..0801b39e 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -43,10 +43,12 @@ allow_attachments = boolean(default=False) [storage:publicstore] +storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/public") base_url = string(default="/mgoblin_media/") [storage:queuestore] +storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/queue") diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py deleted file mode 100644 index f9563031..00000000 --- a/mediagoblin/storage.py +++ /dev/null @@ -1,568 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import os -import shutil -import urlparse -import uuid -import cloudfiles -import mimetypes -import tempfile - -from werkzeug.utils import secure_filename - -from mediagoblin import util - -######## -# Errors -######## - - -class Error(Exception): - pass - - -class InvalidFilepath(Error): - pass - - -class NoWebServing(Error): - pass - - -class NotImplementedError(Error): - pass - - -############################################### -# Storage interface & basic file implementation -############################################### - -class StorageInterface(object): - """ - Interface for the storage API. - - This interface doesn't actually provide behavior, but it defines - what kind of storage patterns subclasses should provide. - - It is important to note that the storage API idea of a "filepath" - is actually like ['dir1', 'dir2', 'file.jpg'], so keep that in - mind while reading method documentation. - - You should set up your __init__ method with whatever keyword - arguments are appropriate to your storage system, but you should - also passively accept all extraneous keyword arguments like: - - def __init__(self, **kwargs): - pass - - See BasicFileStorage as a simple implementation of the - StorageInterface. - """ - - # Whether this file store is on the local filesystem. - local_storage = False - - def __raise_not_implemented(self): - """ - Raise a warning about some component not implemented by a - subclass of this interface. - """ - raise NotImplementedError( - "This feature not implemented in this storage API implementation.") - - def file_exists(self, filepath): - """ - Return a boolean asserting whether or not file at filepath - exists in our storage system. - - Returns: - True / False depending on whether file exists or not. - """ - # Subclasses should override this method. - self.__raise_not_implemented() - - def get_file(self, filepath, mode='r'): - """ - Return a file-like object for reading/writing from this filepath. - - Should create directories, buckets, whatever, as necessary. - """ - # Subclasses should override this method. - self.__raise_not_implemented() - - def delete_file(self, filepath): - """ - Delete or dereference the file at filepath. - - This might need to delete directories, buckets, whatever, for - cleanliness. (Be sure to avoid race conditions on that though) - """ - # Subclasses should override this method. - self.__raise_not_implemented() - - def file_url(self, filepath): - """ - Get the URL for this file. This assumes our storage has been - mounted with some kind of URL which makes this possible. - """ - # Subclasses should override this method. - self.__raise_not_implemented() - - def get_unique_filepath(self, filepath): - """ - If a filename at filepath already exists, generate a new name. - - Eg, if the filename doesn't exist: - >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) - [u'dir1', u'dir2', u'fname.jpg'] - - But if a file does exist, let's get one back with at uuid tacked on: - >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) - [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] - """ - # Make sure we have a clean filepath to start with, since - # we'll be possibly tacking on stuff to the filename. - filepath = clean_listy_filepath(filepath) - - if self.file_exists(filepath): - return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] - else: - return filepath - - def get_local_path(self, filepath): - """ - If this is a local_storage implementation, give us a link to - the local filesystem reference to this file. - - >>> storage_handler.get_local_path(['foo', 'bar', 'baz.jpg']) - u'/path/to/mounting/foo/bar/baz.jpg' - """ - # Subclasses should override this method, if applicable. - self.__raise_not_implemented() - - def copy_locally(self, filepath, dest_path): - """ - Copy this file locally. - - A basic working method for this is provided that should - function both for local_storage systems and remote storge - systems, but if more efficient systems for copying locally - apply to your system, override this method with something more - appropriate. - """ - if self.local_storage: - shutil.copy( - self.get_local_path(filepath), dest_path) - else: - with self.get_file(filepath, 'rb') as source_file: - with file(dest_path, 'wb') as dest_file: - dest_file.write(source_file.read()) - - -class BasicFileStorage(StorageInterface): - """ - Basic local filesystem implementation of storage API - """ - - local_storage = True - - def __init__(self, base_dir, base_url=None, **kwargs): - """ - Keyword arguments: - - base_dir: Base directory things will be served out of. MUST - be an absolute path. - - base_url: URL files will be served from - """ - self.base_dir = base_dir - self.base_url = base_url - - def _resolve_filepath(self, filepath): - """ - Transform the given filepath into a local filesystem filepath. - """ - return os.path.join( - self.base_dir, *clean_listy_filepath(filepath)) - - def file_exists(self, filepath): - return os.path.exists(self._resolve_filepath(filepath)) - - def get_file(self, filepath, mode='r'): - # Make directories if necessary - if len(filepath) > 1: - directory = self._resolve_filepath(filepath[:-1]) - if not os.path.exists(directory): - os.makedirs(directory) - - # Grab and return the file in the mode specified - return open(self._resolve_filepath(filepath), mode) - - def delete_file(self, filepath): - # TODO: Also delete unused directories if empty (safely, with - # checks to avoid race conditions). - os.remove(self._resolve_filepath(filepath)) - - def file_url(self, filepath): - if not self.base_url: - raise NoWebServing( - "base_url not set, cannot provide file urls") - - return urlparse.urljoin( - self.base_url, - '/'.join(clean_listy_filepath(filepath))) - - def get_local_path(self, filepath): - return self._resolve_filepath(filepath) - - -# ---------------------------------------------------- -# OpenStack/Rackspace Cloud's Swift/CloudFiles support -# ---------------------------------------------------- - -class CloudFilesStorage(StorageInterface): - def __init__(self, **kwargs): - self.param_container = kwargs.get('cloudfiles_container') - self.param_user = kwargs.get('cloudfiles_user') - self.param_api_key = kwargs.get('cloudfiles_api_key') - self.param_host = kwargs.get('cloudfiles_host') - self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') - - if not self.param_host: - print('No CloudFiles host URL specified, ' - 'defaulting to Rackspace US') - - self.connection = cloudfiles.get_connection( - username=self.param_user, - api_key=self.param_api_key, - servicenet=True if self.param_use_servicenet == 'true' or \ - self.param_use_servicenet == True else False) - - if not self.param_container == \ - self.connection.get_container(self.param_container): - self.container = self.connection.create_container( - self.param_container) - self.container.make_public( - ttl=60 * 60 * 2) - else: - self.container = self.connection.get_container( - self.param_container) - - self.container_uri = self.container.public_uri() - - def _resolve_filepath(self, filepath): - return '/'.join( - clean_listy_filepath(filepath)) - - def file_exists(self, filepath): - try: - object = self.container.get_object( - self._resolve_filepath(filepath)) - return True - except cloudfiles.errors.NoSuchObject: - return False - - def get_file(self, filepath, *args, **kwargs): - """ - - Doesn't care about the "mode" argument - """ - try: - obj = self.container.get_object( - self._resolve_filepath(filepath)) - except cloudfiles.errors.NoSuchObject: - obj = self.container.create_object( - self._resolve_filepath(filepath)) - - mimetype = mimetypes.guess_type( - filepath[-1]) - - if mimetype: - obj.content_type = mimetype[0] - - return CloudFilesStorageObjectWrapper(obj, *args, **kwargs) - - def delete_file(self, filepath): - # TODO: Also delete unused directories if empty (safely, with - # checks to avoid race conditions). - self.container.delete_object( - self._resolve_filepath(filepath)) - - def file_url(self, filepath): - return '/'.join([ - self.container_uri, - self._resolve_filepath(filepath)]) - - -class CloudFilesStorageObjectWrapper(): - """ - Wrapper for python-cloudfiles's cloudfiles.storage_object.Object - used to circumvent the mystic `medium.jpg` corruption issue, where - we had both python-cloudfiles and PIL doing buffering on both - ends and that breaking things. - - This wrapper currently meets mediagoblin's needs for a public_store - file-like object. - """ - def __init__(self, storage_object, *args, **kwargs): - self.storage_object = storage_object - - def read(self, *args, **kwargs): - return self.storage_object.read(*args, **kwargs) - - def write(self, data, *args, **kwargs): - """ - write data to the cloudfiles storage object - - The original motivation for this wrapper is to ensure - that buffered writing to a cloudfiles storage object does not overwrite - any preexisting data. - - Currently this method does not support any write modes except "append". - However if we should need it it would be easy implement. - """ - if self.storage_object.size and type(data) == str: - data = self.read() + data - - self.storage_object.write(data, *args, **kwargs) - - def close(self): - pass - - def __enter__(self): - """ - Context Manager API implementation - http://docs.python.org/library/stdtypes.html#context-manager-types - """ - return self - - def __exit__(self, *exc_info): - """ - Context Manger API implementation - see self.__enter__() - """ - self.close() - - -# ------------ -# MountStorage -# ------------ - -class MountStorage(StorageInterface): - """ - Experimental "Mount" virtual Storage Interface - - This isn't an interface to some real storage, instead it's a - redirecting interface, that redirects requests to other - "StorageInterface"s. - - For example, say you have the paths: - - 1. ['user_data', 'cwebber', 'avatar.jpg'] - 2. ['user_data', 'elrond', 'avatar.jpg'] - 3. ['media_entries', '34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg'] - - You could mount media_entries under CloudFileStorage and user_data - under BasicFileStorage. Then 1 would be passed to - BasicFileStorage under the path ['cwebber', 'avatar.jpg'] and 3 - would be passed to CloudFileStorage under - ['34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg']. - - In other words, this is kind of like mounting /home/ and /etc/ - under different filesystems on your operating system... but with - mediagoblin filestorages :) - - To set this up, you currently need to call the mount() method with - the target path and a backend, that shall be available under that - target path. You have to mount things in a sensible order, - especially you can't mount ["a", "b"] before ["a"]. - """ - def __init__(self, **kwargs): - self.mounttab = {} - - def mount(self, dirpath, backend): - """ - Mount a new backend under dirpath - """ - new_ent = clean_listy_filepath(dirpath) - - print "Mounting:", repr(new_ent) - already, rem_1, table, rem_2 = self._resolve_to_backend(new_ent, True) - print "===", repr(already), repr(rem_1), repr(rem_2), len(table) - - assert (len(rem_2) > 0) or (None not in table), \ - "That path is already mounted" - assert (len(rem_2) > 0) or (len(table)==0), \ - "A longer path is already mounted here" - - for part in rem_2: - table[part] = {} - table = table[part] - table[None] = backend - - def _resolve_to_backend(self, filepath, extra_info = False): - """ - extra_info = True is for internal use! - - Normally, returns the backend and the filepath inside that backend. - - With extra_info = True it returns the last directory node and the - remaining filepath from there in addition. - """ - table = self.mounttab - filepath = filepath[:] - res_fp = None - while True: - new_be = table.get(None) - if (new_be is not None) or res_fp is None: - res_be = new_be - res_fp = filepath[:] - res_extra = (table, filepath[:]) - # print "... New res: %r, %r, %r" % (res_be, res_fp, res_extra) - if len(filepath) == 0: - break - query = filepath.pop(0) - entry = table.get(query) - if entry is not None: - table = entry - res_extra = (table, filepath[:]) - else: - break - if extra_info: - return (res_be, res_fp) + res_extra - else: - return (res_be, res_fp) - - def resolve_to_backend(self, filepath): - backend, filepath = self._resolve_to_backend(filepath) - if backend is None: - raise Error("Path not mounted") - return backend, filepath - - def __repr__(self, table = None, indent = []): - res = [] - if table is None: - res.append("MountStorage<") - table = self.mounttab - v = table.get(None) - if v: - res.append(" " * len(indent) + repr(indent) + ": " + repr(v)) - for k, v in table.iteritems(): - if k == None: - continue - res.append(" " * len(indent) + repr(k) + ":") - res += self.__repr__(v, indent + [k]) - if table is self.mounttab: - res.append(">") - return "\n".join(res) - else: - return res - - def file_exists(self, filepath): - backend, filepath = self.resolve_to_backend(filepath) - return backend.file_exists(filepath) - - def get_file(self, filepath, mode='r'): - backend, filepath = self.resolve_to_backend(filepath) - return backend.get_file(filepath, mode) - - def delete_file(self, filepath): - backend, filepath = self.resolve_to_backend(filepath) - return backend.delete_file(filepath) - - def file_url(self, filepath): - backend, filepath = self.resolve_to_backend(filepath) - return backend.file_url(filepath) - - def get_local_path(self, filepath): - backend, filepath = self.resolve_to_backend(filepath) - return backend.get_local_path(filepath) - - def copy_locally(self, filepath, dest_path): - """ - Need to override copy_locally, because the local_storage - attribute is not correct. - """ - backend, filepath = self.resolve_to_backend(filepath) - backend.copy_locally(filepath, dest_path) - - -########### -# Utilities -########### - -def clean_listy_filepath(listy_filepath): - """ - Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and - clean out any nastiness from it. - - - >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg']) - [u'dir1', u'foo_.._nasty', u'linooks.jpg'] - - Args: - - listy_filepath: a list of filepath components, mediagoblin - storage API style. - - Returns: - A cleaned list of unicode objects. - """ - cleaned_filepath = [ - unicode(secure_filename(filepath)) - for filepath in listy_filepath] - - if u'' in cleaned_filepath: - raise InvalidFilepath( - "A filename component could not be resolved into a usable name.") - - return cleaned_filepath - - -def storage_system_from_config(config_section): - """ - Utility for setting up a storage system from a config section. - - Note that a special argument may be passed in to - the config_section which is "storage_class" which will provide an - import path to a storage system. This defaults to - "mediagoblin.storage:BasicFileStorage" if otherwise undefined. - - Arguments: - - config_section: dictionary of config parameters - - Returns: - An instantiated storage system. - - Example: - storage_system_from_config( - {'base_url': '/media/', - 'base_dir': '/var/whatever/media/'}) - - Will return: - BasicFileStorage( - base_url='/media/', - base_dir='/var/whatever/media') - """ - # This construct is needed, because dict(config) does - # not replace the variables in the config items. - config_params = dict(config_section.iteritems()) - - if 'storage_class' in config_params: - storage_class = config_params['storage_class'] - config_params.pop('storage_class') - else: - storage_class = "mediagoblin.storage:BasicFileStorage" - - storage_class = util.import_component(storage_class) - return storage_class(**config_params) diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py new file mode 100644 index 00000000..8665d9e5 --- /dev/null +++ b/mediagoblin/storage/__init__.py @@ -0,0 +1,240 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import shutil +import urlparse +import uuid + +from werkzeug.utils import secure_filename + +from mediagoblin import util + +######## +# Errors +######## + + +class Error(Exception): + pass + + +class InvalidFilepath(Error): + pass + + +class NoWebServing(Error): + pass + + +class NotImplementedError(Error): + pass + + +############################################### +# Storage interface & basic file implementation +############################################### + +class StorageInterface(object): + """ + Interface for the storage API. + + This interface doesn't actually provide behavior, but it defines + what kind of storage patterns subclasses should provide. + + It is important to note that the storage API idea of a "filepath" + is actually like ['dir1', 'dir2', 'file.jpg'], so keep that in + mind while reading method documentation. + + You should set up your __init__ method with whatever keyword + arguments are appropriate to your storage system, but you should + also passively accept all extraneous keyword arguments like: + + def __init__(self, **kwargs): + pass + + See BasicFileStorage as a simple implementation of the + StorageInterface. + """ + + # Whether this file store is on the local filesystem. + local_storage = False + + def __raise_not_implemented(self): + """ + Raise a warning about some component not implemented by a + subclass of this interface. + """ + raise NotImplementedError( + "This feature not implemented in this storage API implementation.") + + def file_exists(self, filepath): + """ + Return a boolean asserting whether or not file at filepath + exists in our storage system. + + Returns: + True / False depending on whether file exists or not. + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def get_file(self, filepath, mode='r'): + """ + Return a file-like object for reading/writing from this filepath. + + Should create directories, buckets, whatever, as necessary. + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def delete_file(self, filepath): + """ + Delete or dereference the file at filepath. + + This might need to delete directories, buckets, whatever, for + cleanliness. (Be sure to avoid race conditions on that though) + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def file_url(self, filepath): + """ + Get the URL for this file. This assumes our storage has been + mounted with some kind of URL which makes this possible. + """ + # Subclasses should override this method. + self.__raise_not_implemented() + + def get_unique_filepath(self, filepath): + """ + If a filename at filepath already exists, generate a new name. + + Eg, if the filename doesn't exist: + >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) + [u'dir1', u'dir2', u'fname.jpg'] + + But if a file does exist, let's get one back with at uuid tacked on: + >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) + [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] + """ + # Make sure we have a clean filepath to start with, since + # we'll be possibly tacking on stuff to the filename. + filepath = clean_listy_filepath(filepath) + + if self.file_exists(filepath): + return filepath[:-1] + ["%s-%s" % (uuid.uuid4(), filepath[-1])] + else: + return filepath + + def get_local_path(self, filepath): + """ + If this is a local_storage implementation, give us a link to + the local filesystem reference to this file. + + >>> storage_handler.get_local_path(['foo', 'bar', 'baz.jpg']) + u'/path/to/mounting/foo/bar/baz.jpg' + """ + # Subclasses should override this method, if applicable. + self.__raise_not_implemented() + + def copy_locally(self, filepath, dest_path): + """ + Copy this file locally. + + A basic working method for this is provided that should + function both for local_storage systems and remote storge + systems, but if more efficient systems for copying locally + apply to your system, override this method with something more + appropriate. + """ + if self.local_storage: + shutil.copy( + self.get_local_path(filepath), dest_path) + else: + with self.get_file(filepath, 'rb') as source_file: + with file(dest_path, 'wb') as dest_file: + dest_file.write(source_file.read()) + + +########### +# Utilities +########### + +def clean_listy_filepath(listy_filepath): + """ + Take a listy filepath (like ['dir1', 'dir2', 'filename.jpg']) and + clean out any nastiness from it. + + + >>> clean_listy_filepath([u'/dir1/', u'foo/../nasty', u'linooks.jpg']) + [u'dir1', u'foo_.._nasty', u'linooks.jpg'] + + Args: + - listy_filepath: a list of filepath components, mediagoblin + storage API style. + + Returns: + A cleaned list of unicode objects. + """ + cleaned_filepath = [ + unicode(secure_filename(filepath)) + for filepath in listy_filepath] + + if u'' in cleaned_filepath: + raise InvalidFilepath( + "A filename component could not be resolved into a usable name.") + + return cleaned_filepath + + +def storage_system_from_config(config_section): + """ + Utility for setting up a storage system from a config section. + + Note that a special argument may be passed in to + the config_section which is "storage_class" which will provide an + import path to a storage system. This defaults to + "mediagoblin.storage:BasicFileStorage" if otherwise undefined. + + Arguments: + - config_section: dictionary of config parameters + + Returns: + An instantiated storage system. + + Example: + storage_system_from_config( + {'base_url': '/media/', + 'base_dir': '/var/whatever/media/'}) + + Will return: + BasicFileStorage( + base_url='/media/', + base_dir='/var/whatever/media') + """ + # This construct is needed, because dict(config) does + # not replace the variables in the config items. + config_params = dict(config_section.iteritems()) + + if 'storage_class' in config_params: + storage_class = config_params['storage_class'] + config_params.pop('storage_class') + else: + storage_class = 'mediagoblin.storage.filestorage:BasicFileStorage' + + storage_class = util.import_component(storage_class) + return storage_class(**config_params) diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py new file mode 100644 index 00000000..b1dd9450 --- /dev/null +++ b/mediagoblin/storage/cloudfiles.py @@ -0,0 +1,156 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +''' +Make it so that ``import cloudfiles`` does not pick THIS file, but the +python-cloudfiles one. + +http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports +''' +from __future__ import absolute_import + +from mediagoblin.storage import StorageInterface, clean_listy_filepath + +import cloudfiles +import mimetypes + +class CloudFilesStorage(StorageInterface): + ''' + OpenStack/Rackspace Cloud's Swift/CloudFiles support + ''' + + local_storage = False + + def __init__(self, **kwargs): + self.param_container = kwargs.get('cloudfiles_container') + self.param_user = kwargs.get('cloudfiles_user') + self.param_api_key = kwargs.get('cloudfiles_api_key') + self.param_host = kwargs.get('cloudfiles_host') + self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') + + if not self.param_host: + print('No CloudFiles host URL specified, ' + 'defaulting to Rackspace US') + + self.connection = cloudfiles.get_connection( + username=self.param_user, + api_key=self.param_api_key, + servicenet=True if self.param_use_servicenet == 'true' or \ + self.param_use_servicenet == True else False) + + if not self.param_container == \ + self.connection.get_container(self.param_container): + self.container = self.connection.create_container( + self.param_container) + self.container.make_public( + ttl=60 * 60 * 2) + else: + self.container = self.connection.get_container( + self.param_container) + + self.container_uri = self.container.public_uri() + + def _resolve_filepath(self, filepath): + return '/'.join( + clean_listy_filepath(filepath)) + + def file_exists(self, filepath): + try: + object = self.container.get_object( + self._resolve_filepath(filepath)) + return True + except cloudfiles.errors.NoSuchObject: + return False + + def get_file(self, filepath, *args, **kwargs): + """ + - Doesn't care about the "mode" argument + """ + try: + obj = self.container.get_object( + self._resolve_filepath(filepath)) + except cloudfiles.errors.NoSuchObject: + obj = self.container.create_object( + self._resolve_filepath(filepath)) + + mimetype = mimetypes.guess_type( + filepath[-1]) + + if mimetype: + obj.content_type = mimetype[0] + + return CloudFilesStorageObjectWrapper(obj, *args, **kwargs) + + def delete_file(self, filepath): + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + self.container.delete_object( + self._resolve_filepath(filepath)) + + def file_url(self, filepath): + return '/'.join([ + self.container_uri, + self._resolve_filepath(filepath)]) + + +class CloudFilesStorageObjectWrapper(): + """ + Wrapper for python-cloudfiles's cloudfiles.storage_object.Object + used to circumvent the mystic `medium.jpg` corruption issue, where + we had both python-cloudfiles and PIL doing buffering on both + ends and that breaking things. + + This wrapper currently meets mediagoblin's needs for a public_store + file-like object. + """ + def __init__(self, storage_object, *args, **kwargs): + self.storage_object = storage_object + + def read(self, *args, **kwargs): + return self.storage_object.read(*args, **kwargs) + + def write(self, data, *args, **kwargs): + """ + write data to the cloudfiles storage object + + The original motivation for this wrapper is to ensure + that buffered writing to a cloudfiles storage object does not overwrite + any preexisting data. + + Currently this method does not support any write modes except "append". + However if we should need it it would be easy implement. + """ + if self.storage_object.size and type(data) == str: + data = self.read() + data + + self.storage_object.write(data, *args, **kwargs) + + def close(self): + pass + + def __enter__(self): + """ + Context Manager API implementation + http://docs.python.org/library/stdtypes.html#context-manager-types + """ + return self + + def __exit__(self, *exc_info): + """ + Context Manger API implementation + see self.__enter__() + """ + self.close() diff --git a/mediagoblin/storage/filestorage.py b/mediagoblin/storage/filestorage.py new file mode 100644 index 00000000..22d6eb5a --- /dev/null +++ b/mediagoblin/storage/filestorage.py @@ -0,0 +1,78 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.storage import ( + StorageInterface, + clean_listy_filepath, + NoWebServing) + +import os +import urlparse + + +class BasicFileStorage(StorageInterface): + """ + Basic local filesystem implementation of storage API + """ + + local_storage = True + + def __init__(self, base_dir, base_url=None, **kwargs): + """ + Keyword arguments: + - base_dir: Base directory things will be served out of. MUST + be an absolute path. + - base_url: URL files will be served from + """ + self.base_dir = base_dir + self.base_url = base_url + + def _resolve_filepath(self, filepath): + """ + Transform the given filepath into a local filesystem filepath. + """ + return os.path.join( + self.base_dir, *clean_listy_filepath(filepath)) + + def file_exists(self, filepath): + return os.path.exists(self._resolve_filepath(filepath)) + + def get_file(self, filepath, mode='r'): + # Make directories if necessary + if len(filepath) > 1: + directory = self._resolve_filepath(filepath[:-1]) + if not os.path.exists(directory): + os.makedirs(directory) + + # Grab and return the file in the mode specified + return open(self._resolve_filepath(filepath), mode) + + def delete_file(self, filepath): + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + os.remove(self._resolve_filepath(filepath)) + + def file_url(self, filepath): + if not self.base_url: + raise NoWebServing( + "base_url not set, cannot provide file urls") + + return urlparse.urljoin( + self.base_url, + '/'.join(clean_listy_filepath(filepath))) + + def get_local_path(self, filepath): + return self._resolve_filepath(filepath) diff --git a/mediagoblin/storage/mountstorage.py b/mediagoblin/storage/mountstorage.py new file mode 100644 index 00000000..6adb7a0d --- /dev/null +++ b/mediagoblin/storage/mountstorage.py @@ -0,0 +1,156 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from medigoblin.storage import StorageInterface, clean_listy_filepath + + +class MountStorage(StorageInterface): + """ + Experimental "Mount" virtual Storage Interface + + This isn't an interface to some real storage, instead it's a + redirecting interface, that redirects requests to other + "StorageInterface"s. + + For example, say you have the paths: + + 1. ['user_data', 'cwebber', 'avatar.jpg'] + 2. ['user_data', 'elrond', 'avatar.jpg'] + 3. ['media_entries', '34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg'] + + You could mount media_entries under CloudFileStorage and user_data + under BasicFileStorage. Then 1 would be passed to + BasicFileStorage under the path ['cwebber', 'avatar.jpg'] and 3 + would be passed to CloudFileStorage under + ['34352f304c3f4d0ad8ad0f043522b6f2', 'thumb.jpg']. + + In other words, this is kind of like mounting /home/ and /etc/ + under different filesystems on your operating system... but with + mediagoblin filestorages :) + + To set this up, you currently need to call the mount() method with + the target path and a backend, that shall be available under that + target path. You have to mount things in a sensible order, + especially you can't mount ["a", "b"] before ["a"]. + """ + def __init__(self, **kwargs): + self.mounttab = {} + + def mount(self, dirpath, backend): + """ + Mount a new backend under dirpath + """ + new_ent = clean_listy_filepath(dirpath) + + print "Mounting:", repr(new_ent) + already, rem_1, table, rem_2 = self._resolve_to_backend(new_ent, True) + print "===", repr(already), repr(rem_1), repr(rem_2), len(table) + + assert (len(rem_2) > 0) or (None not in table), \ + "That path is already mounted" + assert (len(rem_2) > 0) or (len(table) == 0), \ + "A longer path is already mounted here" + + for part in rem_2: + table[part] = {} + table = table[part] + table[None] = backend + + def _resolve_to_backend(self, filepath, extra_info=False): + """ + extra_info = True is for internal use! + + Normally, returns the backend and the filepath inside that backend. + + With extra_info = True it returns the last directory node and the + remaining filepath from there in addition. + """ + table = self.mounttab + filepath = filepath[:] + res_fp = None + while True: + new_be = table.get(None) + if (new_be is not None) or res_fp is None: + res_be = new_be + res_fp = filepath[:] + res_extra = (table, filepath[:]) + # print "... New res: %r, %r, %r" % (res_be, res_fp, res_extra) + if len(filepath) == 0: + break + query = filepath.pop(0) + entry = table.get(query) + if entry is not None: + table = entry + res_extra = (table, filepath[:]) + else: + break + if extra_info: + return (res_be, res_fp) + res_extra + else: + return (res_be, res_fp) + + def resolve_to_backend(self, filepath): + backend, filepath = self._resolve_to_backend(filepath) + if backend is None: + raise Error("Path not mounted") + return backend, filepath + + def __repr__(self, table=None, indent=[]): + res = [] + if table is None: + res.append("MountStorage<") + table = self.mounttab + v = table.get(None) + if v: + res.append(" " * len(indent) + repr(indent) + ": " + repr(v)) + for k, v in table.iteritems(): + if k == None: + continue + res.append(" " * len(indent) + repr(k) + ":") + res += self.__repr__(v, indent + [k]) + if table is self.mounttab: + res.append(">") + return "\n".join(res) + else: + return res + + def file_exists(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_exists(filepath) + + def get_file(self, filepath, mode='r'): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_file(filepath, mode) + + def delete_file(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.delete_file(filepath) + + def file_url(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.file_url(filepath) + + def get_local_path(self, filepath): + backend, filepath = self.resolve_to_backend(filepath) + return backend.get_local_path(filepath) + + def copy_locally(self, filepath, dest_path): + """ + Need to override copy_locally, because the local_storage + attribute is not correct. + """ + backend, filepath = self.resolve_to_backend(filepath) + backend.copy_locally(filepath, dest_path) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 9c96f6ca..46ecb2ec 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -52,7 +52,7 @@ class FakeStorageSystem(): self.foobie = foobie self.blech = blech -class FakeRemoteStorage(storage.BasicFileStorage): +class FakeRemoteStorage(storage.filestorage.BasicFileStorage): # Theoretically despite this, all the methods should work but it # should force copying to the workbench local_storage = False @@ -66,7 +66,7 @@ def test_storage_system_from_config(): 'garbage_arg': 'trash'}) assert this_storage.base_url == 'http://example.org/moodia/' assert this_storage.base_dir == '/tmp/' - assert this_storage.__class__ is storage.BasicFileStorage + assert this_storage.__class__ is storage.filestorage.BasicFileStorage this_storage = storage.storage_system_from_config( {'foobie': 'eiboof', @@ -88,7 +88,7 @@ def get_tmp_filestorage(mount_url=None, fake_remote=False): if fake_remote: this_storage = FakeRemoteStorage(tmpdir, mount_url) else: - this_storage = storage.BasicFileStorage(tmpdir, mount_url) + this_storage = storage.filestorage.BasicFileStorage(tmpdir, mount_url) return tmpdir, this_storage -- cgit v1.2.3 From fd10c71644f12b0a56247c782566af1c37df5851 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 14 Sep 2011 02:08:01 +0200 Subject: Fixed ./bin/gmg. import_export would not find BasicFileStorage, and ./bin/gmg would throw an error no matter what command you tried to run. --- mediagoblin/gmg_commands/import_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index fc5c88a8..05edbfc8 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -17,7 +17,7 @@ from mediagoblin import mg_globals from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.init.config import read_mediagoblin_config -from mediagoblin.storage import BasicFileStorage +from mediagoblin.storage.filestorage import BasicFileStorage from mediagoblin.init import setup_storage, setup_global_and_app_config import shutil -- cgit v1.2.3 From 32d1a69d2f1293cb53cf9620f0e0a4f266ad230b Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 14 Sep 2011 19:52:47 +0200 Subject: Templates: Use request.staticdirect instead of /mgoblin_static Any reference to static, shipped content should use request.staticdirect instead of the default path. Especially if hosting mediagoblin via fastcgi, the paths might need changing. --- mediagoblin/templates/mediagoblin/utils/pagination.html | 4 ++-- mediagoblin/templates/mediagoblin/utils/prev_next.html | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 87e15e0f..0df3bfea 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -36,7 +36,7 @@ {% set prev_url = pagination.get_page_url_explicit( base_url, get_params, pagination.page - 1) %} - Previous page + Previous page {% trans %}Newer{% endtrans %} {% endif %} {% if pagination.has_next %} @@ -44,7 +44,7 @@ base_url, get_params, pagination.page + 1) %} {% trans %}Older{% endtrans %} - Next page + Next page {% endif %}
Go to page: diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 74f855ed..75903076 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -25,23 +25,23 @@ {# There are no previous entries for the very first media entry #} {% if prev_entry_url %} - Previous image + Previous image {% else %} {# This is the first entry. display greyed-out 'previous' image #} {% endif %} {# Likewise, this could be the very last media entry #} {% if next_entry_url %} - Next image + Next image {% else %} {# This is the last entry. display greyed-out 'next' image #} {% endif %} -- cgit v1.2.3 From dd1756ee19fc22d13bd207174e37ec5a68892a89 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 15 Sep 2011 13:19:25 +0200 Subject: mountstorage - Changed typo in import --- mediagoblin/storage/mountstorage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/storage/mountstorage.py b/mediagoblin/storage/mountstorage.py index 6adb7a0d..7239931f 100644 --- a/mediagoblin/storage/mountstorage.py +++ b/mediagoblin/storage/mountstorage.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from medigoblin.storage import StorageInterface, clean_listy_filepath +from mediagoblin.storage import StorageInterface, clean_listy_filepath class MountStorage(StorageInterface): -- cgit v1.2.3 From 93bdab9daad3ae431afd41a2efaefae05a555d88 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 23 Sep 2011 02:35:57 +0200 Subject: Multimedia support - Commiting from a not yet finished state - Details below * DONE Initially testing with arista ** DONE Video display templates *** TODO Multi-browser support ** TODO Video thumbnails ** TODO Link to original video ** TODO Video cropping Also contains a lot of "debug" print's --- mediagoblin/db/migrations.py | 8 + mediagoblin/init/celery/__init__.py | 5 + mediagoblin/media_types/__init__.py | 70 ++++++ mediagoblin/media_types/image/__init__.py | 28 +++ mediagoblin/media_types/image/processing.py | 207 ++++++++++++++++ mediagoblin/media_types/video/__init__.py | 26 +++ mediagoblin/media_types/video/processing.py | 260 +++++++++++++++++++++ mediagoblin/storage/cloudfiles.py | 10 +- mediagoblin/submit/views.py | 13 +- .../mediagoblin/media_displays/image.html | 1 + .../mediagoblin/media_displays/video.html | 8 + .../templates/mediagoblin/user_pages/media.html | 32 +-- mediagoblin/user_pages/views.py | 6 +- 13 files changed, 650 insertions(+), 24 deletions(-) create mode 100644 mediagoblin/media_types/__init__.py create mode 100644 mediagoblin/media_types/image/__init__.py create mode 100644 mediagoblin/media_types/image/processing.py create mode 100644 mediagoblin/media_types/video/__init__.py create mode 100644 mediagoblin/media_types/video/processing.py create mode 100644 mediagoblin/templates/mediagoblin/media_displays/image.html create mode 100644 mediagoblin/templates/mediagoblin/media_displays/video.html diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 755f49c5..01df7208 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -107,3 +107,11 @@ def user_add_forgot_password_token_and_expires(database): {'fp_token_expire': {'$exists': False}}, {'$set': {'fp_token_expire': None}}, multi=True) + + +@RegisterMigration(7) +def media_type_image_to_multimedia_type_image(database): + database['media_entries'].update( + {'media_type': 'image'}, + {'$set': {'media_type': 'mediagoblin.media_types.image'}}, + multi=True) diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index c58b1305..05c54b05 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -17,8 +17,13 @@ import os import sys +from mediagoblin.media_types import get_media_types + MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media'] +MANDATORY_CELERY_IMPORTS = [i for i in get_media_types()] + +print(MANDATORY_CELERY_IMPORTS) DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module' diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py new file mode 100644 index 00000000..67dab418 --- /dev/null +++ b/mediagoblin/media_types/__init__.py @@ -0,0 +1,70 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import sys + +class FileTypeNotSupported(Exception): + pass + +class InvalidFileType(Exception): + pass + +MEDIA_TYPES = [ + 'mediagoblin.media_types.image', + 'mediagoblin.media_types.video'] + + +def get_media_types(): + for media_type in MEDIA_TYPES: + yield media_type + + +def get_media_managers(): + for media_type in get_media_types(): + ''' + FIXME + __import__ returns the lowest-level module. If the plugin is located + outside the conventional plugin module tree, it will not be loaded + properly because of the [...]ugin.media_types. + + We need this if we want to support a separate site-specific plugin + folder. + ''' + try: + __import__(media_type) + except ImportError as e: + raise Exception('ERROR: Could not import {0}: {1}'.format(media_type, e)) + + yield media_type, sys.modules[media_type].MEDIA_MANAGER + +def get_media_manager(_media_type = None): + for media_type, manager in get_media_managers(): + if media_type in _media_type: + return manager + + +def get_media_type_and_manager(filename): + for media_type, manager in get_media_managers(): + if filename.find('.') > 0: + ext = os.path.splitext(filename)[1].lower() + else: + raise InvalidFileType( + 'Could not find any file extension in "{0}"'.format( + filename)) + + if ext[1:] in manager['accepted_extensions']: + return media_type, manager diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py new file mode 100644 index 00000000..0cd0383f --- /dev/null +++ b/mediagoblin/media_types/image/__init__.py @@ -0,0 +1,28 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.media_types.image.processing import process_media + + +MEDIA_MANAGER = { + "human_readable": "Image", + "processor": process_media, # alternately a string, + # 'mediagoblin.media_types.image.processing'? + "display_template": "mediagoblin/media_displays/image.html", + "default_thumb": "images/media_thumbs/image.jpg", + "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"], + "accepted_mimetypes": [ + "image/jpeg", "image/png", "image/gif", "image/tiff"]} diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py new file mode 100644 index 00000000..2c4ad2b1 --- /dev/null +++ b/mediagoblin/media_types/image/processing.py @@ -0,0 +1,207 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import Image + +from celery.task import Task +from celery import registry + +from mediagoblin.db.util import ObjectId +from mediagoblin import mg_globals as mgg + +from mediagoblin.util import lazy_pass_to_ugettext as _ + +THUMB_SIZE = 180, 180 +MEDIUM_SIZE = 640, 640 + + +def create_pub_filepath(entry, filename): + return mgg.public_store.get_unique_filepath( + ['media_entries', + unicode(entry['_id']), + filename]) + + +class BaseProcessingFail(Exception): + """ + Base exception that all other processing failure messages should + subclass from. + + You shouldn't call this itself; instead you should subclass it + and provid the exception_path and general_message applicable to + this error. + """ + general_message = u'' + + @property + def exception_path(self): + return u"%s:%s" % ( + self.__class__.__module__, self.__class__.__name__) + + def __init__(self, **metadata): + self.metadata = metadata or {} + + +class BadMediaFail(BaseProcessingFail): + """ + Error that should be raised when an inappropriate file was given + for the media type specified. + """ + general_message = _(u'Invalid file given for media type.') + + +################################ +# Media processing initial steps +################################ + +class ProcessMedia(Task): + """ + Pass this entry off for processing. + """ + def run(self, media_id): + """ + Pass the media entry off to the appropriate processing function + (for now just process_image...) + """ + entry = mgg.database.MediaEntry.one( + {'_id': ObjectId(media_id)}) + + # Try to process, and handle expected errors. + try: + process_image(entry) + except BaseProcessingFail, exc: + mark_entry_failed(entry[u'_id'], exc) + return + + entry['state'] = u'processed' + entry.save() + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """ + If the processing failed we should mark that in the database. + + Assuming that the exception raised is a subclass of BaseProcessingFail, + we can use that to get more information about the failure and store that + for conveying information to users about the failure, etc. + """ + entry_id = args[0] + mark_entry_failed(entry_id, exc) + + +process_media = registry.tasks[ProcessMedia.name] + + +def mark_entry_failed(entry_id, exc): + """ + Mark a media entry as having failed in its conversion. + + Uses the exception that was raised to mark more information. If the + exception is a derivative of BaseProcessingFail then we can store extra + information that can be useful for users telling them why their media failed + to process. + + Args: + - entry_id: The id of the media entry + + """ + # Was this a BaseProcessingFail? In other words, was this a + # type of error that we know how to handle? + if isinstance(exc, BaseProcessingFail): + # Looks like yes, so record information about that failure and any + # metadata the user might have supplied. + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': exc.exception_path, + u'fail_metadata': exc.metadata}}) + else: + # Looks like no, so just mark it as failed and don't record a + # failure_error (we'll assume it wasn't handled) and don't record + # metadata (in fact overwrite it if somehow it had previous info + # here) + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': None, + u'fail_metadata': {}}}) + + +def process_image(entry): + """ + Code to process an image + """ + workbench = mgg.workbench_manager.create_workbench() + + queued_filepath = entry['queued_media_file'] + queued_filename = workbench.localized_file( + mgg.queue_store, queued_filepath, + 'source') + + try: + thumb = Image.open(queued_filename) + except IOError: + raise BadMediaFail() + + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + # ensure color mode is compatible with jpg + if thumb.mode != "RGB": + thumb = thumb.convert("RGB") + + thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') + + with thumb_file: + thumb.save(thumb_file, "JPEG", quality=90) + + # If the size of the original file exceeds the specified size of a `medium` + # file, a `medium.jpg` files is created and later associated with the media + # entry. + medium = Image.open(queued_filename) + medium_processed = False + + if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: + medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) + + if medium.mode != "RGB": + medium = medium.convert("RGB") + + medium_filepath = create_pub_filepath(entry, 'medium.jpg') + medium_file = mgg.public_store.get_file(medium_filepath, 'w') + + with medium_file: + medium.save(medium_file, "JPEG", quality=90) + medium_processed = True + + # we have to re-read because unlike PIL, not everything reads + # things in string representation :) + queued_file = file(queued_filename, 'rb') + + with queued_file: + original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + + with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + original_file.write(queued_file.read()) + + mgg.queue_store.delete_file(queued_filepath) + entry['queued_media_file'] = [] + media_files_dict = entry.setdefault('media_files', {}) + media_files_dict['thumb'] = thumb_filepath + media_files_dict['original'] = original_filepath + if medium_processed: + media_files_dict['medium'] = medium_filepath + + # clean up workbench + workbench.destroy_self() diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py new file mode 100644 index 00000000..2a36623e --- /dev/null +++ b/mediagoblin/media_types/video/__init__.py @@ -0,0 +1,26 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.media_types.video.processing import process_media + + +MEDIA_MANAGER = { + "human_readable": "Video", + "processor": process_media, # alternately a string, + # 'mediagoblin.media_types.image.processing'? + "display_template": "mediagoblin/media_displays/video.html", + "default_thumb": "images/media_thumbs/video.jpg", + "accepted_extensions": ["mp4", "mov", "webm", "avi", "3gp", "3gpp"]} diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py new file mode 100644 index 00000000..94784836 --- /dev/null +++ b/mediagoblin/media_types/video/processing.py @@ -0,0 +1,260 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import Image +import tempfile + +from celery.task import Task +from celery import registry + +from mediagoblin.db.util import ObjectId +from mediagoblin import mg_globals as mgg + +from mediagoblin.util import lazy_pass_to_ugettext as _ + +import gobject + +import gst +import arista + +from arista.transcoder import TranscoderOptions + +THUMB_SIZE = 180, 180 +MEDIUM_SIZE = 640, 640 +ARISTA_DEVICE_KEY = 'web' + + +loop = None + + +def process_video(entry): + """ + Code to process a video + """ + info = {} + workbench = mgg.workbench_manager.create_workbench() + + queued_filepath = entry['queued_media_file'] + queued_filename = workbench.localized_file( + mgg.queue_store, queued_filepath, + 'source') + + arista.init() + + devices = arista.presets.get() + device = devices[ARISTA_DEVICE_KEY] + + queue = arista.queue.TranscodeQueue() + + info['tmp_file'] = tmp_file = tempfile.NamedTemporaryFile() + + info['medium_filepath'] = medium_filepath = create_pub_filepath(entry, 'video.webm') + + output = tmp_file.name + + uri = 'file://' + queued_filename + + preset = device.presets[device.default] + + opts = TranscoderOptions(uri, preset, output) + + queue.append(opts) + + info['entry'] = entry + + queue.connect("entry-start", entry_start, info) +# queue.connect("entry-pass-setup", entry_pass_setup, options) + queue.connect("entry-error", entry_error, info) + queue.connect("entry-complete", entry_complete, info) + + info['loop'] = loop = gobject.MainLoop() + + loop.run() + + # we have to re-read because unlike PIL, not everything reads + # things in string representation :) + queued_file = file(queued_filename, 'rb') + + with queued_file: + original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + + with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + original_file.write(queued_file.read()) + + mgg.queue_store.delete_file(queued_filepath) + entry['queued_media_file'] = [] + media_files_dict = entry.setdefault('media_files', {}) + media_files_dict['original'] = original_filepath + + # clean up workbench + workbench.destroy_self() + + +def create_pub_filepath(entry, filename): + return mgg.public_store.get_unique_filepath( + ['media_entries', + unicode(entry['_id']), + filename]) + + +class BaseProcessingFail(Exception): + """ + Base exception that all other processing failure messages should + subclass from. + + You shouldn't call this itself; instead you should subclass it + and provid the exception_path and general_message applicable to + this error. + """ + general_message = u'' + + @property + def exception_path(self): + return u"%s:%s" % ( + self.__class__.__module__, self.__class__.__name__) + + def __init__(self, **metadata): + self.metadata = metadata or {} + + +class BadMediaFail(BaseProcessingFail): + """ + Error that should be raised when an inappropriate file was given + for the media type specified. + """ + general_message = _(u'Invalid file given for media type.') + + +################################ +# Media processing initial steps +################################ + +class ProcessMedia(Task): + """ + Pass this entry off for processing. + """ + def run(self, media_id): + """ + Pass the media entry off to the appropriate processing function + (for now just process_image...) + """ + entry = mgg.database.MediaEntry.one( + {'_id': ObjectId(media_id)}) + + # Try to process, and handle expected errors. + try: + process_video(entry) + except BaseProcessingFail, exc: + mark_entry_failed(entry[u'_id'], exc) + return + + entry['state'] = u'processed' + entry.save() + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """ + If the processing failed we should mark that in the database. + + Assuming that the exception raised is a subclass of BaseProcessingFail, + we can use that to get more information about the failure and store that + for conveying information to users about the failure, etc. + """ + entry_id = args[0] + mark_entry_failed(entry_id, exc) + + +process_media = registry.tasks[ProcessMedia.name] + + +def mark_entry_failed(entry_id, exc): + """ + Mark a media entry as having failed in its conversion. + + Uses the exception that was raised to mark more information. If the + exception is a derivative of BaseProcessingFail then we can store extra + information that can be useful for users telling them why their media failed + to process. + + Args: + - entry_id: The id of the media entry + + """ + # Was this a BaseProcessingFail? In other words, was this a + # type of error that we know how to handle? + if isinstance(exc, BaseProcessingFail): + # Looks like yes, so record information about that failure and any + # metadata the user might have supplied. + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': exc.exception_path, + u'fail_metadata': exc.metadata}}) + else: + # Looks like no, so just mark it as failed and don't record a + # failure_error (we'll assume it wasn't handled) and don't record + # metadata (in fact overwrite it if somehow it had previous info + # here) + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': None, + u'fail_metadata': {}}}) + + +def entry_start(queue, entry, options): + print(queue, entry, options) + +def entry_complete(queue, entry, info): + entry.transcoder.stop() + gobject.idle_add(info['loop'].quit) + + with info['tmp_file'] as tmp_file: + mgg.public_store.get_file(info['medium_filepath'], 'wb').write( + tmp_file.read()) + info['entry']['media_files']['medium'] = info['medium_filepath'] + + print('\n=== DONE! ===\n') + + print(queue, entry, info) + +def entry_error(queue, entry, options): + print(queue, entry, options) + +def signal_handler(signum, frame): + """ + Handle Ctr-C gracefully and shut down the transcoder. + """ + global interrupted + print + print _("Interrupt caught. Cleaning up... (Ctrl-C to force exit)") + interrupted = True + signal.signal(signal.SIGINT, signal.SIG_DFL) + +def check_interrupted(): + """ + Check whether we have been interrupted by Ctrl-C and stop the + transcoder. + """ + if interrupted: + try: + source = transcoder.pipe.get_by_name("source") + source.send_event(gst.event_new_eos()) + except: + # Something pretty bad happened... just exit! + gobject.idle_add(loop.quit) + + return False + return True diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py index b1dd9450..85d52242 100644 --- a/mediagoblin/storage/cloudfiles.py +++ b/mediagoblin/storage/cloudfiles.py @@ -97,8 +97,14 @@ class CloudFilesStorage(StorageInterface): def delete_file(self, filepath): # TODO: Also delete unused directories if empty (safely, with # checks to avoid race conditions). - self.container.delete_object( - self._resolve_filepath(filepath)) + try: + self.container.delete_object( + self._resolve_filepath(filepath)) + except cloudfiles.container.ResponseError: + pass + finally: + pass + def file_url(self, filepath): return '/'.join([ diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index e24d78f3..78f52160 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -28,8 +28,9 @@ from mediagoblin.util import ( from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security -from mediagoblin.process_media import process_media, mark_entry_failed +from mediagoblin.process_media import mark_entry_failed from mediagoblin.messages import add_message, SUCCESS +from mediagoblin.media_types import get_media_type_and_manager @require_active_login @@ -45,15 +46,15 @@ def submit_start(request): and request.POST['file'].file): submit_form.file.errors.append( _(u'You must provide a file.')) - elif not security.check_filetype(request.POST['file']): - submit_form.file.errors.append( - _(u"The file doesn't seem to be an image!")) else: filename = request.POST['file'].filename + media_type, media_manager = get_media_type_and_manager(filename) + # create entry and save in database entry = request.db.MediaEntry() entry['_id'] = ObjectId() + entry['media_type'] = unicode(media_type) entry['title'] = ( unicode(request.POST['title']) or unicode(splitext(filename)[0])) @@ -62,7 +63,6 @@ def submit_start(request): entry['description_html'] = cleaned_markdown_conversion( entry['description']) - entry['media_type'] = u'image' # heh entry['uploader'] = request.user['_id'] # Process the user's folksonomy "tags" @@ -72,6 +72,7 @@ def submit_start(request): # Generate a slug from the title entry.generate_slug() + # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', @@ -103,7 +104,7 @@ def submit_start(request): # (... don't change entry after this point to avoid race # conditions with changes to the document via processing code) try: - process_media.apply_async( + media_manager['processor'].apply_async( [unicode(entry['_id'])], {}, task_id=task_id) except BaseException as exc: diff --git a/mediagoblin/templates/mediagoblin/media_displays/image.html b/mediagoblin/templates/mediagoblin/media_displays/image.html new file mode 100644 index 00000000..ad60fa94 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_displays/image.html @@ -0,0 +1 @@ +{% extends 'mediagoblin/user_pages/media.html' %} diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html new file mode 100644 index 00000000..37586924 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -0,0 +1,8 @@ +{% extends 'mediagoblin/user_pages/media.html' %} +{% block mediagoblin_media %} + +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 442bef6d..82a48e7c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -24,24 +24,26 @@ {% if media %}
- {% set display_media = request.app.public_store.file_url( - media.get_display_media(media.media_files)) %} - - {# if there's a medium file size, that means the medium size - # isn't the original... so link to the original! - #} - {% if media['media_files'].has_key('medium') %} - + {% block mediagoblin_media %} + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} + + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media['media_files'].has_key('medium') %} + + Image for {{ media.title }} + + {% else %} Image for {{ media.title }} - - {% else %} - Image for {{ media.title }} - {% endif %} + {% endif %} + {% endblock %}

diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 6a82d718..5458c694 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -29,6 +29,8 @@ from mediagoblin.decorators import (uses_pagination, get_user_media_entry, from werkzeug.contrib.atom import AtomFeed +from mediagoblin.media_types import get_media_manager + @uses_pagination def user_home(request, page): @@ -113,9 +115,11 @@ def media_home(request, media, page, **kwargs): comment_form = user_forms.MediaCommentForm(request.POST) + media_template_name = get_media_manager(media['media_type'])['display_template'] + return render_to_response( request, - 'mediagoblin/user_pages/media.html', + media_template_name, {'media': media, 'comments': comments, 'pagination': pagination, -- cgit v1.2.3 From 1f255101f54579760f2238d70dd3aa0b3cd4ba92 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 24 Sep 2011 02:21:46 +0200 Subject: Multimedia support - Refractored video processing. --- mediagoblin/media_types/__init__.py | 1 + .../media_types/video/presets/web-advanced.json | 505 +++++++++++ mediagoblin/media_types/video/presets/web-flv.png | Bin 0 -> 2234 bytes mediagoblin/media_types/video/presets/web-webm.svg | 259 ++++++ mediagoblin/media_types/video/presets/web.svg | 982 +++++++++++++++++++++ mediagoblin/media_types/video/processing.py | 186 ++-- mediagoblin/static/images/media_thumbs/video.jpg | Bin 0 -> 7278 bytes .../mediagoblin/media_displays/video.html | 8 + 8 files changed, 1875 insertions(+), 66 deletions(-) create mode 100644 mediagoblin/media_types/video/presets/web-advanced.json create mode 100644 mediagoblin/media_types/video/presets/web-flv.png create mode 100644 mediagoblin/media_types/video/presets/web-webm.svg create mode 100644 mediagoblin/media_types/video/presets/web.svg create mode 100644 mediagoblin/static/images/media_thumbs/video.jpg diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 67dab418..6a368cda 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -51,6 +51,7 @@ def get_media_managers(): yield media_type, sys.modules[media_type].MEDIA_MANAGER + def get_media_manager(_media_type = None): for media_type, manager in get_media_managers(): if media_type in _media_type: diff --git a/mediagoblin/media_types/video/presets/web-advanced.json b/mediagoblin/media_types/video/presets/web-advanced.json new file mode 100644 index 00000000..ce1d22ff --- /dev/null +++ b/mediagoblin/media_types/video/presets/web-advanced.json @@ -0,0 +1,505 @@ +{ + "make": "Generic", + "model": "Web Browser (Advanced)", + "description": "Media for World Wide Web", + "version": "0.1", + "author": { + "name": "Dionisio E Alonso", + "email": "dealonso@gmail.com" + }, + "icon": "file://web.svg", + "default": "WebM 480p", + "presets": [ + { + "name": "H.264 720p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 720p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 720p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 576p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 576p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 576p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 480p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 480p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 480p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 360p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 360p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 360p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + } + ] +} diff --git a/mediagoblin/media_types/video/presets/web-flv.png b/mediagoblin/media_types/video/presets/web-flv.png new file mode 100644 index 00000000..b75699f4 Binary files /dev/null and b/mediagoblin/media_types/video/presets/web-flv.png differ diff --git a/mediagoblin/media_types/video/presets/web-webm.svg b/mediagoblin/media_types/video/presets/web-webm.svg new file mode 100644 index 00000000..4e5b3e97 --- /dev/null +++ b/mediagoblin/media_types/video/presets/web-webm.svg @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/presets/web.svg b/mediagoblin/media_types/video/presets/web.svg new file mode 100644 index 00000000..c0c68244 --- /dev/null +++ b/mediagoblin/media_types/video/presets/web.svg @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Globe + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + globe + international + web + www + internet + network + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 94784836..4cae1fd8 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -16,6 +16,7 @@ import Image import tempfile +import pkg_resources from celery.task import Task from celery import registry @@ -25,10 +26,14 @@ from mediagoblin import mg_globals as mgg from mediagoblin.util import lazy_pass_to_ugettext as _ +import mediagoblin.media_types.video + import gobject +gobject.threads_init() import gst import arista +import logging from arista.transcoder import TranscoderOptions @@ -38,12 +43,17 @@ ARISTA_DEVICE_KEY = 'web' loop = None +logger = logging.getLogger(__name__) +logging.basicConfig() +logger.setLevel(logging.DEBUG) def process_video(entry): """ Code to process a video """ + global loop + loop = None info = {} workbench = mgg.workbench_manager.create_workbench() @@ -54,8 +64,11 @@ def process_video(entry): arista.init() - devices = arista.presets.get() - device = devices[ARISTA_DEVICE_KEY] + + web_advanced_preset = pkg_resources.resource_filename( + __name__, + 'presets/web-advanced.json') + device = arista.presets.load(web_advanced_preset) queue = arista.queue.TranscodeQueue() @@ -69,38 +82,127 @@ def process_video(entry): preset = device.presets[device.default] + logger.debug('preset: {0}'.format(preset)) + opts = TranscoderOptions(uri, preset, output) queue.append(opts) info['entry'] = entry - queue.connect("entry-start", entry_start, info) -# queue.connect("entry-pass-setup", entry_pass_setup, options) - queue.connect("entry-error", entry_error, info) - queue.connect("entry-complete", entry_complete, info) + queue.connect("entry-start", _transcoding_start, info) + queue.connect("entry-pass-setup", _transcoding_pass_setup, info) + queue.connect("entry-error", _transcoding_error, info) + queue.connect("entry-complete", _transcoding_complete, info) info['loop'] = loop = gobject.MainLoop() + info['queued_filename'] = queued_filename + info['queued_filepath'] = queued_filepath + info['workbench'] = workbench + + logger.debug('info: {0}'.format(info)) loop.run() + + ''' + try: + #thumb = Image.open(mediagoblin.media_types.video.MEDIA_MANAGER['default_thumb']) + except IOError: + raise BadMediaFail() + + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + # ensure color mode is compatible with jpg + if thumb.mode != "RGB": + thumb = thumb.convert("RGB") + + thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') + + with thumb_file: + thumb.save(thumb_file, "JPEG", quality=90) + ''' - # we have to re-read because unlike PIL, not everything reads - # things in string representation :) - queued_file = file(queued_filename, 'rb') +def __close_processing(queue, qentry, info, error=False): + ''' + Update MediaEntry, move files, handle errors + ''' + if not error: + qentry.transcoder.stop() + gobject.idle_add(info['loop'].quit) + info['loop'].quit() - with queued_file: - original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + print('\n-> Saving video...\n') - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: - original_file.write(queued_file.read()) + with info['tmp_file'] as tmp_file: + mgg.public_store.get_file(info['medium_filepath'], 'wb').write( + tmp_file.read()) + info['entry']['media_files']['medium'] = info['medium_filepath'] - mgg.queue_store.delete_file(queued_filepath) - entry['queued_media_file'] = [] - media_files_dict = entry.setdefault('media_files', {}) - media_files_dict['original'] = original_filepath + print('\n=== DONE! ===\n') + + # we have to re-read because unlike PIL, not everything reads + # things in string representation :) + queued_file = file(info['queued_filename'], 'rb') + + with queued_file: + original_filepath = create_pub_filepath(info['entry'], info['queued_filepath'][-1]) + + with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + original_file.write(queued_file.read()) + + mgg.queue_store.delete_file(info['queued_filepath']) + info['entry']['queued_media_file'] = [] + media_files_dict = info['entry'].setdefault('media_files', {}) + media_files_dict['original'] = original_filepath + # media_files_dict['thumb'] = thumb_filepath + + info['entry']['state'] = u'processed' + info['entry'].save() + + else: + qentry.transcoder.stop() + gobject.idle_add(info['loop'].quit) + info['loop'].quit() + info['entry']['state'] = u'failed' + info['entry'].save() # clean up workbench - workbench.destroy_self() + info['workbench'].destroy_self() + + +def _transcoding_start(queue, qentry, info): + logger.info('-> Starting transcoding') + logger.debug(queue, qentry, info) + +def _transcoding_complete(*args): + __close_processing(*args) + print(args) + +def _transcoding_error(*args): + logger.info('-> Error') + __close_processing(*args, error=True) + logger.debug(*args) + +def _transcoding_pass_setup(queue, qentry, options): + logger.info('-> Pass setup') + logger.debug(queue, qentry, options) + + +def check_interrupted(): + """ + Check whether we have been interrupted by Ctrl-C and stop the + transcoder. + """ + if interrupted: + try: + source = transcoder.pipe.get_by_name("source") + source.send_event(gst.event_new_eos()) + except: + # Something pretty bad happened... just exit! + gobject.idle_add(loop.quit) + + return False + return True def create_pub_filepath(entry, filename): @@ -161,9 +263,6 @@ class ProcessMedia(Task): mark_entry_failed(entry[u'_id'], exc) return - entry['state'] = u'processed' - entry.save() - def on_failure(self, exc, task_id, args, kwargs, einfo): """ If the processing failed we should mark that in the database. @@ -213,48 +312,3 @@ def mark_entry_failed(entry_id, exc): u'fail_error': None, u'fail_metadata': {}}}) - -def entry_start(queue, entry, options): - print(queue, entry, options) - -def entry_complete(queue, entry, info): - entry.transcoder.stop() - gobject.idle_add(info['loop'].quit) - - with info['tmp_file'] as tmp_file: - mgg.public_store.get_file(info['medium_filepath'], 'wb').write( - tmp_file.read()) - info['entry']['media_files']['medium'] = info['medium_filepath'] - - print('\n=== DONE! ===\n') - - print(queue, entry, info) - -def entry_error(queue, entry, options): - print(queue, entry, options) - -def signal_handler(signum, frame): - """ - Handle Ctr-C gracefully and shut down the transcoder. - """ - global interrupted - print - print _("Interrupt caught. Cleaning up... (Ctrl-C to force exit)") - interrupted = True - signal.signal(signal.SIGINT, signal.SIG_DFL) - -def check_interrupted(): - """ - Check whether we have been interrupted by Ctrl-C and stop the - transcoder. - """ - if interrupted: - try: - source = transcoder.pipe.get_by_name("source") - source.send_event(gst.event_new_eos()) - except: - # Something pretty bad happened... just exit! - gobject.idle_add(loop.quit) - - return False - return True diff --git a/mediagoblin/static/images/media_thumbs/video.jpg b/mediagoblin/static/images/media_thumbs/video.jpg new file mode 100644 index 00000000..841dc796 Binary files /dev/null and b/mediagoblin/static/images/media_thumbs/video.jpg differ diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index 37586924..22b19240 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -5,4 +5,12 @@ media['media_files']['medium']) }}" type='video/webm; codecs="vp8, vorbis"' /> + {% if 'original' in media.media_files %} + + {%- trans -%} + Original + {%- endtrans -%} + + {% endif %} {% endblock %} -- cgit v1.2.3 From 31370dbc2c0711798352e2af5708e5d58cbcb704 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 25 Sep 2011 20:26:06 -0500 Subject: Stripping out whitespace on these translation blocks. {% trans -%} ;o {%- endtrans %} --- mediagoblin/templates/mediagoblin/auth/fp_changed_success.html | 4 ++-- mediagoblin/templates/mediagoblin/auth/fp_email_sent.html | 4 ++-- mediagoblin/templates/mediagoblin/root.html | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html b/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html index d6633ec6..7cea312d 100644 --- a/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html +++ b/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html @@ -19,9 +19,9 @@ {% block mediagoblin_content %}

- {% trans %} + {% trans -%} Your password has been changed. Try to log in now. - {% endtrans %} + {%- endtrans %}

{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html b/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html index bc79b970..69aac6b3 100644 --- a/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html +++ b/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html @@ -19,9 +19,9 @@ {% block mediagoblin_content %}

- {% trans %} + {% trans -%} Check your inbox. We sent an email with a URL for changing your password. - {% endtrans %} + {%- endtrans %}

{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 854fca51..e3ca9726 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -36,11 +36,11 @@ {% if allow_registration %}

{% trans %}Excited to join us?{% endtrans %}

- {% trans register_url=request.urlgen('mediagoblin.auth.register') %} + {% trans register_url=request.urlgen('mediagoblin.auth.register') -%} Create a free account or Set up MediaGoblin on your own server - {% endtrans %} + {%- endtrans %} {% endif %}

-- cgit v1.2.3 From e9b2d7b498f6c9206659b3a252f631a8d11c1b4c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 25 Sep 2011 20:31:00 -0500 Subject: Updating translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 11549 -> 11461 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 10915 -> 10827 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 21 +- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 10738 -> 10686 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 46 +- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 11114 -> 11175 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 42 +- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 11232 -> 11144 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 10898 bytes mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 520 ++++++++++++++++++++++ mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 11184 -> 11096 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 10655 -> 10567 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 10261 -> 10173 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 10608 -> 10520 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 10955 -> 10905 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 50 ++- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 13306 -> 13546 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 45 +- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 10724 -> 10636 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 10587 -> 10499 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 10836 -> 10748 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 19 +- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 10463 -> 10375 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 19 +- 33 files changed, 682 insertions(+), 251 deletions(-) create mode 100644 mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo create mode 100644 mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index 146a588f..1d75d517 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index eb1c5f2d..b5057b9d 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -242,11 +242,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -262,17 +260,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index bb7538c2..06a01632 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 3aaabce0..81462e27 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -261,11 +261,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -281,17 +279,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 6ff8e8df..16a235a2 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -233,14 +233,12 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a " +"free account\n" " or\n" " Set up MediaGoblin on " -"your own server\n" -" " +"your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -256,18 +254,11 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your " -"password.\n" -" " +msgid "Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index b260cb16..506e882b 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 296f1b4b..270b043f 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -193,8 +193,8 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Funkcias per <a href=\"http://mediagoblin.org\">MediaGoblin</a>," -" unu el la <a href=\"http://gnu.org/\">projektoj de GNU</a>" +"Funkcias per MediaGoblin, unu el la " +"projektoj de GNU" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" @@ -244,9 +244,9 @@ msgid "" "href=\"http://mediagoblin.org/pages/join.html\">You can help us improve this" " software!)" msgstr "" -"Vivanta per homoj kiel vi. (<a " -"href=\"http://mediagoblin.org/pages/join.html\">Vi povas helpi al ni " -"plibonigi la programon!</a>)" +"Vivanta per homoj kiel vi. (Vi povas helpi al ni " +"plibonigi la programon!)" #: mediagoblin/templates/mediagoblin/root.html:38 msgid "Excited to join us?" @@ -255,37 +255,30 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 msgid "Most recent media" -msgstr "" +msgstr "Plej nove aldonitaj dosieroj" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 msgid "Enter your new password" -msgstr "" +msgstr "Enigu vian novan pasvorton" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Enter your username or email" -msgstr "" +msgstr "Enigu vian salutnomon aŭ retpoŝtadreson" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 @@ -301,6 +294,13 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Saluton, %(username)s,\n" +"\n" +"por ŝanĝi vian pasvorton ĉe GNUa MediaGoblin, sekvu la jenan retadreson per via TTT-legilo:\n" +"\n" +"%(verification_url)s\n" +"\n" +"Se vi pensas, ke ĉi tiu retletero estas sendita erare, simple ignoru ĝin kaj plu restu feliĉa koboldo!" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" @@ -316,11 +316,11 @@ msgstr "Kreu ĝin ĉi tie!" #: mediagoblin/templates/mediagoblin/auth/login.html:48 msgid "Forgot your password?" -msgstr "" +msgstr "Ĉu vi forgesis vian pasvorton?" #: mediagoblin/templates/mediagoblin/auth/login.html:51 msgid "Change it!" -msgstr "" +msgstr "Ŝanĝu ĝin!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index 7c7dea0d..2e64b814 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 85da5dbe..083a87a5 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -82,6 +82,9 @@ msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +"No se pudo enviar un correo electrónico de recuperación de contraseñas " +"porque su nombre de usuario está inactivo o la dirección de su cuenta de " +"correo electrónico no ha sido verificada." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" @@ -197,10 +200,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Potenciado por MediaGoblin, a GNU project" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -253,42 +258,35 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:38 msgid "Excited to join us?" -msgstr "" +msgstr "Te emociona trabajar con nosotros?" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 msgid "Most recent media" -msgstr "" +msgstr "El contenido más reciente" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 msgid "Enter your new password" -msgstr "" +msgstr "Ingrese su nueva contraseña" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Enter your username or email" -msgstr "" +msgstr "Introduzca su nombre de usuario o correo electrónico" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 @@ -304,6 +302,10 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Hola %(username)s , para cambiar su contraseña de GNU MediaGoblin, abra lal " +"siguiente URL en su navegador: %(verification_url)s Si usted piensa que " +"esto es un error, simplemente ignore este mensaje y siga siendo un duende " +"feliz!" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" @@ -319,11 +321,11 @@ msgstr "¡Crea una aquí!" #: mediagoblin/templates/mediagoblin/auth/login.html:48 msgid "Forgot your password?" -msgstr "" +msgstr "¿Olvidaste tu contraseña?" #: mediagoblin/templates/mediagoblin/auth/login.html:51 msgid "Change it!" -msgstr "" +msgstr "Cambiarlo!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index baab45ab..5b3adb77 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 032399d6..a9b9f160 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -263,11 +263,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -283,17 +281,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..9a010192 Binary files /dev/null and b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..67db7ca2 --- /dev/null +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,520 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# , 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" +"Last-Translator: cwebber \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +msgid "Username" +msgstr "Nome utente" + +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +msgid "Password" +msgstr "Password" + +#: mediagoblin/auth/forms.py:35 +msgid "Passwords must match." +msgstr "Le password devono coincidere" + +#: mediagoblin/auth/forms.py:37 +msgid "Confirm password" +msgstr "Conferma password" + +#: mediagoblin/auth/forms.py:39 +msgid "Type it again here to make sure there are no spelling mistakes." +msgstr "Scrivilo ancora qui per assicurarti che non ci siano errori" + +#: mediagoblin/auth/forms.py:42 +msgid "Email address" +msgstr "Indirizzo email" + +#: mediagoblin/auth/views.py:42 +msgid "Sorry, registration is disabled on this instance." +msgstr "Spiacente, registrazione è disabilitata su questa istanza" + +#: mediagoblin/auth/views.py:60 +msgid "Sorry, a user with that name already exists." +msgstr "Spiacente, esiste già un utente con quel nome" + +#: mediagoblin/auth/views.py:64 +msgid "Sorry, that email address has already been taken." +msgstr "Spiacente, quell'indirizzo email è già stato preso." + +#: mediagoblin/auth/views.py:165 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" +"Il tuo indirizzo email è stato verificato. Puoi ora fare login, modificare " +"il tuo profilo, e inserire immagini!" + +#: mediagoblin/auth/views.py:171 +msgid "The verification key or user id is incorrect" +msgstr "La chiave di verifica o l'id utente è sbagliato" + +#: mediagoblin/auth/views.py:192 +msgid "Resent your verification email." +msgstr "Rispedisci email di verifica" + +#: mediagoblin/auth/views.py:228 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + +#: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "Titolo" + +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "Tags" + +#: mediagoblin/edit/forms.py:33 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:34 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:35 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" + +#: mediagoblin/edit/forms.py:42 +msgid "Bio" +msgstr "Bio" + +#: mediagoblin/edit/forms.py:45 +msgid "Website" +msgstr "Sito web" + +#: mediagoblin/edit/views.py:63 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:84 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" +"Stai modificando documenti multimediale di un altro utente. Procedi con " +"attenzione." + +#: mediagoblin/edit/views.py:154 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "Stai modificando il profilo di un utente. Procedi con attenzione." + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "documento non valido come tipo multimediale." + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "Documento" + +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Descrizione di questo lavoro" + +#: mediagoblin/submit/views.py:47 +msgid "You must provide a file." +msgstr "Devi specificare un documento." + +#: mediagoblin/submit/views.py:50 +msgid "The file doesn't seem to be an image!" +msgstr "Il documento non sembra essere un'immagine!" + +#: mediagoblin/submit/views.py:122 +msgid "Woohoo! Submitted!" +msgstr "Evviva! " + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "Oops!" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "Non sembra esserci una pagina a questo indirizzo. Spiacente!" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" +"Se sei sicuro che l'indirizzo è corretto, forse la pagina che stai cercando " +"è stata spostata o cancellata." + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "Immagine di 404 folletti che stressano" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "GNU MediaGoblin" + +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "MediaGoblin logo" + +#: mediagoblin/templates/mediagoblin/base.html:52 +msgid "Submit media" +msgstr "Inoltra file multimediale" + +#: mediagoblin/templates/mediagoblin/base.html:63 +msgid "verify your email!" +msgstr "verifica il tuo indirizzo email!" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:26 +#: mediagoblin/templates/mediagoblin/auth/login.html:34 +msgid "Log in" +msgstr "Accedi" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "" +"Powered by MediaGoblin, a GNU project" +msgstr "" +"Powered by MediaGoblin, un progetto " +"GNU" + +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "Esplora" + +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "Ciao, amante del multimedia! MediaGoblin è..." + +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "Il posto perfetto per i tuoi documenti multimediali!" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" +"Un posto per collaborare con altri e mostrare le proprie creazioni originali" +" e derivate!" + +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" +"Libero, come in libertà. (Siamo un progetto GNU, dopotutto.)" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" +"Con l'obbiettivo di rendere il mondo un posto migliore attraverso la " +"decentrelizzazione e (finalmente, presto!) federazione!" + +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" +"Fatto per estensibilità. (Numerosi tipi multimediali saranno presto aggiunti" +" al programma, incluso il supporto video!)" + +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "Eccitato di unirti a noi?" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "Documenti multimediali più recenti" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 +msgid "Enter your new password" +msgstr "Inserisci la tua nuova password" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Enter your username or email" +msgstr "Inserisci il tuo nome utente o email" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "Your password has been changed. Try to log in now." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"Check your inbox. We sent an email with a URL for changing your password." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:29 +msgid "Logging in failed!" +msgstr "Accesso fallito!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:42 +msgid "Don't have an account yet?" +msgstr "Non hai ancora un account?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:45 +msgid "Create one here!" +msgstr "Creane uno qui!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:48 +msgid "Forgot your password?" +msgstr "Hai dimenticato la password?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:51 +msgid "Change it!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "Crea un account!" + +#: mediagoblin/templates/mediagoblin/auth/register.html:30 +msgid "Create" +msgstr "Crea" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "" +"Ciao %(username)s,\n" +"\n" +"per attivare il tuo account GNU MediaGoblin, apri il seguente URL nel tuo navigatore web.\n" +"\n" +"%(verification_url)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "Stai modificando %(media_title)s" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 +msgid "Cancel" +msgstr "Annulla" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +msgid "Save changes" +msgstr "Salva i cambiamenti" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "Stai modificando il profilo di %(username)s" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "Media taggata con:" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "Inoltra documento multimediale" + +#: mediagoblin/templates/mediagoblin/submit/start.html:29 +msgid "Submit" +msgstr "Conferma" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "%(username)s's media" +msgstr "Documenti multimediali di %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "Mi dispiace, utente non trovato" + +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 +#, python-format +msgid "Really delete %(title)s?" +msgstr "Vuoi davvero cancellare %(title)s?" + +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" +msgstr "Cancella permanentemente" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "Pannello di elaborazione media" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "Puoi seguire lo stato dell'elaborazione per la tua galleria qui." + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "Media in elaborazione" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "Nessun documento multimediale in elaborazione" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "L'elaborazione di questi upload è fallita:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "è necessario verificare email" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "Quasi finito! Il tuo account deve ancora essere attivato." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" +"In breve dovresti ricevere un email contenente istruzioni su come fare." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "Nel caso non fosse:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "Rispedisci email di verifica" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" +"Qualcuno ha registrato un account con questo nome utente, ma deve ancora " +"essere attivato." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can log in and resend it." +msgstr "" +"Se sei quella persona ma hai perso l'email di verifica, puoi accedere e rispedirlo." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "profilo di %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "Ecco un posto dove raccontare agli altri di te." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +msgid "Edit profile" +msgstr "Modifica profilo" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "Questo utente non ha (ancora) compilato il proprio profilo." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#, python-format +msgid "View all of %(username)s's media" +msgstr "Visualizza tutti i file multimediali di %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" +"Questo è dove i tuoi documenti multimediali appariranno, ma sembra che tu " +"non abbia ancora aggiunto niente." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "Aggiungi documenti multimediali" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "Non sembra ci sia ancora nessun documento multimediali qui.." + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "feed icon" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "Atom feed" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "Più nuovo" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "Più vecchio" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "Commento" + +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "Sono sicuro di volerlo cancellare" + +#: mediagoblin/user_pages/views.py:175 +msgid "You are about to delete another user's media. Proceed with caution." +msgstr "" +"Stai cancellando un documento multimediale di un altro utente. Procedi con " +"attenzione." + + diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index efd3e3f4..4bdc4d5a 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 79be3177..ebc8ad52 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -236,11 +236,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -256,17 +254,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index 261e5e95..57447395 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index b9e0896d..c982eb95 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -241,11 +241,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -261,17 +259,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index 9e4cf80f..7bf5a87a 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index cc0e495a..4e1c382b 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -246,11 +246,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -266,17 +264,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 686989fc..189733f6 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 02054003..6d0195fe 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -238,11 +238,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -258,17 +256,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 994d6f30..f43e25f6 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 967f7dbb..2d2ce467 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -45,7 +45,7 @@ msgstr "Adresa de e-mail" #: mediagoblin/auth/views.py:42 msgid "Sorry, registration is disabled on this instance." -msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe această instanță." +msgstr "Ne pare rău, dar înscrierile sunt dezactivate pe acest server." #: mediagoblin/auth/views.py:60 msgid "Sorry, a user with that name already exists." @@ -76,6 +76,8 @@ msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +"E-mailul pentru recuperarea parolei nu a putut fi trimis deoarece contul tău" +" e inactiv sau adresa ta de e-mail nu a fost confirmată." #: mediagoblin/edit/forms.py:26 mediagoblin/submit/forms.py:27 msgid "Title" @@ -197,7 +199,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Explorează" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -250,42 +252,35 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:38 msgid "Excited to join us?" -msgstr "" +msgstr "Vrei să ni te alături?" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 msgid "Most recent media" -msgstr "" +msgstr "Cele mai recente fișiere" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 msgid "Enter your new password" -msgstr "" +msgstr "Introdu noua parolă" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Enter your username or email" -msgstr "" +msgstr "Introdu numele de utilizator sau adresa de e-mail" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 @@ -301,6 +296,13 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Bună, %(username)s\n" +"\n" +"Pentru a modifica parola ta la GNU MediaGoblin, accesează adresa următoare:\n" +"\n" +"%(verification_url)s\n" +"\n" +"Dacă ai primit acest mesaj din greșeală, ignoră-l și fii mai departe un elf fericit!" #: mediagoblin/templates/mediagoblin/auth/login.html:29 msgid "Logging in failed!" @@ -316,11 +318,11 @@ msgstr "Creează-l aici!" #: mediagoblin/templates/mediagoblin/auth/login.html:48 msgid "Forgot your password?" -msgstr "" +msgstr "Ai uitat parola?" #: mediagoblin/templates/mediagoblin/auth/login.html:51 msgid "Change it!" -msgstr "" +msgstr "Schimb-o!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" @@ -342,7 +344,7 @@ msgid "" msgstr "" "Bună, %(username)s,\n" "\n" -"pentru activarea contului tău GNU MediaGoblin, accesează adresa următoare:\n" +"pentru activarea contului tău la GNU MediaGoblin, accesează adresa următoare:\n" "\n" "%(verification_url)s" @@ -421,7 +423,7 @@ msgstr "Aceste fișiere nu au putut fi procesate:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 msgid "Email verification needed" -msgstr "Este necesară verificarea adresei de e-mail" +msgstr "Este necesară confirmarea adresei de e-mail" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." @@ -478,7 +480,7 @@ msgstr "Acest utilizator nu și-a completat (încă) profilul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format msgid "View all of %(username)s's media" -msgstr "Toate fișierele media ale lui %(username)s" +msgstr "Vezi toate fișierele media ale lui %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:135 msgid "" diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 2b698e4d..c1eab2ba 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 865f5424..ffdeab2e 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -37,7 +37,7 @@ msgstr "Подтвердите пароль" #: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Type it again here to make sure there are no spelling mistakes." +msgstr "Наберите его ещё раз здесь, чтобы избежать опечаток." #: mediagoblin/auth/forms.py:42 msgid "Email address" @@ -53,7 +53,7 @@ msgstr "Извините, пользователь с этим именем уж #: mediagoblin/auth/views.py:64 msgid "Sorry, that email address has already been taken." -msgstr "Извините, этот адрес электнонной почты уже занят." +msgstr "Извините, этот адрес электронной почты уже занят." #: mediagoblin/auth/views.py:165 msgid "" @@ -197,7 +197,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Привет, любитель мультимедиа! MediaGoblin это…" +msgstr "Привет, любитель мультимедиа! MediaGoblin…" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "The perfect place for your media!" @@ -230,8 +230,8 @@ msgid "" "Built for extensibility. (Multiple media types coming soon to the software," " including video support!)" msgstr "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"Рассчитан на расширяемость. (В программе скоро должна появиться поддержка " +"других видов мультимедиа, таких как видео!)" #: mediagoblin/templates/mediagoblin/root.html:34 msgid "" @@ -250,37 +250,30 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 msgid "Most recent media" -msgstr "" +msgstr "Самые новые файлы" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:27 msgid "Enter your new password" -msgstr "" +msgstr "Введите свой новый пароль" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Enter your username or email" -msgstr "" +msgstr "Введите Ваше имя пользователя или адрес электронной почты" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 @@ -311,11 +304,11 @@ msgstr "Создайте здесь!" #: mediagoblin/templates/mediagoblin/auth/login.html:48 msgid "Forgot your password?" -msgstr "" +msgstr "Забыли свой пароль?" #: mediagoblin/templates/mediagoblin/auth/login.html:51 msgid "Change it!" -msgstr "" +msgstr "Смените его!" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" @@ -376,7 +369,7 @@ msgstr "Подтвердить" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 #, python-format msgid "%(username)s's media" -msgstr "Файлы пользователя <a href=\"%(user_url)s\">%(username)s</a>" +msgstr "Файлы пользователя %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 #: mediagoblin/templates/mediagoblin/user_pages/user.html:32 @@ -436,7 +429,7 @@ msgstr "А если нет, то:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:54 msgid "Resend verification email" -msgstr "Повторно отправить подверждение на адрес электнонной почты" +msgstr "Повторно отправить подверждение на адрес электронной почты" #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "" @@ -516,6 +509,6 @@ msgstr "Я уверен, что хочу удалить это" #: mediagoblin/user_pages/views.py:175 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "" +msgstr "Вы на пороге удаления файла другого пользователя. Будьте осторожны." diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index d1ce44b2..4c433381 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index 17ffeec0..39c6b9a5 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -249,11 +249,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -269,17 +267,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index d09aea44..3c5d864b 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index da928da6..8f2373c8 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -235,11 +235,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -255,17 +253,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index 5f8ac655..2cdf2fee 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index f38166a5..08a4bc15 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -256,11 +256,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -276,17 +274,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index e0117391..adc3548e 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 9e4380c2..1d86f1f9 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-09-11 16:16-0500\n" -"PO-Revision-Date: 2011-09-11 21:16+0000\n" +"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"PO-Revision-Date: 2011-09-26 01:25+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -241,11 +241,9 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"\n" -" Create a free account\n" +"Create a free account\n" " or\n" -" Set up MediaGoblin on your own server\n" -" " +" Set up MediaGoblin on your own server" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:53 @@ -261,17 +259,12 @@ msgid "Enter your username or email" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "" -"\n" -" Your password has been changed. Try to log in now.\n" -" " +msgid "Your password has been changed. Try to log in now." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" -"\n" -" Check your inbox. We sent an email with a URL for changing your password.\n" -" " +"Check your inbox. We sent an email with a URL for changing your password." msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 -- cgit v1.2.3 From 81291bbb896d04fee66b9482f479b3fc6e6e07f5 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 28 Sep 2011 21:00:33 +0200 Subject: Added arista to install requires --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 06626926..7417fb97 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ setup( 'ConfigObj', 'Markdown', 'python-cloudfiles', + 'arista', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', -- cgit v1.2.3 From 62be795e9141f951a92d5c44a974db9875df197d Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 29 Sep 2011 00:57:07 +0200 Subject: Renamed video.presets => video.devices --- .../media_types/video/devices/web-advanced.json | 505 +++++++++++ mediagoblin/media_types/video/devices/web-flv.png | Bin 0 -> 2234 bytes mediagoblin/media_types/video/devices/web-webm.svg | 259 ++++++ mediagoblin/media_types/video/devices/web.svg | 982 +++++++++++++++++++++ .../media_types/video/presets/web-advanced.json | 505 ----------- mediagoblin/media_types/video/presets/web-flv.png | Bin 2234 -> 0 bytes mediagoblin/media_types/video/presets/web-webm.svg | 259 ------ mediagoblin/media_types/video/presets/web.svg | 982 --------------------- 8 files changed, 1746 insertions(+), 1746 deletions(-) create mode 100644 mediagoblin/media_types/video/devices/web-advanced.json create mode 100644 mediagoblin/media_types/video/devices/web-flv.png create mode 100644 mediagoblin/media_types/video/devices/web-webm.svg create mode 100644 mediagoblin/media_types/video/devices/web.svg delete mode 100644 mediagoblin/media_types/video/presets/web-advanced.json delete mode 100644 mediagoblin/media_types/video/presets/web-flv.png delete mode 100644 mediagoblin/media_types/video/presets/web-webm.svg delete mode 100644 mediagoblin/media_types/video/presets/web.svg diff --git a/mediagoblin/media_types/video/devices/web-advanced.json b/mediagoblin/media_types/video/devices/web-advanced.json new file mode 100644 index 00000000..ce1d22ff --- /dev/null +++ b/mediagoblin/media_types/video/devices/web-advanced.json @@ -0,0 +1,505 @@ +{ + "make": "Generic", + "model": "Web Browser (Advanced)", + "description": "Media for World Wide Web", + "version": "0.1", + "author": { + "name": "Dionisio E Alonso", + "email": "dealonso@gmail.com" + }, + "icon": "file://web.svg", + "default": "WebM 480p", + "presets": [ + { + "name": "H.264 720p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 720p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 720p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 576p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 576p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 576p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 480p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 480p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 480p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 360p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 360p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 360p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + } + ] +} diff --git a/mediagoblin/media_types/video/devices/web-flv.png b/mediagoblin/media_types/video/devices/web-flv.png new file mode 100644 index 00000000..b75699f4 Binary files /dev/null and b/mediagoblin/media_types/video/devices/web-flv.png differ diff --git a/mediagoblin/media_types/video/devices/web-webm.svg b/mediagoblin/media_types/video/devices/web-webm.svg new file mode 100644 index 00000000..4e5b3e97 --- /dev/null +++ b/mediagoblin/media_types/video/devices/web-webm.svg @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/devices/web.svg b/mediagoblin/media_types/video/devices/web.svg new file mode 100644 index 00000000..c0c68244 --- /dev/null +++ b/mediagoblin/media_types/video/devices/web.svg @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Globe + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + globe + international + web + www + internet + network + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/presets/web-advanced.json b/mediagoblin/media_types/video/presets/web-advanced.json deleted file mode 100644 index ce1d22ff..00000000 --- a/mediagoblin/media_types/video/presets/web-advanced.json +++ /dev/null @@ -1,505 +0,0 @@ -{ - "make": "Generic", - "model": "Web Browser (Advanced)", - "description": "Media for World Wide Web", - "version": "0.1", - "author": { - "name": "Dionisio E Alonso", - "email": "dealonso@gmail.com" - }, - "icon": "file://web.svg", - "default": "WebM 480p", - "presets": [ - { - "name": "H.264 720p", - "extension": "mp4", - "container": "qtmux", - "vcodec": { - "name": "x264enc", - "container": "qtmux", - "width": [ - 960, 1280 - ], - "height": [ - 720, 720 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "qtmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - { - "name": "WebM 720p", - "extension": "webm", - "container": "webmmux", - "icon": "file://web-webm.svg", - "vcodec": { - "name": "vp8enc", - "container": "webmmux", - "width": [ - 960, 1280 - ], - "height": [ - 720, 720 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "quality=5.75 threads=%(threads)s speed=2" - ] - }, - "acodec": { - "name": "vorbisenc", - "container": "webmmux", - "width": [ - 8, 32 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "quality=0.3" - ] - } - }, - { - "name": "Flash Video 720p", - "extension": "flv", - "icon": "file://web-flv.png", - "container": "flvmux", - "vcodec": { - "name": "x264enc", - "container": "flvmux", - "width": [ - 960, 1280 - ], - "height": [ - 720, 720 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "flvmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - - { - "name": "H.264 576p", - "extension": "mp4", - "container": "qtmux", - "vcodec": { - "name": "x264enc", - "container": "qtmux", - "width": [ - 768, 1024 - ], - "height": [ - 576, 576 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "qtmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - { - "name": "WebM 576p", - "extension": "webm", - "container": "webmmux", - "icon": "file://web-webm.svg", - "vcodec": { - "name": "vp8enc", - "container": "webmmux", - "width": [ - 768, 1024 - ], - "height": [ - 576, 576 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "quality=5.75 threads=%(threads)s speed=2" - ] - }, - "acodec": { - "name": "vorbisenc", - "container": "webmmux", - "width": [ - 8, 32 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "quality=0.3" - ] - } - }, - { - "name": "Flash Video 576p", - "extension": "flv", - "icon": "file://web-flv.png", - "container": "flvmux", - "vcodec": { - "name": "x264enc", - "container": "flvmux", - "width": [ - 768, 1024 - ], - "height": [ - 576, 576 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "flvmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - - { - "name": "H.264 480p", - "extension": "mp4", - "container": "qtmux", - "vcodec": { - "name": "x264enc", - "container": "qtmux", - "width": [ - 640, 854 - ], - "height": [ - 480, 480 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "qtmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - { - "name": "WebM 480p", - "extension": "webm", - "container": "webmmux", - "icon": "file://web-webm.svg", - "vcodec": { - "name": "vp8enc", - "container": "webmmux", - "width": [ - 640, 854 - ], - "height": [ - 480, 480 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "quality=5.75 threads=%(threads)s speed=2" - ] - }, - "acodec": { - "name": "vorbisenc", - "container": "webmmux", - "width": [ - 8, 32 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "quality=0.3" - ] - } - }, - { - "name": "Flash Video 480p", - "extension": "flv", - "icon": "file://web-flv.png", - "container": "flvmux", - "vcodec": { - "name": "x264enc", - "container": "flvmux", - "width": [ - 640, 854 - ], - "height": [ - 480, 480 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "flvmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - - { - "name": "H.264 360p", - "extension": "mp4", - "container": "qtmux", - "vcodec": { - "name": "x264enc", - "container": "qtmux", - "width": [ - 480, 640 - ], - "height": [ - 360, 360 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "qtmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - }, - { - "name": "WebM 360p", - "extension": "webm", - "container": "webmmux", - "icon": "file://web-webm.svg", - "vcodec": { - "name": "vp8enc", - "container": "webmmux", - "width": [ - 480, 640 - ], - "height": [ - 360, 360 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "quality=5.75 threads=%(threads)s speed=2" - ] - }, - "acodec": { - "name": "vorbisenc", - "container": "webmmux", - "width": [ - 8, 32 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "quality=0.3" - ] - } - }, - { - "name": "Flash Video 360p", - "extension": "flv", - "icon": "file://web-flv.png", - "container": "flvmux", - "vcodec": { - "name": "x264enc", - "container": "flvmux", - "width": [ - 480, 640 - ], - "height": [ - 360, 360 - ], - "rate": [ - 1, 30 - ], - "passes": [ - "pass=qual quantizer=23 subme=6 cabac=0 threads=0" - ] - }, - "acodec": { - "name": "faac", - "container": "flvmux", - "width": [ - 8, 24 - ], - "depth": [ - 8, 24 - ], - "rate": [ - 8000, 96000 - ], - "channels": [ - 1, 2 - ], - "passes": [ - "bitrate=131072 profile=LC" - ] - } - } - ] -} diff --git a/mediagoblin/media_types/video/presets/web-flv.png b/mediagoblin/media_types/video/presets/web-flv.png deleted file mode 100644 index b75699f4..00000000 Binary files a/mediagoblin/media_types/video/presets/web-flv.png and /dev/null differ diff --git a/mediagoblin/media_types/video/presets/web-webm.svg b/mediagoblin/media_types/video/presets/web-webm.svg deleted file mode 100644 index 4e5b3e97..00000000 --- a/mediagoblin/media_types/video/presets/web-webm.svg +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/mediagoblin/media_types/video/presets/web.svg b/mediagoblin/media_types/video/presets/web.svg deleted file mode 100644 index c0c68244..00000000 --- a/mediagoblin/media_types/video/presets/web.svg +++ /dev/null @@ -1,982 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Globe - - - Jakub Steiner - - - - - Tuomas Kuosmanen - - - - http://jimmac.musichall.cz - - - globe - international - web - www - internet - network - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From 6347605c1e57e2f428b682740048c68cb54837c2 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 29 Sep 2011 20:15:53 +0200 Subject: When using paste's static content server to serve media entries and other files the client should have some idea on how long it can cache those files locally before asking again for them. The old setting was: Don't allow the client to cache. New setting: 1 week for the media entries (they don't change, ever) 1 day for css/logos, etc. They change on an update, so people might want to see the new design soon. --- paste.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/paste.ini b/paste.ini index fc459989..7eee528b 100644 --- a/paste.ini +++ b/paste.ini @@ -19,10 +19,12 @@ config = %(here)s/mediagoblin.ini [app:publicstore_serve] use = egg:Paste#static document_root = %(here)s/user_dev/media/public/ +cache_max_age = 604800 [app:mediagoblin_static] use = egg:Paste#static document_root = %(here)s/mediagoblin/static/ +cache_max_age = 86400 [filter:beaker] use = egg:Beaker#beaker_session -- cgit v1.2.3 From bf33272f03a28c86b91750fed354b75062f516e6 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 30 Sep 2011 22:27:47 +0200 Subject: Give debug message in email debug mode If the server is running in email debug mode (current default), users have often asked where the mail is. So tell them in the web browser that their mail is on the console. --- mediagoblin/auth/views.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index f67f0588..b6f38fec 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -30,6 +30,19 @@ from mediagoblin.auth.lib import send_verification_email, \ send_fp_verification_email +def email_debug_message(request): + """ + If the server is running in email debug mode (which is + the current default), give a debug message to the user + so that they have an idea where to find their email. + """ + if mg_globals.app_config['email_debug_mode']: + # DEBUG message, no need to translate + messages.add_message(request, messages.DEBUG, + u"This instance is running in email debug mode. " + u"The email will be on the console of the server process.") + + def register(request): """ Your classic registration view! @@ -78,6 +91,7 @@ def register(request): request.session.save() # send verification email + email_debug_message(request) send_verification_email(user, request) # redirect the user to their homepage... there will be a @@ -184,6 +198,7 @@ def resend_activation(request): request.user[u'verification_key'] = unicode(uuid.uuid4()) request.user.save() + email_debug_message(request) send_verification_email(request.user, request) messages.add_message( @@ -204,6 +219,11 @@ def forgot_password(request): fp_form = auth_forms.ForgotPassForm(request.POST) if request.method == 'POST' and fp_form.validate(): + + # Here, so it doesn't depend on the actual mail being sent + # and thus doesn't reveal, wether mail was sent. + email_debug_message(request) + # '$or' not available till mongodb 1.5.3 user = request.db.User.find_one( {'username': request.POST['username']}) -- cgit v1.2.3 From ae3bc7fabf8e0abb5f3d8b6534ca451890bbe90b Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Sat, 1 Oct 2011 09:31:42 -0400 Subject: Moved common, translation, template, and url code out of util.py and into tools/[file].py --- mediagoblin/app.py | 5 +- mediagoblin/auth/forms.py | 2 +- mediagoblin/auth/lib.py | 3 +- mediagoblin/auth/views.py | 2 +- mediagoblin/db/models.py | 4 +- mediagoblin/process_media/errors.py | 2 +- mediagoblin/submit/forms.py | 2 +- mediagoblin/submit/views.py | 2 +- mediagoblin/tests/test_auth.py | 106 +++++----- mediagoblin/tests/test_messages.py | 4 +- mediagoblin/tests/test_submission.py | 42 ++-- mediagoblin/tests/test_util.py | 36 ++-- mediagoblin/tools/__init__.py | 0 mediagoblin/tools/common.py | 18 ++ mediagoblin/tools/template.py | 114 ++++++++++ mediagoblin/tools/translate.py | 167 +++++++++++++++ mediagoblin/tools/url.py | 31 +++ mediagoblin/user_pages/forms.py | 2 +- mediagoblin/user_pages/views.py | 2 +- mediagoblin/util.py | 395 ++++++++++++++++++----------------- 20 files changed, 636 insertions(+), 303 deletions(-) create mode 100644 mediagoblin/tools/__init__.py create mode 100644 mediagoblin/tools/common.py create mode 100644 mediagoblin/tools/template.py create mode 100644 mediagoblin/tools/translate.py create mode 100644 mediagoblin/tools/url.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index dd5f0b89..5ee3b973 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -21,6 +21,7 @@ import routes from webob import Request, exc from mediagoblin import routing, util, middleware +from mediagoblin.tools import translate, template from mediagoblin.mg_globals import setup_globals from mediagoblin.init.celery import setup_celery_from_config from mediagoblin.init import (get_jinja_loader, get_staticdirector, @@ -123,9 +124,9 @@ class MediaGoblinApp(object): # Attach self as request.app # Also attach a few utilities from request.app for convenience? request.app = self - request.locale = util.get_locale_from_request(request) + request.locale = translate.get_locale_from_request(request) - request.template_env = util.get_jinja_env( + request.template_env = template.get_jinja_env( self.template_loader, request.locale) request.db = self.db request.staticdirect = self.staticdirector diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 6339b4a3..a932ad26 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -17,7 +17,7 @@ import wtforms import re -from mediagoblin.util import fake_ugettext_passthrough as _ +from mediagoblin.tools.translate import fake_ugettext_passthrough as _ class RegistrationForm(wtforms.Form): diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index d7d351a5..bf5a2399 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -19,7 +19,8 @@ import random import bcrypt -from mediagoblin.util import send_email, render_template +from mediagoblin.util import send_email +from mediagoblin.tools.template import render_template from mediagoblin import mg_globals diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index f67f0588..9bfa93cf 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -22,7 +22,7 @@ from webob import exc from mediagoblin import messages from mediagoblin import mg_globals from mediagoblin.util import render_to_response, redirect, render_404 -from mediagoblin.util import pass_to_ugettext as _ +from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.db.util import ObjectId, InvalidId from mediagoblin.auth import lib as auth_lib from mediagoblin.auth import forms as auth_forms diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index bbddada6..eacc801c 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -25,7 +25,7 @@ from mediagoblin.db import migrations from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.util import Pagination from mediagoblin.util import DISPLAY_IMAGE_FETCHING_ORDER - +from mediagoblin.tools import url ################### # Custom validators @@ -242,7 +242,7 @@ class MediaEntry(Document): pass def generate_slug(self): - self['slug'] = util.slugify(self['title']) + self['slug'] = url.slugify(self['title']) duplicate = mg_globals.database.media_entries.find_one( {'slug': self['slug']}) diff --git a/mediagoblin/process_media/errors.py b/mediagoblin/process_media/errors.py index 156f0a01..8003ffaf 100644 --- a/mediagoblin/process_media/errors.py +++ b/mediagoblin/process_media/errors.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.util import lazy_pass_to_ugettext as _ +from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ class BaseProcessingFail(Exception): """ diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index a999c714..200ce4e4 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -18,7 +18,7 @@ import wtforms from mediagoblin.util import tag_length_validator -from mediagoblin.util import fake_ugettext_passthrough as _ +from mediagoblin.tools.translate import fake_ugettext_passthrough as _ class SubmitStartForm(wtforms.Form): diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index e24d78f3..cd34e006 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -25,7 +25,7 @@ from mediagoblin.db.util import ObjectId from mediagoblin.util import ( render_to_response, redirect, cleaned_markdown_conversion, \ convert_to_tag_list_of_dicts) -from mediagoblin.util import pass_to_ugettext as _ +from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.process_media import process_media, mark_entry_failed diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index fbbe1613..f00456c4 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -22,7 +22,7 @@ from nose.tools import assert_equal from mediagoblin.auth import lib as auth_lib from mediagoblin.tests.tools import setup_fresh_app from mediagoblin import mg_globals -from mediagoblin import util +from mediagoblin.tools import template ######################## @@ -76,16 +76,16 @@ def test_register_views(test_app): test_app.get('/auth/register/') # Make sure it rendered with the appropriate template - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/auth/register.html') # Try to register without providing anything, should error # -------------------------------------------------------- - util.clear_test_template_context() + template.clear_test_template_context() test_app.post( '/auth/register/', {}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] form = context['register_form'] assert form.username.errors == [u'This field is required.'] assert form.password.errors == [u'This field is required.'] @@ -96,14 +96,14 @@ def test_register_views(test_app): # -------------------------------------------------------- ## too short - util.clear_test_template_context() + template.clear_test_template_context() test_app.post( '/auth/register/', { 'username': 'l', 'password': 'o', 'confirm_password': 'o', 'email': 'l'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] form = context['register_form'] assert form.username.errors == [ @@ -112,12 +112,12 @@ def test_register_views(test_app): u'Field must be between 6 and 30 characters long.'] ## bad form - util.clear_test_template_context() + template.clear_test_template_context() test_app.post( '/auth/register/', { 'username': '@_@', 'email': 'lollerskates'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] form = context['register_form'] assert form.username.errors == [ @@ -126,12 +126,12 @@ def test_register_views(test_app): u'Invalid email address.'] ## mismatching passwords - util.clear_test_template_context() + template.clear_test_template_context() test_app.post( '/auth/register/', { 'password': 'herpderp', 'confirm_password': 'derpherp'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] form = context['register_form'] assert form.password.errors == [ @@ -142,7 +142,7 @@ def test_register_views(test_app): # Successful register # ------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/register/', { 'username': 'happygirl', @@ -155,7 +155,7 @@ def test_register_views(test_app): assert_equal( urlparse.urlsplit(response.location)[2], '/u/happygirl/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/user_pages/user.html') ## Make sure user is in place @@ -166,15 +166,15 @@ def test_register_views(test_app): assert new_user['email_verified'] == False ## Make sure user is logged in - request = util.TEMPLATE_TEST_CONTEXT[ + request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] assert request.session['user_id'] == unicode(new_user['_id']) ## Make sure we get email confirmation, and try verifying - assert len(util.EMAIL_TEST_INBOX) == 1 - message = util.EMAIL_TEST_INBOX.pop() + assert len(template.EMAIL_TEST_INBOX) == 1 + message = template.EMAIL_TEST_INBOX.pop() assert message['To'] == 'happygrrl@example.org' - email_context = util.TEMPLATE_TEST_CONTEXT[ + email_context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/auth/verification_email.txt'] assert email_context['verification_url'] in message.get_payload(decode=True) @@ -190,12 +190,12 @@ def test_register_views(test_app): new_user['verification_key']] ## Try verifying with bs verification key, shouldn't work - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.get( "/auth/verify_email/?userid=%s&token=total_bs" % unicode( new_user['_id'])) response.follow() - context = util.TEMPLATE_TEST_CONTEXT[ + context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html'] # assert context['verification_successful'] == True # TODO: Would be good to test messages here when we can do so... @@ -206,10 +206,10 @@ def test_register_views(test_app): assert new_user['email_verified'] == False ## Verify the email activation works - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.get("%s?%s" % (path, get_params)) response.follow() - context = util.TEMPLATE_TEST_CONTEXT[ + context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html'] # assert context['verification_successful'] == True # TODO: Would be good to test messages here when we can do so... @@ -222,7 +222,7 @@ def test_register_views(test_app): # Uniqueness checks # ----------------- ## We shouldn't be able to register with that user twice - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/register/', { 'username': 'happygirl', @@ -230,7 +230,7 @@ def test_register_views(test_app): 'confirm_password': 'iamsohappy2', 'email': 'happygrrl2@example.org'}) - context = util.TEMPLATE_TEST_CONTEXT[ + context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/auth/register.html'] form = context['register_form'] assert form.username.errors == [ @@ -240,7 +240,7 @@ def test_register_views(test_app): ### Oops, forgot the password # ------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/forgot_password/', {'username': 'happygirl'}) @@ -250,14 +250,14 @@ def test_register_views(test_app): assert_equal( urlparse.urlsplit(response.location)[2], '/auth/forgot_password/email_sent/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/auth/fp_email_sent.html') ## Make sure link to change password is sent by email - assert len(util.EMAIL_TEST_INBOX) == 1 - message = util.EMAIL_TEST_INBOX.pop() + assert len(template.EMAIL_TEST_INBOX) == 1 + message = template.EMAIL_TEST_INBOX.pop() assert message['To'] == 'happygrrl@example.org' - email_context = util.TEMPLATE_TEST_CONTEXT[ + email_context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/auth/fp_verification_email.txt'] #TODO - change the name of verification_url to something forgot-password-ish assert email_context['verification_url'] in message.get_payload(decode=True) @@ -277,14 +277,14 @@ def test_register_views(test_app): assert (new_user['fp_token_expire'] - datetime.datetime.now()).days == 9 ## Try using a bs password-changing verification key, shouldn't work - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.get( "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( new_user['_id']), status=400) assert response.status == '400 Bad Request' ## Try using an expired token to change password, shouldn't work - util.clear_test_template_context() + template.clear_test_template_context() real_token_expiration = new_user['fp_token_expire'] new_user['fp_token_expire'] = datetime.datetime.now() new_user.save() @@ -294,12 +294,12 @@ def test_register_views(test_app): new_user.save() ## Verify step 1 of password-change works -- can see form to change password - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.get("%s?%s" % (path, get_params)) - assert util.TEMPLATE_TEST_CONTEXT.has_key('mediagoblin/auth/change_fp.html') + assert template.TEMPLATE_TEST_CONTEXT.has_key('mediagoblin/auth/change_fp.html') ## Verify step 2.1 of password-change works -- report success to user - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/forgot_password/verify/', { 'userid': parsed_get_params['userid'], @@ -307,11 +307,11 @@ def test_register_views(test_app): 'confirm_password': 'iamveryveryhappy', 'token': parsed_get_params['token']}) response.follow() - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/auth/fp_changed_success.html') ## Verify step 2.2 of password-change works -- login w/ new password success - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'happygirl', @@ -322,7 +322,7 @@ def test_register_views(test_app): assert_equal( urlparse.urlsplit(response.location)[2], '/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/root.html') @@ -341,61 +341,61 @@ def test_authentication_views(test_app): # Get login # --------- test_app.get('/auth/login/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/auth/login.html') # Failed login - blank form # ------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post('/auth/login/') - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] form = context['login_form'] assert form.username.errors == [u'This field is required.'] assert form.password.errors == [u'This field is required.'] # Failed login - blank user # ------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'password': u'toast'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] form = context['login_form'] assert form.username.errors == [u'This field is required.'] # Failed login - blank password # ----------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'chris'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] form = context['login_form'] assert form.password.errors == [u'This field is required.'] # Failed login - bad user # ----------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'steve', 'password': 'toast'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] assert context['login_failed'] # Failed login - bad password # --------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'chris', 'password': 'jam'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html'] assert context['login_failed'] # Successful login # ---------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'chris', @@ -406,17 +406,17 @@ def test_authentication_views(test_app): assert_equal( urlparse.urlsplit(response.location)[2], '/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/root.html') # Make sure user is in the session - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] session = context['request'].session assert session['user_id'] == unicode(test_user['_id']) # Successful logout # ----------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.get('/auth/logout/') # Should be redirected to index page @@ -424,17 +424,17 @@ def test_authentication_views(test_app): assert_equal( urlparse.urlsplit(response.location)[2], '/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/root.html') # Make sure the user is not in the session - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] session = context['request'].session assert session.has_key('user_id') == False # User is redirected to custom URL if POST['next'] is set # ------------------------------------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = test_app.post( '/auth/login/', { 'username': u'chris', diff --git a/mediagoblin/tests/test_messages.py b/mediagoblin/tests/test_messages.py index 9c57a151..2635f4d7 100644 --- a/mediagoblin/tests/test_messages.py +++ b/mediagoblin/tests/test_messages.py @@ -16,7 +16,7 @@ from mediagoblin.messages import fetch_messages, add_message from mediagoblin.tests.tools import setup_fresh_app -from mediagoblin import util +from mediagoblin.tools import template @setup_fresh_app @@ -28,7 +28,7 @@ def test_messages(test_app): """ # Aquire a request object test_app.get('/') - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] request = context['request'] # The message queue should be empty diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 007c0348..1c657e6c 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -22,7 +22,7 @@ from nose.tools import assert_equal, assert_true, assert_false from mediagoblin.auth import lib as auth_lib from mediagoblin.tests.tools import setup_fresh_app, get_test_app from mediagoblin import mg_globals -from mediagoblin import util +from mediagoblin.tools import template, common GOOD_JPG = pkg_resources.resource_filename( 'mediagoblin.tests', 'test_submission/good.jpg') @@ -63,20 +63,20 @@ class TestSubmission: def test_missing_fields(self): # Test blank form # --------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', {}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] assert form.file.errors == [u'You must provide a file.'] # Test blank file # --------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'test title'}) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] assert form.file.errors == [u'You must provide a file.'] @@ -84,7 +84,7 @@ class TestSubmission: def test_normal_uploads(self): # Test JPG # -------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Normal upload 1' @@ -96,12 +96,12 @@ class TestSubmission: assert_equal( urlparse.urlsplit(response.location)[2], '/u/chris/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/user_pages/user.html') # Test PNG # -------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Normal upload 2' @@ -112,13 +112,13 @@ class TestSubmission: assert_equal( urlparse.urlsplit(response.location)[2], '/u/chris/') - assert util.TEMPLATE_TEST_CONTEXT.has_key( + assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/user_pages/user.html') def test_tags(self): # Good tag string # -------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Balanced Goblin', @@ -128,7 +128,7 @@ class TestSubmission: # New media entry with correct tags should be created response.follow() - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html'] request = context['request'] media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] assert_equal(media['tags'], @@ -137,7 +137,7 @@ class TestSubmission: # Test tags that are too long # --------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Balanced Goblin', @@ -146,14 +146,14 @@ class TestSubmission: 'file', GOOD_JPG)]) # Too long error should be raised - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] assert form.tags.errors == [ u'Tags must be shorter than 50 characters. Tags that are too long'\ ': ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu'] def test_delete(self): - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Balanced Goblin', @@ -163,7 +163,7 @@ class TestSubmission: # Post image response.follow() - request = util.TEMPLATE_TEST_CONTEXT[ + request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] @@ -183,7 +183,7 @@ class TestSubmission: response.follow() - request = util.TEMPLATE_TEST_CONTEXT[ + request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] @@ -202,7 +202,7 @@ class TestSubmission: response.follow() - request = util.TEMPLATE_TEST_CONTEXT[ + request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] # Does media entry still exist? @@ -213,14 +213,14 @@ class TestSubmission: def test_malicious_uploads(self): # Test non-suppoerted file with non-supported extension # ----------------------------------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Malicious Upload 1' }, upload_files=[( 'file', EVIL_FILE)]) - context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] assert form.file.errors == ['The file doesn\'t seem to be an image!'] @@ -230,7 +230,7 @@ class TestSubmission: # Test non-supported file with .jpg extension # ------------------------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Malicious Upload 2' @@ -250,7 +250,7 @@ class TestSubmission: # Test non-supported file with .png extension # ------------------------------------------- - util.clear_test_template_context() + template.clear_test_template_context() response = self.test_app.post( '/submit/', { 'title': 'Malicious Upload 3' diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index c2a3a67f..cdc62b7d 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -17,7 +17,7 @@ import email from mediagoblin import util - +from mediagoblin.tools import url, translate util._activate_testing() @@ -71,38 +71,38 @@ I hope you like unit tests JUST AS MUCH AS I DO!""" I hope you like unit tests JUST AS MUCH AS I DO!""" def test_slugify(): - assert util.slugify('a walk in the park') == 'a-walk-in-the-park' - assert util.slugify('A Walk in the Park') == 'a-walk-in-the-park' - assert util.slugify('a walk in the park') == 'a-walk-in-the-park' - assert util.slugify('a walk in-the-park') == 'a-walk-in-the-park' - assert util.slugify('a w@lk in the park?') == 'a-w-lk-in-the-park' - assert util.slugify(u'a walk in the par\u0107') == 'a-walk-in-the-parc' - assert util.slugify(u'\u00E0\u0042\u00E7\u010F\u00EB\u0066') == 'abcdef' + assert url.slugify('a walk in the park') == 'a-walk-in-the-park' + assert url.slugify('A Walk in the Park') == 'a-walk-in-the-park' + assert url.slugify('a walk in the park') == 'a-walk-in-the-park' + assert url.slugify('a walk in-the-park') == 'a-walk-in-the-park' + assert url.slugify('a w@lk in the park?') == 'a-w-lk-in-the-park' + assert url.slugify(u'a walk in the par\u0107') == 'a-walk-in-the-parc' + assert url.slugify(u'\u00E0\u0042\u00E7\u010F\u00EB\u0066') == 'abcdef' def test_locale_to_lower_upper(): """ Test cc.i18n.util.locale_to_lower_upper() """ - assert util.locale_to_lower_upper('en') == 'en' - assert util.locale_to_lower_upper('en_US') == 'en_US' - assert util.locale_to_lower_upper('en-us') == 'en_US' + assert translate.locale_to_lower_upper('en') == 'en' + assert translate.locale_to_lower_upper('en_US') == 'en_US' + assert translate.locale_to_lower_upper('en-us') == 'en_US' # crazy renditions. Useful? - assert util.locale_to_lower_upper('en-US') == 'en_US' - assert util.locale_to_lower_upper('en_us') == 'en_US' + assert translate.locale_to_lower_upper('en-US') == 'en_US' + assert translate.locale_to_lower_upper('en_us') == 'en_US' def test_locale_to_lower_lower(): """ Test cc.i18n.util.locale_to_lower_lower() """ - assert util.locale_to_lower_lower('en') == 'en' - assert util.locale_to_lower_lower('en_US') == 'en-us' - assert util.locale_to_lower_lower('en-us') == 'en-us' + assert translate.locale_to_lower_lower('en') == 'en' + assert translate.locale_to_lower_lower('en_US') == 'en-us' + assert translate.locale_to_lower_lower('en-us') == 'en-us' # crazy renditions. Useful? - assert util.locale_to_lower_lower('en-US') == 'en-us' - assert util.locale_to_lower_lower('en_us') == 'en-us' + assert translate.locale_to_lower_lower('en-US') == 'en-us' + assert translate.locale_to_lower_lower('en_us') == 'en-us' def test_html_cleaner(): diff --git a/mediagoblin/tools/__init__.py b/mediagoblin/tools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mediagoblin/tools/common.py b/mediagoblin/tools/common.py new file mode 100644 index 00000000..dccceccb --- /dev/null +++ b/mediagoblin/tools/common.py @@ -0,0 +1,18 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +global TESTS_ENABLED +TESTS_ENABLED = False diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py new file mode 100644 index 00000000..c346c33d --- /dev/null +++ b/mediagoblin/tools/template.py @@ -0,0 +1,114 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from math import ceil +import jinja2 +from babel.localedata import exists +from babel.support import LazyProxy +from mediagoblin import mg_globals +from mediagoblin import messages +from mediagoblin.tools import common +from mediagoblin.tools.translate import setup_gettext + +SETUP_JINJA_ENVS = {} + +def get_jinja_env(template_loader, locale): + """ + Set up the Jinja environment, + + (In the future we may have another system for providing theming; + for now this is good enough.) + """ + setup_gettext(locale) + + # If we have a jinja environment set up with this locale, just + # return that one. + if SETUP_JINJA_ENVS.has_key(locale): + return SETUP_JINJA_ENVS[locale] + + template_env = jinja2.Environment( + loader=template_loader, autoescape=True, + extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) + + template_env.install_gettext_callables( + mg_globals.translations.ugettext, + mg_globals.translations.ungettext) + + # All templates will know how to ... + # ... fetch all waiting messages and remove them from the queue + # ... construct a grid of thumbnails or other media + template_env.globals['fetch_messages'] = messages.fetch_messages + template_env.globals['gridify_list'] = gridify_list + template_env.globals['gridify_cursor'] = gridify_cursor + + if exists(locale): + SETUP_JINJA_ENVS[locale] = template_env + + return template_env + +# We'll store context information here when doing unit tests +TEMPLATE_TEST_CONTEXT = {} + + +def render_template(request, template_path, context): + """ + Render a template with context. + + Always inserts the request into the context, so you don't have to. + Also stores the context if we're doing unit tests. Helpful! + """ + template = request.template_env.get_template( + template_path) + context['request'] = request + rendered = template.render(context) + + if common.TESTS_ENABLED: + TEMPLATE_TEST_CONTEXT[template_path] = context + + return rendered + + +def clear_test_template_context(): + global TEMPLATE_TEST_CONTEXT + TEMPLATE_TEST_CONTEXT = {} + +def gridify_list(this_list, num_cols=5): + """ + Generates a list of lists where each sub-list's length depends on + the number of columns in the list + """ + grid = [] + + # Figure out how many rows we should have + num_rows = int(ceil(float(len(this_list)) / num_cols)) + + for row_num in range(num_rows): + slice_min = row_num * num_cols + slice_max = (row_num + 1) * num_cols + + row = this_list[slice_min:slice_max] + + grid.append(row) + + return grid + + +def gridify_cursor(this_cursor, num_cols=5): + """ + Generates a list of lists where each sub-list's length depends on + the number of columns in the list + """ + return gridify_list(list(this_cursor), num_cols) diff --git a/mediagoblin/tools/translate.py b/mediagoblin/tools/translate.py new file mode 100644 index 00000000..2c2a710d --- /dev/null +++ b/mediagoblin/tools/translate.py @@ -0,0 +1,167 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import gettext +import pkg_resources +from babel.localedata import exists +from babel.support import LazyProxy + +from mediagoblin import mg_globals + +################### +# Translation tools +################### + + +TRANSLATIONS_PATH = pkg_resources.resource_filename( + 'mediagoblin', 'i18n') + + +def locale_to_lower_upper(locale): + """ + Take a locale, regardless of style, and format it like "en-us" + """ + if '-' in locale: + lang, country = locale.split('-', 1) + return '%s_%s' % (lang.lower(), country.upper()) + elif '_' in locale: + lang, country = locale.split('_', 1) + return '%s_%s' % (lang.lower(), country.upper()) + else: + return locale.lower() + + +def locale_to_lower_lower(locale): + """ + Take a locale, regardless of style, and format it like "en_US" + """ + if '_' in locale: + lang, country = locale.split('_', 1) + return '%s-%s' % (lang.lower(), country.lower()) + else: + return locale.lower() + + +def get_locale_from_request(request): + """ + Figure out what target language is most appropriate based on the + request + """ + request_form = request.GET or request.POST + + if request_form.has_key('lang'): + return locale_to_lower_upper(request_form['lang']) + + accept_lang_matches = request.accept_language.best_matches() + + # Your routing can explicitly specify a target language + matchdict = request.matchdict or {} + + if matchdict.has_key('locale'): + target_lang = matchdict['locale'] + elif request.session.has_key('target_lang'): + target_lang = request.session['target_lang'] + # Pull the first acceptable language + elif accept_lang_matches: + target_lang = accept_lang_matches[0] + # Fall back to English + else: + target_lang = 'en' + + return locale_to_lower_upper(target_lang) + +SETUP_GETTEXTS = {} + +def setup_gettext(locale): + """ + Setup the gettext instance based on this locale + """ + # Later on when we have plugins we may want to enable the + # multi-translations system they have so we can handle plugin + # translations too + + # TODO: fallback nicely on translations from pt_PT to pt if not + # available, etc. + if SETUP_GETTEXTS.has_key(locale): + this_gettext = SETUP_GETTEXTS[locale] + else: + this_gettext = gettext.translation( + 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) + if exists(locale): + SETUP_GETTEXTS[locale] = this_gettext + + mg_globals.setup_globals( + translations=this_gettext) + + +# Force en to be setup before anything else so that +# mg_globals.translations is never None +setup_gettext('en') + + +def pass_to_ugettext(*args, **kwargs): + """ + Pass a translation on to the appropriate ugettext method. + + The reason we can't have a global ugettext method is because + mg_globals gets swapped out by the application per-request. + """ + return mg_globals.translations.ugettext( + *args, **kwargs) + + +def lazy_pass_to_ugettext(*args, **kwargs): + """ + Lazily pass to ugettext. + + This is useful if you have to define a translation on a module + level but you need it to not translate until the time that it's + used as a string. + """ + return LazyProxy(pass_to_ugettext, *args, **kwargs) + + +def pass_to_ngettext(*args, **kwargs): + """ + Pass a translation on to the appropriate ngettext method. + + The reason we can't have a global ngettext method is because + mg_globals gets swapped out by the application per-request. + """ + return mg_globals.translations.ngettext( + *args, **kwargs) + + +def lazy_pass_to_ngettext(*args, **kwargs): + """ + Lazily pass to ngettext. + + This is useful if you have to define a translation on a module + level but you need it to not translate until the time that it's + used as a string. + """ + return LazyProxy(pass_to_ngettext, *args, **kwargs) + + +def fake_ugettext_passthrough(string): + """ + Fake a ugettext call for extraction's sake ;) + + In wtforms there's a separate way to define a method to translate + things... so we just need to mark up the text so that it can be + extracted, not so that it's actually run through gettext. + """ + return string diff --git a/mediagoblin/tools/url.py b/mediagoblin/tools/url.py new file mode 100644 index 00000000..458ef2c8 --- /dev/null +++ b/mediagoblin/tools/url.py @@ -0,0 +1,31 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import re +import translitcodec + +_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') + +def slugify(text, delim=u'-'): + """ + Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ + """ + result = [] + for word in _punct_re.split(text.lower()): + word = word.encode('translit/long') + if word: + result.append(word) + return unicode(delim.join(result)) diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 57061d34..301f1f0a 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -16,7 +16,7 @@ import wtforms -from mediagoblin.util import fake_ugettext_passthrough as _ +from mediagoblin.tools.translate import fake_ugettext_passthrough as _ class MediaCommentForm(wtforms.Form): diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 6a82d718..40c7ffce 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -21,7 +21,7 @@ from mediagoblin.db.util import DESCENDING, ObjectId from mediagoblin.util import ( Pagination, render_to_response, redirect, cleaned_markdown_conversion, render_404, delete_media_files) -from mediagoblin.util import pass_to_ugettext as _ +from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.user_pages import forms as user_forms from mediagoblin.decorators import (uses_pagination, get_user_media_entry, diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 7ff3ec7f..35755ccf 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -17,41 +17,42 @@ from __future__ import division from email.MIMEText import MIMEText -import gettext -import pkg_resources +#import gettext +#import pkg_resources import smtplib import sys -import re +#import re +#import translitcodec import urllib from math import ceil, floor import copy import wtforms -from babel.localedata import exists -from babel.support import LazyProxy -import jinja2 -import translitcodec +#from babel.localedata import exists +#from babel.support import LazyProxy +#import jinja2 from webob import Response, exc from lxml.html.clean import Cleaner import markdown from wtforms.form import Form from mediagoblin import mg_globals -from mediagoblin import messages +#from mediagoblin import messages from mediagoblin.db.util import ObjectId +from mediagoblin.tools import url +from mediagoblin.tools import common +from mediagoblin.tools.template import TEMPLATE_TEST_CONTEXT, render_template from itertools import izip, count DISPLAY_IMAGE_FETCHING_ORDER = [u'medium', u'original', u'thumb'] -TESTS_ENABLED = False def _activate_testing(): """ Call this to activate testing in util.py """ - global TESTS_ENABLED - TESTS_ENABLED = True + common.TESTS_ENABLED = True def clear_test_buckets(): """ @@ -73,64 +74,64 @@ def clear_test_buckets(): clear_test_template_context() -SETUP_JINJA_ENVS = {} +# SETUP_JINJA_ENVS = {} -def get_jinja_env(template_loader, locale): - """ - Set up the Jinja environment, +# def get_jinja_env(template_loader, locale): +# """ +# Set up the Jinja environment, - (In the future we may have another system for providing theming; - for now this is good enough.) - """ - setup_gettext(locale) +# (In the future we may have another system for providing theming; +# for now this is good enough.) +# """ +# setup_gettext(locale) - # If we have a jinja environment set up with this locale, just - # return that one. - if SETUP_JINJA_ENVS.has_key(locale): - return SETUP_JINJA_ENVS[locale] +# # If we have a jinja environment set up with this locale, just +# # return that one. +# if SETUP_JINJA_ENVS.has_key(locale): +# return SETUP_JINJA_ENVS[locale] - template_env = jinja2.Environment( - loader=template_loader, autoescape=True, - extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) +# template_env = jinja2.Environment( +# loader=template_loader, autoescape=True, +# extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) - template_env.install_gettext_callables( - mg_globals.translations.ugettext, - mg_globals.translations.ungettext) +# template_env.install_gettext_callables( +# mg_globals.translations.ugettext, +# mg_globals.translations.ungettext) - # All templates will know how to ... - # ... fetch all waiting messages and remove them from the queue - # ... construct a grid of thumbnails or other media - template_env.globals['fetch_messages'] = messages.fetch_messages - template_env.globals['gridify_list'] = gridify_list - template_env.globals['gridify_cursor'] = gridify_cursor +# # All templates will know how to ... +# # ... fetch all waiting messages and remove them from the queue +# # ... construct a grid of thumbnails or other media +# template_env.globals['fetch_messages'] = messages.fetch_messages +# template_env.globals['gridify_list'] = gridify_list +# template_env.globals['gridify_cursor'] = gridify_cursor - if exists(locale): - SETUP_JINJA_ENVS[locale] = template_env +# if exists(locale): +# SETUP_JINJA_ENVS[locale] = template_env - return template_env +# return template_env -# We'll store context information here when doing unit tests -TEMPLATE_TEST_CONTEXT = {} +# # We'll store context information here when doing unit tests +# TEMPLATE_TEST_CONTEXT = {} -def render_template(request, template_path, context): - """ - Render a template with context. +# def render_template(request, template_path, context): +# """ +# Render a template with context. - Always inserts the request into the context, so you don't have to. - Also stores the context if we're doing unit tests. Helpful! - """ - template = request.template_env.get_template( - template_path) - context['request'] = request - rendered = template.render(context) +# Always inserts the request into the context, so you don't have to. +# Also stores the context if we're doing unit tests. Helpful! +# """ +# template = request.template_env.get_template( +# template_path) +# context['request'] = request +# rendered = template.render(context) - if TESTS_ENABLED: - TEMPLATE_TEST_CONTEXT[template_path] = context +# if TESTS_ENABLED: +# TEMPLATE_TEST_CONTEXT[template_path] = context - return rendered +# return rendered def clear_test_template_context(): @@ -195,18 +196,18 @@ def import_component(import_string): func = getattr(module, func_name) return func -_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') +# _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') -def slugify(text, delim=u'-'): - """ - Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ - """ - result = [] - for word in _punct_re.split(text.lower()): - word = word.encode('translit/long') - if word: - result.append(word) - return unicode(delim.join(result)) +# def slugify(text, delim=u'-'): +# """ +# Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ +# """ +# result = [] +# for word in _punct_re.split(text.lower()): +# word = word.encode('translit/long') +# if word: +# result.append(word) +# return unicode(delim.join(result)) ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### Special email test stuff begins HERE @@ -274,7 +275,7 @@ def send_email(from_addr, to_addrs, subject, message_body): - subject: subject of the email - message_body: email body text """ - if TESTS_ENABLED or mg_globals.app_config['email_debug_mode']: + if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']: mhost = FakeMhost() elif not mg_globals.app_config['email_debug_mode']: mhost = smtplib.SMTP( @@ -296,7 +297,7 @@ def send_email(from_addr, to_addrs, subject, message_body): message['From'] = from_addr message['To'] = ', '.join(to_addrs) - if TESTS_ENABLED: + if common.TESTS_ENABLED: EMAIL_TEST_INBOX.append(message) if mg_globals.app_config['email_debug_mode']: @@ -310,67 +311,67 @@ def send_email(from_addr, to_addrs, subject, message_body): return mhost.sendmail(from_addr, to_addrs, message.as_string()) -################### -# Translation tools -################### +# ################### +# # Translation tools +# ################### -TRANSLATIONS_PATH = pkg_resources.resource_filename( - 'mediagoblin', 'i18n') +# TRANSLATIONS_PATH = pkg_resources.resource_filename( +# 'mediagoblin', 'i18n') -def locale_to_lower_upper(locale): - """ - Take a locale, regardless of style, and format it like "en-us" - """ - if '-' in locale: - lang, country = locale.split('-', 1) - return '%s_%s' % (lang.lower(), country.upper()) - elif '_' in locale: - lang, country = locale.split('_', 1) - return '%s_%s' % (lang.lower(), country.upper()) - else: - return locale.lower() +# def locale_to_lower_upper(locale): +# """ +# Take a locale, regardless of style, and format it like "en-us" +# """ +# if '-' in locale: +# lang, country = locale.split('-', 1) +# return '%s_%s' % (lang.lower(), country.upper()) +# elif '_' in locale: +# lang, country = locale.split('_', 1) +# return '%s_%s' % (lang.lower(), country.upper()) +# else: +# return locale.lower() -def locale_to_lower_lower(locale): - """ - Take a locale, regardless of style, and format it like "en_US" - """ - if '_' in locale: - lang, country = locale.split('_', 1) - return '%s-%s' % (lang.lower(), country.lower()) - else: - return locale.lower() +# def locale_to_lower_lower(locale): +# """ +# Take a locale, regardless of style, and format it like "en_US" +# """ +# if '_' in locale: +# lang, country = locale.split('_', 1) +# return '%s-%s' % (lang.lower(), country.lower()) +# else: +# return locale.lower() -def get_locale_from_request(request): - """ - Figure out what target language is most appropriate based on the - request - """ - request_form = request.GET or request.POST +# def get_locale_from_request(request): +# """ +# Figure out what target language is most appropriate based on the +# request +# """ +# request_form = request.GET or request.POST - if request_form.has_key('lang'): - return locale_to_lower_upper(request_form['lang']) +# if request_form.has_key('lang'): +# return locale_to_lower_upper(request_form['lang']) - accept_lang_matches = request.accept_language.best_matches() +# accept_lang_matches = request.accept_language.best_matches() - # Your routing can explicitly specify a target language - matchdict = request.matchdict or {} +# # Your routing can explicitly specify a target language +# matchdict = request.matchdict or {} - if matchdict.has_key('locale'): - target_lang = matchdict['locale'] - elif request.session.has_key('target_lang'): - target_lang = request.session['target_lang'] - # Pull the first acceptable language - elif accept_lang_matches: - target_lang = accept_lang_matches[0] - # Fall back to English - else: - target_lang = 'en' +# if matchdict.has_key('locale'): +# target_lang = matchdict['locale'] +# elif request.session.has_key('target_lang'): +# target_lang = request.session['target_lang'] +# # Pull the first acceptable language +# elif accept_lang_matches: +# target_lang = accept_lang_matches[0] +# # Fall back to English +# else: +# target_lang = 'en' - return locale_to_lower_upper(target_lang) +# return locale_to_lower_upper(target_lang) # A super strict version of the lxml.html cleaner class @@ -424,7 +425,7 @@ def convert_to_tag_list_of_dicts(tag_string): if tag.strip() and tag.strip() not in [t['name'] for t in taglist]: taglist.append({'name': tag.strip(), - 'slug': slugify(tag.strip())}) + 'slug': url.slugify(tag.strip())}) return taglist @@ -472,88 +473,88 @@ def cleaned_markdown_conversion(text): return clean_html(MARKDOWN_INSTANCE.convert(text)) -SETUP_GETTEXTS = {} +# SETUP_GETTEXTS = {} -def setup_gettext(locale): - """ - Setup the gettext instance based on this locale - """ - # Later on when we have plugins we may want to enable the - # multi-translations system they have so we can handle plugin - # translations too +# def setup_gettext(locale): +# """ +# Setup the gettext instance based on this locale +# """ +# # Later on when we have plugins we may want to enable the +# # multi-translations system they have so we can handle plugin +# # translations too - # TODO: fallback nicely on translations from pt_PT to pt if not - # available, etc. - if SETUP_GETTEXTS.has_key(locale): - this_gettext = SETUP_GETTEXTS[locale] - else: - this_gettext = gettext.translation( - 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) - if exists(locale): - SETUP_GETTEXTS[locale] = this_gettext +# # TODO: fallback nicely on translations from pt_PT to pt if not +# # available, etc. +# if SETUP_GETTEXTS.has_key(locale): +# this_gettext = SETUP_GETTEXTS[locale] +# else: +# this_gettext = gettext.translation( +# 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) +# if exists(locale): +# SETUP_GETTEXTS[locale] = this_gettext - mg_globals.setup_globals( - translations=this_gettext) +# mg_globals.setup_globals( +# translations=this_gettext) -# Force en to be setup before anything else so that -# mg_globals.translations is never None -setup_gettext('en') +# # Force en to be setup before anything else so that +# # mg_globals.translations is never None +# setup_gettext('en') -def pass_to_ugettext(*args, **kwargs): - """ - Pass a translation on to the appropriate ugettext method. +# def pass_to_ugettext(*args, **kwargs): +# """ +# Pass a translation on to the appropriate ugettext method. - The reason we can't have a global ugettext method is because - mg_globals gets swapped out by the application per-request. - """ - return mg_globals.translations.ugettext( - *args, **kwargs) +# The reason we can't have a global ugettext method is because +# mg_globals gets swapped out by the application per-request. +# """ +# return mg_globals.translations.ugettext( +# *args, **kwargs) -def lazy_pass_to_ugettext(*args, **kwargs): - """ - Lazily pass to ugettext. +# def lazy_pass_to_ugettext(*args, **kwargs): +# """ +# Lazily pass to ugettext. - This is useful if you have to define a translation on a module - level but you need it to not translate until the time that it's - used as a string. - """ - return LazyProxy(pass_to_ugettext, *args, **kwargs) +# This is useful if you have to define a translation on a module +# level but you need it to not translate until the time that it's +# used as a string. +# """ +# return LazyProxy(pass_to_ugettext, *args, **kwargs) -def pass_to_ngettext(*args, **kwargs): - """ - Pass a translation on to the appropriate ngettext method. +# def pass_to_ngettext(*args, **kwargs): +# """ +# Pass a translation on to the appropriate ngettext method. - The reason we can't have a global ngettext method is because - mg_globals gets swapped out by the application per-request. - """ - return mg_globals.translations.ngettext( - *args, **kwargs) +# The reason we can't have a global ngettext method is because +# mg_globals gets swapped out by the application per-request. +# """ +# return mg_globals.translations.ngettext( +# *args, **kwargs) -def lazy_pass_to_ngettext(*args, **kwargs): - """ - Lazily pass to ngettext. +# def lazy_pass_to_ngettext(*args, **kwargs): +# """ +# Lazily pass to ngettext. - This is useful if you have to define a translation on a module - level but you need it to not translate until the time that it's - used as a string. - """ - return LazyProxy(pass_to_ngettext, *args, **kwargs) +# This is useful if you have to define a translation on a module +# level but you need it to not translate until the time that it's +# used as a string. +# """ +# return LazyProxy(pass_to_ngettext, *args, **kwargs) -def fake_ugettext_passthrough(string): - """ - Fake a ugettext call for extraction's sake ;) +# def fake_ugettext_passthrough(string): +# """ +# Fake a ugettext call for extraction's sake ;) - In wtforms there's a separate way to define a method to translate - things... so we just need to mark up the text so that it can be - extracted, not so that it's actually run through gettext. - """ - return string +# In wtforms there's a separate way to define a method to translate +# things... so we just need to mark up the text so that it can be +# extracted, not so that it's actually run through gettext. +# """ +# return string PAGINATION_DEFAULT_PER_PAGE = 30 @@ -646,33 +647,33 @@ class Pagination(object): request.path_info, request.GET, page_no) -def gridify_list(this_list, num_cols=5): - """ - Generates a list of lists where each sub-list's length depends on - the number of columns in the list - """ - grid = [] +# def gridify_list(this_list, num_cols=5): +# """ +# Generates a list of lists where each sub-list's length depends on +# the number of columns in the list +# """ +# grid = [] - # Figure out how many rows we should have - num_rows = int(ceil(float(len(this_list)) / num_cols)) +# # Figure out how many rows we should have +# num_rows = int(ceil(float(len(this_list)) / num_cols)) - for row_num in range(num_rows): - slice_min = row_num * num_cols - slice_max = (row_num + 1) * num_cols +# for row_num in range(num_rows): +# slice_min = row_num * num_cols +# slice_max = (row_num + 1) * num_cols - row = this_list[slice_min:slice_max] +# row = this_list[slice_min:slice_max] - grid.append(row) +# grid.append(row) - return grid +# return grid -def gridify_cursor(this_cursor, num_cols=5): - """ - Generates a list of lists where each sub-list's length depends on - the number of columns in the list - """ - return gridify_list(list(this_cursor), num_cols) +# def gridify_cursor(this_cursor, num_cols=5): +# """ +# Generates a list of lists where each sub-list's length depends on +# the number of columns in the list +# """ +# return gridify_list(list(this_cursor), num_cols) def render_404(request): -- cgit v1.2.3 From 5d2abe45b2bae9111d4f1bda645b53414d2b240d Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 12:48:43 -0700 Subject: PEP8-ification. --- mediagoblin/middleware/csrf.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index a372d0b5..68ece6d3 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -34,17 +34,19 @@ class CsrfForm(Form): """Simple form to handle rendering a CSRF token and confirming it is included in the POST.""" - csrf_token = HiddenField("", + csrf_token = HiddenField("", [validators.Required()]) + def render_csrf_form_token(request): """Render the CSRF token in a format suitable for inclusion in a form.""" - form = CsrfForm(csrf_token = request.environ['CSRF_TOKEN']) + form = CsrfForm(csrf_token=request.environ['CSRF_TOKEN']) return form.csrf_token + class CsrfMiddleware(object): """CSRF Protection Middleware @@ -87,7 +89,8 @@ class CsrfMiddleware(object): response.set_cookie( mg_globals.app_config['csrf_cookie_name'], request.environ['CSRF_TOKEN'], - max_age=60*60*24*7*52, path='/', + max_age=60 * 60 * 24 * 7 * 52, + path='/', domain=mg_globals.app_config.get('csrf_cookie_domain', None), secure=(request.scheme.lower() == 'https'), httponly=True) @@ -98,10 +101,9 @@ class CsrfMiddleware(object): def _make_token(self, request): """Generate a new token to use for CSRF protection.""" - return hashlib.md5("%s%s" % - (randrange(0, self.MAX_CSRF_KEY), - mg_globals.app_config['secret_key']) - ).hexdigest() + return hashlib.md5("%s%s" % + (randrange(0, self.MAX_CSRF_KEY), + mg_globals.app_config['secret_key'])).hexdigest() def verify_tokens(self, request): """Verify that the CSRF Cookie exists and that it matches the @@ -109,7 +111,7 @@ class CsrfMiddleware(object): # confirm the cookie token was presented cookie_token = request.cookies.get( - mg_globals.app_config['csrf_cookie_name'], + mg_globals.app_config['csrf_cookie_name'], None) if cookie_token is None: @@ -128,4 +130,3 @@ class CsrfMiddleware(object): # either the tokens didn't match or the form token wasn't # present; either way, the request is denied return HTTPForbidden() - -- cgit v1.2.3 From 7e694e5fd858aeaea7eb7e9a9062b36d17a3b7f7 Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 13:13:14 -0700 Subject: #361: Don't test for CSRF token if we're running unit tests. --- mediagoblin/middleware/csrf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index 68ece6d3..d41bcd87 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -77,7 +77,10 @@ class CsrfMiddleware(object): # if this is a non-"safe" request (ie, one that could have # side effects), confirm that the CSRF tokens are present and # valid - if request.method not in self.SAFE_HTTP_METHODS: + if request.method not in self.SAFE_HTTP_METHODS \ + and ('gmg.verify_csrf' in request.environ or + 'paste.testing' not in request.environ): + return self.verify_tokens(request) def process_response(self, request, response): -- cgit v1.2.3 From 4f475d3024f689c1c461dc26bd679dfb514a46ef Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 14:21:02 -0700 Subject: #361 Unit tests for CSRF Middleware --- mediagoblin/tests/test_csrf_middleware.py | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 mediagoblin/tests/test_csrf_middleware.py diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py new file mode 100644 index 00000000..cf03fe58 --- /dev/null +++ b/mediagoblin/tests/test_csrf_middleware.py @@ -0,0 +1,69 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import urlparse +import datetime + +from nose.tools import assert_equal + +from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin import mg_globals + + +@setup_fresh_app +def test_csrf_cookie_set(test_app): + + # get login page + response = test_app.get('/auth/login/') + + # assert that the mediagoblin nonce cookie has been set + assert 'Set-Cookie' in response.headers + assert 'mediagoblin_nonce' in response.cookies_set + + # assert that we're also sending a vary header + assert response.headers.get('Vary', False) == 'Cookie' + + +@setup_fresh_app +def test_csrf_token_must_match(test_app): + + # construct a request with no cookie or form token + assert test_app.post('/auth/login/', + extra_environ={'gmg.verify_csrf': True}, + expect_errors=True).status_int == 403 + + # construct a request with a cookie, but no form token + assert test_app.post('/auth/login/', + headers={'Cookie': str('%s=foo; ' % + mg_globals.app_config['csrf_cookie_name'])}, + extra_environ={'gmg.verify_csrf': True}, + expect_errors=True).status_int == 403 + + # if both the cookie and form token are provided, they must match + assert test_app.post('/auth/login/', + {'csrf_token': 'blarf'}, + headers={'Cookie': str('%s=foo; ' % + mg_globals.app_config['csrf_cookie_name'])}, + extra_environ={'gmg.verify_csrf': True}, + expect_errors=True).\ + status_int == 403 + + assert test_app.post('/auth/login/', + {'csrf_token': 'foo'}, + headers={'Cookie': str('%s=foo; ' % + mg_globals.app_config['csrf_cookie_name'])}, + extra_environ={'gmg.verify_csrf': True}).\ + status_int == 200 -- cgit v1.2.3 From 9202e5a1e15183b134fa15c4e1290dea8ed2acbe Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 14:24:49 -0700 Subject: #361: Removing additional secret key, per CW's request. --- mediagoblin/config_spec.ini | 1 - mediagoblin/middleware/csrf.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 37fe7130..298a6951 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -42,7 +42,6 @@ celery_setup_elsewhere = boolean(default=False) allow_attachments = boolean(default=False) # Cookie stuff -secret_key = string(default="Something Super Duper Secrit!") csrf_cookie_name = string(default='mediagoblin_nonce') [storage:publicstore] diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index d41bcd87..44b799d5 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -106,7 +106,7 @@ class CsrfMiddleware(object): return hashlib.md5("%s%s" % (randrange(0, self.MAX_CSRF_KEY), - mg_globals.app_config['secret_key'])).hexdigest() + randrange(0, self.MAX_CSRF_KEY))).hexdigest() def verify_tokens(self, request): """Verify that the CSRF Cookie exists and that it matches the -- cgit v1.2.3 From 03ae172a60a87625e5281eb9766aa5bf3e37d0f4 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Sat, 1 Oct 2011 18:05:17 -0400 Subject: Finished splitting util.py into separate files. --- mediagoblin/tools/common.py | 19 +++++++ mediagoblin/tools/files.py | 32 +++++++++++ mediagoblin/tools/mail.py | 120 ++++++++++++++++++++++++++++++++++++++++ mediagoblin/tools/pagination.py | 109 ++++++++++++++++++++++++++++++++++++ mediagoblin/tools/request.py | 37 +++++++++++++ mediagoblin/tools/response.py | 44 +++++++++++++++ mediagoblin/tools/testing.py | 45 +++++++++++++++ mediagoblin/tools/text.py | 117 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 523 insertions(+) create mode 100644 mediagoblin/tools/files.py create mode 100644 mediagoblin/tools/mail.py create mode 100644 mediagoblin/tools/pagination.py create mode 100644 mediagoblin/tools/request.py create mode 100644 mediagoblin/tools/response.py create mode 100644 mediagoblin/tools/testing.py create mode 100644 mediagoblin/tools/text.py diff --git a/mediagoblin/tools/common.py b/mediagoblin/tools/common.py index dccceccb..ea4541a8 100644 --- a/mediagoblin/tools/common.py +++ b/mediagoblin/tools/common.py @@ -14,5 +14,24 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import sys + +DISPLAY_IMAGE_FETCHING_ORDER = [u'medium', u'original', u'thumb'] + global TESTS_ENABLED TESTS_ENABLED = False + +def import_component(import_string): + """ + Import a module component defined by STRING. Probably a method, + class, or global variable. + + Args: + - import_string: a string that defines what to import. Written + in the format of "module1.module2:component" + """ + module_name, func_name = import_string.split(':', 1) + __import__(module_name) + module = sys.modules[module_name] + func = getattr(module, func_name) + return func diff --git a/mediagoblin/tools/files.py b/mediagoblin/tools/files.py new file mode 100644 index 00000000..e0bf0569 --- /dev/null +++ b/mediagoblin/tools/files.py @@ -0,0 +1,32 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin import mg_globals + +def delete_media_files(media): + """ + Delete all files associated with a MediaEntry + + Arguments: + - media: A MediaEntry document + """ + for listpath in media['media_files'].itervalues(): + mg_globals.public_store.delete_file( + listpath) + + for attachment in media['attachment_files']: + mg_globals.public_store.delete_file( + attachment['filepath']) diff --git a/mediagoblin/tools/mail.py b/mediagoblin/tools/mail.py new file mode 100644 index 00000000..826acdbf --- /dev/null +++ b/mediagoblin/tools/mail.py @@ -0,0 +1,120 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import smtplib +from email.MIMEText import MIMEText +from mediagoblin import mg_globals +from mediagoblin.tools import common + +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### Special email test stuff begins HERE +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# We have two "test inboxes" here: +# +# EMAIL_TEST_INBOX: +# ---------------- +# If you're writing test views, you'll probably want to check this. +# It contains a list of MIMEText messages. +# +# EMAIL_TEST_MBOX_INBOX: +# ---------------------- +# This collects the messages from the FakeMhost inbox. It's reslly +# just here for testing the send_email method itself. +# +# Anyway this contains: +# - from +# - to: a list of email recipient addresses +# - message: not just the body, but the whole message, including +# headers, etc. +# +# ***IMPORTANT!*** +# ---------------- +# Before running tests that call functions which send email, you should +# always call _clear_test_inboxes() to "wipe" the inboxes clean. + +EMAIL_TEST_INBOX = [] +EMAIL_TEST_MBOX_INBOX = [] + +class FakeMhost(object): + """ + Just a fake mail host so we can capture and test messages + from send_email + """ + def login(self, *args, **kwargs): + pass + + def sendmail(self, from_addr, to_addrs, message): + EMAIL_TEST_MBOX_INBOX.append( + {'from': from_addr, + 'to': to_addrs, + 'message': message}) + +def _clear_test_inboxes(): + global EMAIL_TEST_INBOX + global EMAIL_TEST_MBOX_INBOX + EMAIL_TEST_INBOX = [] + EMAIL_TEST_MBOX_INBOX = [] + +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +### +### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def send_email(from_addr, to_addrs, subject, message_body): + """ + Simple email sending wrapper, use this so we can capture messages + for unit testing purposes. + + Args: + - from_addr: address you're sending the email from + - to_addrs: list of recipient email addresses + - subject: subject of the email + - message_body: email body text + """ + if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']: + mhost = FakeMhost() + elif not mg_globals.app_config['email_debug_mode']: + mhost = smtplib.SMTP( + mg_globals.app_config['email_smtp_host'], + mg_globals.app_config['email_smtp_port']) + + # SMTP.__init__ Issues SMTP.connect implicitly if host + if not mg_globals.app_config['email_smtp_host']: # e.g. host = '' + mhost.connect() # We SMTP.connect explicitly + + if mg_globals.app_config['email_smtp_user'] \ + or mg_globals.app_config['email_smtp_pass']: + mhost.login( + mg_globals.app_config['email_smtp_user'], + mg_globals.app_config['email_smtp_pass']) + + message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8') + message['Subject'] = subject + message['From'] = from_addr + message['To'] = ', '.join(to_addrs) + + if common.TESTS_ENABLED: + EMAIL_TEST_INBOX.append(message) + + if mg_globals.app_config['email_debug_mode']: + print u"===== Email =====" + print u"From address: %s" % message['From'] + print u"To addresses: %s" % message['To'] + print u"Subject: %s" % message['Subject'] + print u"-- Body: --" + print message.get_payload(decode=True) + + return mhost.sendmail(from_addr, to_addrs, message.as_string()) diff --git a/mediagoblin/tools/pagination.py b/mediagoblin/tools/pagination.py new file mode 100644 index 00000000..859b60fb --- /dev/null +++ b/mediagoblin/tools/pagination.py @@ -0,0 +1,109 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import urllib +import copy +from math import ceil, floor +from itertools import izip, count + +PAGINATION_DEFAULT_PER_PAGE = 30 + +class Pagination(object): + """ + Pagination class for mongodb queries. + + Initialization through __init__(self, cursor, page=1, per_page=2), + get actual data slice through __call__(). + """ + + def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE, + jump_to_id=False): + """ + Initializes Pagination + + Args: + - page: requested page + - per_page: number of objects per page + - cursor: db cursor + - jump_to_id: ObjectId, sets the page to the page containing the object + with _id == jump_to_id. + """ + self.page = page + self.per_page = per_page + self.cursor = cursor + self.total_count = self.cursor.count() + self.active_id = None + + if jump_to_id: + cursor = copy.copy(self.cursor) + + for (doc, increment) in izip(cursor, count(0)): + if doc['_id'] == jump_to_id: + self.page = 1 + int(floor(increment / self.per_page)) + + self.active_id = jump_to_id + break + + + def __call__(self): + """ + Returns slice of objects for the requested page + """ + return self.cursor.skip( + (self.page - 1) * self.per_page).limit(self.per_page) + + @property + def pages(self): + return int(ceil(self.total_count / float(self.per_page))) + + @property + def has_prev(self): + return self.page > 1 + + @property + def has_next(self): + return self.page < self.pages + + def iter_pages(self, left_edge=2, left_current=2, + right_current=5, right_edge=2): + last = 0 + for num in xrange(1, self.pages + 1): + if num <= left_edge or \ + (num > self.page - left_current - 1 and \ + num < self.page + right_current) or \ + num > self.pages - right_edge: + if last + 1 != num: + yield None + yield num + last = num + + def get_page_url_explicit(self, base_url, get_params, page_no): + """ + Get a page url by adding a page= parameter to the base url + """ + new_get_params = copy.copy(get_params or {}) + new_get_params['page'] = page_no + return "%s?%s" % ( + base_url, urllib.urlencode(new_get_params)) + + def get_page_url(self, request, page_no): + """ + Get a new page url based of the request, and the new page number. + + This is a nice wrapper around get_page_url_explicit() + """ + return self.get_page_url_explicit( + request.path_info, request.GET, page_no) diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py new file mode 100644 index 00000000..b1cbe119 --- /dev/null +++ b/mediagoblin/tools/request.py @@ -0,0 +1,37 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.db.util import ObjectId + +def setup_user_in_request(request): + """ + Examine a request and tack on a request.user parameter if that's + appropriate. + """ + if not request.session.has_key('user_id'): + request.user = None + return + + user = None + user = request.app.db.User.one( + {'_id': ObjectId(request.session['user_id'])}) + + if not user: + # Something's wrong... this user doesn't exist? Invalidate + # this session. + request.session.invalidate() + + request.user = user diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py new file mode 100644 index 00000000..1477b9bc --- /dev/null +++ b/mediagoblin/tools/response.py @@ -0,0 +1,44 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from webob import Response, exc +from mediagoblin.tools.template import render_template + +def render_to_response(request, template, context, status=200): + """Much like Django's shortcut.render()""" + return Response( + render_template(request, template, context), + status=status) + +def render_404(request): + """ + Render a 404. + """ + return render_to_response( + request, 'mediagoblin/404.html', {}, status=400) + +def redirect(request, *args, **kwargs): + """Returns a HTTPFound(), takes a request and then urlgen params""" + + querystring = None + if kwargs.get('querystring'): + querystring = kwargs.get('querystring') + del kwargs['querystring'] + + return exc.HTTPFound( + location=''.join([ + request.urlgen(*args, **kwargs), + querystring if querystring else ''])) diff --git a/mediagoblin/tools/testing.py b/mediagoblin/tools/testing.py new file mode 100644 index 00000000..39435ca5 --- /dev/null +++ b/mediagoblin/tools/testing.py @@ -0,0 +1,45 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.tools import common +from mediagoblin.tools.template import clear_test_template_context +from mediagoblin.tools.mail import EMAIL_TEST_INBOX, EMAIL_TEST_MBOX_INBOX + +def _activate_testing(): + """ + Call this to activate testing in util.py + """ + + common.TESTS_ENABLED = True + +def clear_test_buckets(): + """ + We store some things for testing purposes that should be cleared + when we want a "clean slate" of information for our next round of + tests. Call this function to wipe all that stuff clean. + + Also wipes out some other things we might redefine during testing, + like the jinja envs. + """ + global SETUP_JINJA_ENVS + SETUP_JINJA_ENVS = {} + + global EMAIL_TEST_INBOX + global EMAIL_TEST_MBOX_INBOX + EMAIL_TEST_INBOX = [] + EMAIL_TEST_MBOX_INBOX = [] + + clear_test_template_context() diff --git a/mediagoblin/tools/text.py b/mediagoblin/tools/text.py new file mode 100644 index 00000000..de4bb281 --- /dev/null +++ b/mediagoblin/tools/text.py @@ -0,0 +1,117 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import wtforms +import markdown +from lxml.html.clean import Cleaner + +from mediagoblin import mg_globals +from mediagoblin.tools import url + +# A super strict version of the lxml.html cleaner class +HTML_CLEANER = Cleaner( + scripts=True, + javascript=True, + comments=True, + style=True, + links=True, + page_structure=True, + processing_instructions=True, + embedded=True, + frames=True, + forms=True, + annoying_tags=True, + allow_tags=[ + 'div', 'b', 'i', 'em', 'strong', 'p', 'ul', 'ol', 'li', 'a', 'br'], + remove_unknown_tags=False, # can't be used with allow_tags + safe_attrs_only=True, + add_nofollow=True, # for now + host_whitelist=(), + whitelist_tags=set([])) + +def clean_html(html): + # clean_html barfs on an empty string + if not html: + return u'' + + return HTML_CLEANER.clean_html(html) + +def convert_to_tag_list_of_dicts(tag_string): + """ + Filter input from incoming string containing user tags, + + Strips trailing, leading, and internal whitespace, and also converts + the "tags" text into an array of tags + """ + taglist = [] + if tag_string: + + # Strip out internal, trailing, and leading whitespace + stripped_tag_string = u' '.join(tag_string.strip().split()) + + # Split the tag string into a list of tags + for tag in stripped_tag_string.split( + mg_globals.app_config['tags_delimiter']): + + # Ignore empty or duplicate tags + if tag.strip() and tag.strip() not in [t['name'] for t in taglist]: + + taglist.append({'name': tag.strip(), + 'slug': url.slugify(tag.strip())}) + return taglist + +def media_tags_as_string(media_entry_tags): + """ + Generate a string from a media item's tags, stored as a list of dicts + + This is the opposite of convert_to_tag_list_of_dicts + """ + media_tag_string = '' + if media_entry_tags: + media_tag_string = mg_globals.app_config['tags_delimiter'].join( + [tag['name'] for tag in media_entry_tags]) + return media_tag_string + +TOO_LONG_TAG_WARNING = \ + u'Tags must be shorter than %s characters. Tags that are too long: %s' + +def tag_length_validator(form, field): + """ + Make sure tags do not exceed the maximum tag length. + """ + tags = convert_to_tag_list_of_dicts(field.data) + too_long_tags = [ + tag['name'] for tag in tags + if len(tag['name']) > mg_globals.app_config['tags_max_length']] + + if too_long_tags: + raise wtforms.ValidationError( + TOO_LONG_TAG_WARNING % (mg_globals.app_config['tags_max_length'], \ + ', '.join(too_long_tags))) + + +MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape') + +def cleaned_markdown_conversion(text): + """ + Take a block of text, run it through MarkDown, and clean its HTML. + """ + # Markdown will do nothing with and clean_html can do nothing with + # an empty string :) + if not text: + return u'' + + return clean_html(MARKDOWN_INSTANCE.convert(text)) -- cgit v1.2.3 From 152a3bfaa36d58e44979f217c5799531f780250f Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Sat, 1 Oct 2011 18:05:44 -0400 Subject: Finished splitting util.py into separate files. --- mediagoblin/app.py | 13 +- mediagoblin/auth/lib.py | 2 +- mediagoblin/auth/views.py | 2 +- mediagoblin/db/migrations.py | 2 +- mediagoblin/db/models.py | 12 +- mediagoblin/decorators.py | 2 +- mediagoblin/edit/forms.py | 6 +- mediagoblin/edit/views.py | 11 +- mediagoblin/listings/views.py | 3 +- mediagoblin/storage/__init__.py | 4 +- mediagoblin/submit/forms.py | 2 +- mediagoblin/submit/views.py | 5 +- mediagoblin/tests/test_auth.py | 10 +- mediagoblin/tests/test_tags.py | 11 +- mediagoblin/tests/test_util.py | 23 +- mediagoblin/tests/tools.py | 6 +- mediagoblin/user_pages/views.py | 7 +- mediagoblin/util.py | 699 ---------------------------------------- mediagoblin/views.py | 3 +- 19 files changed, 61 insertions(+), 762 deletions(-) delete mode 100644 mediagoblin/util.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 5ee3b973..0f25a4e5 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -20,8 +20,9 @@ import urllib import routes from webob import Request, exc -from mediagoblin import routing, util, middleware -from mediagoblin.tools import translate, template +from mediagoblin import routing, middleware +from mediagoblin.tools import common, translate, template, response +from mediagoblin.tools import request as mg_request from mediagoblin.mg_globals import setup_globals from mediagoblin.init.celery import setup_celery_from_config from mediagoblin.init import (get_jinja_loader, get_staticdirector, @@ -99,7 +100,7 @@ class MediaGoblinApp(object): setup_workbench() # instantiate application middleware - self.middleware = [util.import_component(m)(self) + self.middleware = [common.import_component(m)(self) for m in middleware.ENABLED_MIDDLEWARE] @@ -131,7 +132,7 @@ class MediaGoblinApp(object): request.db = self.db request.staticdirect = self.staticdirector - util.setup_user_in_request(request) + mg_request.setup_user_in_request(request) # No matching page? if route_match is None: @@ -149,9 +150,9 @@ class MediaGoblinApp(object): # Okay, no matches. 404 time! request.matchdict = {} # in case our template expects it - return util.render_404(request)(environ, start_response) + return response.render_404(request)(environ, start_response) - controller = util.import_component(route_match['controller']) + controller = common.import_component(route_match['controller']) request.start_response = start_response # get the response from the controller diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index bf5a2399..4c57ef88 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -19,7 +19,7 @@ import random import bcrypt -from mediagoblin.util import send_email +from mediagoblin.tools.mail import send_email from mediagoblin.tools.template import render_template from mediagoblin import mg_globals diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 9bfa93cf..88c91565 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -21,7 +21,7 @@ from webob import exc from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.util import render_to_response, redirect, render_404 +from mediagoblin.tools.response import render_to_response, redirect, render_404 from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.db.util import ObjectId, InvalidId from mediagoblin.auth import lib as auth_lib diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 755f49c5..3cafe4f8 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -15,7 +15,7 @@ # along with this program. If not, see . from mediagoblin.db.util import RegisterMigration -from mediagoblin.util import cleaned_markdown_conversion +from mediagoblin.tools.text import cleaned_markdown_conversion # Please see mediagoblin/tests/test_migrations.py for some examples of diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index eacc801c..0f5174cc 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -18,14 +18,12 @@ import datetime, uuid from mongokit import Document -from mediagoblin import util from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals from mediagoblin.db import migrations from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId -from mediagoblin.util import Pagination -from mediagoblin.util import DISPLAY_IMAGE_FETCHING_ORDER -from mediagoblin.tools import url +from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools import url, common ################### # Custom validators @@ -220,7 +218,7 @@ class MediaEntry(Document): return self.db.MediaComment.find({ 'media_entry': self['_id']}).sort('created', DESCENDING) - def get_display_media(self, media_map, fetch_order=DISPLAY_IMAGE_FETCHING_ORDER): + def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): """ Find the best media for display. @@ -234,7 +232,7 @@ class MediaEntry(Document): """ media_sizes = media_map.keys() - for media_size in DISPLAY_IMAGE_FETCHING_ORDER: + for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: if media_size in media_sizes: return media_map[media_size] @@ -304,7 +302,7 @@ class MediaEntry(Document): Get the exception that's appropriate for this error """ if self['fail_error']: - return util.import_component(self['fail_error']) + return common.import_component(self['fail_error']) class MediaComment(Document): diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 7d5978fc..19e22bca 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -17,7 +17,7 @@ from webob import exc -from mediagoblin.util import redirect, render_404 +from mediagoblin.tools.response import redirect, render_404 from mediagoblin.db.util import ObjectId, InvalidId diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index f81d58b2..7e71722c 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -14,12 +14,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - import wtforms -from mediagoblin.util import tag_length_validator, TOO_LONG_TAG_WARNING -from mediagoblin.util import fake_ugettext_passthrough as _ - +from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING +from mediagoblin.tools.translate import fake_ugettext_passthrough as _ class EditForm(wtforms.Form): title = wtforms.TextField( diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 15edfdd6..a6ddb553 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -25,14 +25,15 @@ from werkzeug.utils import secure_filename from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.util import ( - render_to_response, redirect, clean_html, convert_to_tag_list_of_dicts, - media_tags_as_string, cleaned_markdown_conversion) -from mediagoblin.util import pass_to_ugettext as _ + from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import require_active_login, get_user_media_entry - +from mediagoblin.tools.response import render_to_response, redirect +from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.text import ( + clean_html, convert_to_tag_list_of_dicts, + media_tags_as_string, cleaned_markdown_conversion) @get_user_media_entry @require_active_login diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index b3384eb4..01aad803 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -16,7 +16,8 @@ from mediagoblin.db.util import DESCENDING -from mediagoblin.util import Pagination, render_to_response +from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools.response import render_to_response from mediagoblin.decorators import uses_pagination from werkzeug.contrib.atom import AtomFeed diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py index 8665d9e5..9e592b9e 100644 --- a/mediagoblin/storage/__init__.py +++ b/mediagoblin/storage/__init__.py @@ -21,7 +21,7 @@ import uuid from werkzeug.utils import secure_filename -from mediagoblin import util +from mediagoblin.tools import common ######## # Errors @@ -236,5 +236,5 @@ def storage_system_from_config(config_section): else: storage_class = 'mediagoblin.storage.filestorage:BasicFileStorage' - storage_class = util.import_component(storage_class) + storage_class = common.import_component(storage_class) return storage_class(**config_params) diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 200ce4e4..25d6e304 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -17,7 +17,7 @@ import wtforms -from mediagoblin.util import tag_length_validator +from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import fake_ugettext_passthrough as _ diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index cd34e006..7134235e 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -22,10 +22,9 @@ from cgi import FieldStorage from werkzeug.utils import secure_filename from mediagoblin.db.util import ObjectId -from mediagoblin.util import ( - render_to_response, redirect, cleaned_markdown_conversion, \ - convert_to_tag_list_of_dicts) +from mediagoblin.tools.text import cleaned_markdown_conversion, convert_to_tag_list_of_dicts from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.process_media import process_media, mark_entry_failed diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index f00456c4..40961eca 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -22,7 +22,7 @@ from nose.tools import assert_equal from mediagoblin.auth import lib as auth_lib from mediagoblin.tests.tools import setup_fresh_app from mediagoblin import mg_globals -from mediagoblin.tools import template +from mediagoblin.tools import template, mail ######################## @@ -171,8 +171,8 @@ def test_register_views(test_app): assert request.session['user_id'] == unicode(new_user['_id']) ## Make sure we get email confirmation, and try verifying - assert len(template.EMAIL_TEST_INBOX) == 1 - message = template.EMAIL_TEST_INBOX.pop() + assert len(mail.EMAIL_TEST_INBOX) == 1 + message = mail.EMAIL_TEST_INBOX.pop() assert message['To'] == 'happygrrl@example.org' email_context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/auth/verification_email.txt'] @@ -254,8 +254,8 @@ def test_register_views(test_app): 'mediagoblin/auth/fp_email_sent.html') ## Make sure link to change password is sent by email - assert len(template.EMAIL_TEST_INBOX) == 1 - message = template.EMAIL_TEST_INBOX.pop() + assert len(mail.EMAIL_TEST_INBOX) == 1 + message = mail.EMAIL_TEST_INBOX.pop() assert message['To'] == 'happygrrl@example.org' email_context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/auth/fp_verification_email.txt'] diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py index d4628795..a05831c9 100644 --- a/mediagoblin/tests/test_tags.py +++ b/mediagoblin/tests/test_tags.py @@ -15,9 +15,8 @@ # along with this program. If not, see . from mediagoblin.tests.tools import setup_fresh_app -from mediagoblin import util from mediagoblin import mg_globals - +from mediagoblin.tools import text @setup_fresh_app def test_list_of_dicts_conversion(test_app): @@ -28,23 +27,23 @@ def test_list_of_dicts_conversion(test_app): function performs the reverse operation when populating a form to edit tags. """ # Leading, trailing, and internal whitespace should be removed and slugified - assert util.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [ + assert text.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [ {'name': u'sleep', 'slug': u'sleep'}, {'name': u'6 AM', 'slug': u'6-am'}, {'name': u'chainsaw!', 'slug': u'chainsaw'}] # If the user enters two identical tags, record only one of them - assert util.convert_to_tag_list_of_dicts('echo,echo') == [{'name': u'echo', + assert text.convert_to_tag_list_of_dicts('echo,echo') == [{'name': u'echo', 'slug': u'echo'}] # Make sure converting the list of dicts to a string works - assert util.media_tags_as_string([{'name': u'yin', 'slug': u'yin'}, + assert text.media_tags_as_string([{'name': u'yin', 'slug': u'yin'}, {'name': u'yang', 'slug': u'yang'}]) == \ u'yin,yang' # If the tag delimiter is a space then we expect different results mg_globals.app_config['tags_delimiter'] = u' ' - assert util.convert_to_tag_list_of_dicts('unicorn ceramic nazi') == [ + assert text.convert_to_tag_list_of_dicts('unicorn ceramic nazi') == [ {'name': u'unicorn', 'slug': u'unicorn'}, {'name': u'ceramic', 'slug': u'ceramic'}, {'name': u'nazi', 'slug': u'nazi'}] diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index cdc62b7d..48fa8669 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -16,10 +16,9 @@ import email -from mediagoblin import util -from mediagoblin.tools import url, translate +from mediagoblin.tools import common, url, translate, mail, text, testing -util._activate_testing() +testing._activate_testing() def _import_component_testing_method(silly_string): @@ -28,7 +27,7 @@ def _import_component_testing_method(silly_string): def test_import_component(): - imported_func = util.import_component( + imported_func = common.import_component( 'mediagoblin.tests.test_util:_import_component_testing_method') result = imported_func('hooobaladoobala') expected = u"'hooobaladoobala' is the silliest string I've ever seen" @@ -36,10 +35,10 @@ def test_import_component(): def test_send_email(): - util._clear_test_inboxes() + mail._clear_test_inboxes() # send the email - util.send_email( + mail.send_email( "sender@mediagoblin.example.org", ["amanda@example.org", "akila@example.org"], "Testing is so much fun!", @@ -48,8 +47,8 @@ def test_send_email(): I hope you like unit tests JUST AS MUCH AS I DO!""") # check the main inbox - assert len(util.EMAIL_TEST_INBOX) == 1 - message = util.EMAIL_TEST_INBOX.pop() + assert len(mail.EMAIL_TEST_INBOX) == 1 + message = mail.EMAIL_TEST_INBOX.pop() assert message['From'] == "sender@mediagoblin.example.org" assert message['To'] == "amanda@example.org, akila@example.org" assert message['Subject'] == "Testing is so much fun!" @@ -58,8 +57,8 @@ I hope you like unit tests JUST AS MUCH AS I DO!""") I hope you like unit tests JUST AS MUCH AS I DO!""" # Check everything that the FakeMhost.sendmail() method got is correct - assert len(util.EMAIL_TEST_MBOX_INBOX) == 1 - mbox_dict = util.EMAIL_TEST_MBOX_INBOX.pop() + assert len(mail.EMAIL_TEST_MBOX_INBOX) == 1 + mbox_dict = mail.EMAIL_TEST_MBOX_INBOX.pop() assert mbox_dict['from'] == "sender@mediagoblin.example.org" assert mbox_dict['to'] == ["amanda@example.org", "akila@example.org"] mbox_message = email.message_from_string(mbox_dict['message']) @@ -107,7 +106,7 @@ def test_locale_to_lower_lower(): def test_html_cleaner(): # Remove images - result = util.clean_html( + result = text.clean_html( '

Hi everybody! ' '

\n' '

:)

') @@ -118,7 +117,7 @@ def test_html_cleaner(): '') # Remove evil javascript - result = util.clean_html( + result = text.clean_html( '

innocent link!

') assert result == ( '

innocent link!

') diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 308e83ee..cf84da14 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -21,7 +21,7 @@ import os, shutil from paste.deploy import loadapp from webtest import TestApp -from mediagoblin import util +from mediagoblin.tools import testing from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.decorators import _make_safe from mediagoblin.db.open import setup_connection_and_db_from_config @@ -59,7 +59,7 @@ def get_test_app(dump_old_app=True): suicide_if_bad_celery_environ() # Make sure we've turned on testing - util._activate_testing() + testing._activate_testing() # Leave this imported as it sets up celery. from mediagoblin.init.celery import from_tests @@ -117,7 +117,7 @@ def setup_fresh_app(func): """ def wrapper(*args, **kwargs): test_app = get_test_app() - util.clear_test_buckets() + testing.clear_test_buckets() return func(test_app, *args, **kwargs) return _make_safe(wrapper, func) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 40c7ffce..9cec74dc 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,10 +18,11 @@ from webob import exc from mediagoblin import messages, mg_globals from mediagoblin.db.util import DESCENDING, ObjectId -from mediagoblin.util import ( - Pagination, render_to_response, redirect, cleaned_markdown_conversion, - render_404, delete_media_files) +from mediagoblin.tools.text import cleaned_markdown_conversion +from mediagoblin.tools.response import render_to_response, render_404, redirect from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools.files import delete_media_files from mediagoblin.user_pages import forms as user_forms from mediagoblin.decorators import (uses_pagination, get_user_media_entry, diff --git a/mediagoblin/util.py b/mediagoblin/util.py deleted file mode 100644 index 35755ccf..00000000 --- a/mediagoblin/util.py +++ /dev/null @@ -1,699 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from __future__ import division - -from email.MIMEText import MIMEText -#import gettext -#import pkg_resources -import smtplib -import sys -#import re -#import translitcodec -import urllib -from math import ceil, floor -import copy -import wtforms - -#from babel.localedata import exists -#from babel.support import LazyProxy -#import jinja2 -from webob import Response, exc -from lxml.html.clean import Cleaner -import markdown -from wtforms.form import Form - -from mediagoblin import mg_globals -#from mediagoblin import messages -from mediagoblin.db.util import ObjectId -from mediagoblin.tools import url -from mediagoblin.tools import common -from mediagoblin.tools.template import TEMPLATE_TEST_CONTEXT, render_template - -from itertools import izip, count - -DISPLAY_IMAGE_FETCHING_ORDER = [u'medium', u'original', u'thumb'] - -def _activate_testing(): - """ - Call this to activate testing in util.py - """ - - common.TESTS_ENABLED = True - -def clear_test_buckets(): - """ - We store some things for testing purposes that should be cleared - when we want a "clean slate" of information for our next round of - tests. Call this function to wipe all that stuff clean. - - Also wipes out some other things we might redefine during testing, - like the jinja envs. - """ - global SETUP_JINJA_ENVS - SETUP_JINJA_ENVS = {} - - global EMAIL_TEST_INBOX - global EMAIL_TEST_MBOX_INBOX - EMAIL_TEST_INBOX = [] - EMAIL_TEST_MBOX_INBOX = [] - - clear_test_template_context() - - -# SETUP_JINJA_ENVS = {} - - -# def get_jinja_env(template_loader, locale): -# """ -# Set up the Jinja environment, - -# (In the future we may have another system for providing theming; -# for now this is good enough.) -# """ -# setup_gettext(locale) - -# # If we have a jinja environment set up with this locale, just -# # return that one. -# if SETUP_JINJA_ENVS.has_key(locale): -# return SETUP_JINJA_ENVS[locale] - -# template_env = jinja2.Environment( -# loader=template_loader, autoescape=True, -# extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) - -# template_env.install_gettext_callables( -# mg_globals.translations.ugettext, -# mg_globals.translations.ungettext) - -# # All templates will know how to ... -# # ... fetch all waiting messages and remove them from the queue -# # ... construct a grid of thumbnails or other media -# template_env.globals['fetch_messages'] = messages.fetch_messages -# template_env.globals['gridify_list'] = gridify_list -# template_env.globals['gridify_cursor'] = gridify_cursor - -# if exists(locale): -# SETUP_JINJA_ENVS[locale] = template_env - -# return template_env - - -# # We'll store context information here when doing unit tests -# TEMPLATE_TEST_CONTEXT = {} - - -# def render_template(request, template_path, context): -# """ -# Render a template with context. - -# Always inserts the request into the context, so you don't have to. -# Also stores the context if we're doing unit tests. Helpful! -# """ -# template = request.template_env.get_template( -# template_path) -# context['request'] = request -# rendered = template.render(context) - -# if TESTS_ENABLED: -# TEMPLATE_TEST_CONTEXT[template_path] = context - -# return rendered - - -def clear_test_template_context(): - global TEMPLATE_TEST_CONTEXT - TEMPLATE_TEST_CONTEXT = {} - - -def render_to_response(request, template, context, status=200): - """Much like Django's shortcut.render()""" - return Response( - render_template(request, template, context), - status=status) - - -def redirect(request, *args, **kwargs): - """Returns a HTTPFound(), takes a request and then urlgen params""" - - querystring = None - if kwargs.get('querystring'): - querystring = kwargs.get('querystring') - del kwargs['querystring'] - - return exc.HTTPFound( - location=''.join([ - request.urlgen(*args, **kwargs), - querystring if querystring else ''])) - - -def setup_user_in_request(request): - """ - Examine a request and tack on a request.user parameter if that's - appropriate. - """ - if not request.session.has_key('user_id'): - request.user = None - return - - user = None - user = request.app.db.User.one( - {'_id': ObjectId(request.session['user_id'])}) - - if not user: - # Something's wrong... this user doesn't exist? Invalidate - # this session. - request.session.invalidate() - - request.user = user - - -def import_component(import_string): - """ - Import a module component defined by STRING. Probably a method, - class, or global variable. - - Args: - - import_string: a string that defines what to import. Written - in the format of "module1.module2:component" - """ - module_name, func_name = import_string.split(':', 1) - __import__(module_name) - module = sys.modules[module_name] - func = getattr(module, func_name) - return func - -# _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') - -# def slugify(text, delim=u'-'): -# """ -# Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ -# """ -# result = [] -# for word in _punct_re.split(text.lower()): -# word = word.encode('translit/long') -# if word: -# result.append(word) -# return unicode(delim.join(result)) - -### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -### Special email test stuff begins HERE -### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -# We have two "test inboxes" here: -# -# EMAIL_TEST_INBOX: -# ---------------- -# If you're writing test views, you'll probably want to check this. -# It contains a list of MIMEText messages. -# -# EMAIL_TEST_MBOX_INBOX: -# ---------------------- -# This collects the messages from the FakeMhost inbox. It's reslly -# just here for testing the send_email method itself. -# -# Anyway this contains: -# - from -# - to: a list of email recipient addresses -# - message: not just the body, but the whole message, including -# headers, etc. -# -# ***IMPORTANT!*** -# ---------------- -# Before running tests that call functions which send email, you should -# always call _clear_test_inboxes() to "wipe" the inboxes clean. - -EMAIL_TEST_INBOX = [] -EMAIL_TEST_MBOX_INBOX = [] - - -class FakeMhost(object): - """ - Just a fake mail host so we can capture and test messages - from send_email - """ - def login(self, *args, **kwargs): - pass - - def sendmail(self, from_addr, to_addrs, message): - EMAIL_TEST_MBOX_INBOX.append( - {'from': from_addr, - 'to': to_addrs, - 'message': message}) - -def _clear_test_inboxes(): - global EMAIL_TEST_INBOX - global EMAIL_TEST_MBOX_INBOX - EMAIL_TEST_INBOX = [] - EMAIL_TEST_MBOX_INBOX = [] - -### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -### -### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -def send_email(from_addr, to_addrs, subject, message_body): - """ - Simple email sending wrapper, use this so we can capture messages - for unit testing purposes. - - Args: - - from_addr: address you're sending the email from - - to_addrs: list of recipient email addresses - - subject: subject of the email - - message_body: email body text - """ - if common.TESTS_ENABLED or mg_globals.app_config['email_debug_mode']: - mhost = FakeMhost() - elif not mg_globals.app_config['email_debug_mode']: - mhost = smtplib.SMTP( - mg_globals.app_config['email_smtp_host'], - mg_globals.app_config['email_smtp_port']) - - # SMTP.__init__ Issues SMTP.connect implicitly if host - if not mg_globals.app_config['email_smtp_host']: # e.g. host = '' - mhost.connect() # We SMTP.connect explicitly - - if mg_globals.app_config['email_smtp_user'] \ - or mg_globals.app_config['email_smtp_pass']: - mhost.login( - mg_globals.app_config['email_smtp_user'], - mg_globals.app_config['email_smtp_pass']) - - message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8') - message['Subject'] = subject - message['From'] = from_addr - message['To'] = ', '.join(to_addrs) - - if common.TESTS_ENABLED: - EMAIL_TEST_INBOX.append(message) - - if mg_globals.app_config['email_debug_mode']: - print u"===== Email =====" - print u"From address: %s" % message['From'] - print u"To addresses: %s" % message['To'] - print u"Subject: %s" % message['Subject'] - print u"-- Body: --" - print message.get_payload(decode=True) - - return mhost.sendmail(from_addr, to_addrs, message.as_string()) - - -# ################### -# # Translation tools -# ################### - - -# TRANSLATIONS_PATH = pkg_resources.resource_filename( -# 'mediagoblin', 'i18n') - - -# def locale_to_lower_upper(locale): -# """ -# Take a locale, regardless of style, and format it like "en-us" -# """ -# if '-' in locale: -# lang, country = locale.split('-', 1) -# return '%s_%s' % (lang.lower(), country.upper()) -# elif '_' in locale: -# lang, country = locale.split('_', 1) -# return '%s_%s' % (lang.lower(), country.upper()) -# else: -# return locale.lower() - - -# def locale_to_lower_lower(locale): -# """ -# Take a locale, regardless of style, and format it like "en_US" -# """ -# if '_' in locale: -# lang, country = locale.split('_', 1) -# return '%s-%s' % (lang.lower(), country.lower()) -# else: -# return locale.lower() - - -# def get_locale_from_request(request): -# """ -# Figure out what target language is most appropriate based on the -# request -# """ -# request_form = request.GET or request.POST - -# if request_form.has_key('lang'): -# return locale_to_lower_upper(request_form['lang']) - -# accept_lang_matches = request.accept_language.best_matches() - -# # Your routing can explicitly specify a target language -# matchdict = request.matchdict or {} - -# if matchdict.has_key('locale'): -# target_lang = matchdict['locale'] -# elif request.session.has_key('target_lang'): -# target_lang = request.session['target_lang'] -# # Pull the first acceptable language -# elif accept_lang_matches: -# target_lang = accept_lang_matches[0] -# # Fall back to English -# else: -# target_lang = 'en' - -# return locale_to_lower_upper(target_lang) - - -# A super strict version of the lxml.html cleaner class -HTML_CLEANER = Cleaner( - scripts=True, - javascript=True, - comments=True, - style=True, - links=True, - page_structure=True, - processing_instructions=True, - embedded=True, - frames=True, - forms=True, - annoying_tags=True, - allow_tags=[ - 'div', 'b', 'i', 'em', 'strong', 'p', 'ul', 'ol', 'li', 'a', 'br'], - remove_unknown_tags=False, # can't be used with allow_tags - safe_attrs_only=True, - add_nofollow=True, # for now - host_whitelist=(), - whitelist_tags=set([])) - - -def clean_html(html): - # clean_html barfs on an empty string - if not html: - return u'' - - return HTML_CLEANER.clean_html(html) - - -def convert_to_tag_list_of_dicts(tag_string): - """ - Filter input from incoming string containing user tags, - - Strips trailing, leading, and internal whitespace, and also converts - the "tags" text into an array of tags - """ - taglist = [] - if tag_string: - - # Strip out internal, trailing, and leading whitespace - stripped_tag_string = u' '.join(tag_string.strip().split()) - - # Split the tag string into a list of tags - for tag in stripped_tag_string.split( - mg_globals.app_config['tags_delimiter']): - - # Ignore empty or duplicate tags - if tag.strip() and tag.strip() not in [t['name'] for t in taglist]: - - taglist.append({'name': tag.strip(), - 'slug': url.slugify(tag.strip())}) - return taglist - - -def media_tags_as_string(media_entry_tags): - """ - Generate a string from a media item's tags, stored as a list of dicts - - This is the opposite of convert_to_tag_list_of_dicts - """ - media_tag_string = '' - if media_entry_tags: - media_tag_string = mg_globals.app_config['tags_delimiter'].join( - [tag['name'] for tag in media_entry_tags]) - return media_tag_string - -TOO_LONG_TAG_WARNING = \ - u'Tags must be shorter than %s characters. Tags that are too long: %s' - -def tag_length_validator(form, field): - """ - Make sure tags do not exceed the maximum tag length. - """ - tags = convert_to_tag_list_of_dicts(field.data) - too_long_tags = [ - tag['name'] for tag in tags - if len(tag['name']) > mg_globals.app_config['tags_max_length']] - - if too_long_tags: - raise wtforms.ValidationError( - TOO_LONG_TAG_WARNING % (mg_globals.app_config['tags_max_length'], \ - ', '.join(too_long_tags))) - - -MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape') - -def cleaned_markdown_conversion(text): - """ - Take a block of text, run it through MarkDown, and clean its HTML. - """ - # Markdown will do nothing with and clean_html can do nothing with - # an empty string :) - if not text: - return u'' - - return clean_html(MARKDOWN_INSTANCE.convert(text)) - - -# SETUP_GETTEXTS = {} - -# def setup_gettext(locale): -# """ -# Setup the gettext instance based on this locale -# """ -# # Later on when we have plugins we may want to enable the -# # multi-translations system they have so we can handle plugin -# # translations too - -# # TODO: fallback nicely on translations from pt_PT to pt if not -# # available, etc. -# if SETUP_GETTEXTS.has_key(locale): -# this_gettext = SETUP_GETTEXTS[locale] -# else: -# this_gettext = gettext.translation( -# 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) -# if exists(locale): -# SETUP_GETTEXTS[locale] = this_gettext - -# mg_globals.setup_globals( -# translations=this_gettext) - - -# # Force en to be setup before anything else so that -# # mg_globals.translations is never None -# setup_gettext('en') - - -# def pass_to_ugettext(*args, **kwargs): -# """ -# Pass a translation on to the appropriate ugettext method. - -# The reason we can't have a global ugettext method is because -# mg_globals gets swapped out by the application per-request. -# """ -# return mg_globals.translations.ugettext( -# *args, **kwargs) - - -# def lazy_pass_to_ugettext(*args, **kwargs): -# """ -# Lazily pass to ugettext. - -# This is useful if you have to define a translation on a module -# level but you need it to not translate until the time that it's -# used as a string. -# """ -# return LazyProxy(pass_to_ugettext, *args, **kwargs) - - -# def pass_to_ngettext(*args, **kwargs): -# """ -# Pass a translation on to the appropriate ngettext method. - -# The reason we can't have a global ngettext method is because -# mg_globals gets swapped out by the application per-request. -# """ -# return mg_globals.translations.ngettext( -# *args, **kwargs) - - -# def lazy_pass_to_ngettext(*args, **kwargs): -# """ -# Lazily pass to ngettext. - -# This is useful if you have to define a translation on a module -# level but you need it to not translate until the time that it's -# used as a string. -# """ -# return LazyProxy(pass_to_ngettext, *args, **kwargs) - - -# def fake_ugettext_passthrough(string): -# """ -# Fake a ugettext call for extraction's sake ;) - -# In wtforms there's a separate way to define a method to translate -# things... so we just need to mark up the text so that it can be -# extracted, not so that it's actually run through gettext. -# """ -# return string - - -PAGINATION_DEFAULT_PER_PAGE = 30 - -class Pagination(object): - """ - Pagination class for mongodb queries. - - Initialization through __init__(self, cursor, page=1, per_page=2), - get actual data slice through __call__(). - """ - - def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE, - jump_to_id=False): - """ - Initializes Pagination - - Args: - - page: requested page - - per_page: number of objects per page - - cursor: db cursor - - jump_to_id: ObjectId, sets the page to the page containing the object - with _id == jump_to_id. - """ - self.page = page - self.per_page = per_page - self.cursor = cursor - self.total_count = self.cursor.count() - self.active_id = None - - if jump_to_id: - cursor = copy.copy(self.cursor) - - for (doc, increment) in izip(cursor, count(0)): - if doc['_id'] == jump_to_id: - self.page = 1 + int(floor(increment / self.per_page)) - - self.active_id = jump_to_id - break - - - def __call__(self): - """ - Returns slice of objects for the requested page - """ - return self.cursor.skip( - (self.page - 1) * self.per_page).limit(self.per_page) - - @property - def pages(self): - return int(ceil(self.total_count / float(self.per_page))) - - @property - def has_prev(self): - return self.page > 1 - - @property - def has_next(self): - return self.page < self.pages - - def iter_pages(self, left_edge=2, left_current=2, - right_current=5, right_edge=2): - last = 0 - for num in xrange(1, self.pages + 1): - if num <= left_edge or \ - (num > self.page - left_current - 1 and \ - num < self.page + right_current) or \ - num > self.pages - right_edge: - if last + 1 != num: - yield None - yield num - last = num - - def get_page_url_explicit(self, base_url, get_params, page_no): - """ - Get a page url by adding a page= parameter to the base url - """ - new_get_params = copy.copy(get_params or {}) - new_get_params['page'] = page_no - return "%s?%s" % ( - base_url, urllib.urlencode(new_get_params)) - - def get_page_url(self, request, page_no): - """ - Get a new page url based of the request, and the new page number. - - This is a nice wrapper around get_page_url_explicit() - """ - return self.get_page_url_explicit( - request.path_info, request.GET, page_no) - - -# def gridify_list(this_list, num_cols=5): -# """ -# Generates a list of lists where each sub-list's length depends on -# the number of columns in the list -# """ -# grid = [] - -# # Figure out how many rows we should have -# num_rows = int(ceil(float(len(this_list)) / num_cols)) - -# for row_num in range(num_rows): -# slice_min = row_num * num_cols -# slice_max = (row_num + 1) * num_cols - -# row = this_list[slice_min:slice_max] - -# grid.append(row) - -# return grid - - -# def gridify_cursor(this_cursor, num_cols=5): -# """ -# Generates a list of lists where each sub-list's length depends on -# the number of columns in the list -# """ -# return gridify_list(list(this_cursor), num_cols) - - -def render_404(request): - """ - Render a 404. - """ - return render_to_response( - request, 'mediagoblin/404.html', {}, status=400) - -def delete_media_files(media): - """ - Delete all files associated with a MediaEntry - - Arguments: - - media: A MediaEntry document - """ - for listpath in media['media_files'].itervalues(): - mg_globals.public_store.delete_file( - listpath) - - for attachment in media['attachment_files']: - mg_globals.public_store.delete_file( - attachment['filepath']) diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 96687f96..22f9268d 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -15,7 +15,8 @@ # along with this program. If not, see . from mediagoblin import mg_globals -from mediagoblin.util import render_to_response, Pagination +from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools.response import render_to_response from mediagoblin.db.util import DESCENDING from mediagoblin.decorators import uses_pagination -- cgit v1.2.3 From 243c3843bd574129caa7663e25d1a843b2d2dd30 Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 15:10:02 -0700 Subject: Whitespace and formatting cleanup. * Removed trailing whitespace * Line length < 80 where possible * Honor conventions on number of blank lines * Honor conventions about spaces around :, = --- mediagoblin/app.py | 3 +-- mediagoblin/auth/forms.py | 8 +++---- mediagoblin/auth/lib.py | 3 ++- mediagoblin/auth/routing.py | 3 ++- mediagoblin/auth/views.py | 3 +-- mediagoblin/db/__init__.py | 2 +- mediagoblin/db/indexes.py | 5 ++-- mediagoblin/db/migrations.py | 2 +- mediagoblin/db/models.py | 35 +++++++++++++-------------- mediagoblin/db/open.py | 2 +- mediagoblin/db/util.py | 5 ++-- mediagoblin/decorators.py | 2 +- mediagoblin/edit/__init__.py | 2 -- mediagoblin/edit/views.py | 2 +- mediagoblin/gmg_commands/__init__.py | 3 +-- mediagoblin/gmg_commands/import_export.py | 7 +++--- mediagoblin/gmg_commands/migrate.py | 4 ++-- mediagoblin/gmg_commands/users.py | 7 +++--- mediagoblin/init/__init__.py | 18 ++++++++------ mediagoblin/init/celery/__init__.py | 2 +- mediagoblin/init/celery/from_celery.py | 2 +- mediagoblin/init/config.py | 2 +- mediagoblin/listings/routing.py | 1 - mediagoblin/listings/views.py | 3 ++- mediagoblin/messages.py | 2 ++ mediagoblin/middleware/noop.py | 1 + mediagoblin/process_media/__init__.py | 18 +++++++------- mediagoblin/process_media/errors.py | 9 +++---- mediagoblin/storage/cloudfiles.py | 1 + mediagoblin/submit/__init__.py | 2 -- mediagoblin/submit/security.py | 2 +- mediagoblin/submit/views.py | 16 +++++++------ mediagoblin/user_pages/__init__.py | 2 -- mediagoblin/user_pages/views.py | 13 +++++++---- mediagoblin/util.py | 39 ++++++++++++++++++------------- mediagoblin/views.py | 1 + mediagoblin/workbench.py | 4 +++- setup.py | 12 +++++----- 38 files changed, 135 insertions(+), 113 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index dd5f0b89..9bbccf24 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -91,7 +91,7 @@ class MediaGoblinApp(object): # object. ####################################################### - setup_globals(app = self) + setup_globals(app=self) # Workbench *currently* only used by celery, so this only # matters in always eager mode :) @@ -101,7 +101,6 @@ class MediaGoblinApp(object): self.middleware = [util.import_component(m)(self) for m in middleware.ENABLED_MIDDLEWARE] - def __call__(self, environ, start_response): request = Request(environ) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 6339b4a3..aadb5888 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -59,9 +59,10 @@ class ForgotPassForm(wtforms.Form): 'Username or email', [wtforms.validators.Required()]) - def validate_username(form,field): - if not (re.match(r'^\w+$',field.data) or - re.match(r'^.+@[^.].*\.[a-z]{2,10}$',field.data, re.IGNORECASE)): + def validate_username(form, field): + if not (re.match(r'^\w+$', field.data) or + re.match(r'^.+@[^.].*\.[a-z]{2,10}$', field.data, + re.IGNORECASE)): raise wtforms.ValidationError(u'Incorrect input') @@ -82,4 +83,3 @@ class ChangePassForm(wtforms.Form): token = wtforms.HiddenField( '', [wtforms.validators.Required()]) - diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index d7d351a5..0ecccbb5 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -93,6 +93,7 @@ EMAIL_VERIFICATION_TEMPLATE = ( u"http://{host}{uri}?" u"userid={userid}&token={verification_key}") + def send_verification_email(user, request): """ Send the verification email to users to activate their accounts. @@ -127,6 +128,7 @@ EMAIL_FP_VERIFICATION_TEMPLATE = ( u"http://{host}{uri}?" u"userid={userid}&token={fp_verification_key}") + def send_fp_verification_email(user, request): """ Send the verification email to users to change their password. @@ -150,4 +152,3 @@ def send_fp_verification_email(user, request): [user['email']], 'GNU MediaGoblin - Change forgotten password!', rendered_email) - diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 912d89fa..365ccfaa 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -33,7 +33,8 @@ auth_routes = [ controller='mediagoblin.views:simple_template_render'), Route('mediagoblin.auth.forgot_password', '/forgot_password/', controller='mediagoblin.auth.views:forgot_password'), - Route('mediagoblin.auth.verify_forgot_password', '/forgot_password/verify/', + Route('mediagoblin.auth.verify_forgot_password', + '/forgot_password/verify/', controller='mediagoblin.auth.views:verify_forgot_password'), Route('mediagoblin.auth.fp_changed_success', '/forgot_password/changed_success/', diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index f67f0588..afcfcf1e 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -233,8 +233,7 @@ def forgot_password(request): request, 'mediagoblin.user_pages.user_home', user=user['username']) - - # do not reveal whether or not there is a matching user, just move along + # do not reveal whether or not there is a matching user return redirect(request, 'mediagoblin.auth.fp_email_sent') return render_to_response( diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py index c5124b1a..27e8a90f 100644 --- a/mediagoblin/db/__init__.py +++ b/mediagoblin/db/__init__.py @@ -23,7 +23,7 @@ Database Abstraction/Wrapper Layer pymongo. Read beow for why, but note that nobody is actually doing this and there's no proof that we'll ever support more than MongoDB... it would be a huge amount of work to do so. - + If you really want to prove that possible, jump on IRC and talk to us about making such a branch. In the meanwhile, it doesn't hurt to have things as they are... if it ever makes it hard for us to diff --git a/mediagoblin/db/indexes.py b/mediagoblin/db/indexes.py index 75394a31..1dd73f2b 100644 --- a/mediagoblin/db/indexes.py +++ b/mediagoblin/db/indexes.py @@ -93,8 +93,9 @@ MEDIAENTRY_INDEXES = { ('created', DESCENDING)]}, 'state_uploader_tags_created': { - # Indexing on processed?, media uploader, associated tags, and timestamp - # Used for showing media items matching a tag search, most recent first. + # Indexing on processed?, media uploader, associated tags, and + # timestamp Used for showing media items matching a tag + # search, most recent first. 'index': [('state', ASCENDING), ('uploader', ASCENDING), ('tags.slug', DESCENDING), diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 755f49c5..28bb62fc 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -87,7 +87,7 @@ def mediaentry_add_fail_error_and_metadata(database): {'fail_error': {'$exists': False}}, {'$set': {'fail_error': None}}, multi=True) - + collection.update( {'fail_metadata': {'$exists': False}}, {'$set': {'fail_metadata': {}}}, diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index bbddada6..42db3f83 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -14,7 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import datetime, uuid +import datetime +import uuid from mongokit import Document @@ -69,17 +70,17 @@ class User(Document): 'username': unicode, 'email': unicode, 'created': datetime.datetime, - 'plugin_data': dict, # plugins can dump stuff here. + 'plugin_data': dict, # plugins can dump stuff here. 'pw_hash': unicode, 'email_verified': bool, 'status': unicode, 'verification_key': unicode, 'is_admin': bool, - 'url' : unicode, - 'bio' : unicode, # May contain markdown - 'bio_html': unicode, # May contain plaintext, or HTML - 'fp_verification_key': unicode, # forgotten password verification key - 'fp_token_expire': datetime.datetime + 'url': unicode, + 'bio': unicode, # May contain markdown + 'bio_html': unicode, # May contain plaintext, or HTML + 'fp_verification_key': unicode, # forgotten password verification key + 'fp_token_expire': datetime.datetime, } required_fields = ['username', 'created', 'pw_hash', 'email'] @@ -174,8 +175,8 @@ class MediaEntry(Document): critical to this piece of media but may be usefully relevant to people viewing the work. (currently unused.) - - fail_error: path to the exception raised - - fail_metadata: + - fail_error: path to the exception raised + - fail_metadata: """ __collection__ = 'media_entries' @@ -184,11 +185,11 @@ class MediaEntry(Document): 'title': unicode, 'slug': unicode, 'created': datetime.datetime, - 'description': unicode, # May contain markdown/up - 'description_html': unicode, # May contain plaintext, or HTML + 'description': unicode, # May contain markdown/up + 'description_html': unicode, # May contain plaintext, or HTML 'media_type': unicode, - 'media_data': dict, # extra data relevant to this media_type - 'plugin_data': dict, # plugins can dump stuff here. + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. 'tags': [dict], 'state': unicode, @@ -220,7 +221,8 @@ class MediaEntry(Document): return self.db.MediaComment.find({ 'media_entry': self['_id']}).sort('created', DESCENDING) - def get_display_media(self, media_map, fetch_order=DISPLAY_IMAGE_FETCHING_ORDER): + def get_display_media(self, media_map, + fetch_order=DISPLAY_IMAGE_FETCHING_ORDER): """ Find the best media for display. @@ -273,7 +275,7 @@ class MediaEntry(Document): """ Provide a url to the previous entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']}, + cursor = self.db.MediaEntry.find({'_id': {"$gt": self['_id']}, 'uploader': self['uploader'], 'state': 'processed'}).sort( '_id', ASCENDING).limit(1) @@ -286,7 +288,7 @@ class MediaEntry(Document): """ Provide a url to the next entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']}, + cursor = self.db.MediaEntry.find({'_id': {"$lt": self['_id']}, 'uploader': self['uploader'], 'state': 'processed'}).sort( '_id', DESCENDING).limit(1) @@ -353,4 +355,3 @@ def register_models(connection): Register all models in REGISTER_MODELS with this connection. """ connection.register(REGISTER_MODELS) - diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py index e73b6258..e677ba12 100644 --- a/mediagoblin/db/open.py +++ b/mediagoblin/db/open.py @@ -29,7 +29,7 @@ def connect_database_from_config(app_config, use_pymongo=False): port = app_config.get('db_port') if port: port = asint(port) - + if use_pymongo: connection = pymongo.Connection( app_config.get('db_host'), port) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 84a6cbce..38f0233f 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -118,11 +118,12 @@ def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES): ################# # The default migration registry... -# +# # Don't set this yourself! RegisterMigration will automatically fill # this with stuff via decorating methods in migrations.py -class MissingCurrentMigration(Exception): pass +class MissingCurrentMigration(Exception): + pass MIGRATIONS = {} diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 7d5978fc..204ac47a 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -119,6 +119,7 @@ def get_user_media_entry(controller): return _make_safe(wrapper, controller) + def get_media_entry_by_id(controller): """ Pass in a MediaEntry based off of a url component @@ -138,4 +139,3 @@ def get_media_entry_by_id(controller): return controller(request, media=media, *args, **kwargs) return _make_safe(wrapper, controller) - diff --git a/mediagoblin/edit/__init__.py b/mediagoblin/edit/__init__.py index 576bd0f5..ba347c69 100644 --- a/mediagoblin/edit/__init__.py +++ b/mediagoblin/edit/__init__.py @@ -13,5 +13,3 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - - diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 15edfdd6..d15461c0 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -119,7 +119,7 @@ def edit_attachments(request, media): name=request.POST['attachment_name'] \ or request.POST['attachment_file'].filename, filepath=attachment_public_filepath, - created=datetime.utcnow() + created=datetime.utcnow(), )) media.save() diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 0071c65b..b3f69ccc 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -28,7 +28,7 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.migrate:migrate_parser_setup', 'func': 'mediagoblin.gmg_commands.migrate:migrate', 'help': 'Apply all unapplied bulk migrations to the database'}, - 'adduser':{ + 'adduser': { 'setup': 'mediagoblin.gmg_commands.users:adduser_parser_setup', 'func': 'mediagoblin.gmg_commands.users:adduser', 'help': 'Creates an user'}, @@ -80,4 +80,3 @@ def main_cli(): if __name__ == '__main__': main_cli() - diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 05edbfc8..962e545c 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -91,7 +91,7 @@ def _import_database(db, args): args.mongorestore_path, '-d', db.name, os.path.join(args._cache_path['database'], db.name)]) - + p.wait() _log.info('...Database imported') @@ -229,7 +229,8 @@ def env_export(args): ''' if args.cache_path: if os.path.exists(args.cache_path): - _log.error('The cache directory must not exist before you run this script') + _log.error('The cache directory must not exist ' + 'before you run this script') _log.error('Cache directory: {0}'.format(args.cache_path)) return False @@ -245,7 +246,7 @@ def env_export(args): globa_config, app_config = setup_global_and_app_config(args.conf_file) setup_storage() - + connection, db = setup_connection_and_db_from_config( app_config, use_pymongo=True) diff --git a/mediagoblin/gmg_commands/migrate.py b/mediagoblin/gmg_commands/migrate.py index 1a597188..e6dd6f78 100644 --- a/mediagoblin/gmg_commands/migrate.py +++ b/mediagoblin/gmg_commands/migrate.py @@ -55,13 +55,13 @@ def migrate(args): for collection, index_name in removed_indexes: print "Removed index '%s' in collection '%s'" % ( index_name, collection) - + # Migrate print "\n== Applying migrations... ==" migration_manager.migrate_new( pre_callback=_print_started_migration, post_callback=_print_finished_migration) - + # Add new indexes print "\n== Adding new indexes... ==" new_indexes = db_util.add_new_indexes(db) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 5421907d..3fda0e32 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -41,7 +41,7 @@ def adduser(args): db = mg_globals.database users_with_username = \ db.User.find({ - 'username': args.username.lower() + 'username': args.username.lower(), }).count() if users_with_username: @@ -74,7 +74,7 @@ def makeadmin(args): db = mg_globals.database - user = db.User.one({'username':unicode(args.username.lower())}) + user = db.User.one({'username': unicode(args.username.lower())}) if user: user['is_admin'] = True user.save() @@ -100,11 +100,10 @@ def changepw(args): db = mg_globals.database - user = db.User.one({'username':unicode(args.username.lower())}) + user = db.User.one({'username': unicode(args.username.lower())}) if user: user['pw_hash'] = auth_lib.bcrypt_gen_password_hash(args.password) user.save() print 'Password successfully changed' else: print 'The user doesn\'t exist' - diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index b7f52595..f21e2fdd 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -29,8 +29,12 @@ from mediagoblin.workbench import WorkbenchManager from mediagoblin.storage import storage_system_from_config -class Error(Exception): pass -class ImproperlyConfigured(Error): pass +class Error(Exception): + pass + + +class ImproperlyConfigured(Error): + pass def setup_global_and_app_config(config_path): @@ -76,8 +80,8 @@ def setup_database(): "in fact they appear to be from the future?!") setup_globals( - db_connection = connection, - database = db) + db_connection=connection, + database=db) return connection, db @@ -126,8 +130,8 @@ def setup_storage(): queue_store = storage_system_from_config(global_config[key_long]) setup_globals( - public_store = public_store, - queue_store = queue_store) + public_store=public_store, + queue_store=queue_store) return public_store, queue_store @@ -137,7 +141,7 @@ def setup_workbench(): workbench_manager = WorkbenchManager(app_config['workbench_path']) - setup_globals(workbench_manager = workbench_manager) + setup_globals(workbench_manager=workbench_manager) def setup_beaker_cache(): diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index c58b1305..21ce1d39 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -84,6 +84,6 @@ def setup_celery_from_config(app_config, global_config, for key, value in celery_settings.iteritems(): setattr(this_module, key, value) - + if set_environ: os.environ['CELERY_CONFIG_MODULE'] = settings_module diff --git a/mediagoblin/init/celery/from_celery.py b/mediagoblin/init/celery/from_celery.py index 3e5adb98..05669b67 100644 --- a/mediagoblin/init/celery/from_celery.py +++ b/mediagoblin/init/celery/from_celery.py @@ -44,7 +44,7 @@ def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME, if not os.path.exists(mgoblin_conf_file): raise IOError( "MEDIAGOBLIN_CONFIG not set or file does not exist") - + # By setting the environment variable here we should ensure that # this is the module that gets set up. os.environ['CELERY_CONFIG_MODULE'] = module_name diff --git a/mediagoblin/init/config.py b/mediagoblin/init/config.py index 029a0956..ae232e91 100644 --- a/mediagoblin/init/config.py +++ b/mediagoblin/init/config.py @@ -73,7 +73,7 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH): # For now the validator just works with the default functions, # but in the future if we want to add additional validation/configuration # functions we'd add them to validator.functions here. - # + # # See also: # http://www.voidspace.org.uk/python/validate.html#adding-functions validator = Validator() diff --git a/mediagoblin/listings/routing.py b/mediagoblin/listings/routing.py index b72bd015..234f2595 100644 --- a/mediagoblin/listings/routing.py +++ b/mediagoblin/listings/routing.py @@ -25,4 +25,3 @@ tag_routes = [ Route('mediagoblin.listings.tag_atom_feed', "/{tag}/atom/", controller="mediagoblin.listings.views:tag_atom_feed"), ] - diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index b3384eb4..2d61ee9b 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -46,7 +46,7 @@ def tag_listing(request, page): {u'state': u'processed', u'tags.slug': tag_slug}) cursor = cursor.sort('created', DESCENDING) - + pagination = Pagination(page, cursor) media_entries = pagination() @@ -63,6 +63,7 @@ def tag_listing(request, page): ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 15 + def tag_atom_feed(request): """ generates the atom feed with the tag images diff --git a/mediagoblin/messages.py b/mediagoblin/messages.py index dc82fbf6..054d46c0 100644 --- a/mediagoblin/messages.py +++ b/mediagoblin/messages.py @@ -20,11 +20,13 @@ SUCCESS = 'success' WARNING = 'warning' ERROR = 'error' + def add_message(request, level, text): messages = request.session.setdefault('messages', []) messages.append({'level': level, 'text': text}) request.session.save() + def fetch_messages(request, clear_from_session=True): messages = request.session.get('messages') if messages and clear_from_session: diff --git a/mediagoblin/middleware/noop.py b/mediagoblin/middleware/noop.py index 28380232..820b5d9e 100644 --- a/mediagoblin/middleware/noop.py +++ b/mediagoblin/middleware/noop.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . + class NoOpMiddleware(object): def __init__(self, mg_app): diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 2b9eed6e..9a7d5c39 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -65,9 +65,10 @@ class ProcessMedia(Task): """ If the processing failed we should mark that in the database. - Assuming that the exception raised is a subclass of BaseProcessingFail, - we can use that to get more information about the failure and store that - for conveying information to users about the failure, etc. + Assuming that the exception raised is a subclass of + BaseProcessingFail, we can use that to get more information + about the failure and store that for conveying information to + users about the failure, etc. """ entry_id = args[0] mark_entry_failed(entry_id, exc) @@ -80,10 +81,10 @@ def mark_entry_failed(entry_id, exc): """ Mark a media entry as having failed in its conversion. - Uses the exception that was raised to mark more information. If the - exception is a derivative of BaseProcessingFail then we can store extra - information that can be useful for users telling them why their media failed - to process. + Uses the exception that was raised to mark more information. If + the exception is a derivative of BaseProcessingFail then we can + store extra information that can be useful for users telling them + why their media failed to process. Args: - entry_id: The id of the media entry @@ -164,7 +165,8 @@ def process_image(entry): with queued_file: original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + with mgg.public_store.get_file(original_filepath, 'wb') \ + as original_file: original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) diff --git a/mediagoblin/process_media/errors.py b/mediagoblin/process_media/errors.py index 156f0a01..cb236154 100644 --- a/mediagoblin/process_media/errors.py +++ b/mediagoblin/process_media/errors.py @@ -16,17 +16,18 @@ from mediagoblin.util import lazy_pass_to_ugettext as _ + class BaseProcessingFail(Exception): """ Base exception that all other processing failure messages should subclass from. - + You shouldn't call this itself; instead you should subclass it and provid the exception_path and general_message applicable to this error. """ general_message = u'' - + @property def exception_path(self): return u"%s:%s" % ( @@ -34,8 +35,8 @@ class BaseProcessingFail(Exception): def __init__(self, **metadata): self.metadata = metadata or {} - - + + class BadMediaFail(BaseProcessingFail): """ Error that should be raised when an inappropriate file was given diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py index b1dd9450..0d3cc3df 100644 --- a/mediagoblin/storage/cloudfiles.py +++ b/mediagoblin/storage/cloudfiles.py @@ -27,6 +27,7 @@ from mediagoblin.storage import StorageInterface, clean_listy_filepath import cloudfiles import mimetypes + class CloudFilesStorage(StorageInterface): ''' OpenStack/Rackspace Cloud's Swift/CloudFiles support diff --git a/mediagoblin/submit/__init__.py b/mediagoblin/submit/__init__.py index 576bd0f5..ba347c69 100644 --- a/mediagoblin/submit/__init__.py +++ b/mediagoblin/submit/__init__.py @@ -13,5 +13,3 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - - diff --git a/mediagoblin/submit/security.py b/mediagoblin/submit/security.py index 9d62a36e..6708baf7 100644 --- a/mediagoblin/submit/security.py +++ b/mediagoblin/submit/security.py @@ -16,9 +16,9 @@ from mimetypes import guess_type - ALLOWED = ['image/jpeg', 'image/png', 'image/tiff', 'image/gif'] + def check_filetype(posted_file): if not guess_type(posted_file.filename)[0] in ALLOWED: return False diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index e24d78f3..22a13b6d 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -61,8 +61,8 @@ def submit_start(request): entry['description'] = unicode(request.POST.get('description')) entry['description_html'] = cleaned_markdown_conversion( entry['description']) - - entry['media_type'] = u'image' # heh + + entry['media_type'] = u'image' # heh entry['uploader'] = request.user['_id'] # Process the user's folksonomy "tags" @@ -90,8 +90,10 @@ def submit_start(request): # We generate this ourselves so we know what the taks id is for # retrieval later. - # (If we got it off the task's auto-generation, there'd be a risk of - # a race condition when we'd save after sending off the task) + + # (If we got it off the task's auto-generation, there'd be + # a risk of a race condition when we'd save after sending + # off the task) task_id = unicode(uuid.uuid4()) entry['queued_task_id'] = task_id @@ -113,8 +115,8 @@ def submit_start(request): # expect a lot of users to run things in this way we have to # capture stuff here. # - # ... not completely the diaper pattern because the exception is - # re-raised :) + # ... not completely the diaper pattern because the + # exception is re-raised :) mark_entry_failed(entry[u'_id'], exc) # re-raise the exception raise @@ -122,7 +124,7 @@ def submit_start(request): add_message(request, SUCCESS, _('Woohoo! Submitted!')) return redirect(request, "mediagoblin.user_pages.user_home", - user = request.user['username']) + user=request.user['username']) return render_to_response( request, diff --git a/mediagoblin/user_pages/__init__.py b/mediagoblin/user_pages/__init__.py index 576bd0f5..ba347c69 100644 --- a/mediagoblin/user_pages/__init__.py +++ b/mediagoblin/user_pages/__init__.py @@ -13,5 +13,3 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . - - diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 6a82d718..e6ba6b79 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -53,7 +53,7 @@ def user_home(request, page): #if no data is available, return NotFound if media_entries == None: return render_404(request) - + user_gallery_url = request.urlgen( 'mediagoblin.user_pages.user_gallery', user=user['username']) @@ -66,6 +66,7 @@ def user_home(request, page): 'media_entries': media_entries, 'pagination': pagination}) + @uses_pagination def user_gallery(request, page): """'Gallery' of a User()""" @@ -85,7 +86,7 @@ def user_gallery(request, page): #if no data is available, return NotFound if media_entries == None: return render_404(request) - + return render_to_response( request, 'mediagoblin/user_pages/gallery.html', @@ -95,6 +96,7 @@ def user_gallery(request, page): MEDIA_COMMENTS_PER_PAGE = 50 + @get_user_media_entry @uses_pagination def media_home(request, media, page, **kwargs): @@ -142,8 +144,8 @@ def media_post_comment(request): 'Comment posted!') return redirect(request, 'mediagoblin.user_pages.media_home', - media = request.matchdict['media'], - user = request.matchdict['user']) + media=request.matchdict['media'], + user=request.matchdict['user']) @get_user_media_entry @@ -184,6 +186,7 @@ def media_confirm_delete(request, media): ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 15 + def atom_feed(request): """ generates the atom feed with the newest images @@ -204,7 +207,7 @@ def atom_feed(request): feed = AtomFeed(request.matchdict['user'], feed_url=request.url, url=request.host_url) - + for entry in cursor: feed.add(entry.get('title'), entry.get('description_html'), diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 7ff3ec7f..4132b497 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -45,6 +45,8 @@ from itertools import izip, count DISPLAY_IMAGE_FETCHING_ORDER = [u'medium', u'original', u'thumb'] TESTS_ENABLED = False + + def _activate_testing(): """ Call this to activate testing in util.py @@ -78,7 +80,7 @@ SETUP_JINJA_ENVS = {} def get_jinja_env(template_loader, locale): """ - Set up the Jinja environment, + Set up the Jinja environment, (In the future we may have another system for providing theming; for now this is good enough.) @@ -147,7 +149,7 @@ def render_to_response(request, template, context, status=200): def redirect(request, *args, **kwargs): """Returns a HTTPFound(), takes a request and then urlgen params""" - + querystring = None if kwargs.get('querystring'): querystring = kwargs.get('querystring') @@ -197,6 +199,7 @@ def import_component(import_string): _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') + def slugify(text, delim=u'-'): """ Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/ @@ -213,7 +216,7 @@ def slugify(text, delim=u'-'): ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # We have two "test inboxes" here: -# +# # EMAIL_TEST_INBOX: # ---------------- # If you're writing test views, you'll probably want to check this. @@ -233,7 +236,7 @@ def slugify(text, delim=u'-'): # ***IMPORTANT!*** # ---------------- # Before running tests that call functions which send email, you should -# always call _clear_test_inboxes() to "wipe" the inboxes clean. +# always call _clear_test_inboxes() to "wipe" the inboxes clean. EMAIL_TEST_INBOX = [] EMAIL_TEST_MBOX_INBOX = [] @@ -253,6 +256,7 @@ class FakeMhost(object): 'to': to_addrs, 'message': message}) + def _clear_test_inboxes(): global EMAIL_TEST_INBOX global EMAIL_TEST_MBOX_INBOX @@ -263,6 +267,7 @@ def _clear_test_inboxes(): ### ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + def send_email(from_addr, to_addrs, subject, message_body): """ Simple email sending wrapper, use this so we can capture messages @@ -418,7 +423,7 @@ def convert_to_tag_list_of_dicts(tag_string): # Split the tag string into a list of tags for tag in stripped_tag_string.split( - mg_globals.app_config['tags_delimiter']): + mg_globals.app_config['tags_delimiter']): # Ignore empty or duplicate tags if tag.strip() and tag.strip() not in [t['name'] for t in taglist]: @@ -437,12 +442,13 @@ def media_tags_as_string(media_entry_tags): media_tag_string = '' if media_entry_tags: media_tag_string = mg_globals.app_config['tags_delimiter'].join( - [tag['name'] for tag in media_entry_tags]) + [tag['name'] for tag in media_entry_tags]) return media_tag_string TOO_LONG_TAG_WARNING = \ u'Tags must be shorter than %s characters. Tags that are too long: %s' + def tag_length_validator(form, field): """ Make sure tags do not exceed the maximum tag length. @@ -460,6 +466,7 @@ def tag_length_validator(form, field): MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape') + def cleaned_markdown_conversion(text): """ Take a block of text, run it through MarkDown, and clean its HTML. @@ -474,6 +481,7 @@ def cleaned_markdown_conversion(text): SETUP_GETTEXTS = {} + def setup_gettext(locale): """ Setup the gettext instance based on this locale @@ -558,6 +566,7 @@ def fake_ugettext_passthrough(string): PAGINATION_DEFAULT_PER_PAGE = 30 + class Pagination(object): """ Pagination class for mongodb queries. @@ -574,9 +583,9 @@ class Pagination(object): Args: - page: requested page - per_page: number of objects per page - - cursor: db cursor - - jump_to_id: ObjectId, sets the page to the page containing the object - with _id == jump_to_id. + - cursor: db cursor + - jump_to_id: ObjectId, sets the page to the page containing the + object with _id == jump_to_id. """ self.page = page self.per_page = per_page @@ -594,7 +603,6 @@ class Pagination(object): self.active_id = jump_to_id break - def __call__(self): """ Returns slice of objects for the requested page @@ -628,20 +636,18 @@ class Pagination(object): last = num def get_page_url_explicit(self, base_url, get_params, page_no): - """ - Get a page url by adding a page= parameter to the base url - """ + """Get a page url by adding a page= parameter to the base url + """ new_get_params = copy.copy(get_params or {}) new_get_params['page'] = page_no return "%s?%s" % ( base_url, urllib.urlencode(new_get_params)) def get_page_url(self, request, page_no): - """ - Get a new page url based of the request, and the new page number. + """Get a new page url based of the request, and the new page number. This is a nice wrapper around get_page_url_explicit() - """ + """ return self.get_page_url_explicit( request.path_info, request.GET, page_no) @@ -682,6 +688,7 @@ def render_404(request): return render_to_response( request, 'mediagoblin/404.html', {}, status=400) + def delete_media_files(media): """ Delete all files associated with a MediaEntry diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 96687f96..afa6ac91 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -19,6 +19,7 @@ from mediagoblin.util import render_to_response, Pagination from mediagoblin.db.util import DESCENDING from mediagoblin.decorators import uses_pagination + @uses_pagination def root_view(request, page): cursor = request.db.MediaEntry.find( diff --git a/mediagoblin/workbench.py b/mediagoblin/workbench.py index 722f8e27..60a79f47 100644 --- a/mediagoblin/workbench.py +++ b/mediagoblin/workbench.py @@ -42,8 +42,10 @@ class Workbench(object): def __unicode__(self): return unicode(self.dir) + def __str__(self): return str(self.dir) + def __repr__(self): return repr(self.dir) @@ -140,7 +142,7 @@ class WorkbenchManager(object): self.base_workbench_dir = os.path.abspath(base_workbench_dir) if not os.path.exists(self.base_workbench_dir): os.makedirs(self.base_workbench_dir) - + def create_workbench(self): """ Create and return the path to a new workbench (directory). diff --git a/setup.py b/setup.py index 06626926..11c8fe6c 100644 --- a/setup.py +++ b/setup.py @@ -29,16 +29,17 @@ def get_version(): if mo: return mo.group(1) else: - raise RuntimeError("Unable to find version string in %s." % VERSIONFILE) + raise RuntimeError("Unable to find version string in %s." % + VERSIONFILE) setup( - name = "mediagoblin", - version = get_version(), + name="mediagoblin", + version=get_version(), packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), zip_safe=False, # scripts and dependencies - install_requires = [ + install_requires=[ 'setuptools', 'PasteScript', 'beaker', @@ -66,7 +67,7 @@ setup( # 'lxml', ], test_suite='nose.collector', - entry_points = """\ + entry_points="""\ [console_scripts] gmg = mediagoblin.gmg_commands:main_cli pybabel = mediagoblin.babel.messages.frontend:main @@ -83,7 +84,6 @@ setup( [babel.extractors] jinja2 = jinja2.ext:babel_extract """, - license='AGPLv3', author='Free Software Foundation and contributors', author_email='cwebber@gnu.org', -- cgit v1.2.3 From 285ffeddf3542201b83072d3be544c85e9c487c2 Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 1 Oct 2011 15:10:41 -0700 Subject: has_key is deprecated, converting uses to use "in" operator. --- mediagoblin/auth/views.py | 4 ++-- mediagoblin/db/util.py | 2 +- mediagoblin/gmg_commands/__init__.py | 2 +- mediagoblin/init/__init__.py | 4 ++-- mediagoblin/init/celery/__init__.py | 10 +++++----- mediagoblin/staticdirect.py | 6 +++--- mediagoblin/submit/views.py | 2 +- mediagoblin/util.py | 16 ++++++++-------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index afcfcf1e..adf2c315 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -146,7 +146,7 @@ def verify_email(request): you are lucky :) """ # If we don't have userid and token parameters, we can't do anything; 404 - if not request.GET.has_key('userid') or not request.GET.has_key('token'): + if not 'userid' in request.GET or not 'token' in request.GET: return render_404(request) user = request.db.User.find_one( @@ -307,6 +307,6 @@ def _process_for_token(request): formdata = { 'vars': formdata_vars, 'has_userid_and_token': - formdata_vars.has_key('userid') and formdata_vars.has_key('token')} + 'userid' in formdata_vars and 'token' in formdata_vars} return formdata diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 38f0233f..52e97f6d 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -148,7 +148,7 @@ class RegisterMigration(object): """ def __init__(self, migration_number, migration_registry=MIGRATIONS): assert migration_number > 0, "Migration number must be > 0!" - assert not migration_registry.has_key(migration_number), \ + assert migration_number not in migration_registry, \ "Duplicate migration numbers detected! That's not allowed!" self.migration_number = migration_number diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index b3f69ccc..3250c246 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -61,7 +61,7 @@ def main_cli(): subparsers = parser.add_subparsers(help='sub-command help') for command_name, command_struct in SUBCOMMAND_MAP.iteritems(): - if command_struct.has_key('help'): + if 'help' in command_struct: subparser = subparsers.add_parser( command_name, help=command_struct['help']) else: diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index f21e2fdd..08a0618d 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -103,10 +103,10 @@ def get_jinja_loader(user_template_path=None): def get_staticdirector(app_config): - if app_config.has_key('direct_remote_path'): + if 'direct_remote_path' in app_config: return staticdirect.RemoteStaticDirect( app_config['direct_remote_path'].strip()) - elif app_config.has_key('direct_remote_paths'): + elif 'direct_remote_paths' in app_config: direct_remote_path_lines = app_config[ 'direct_remote_paths'].strip().splitlines() return staticdirect.MultiRemoteStaticDirect( diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index 21ce1d39..f7ef9f39 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -40,25 +40,25 @@ def setup_celery_from_config(app_config, global_config, - set_environ: if set, this will CELERY_CONFIG_MODULE to the settings_module """ - if global_config.has_key('celery'): + if 'celery' in global_config: celery_conf = global_config['celery'] else: celery_conf = {} - + celery_settings = {} # set up mongodb stuff celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb' - if not celery_settings.has_key('BROKER_BACKEND'): + if 'BROKER_BACKEND' not in celery_settings: celery_settings['BROKER_BACKEND'] = 'mongodb' celery_mongo_settings = {} - if app_config.has_key('db_host'): + if 'db_host' in app_config: celery_mongo_settings['host'] = app_config['db_host'] if celery_settings['BROKER_BACKEND'] == 'mongodb': celery_settings['BROKER_HOST'] = app_config['db_host'] - if app_config.has_key('db_port'): + if 'db_port' in app_config: celery_mongo_settings['port'] = app_config['db_port'] if celery_settings['BROKER_BACKEND'] == 'mongodb': celery_settings['BROKER_PORT'] = app_config['db_port'] diff --git a/mediagoblin/staticdirect.py b/mediagoblin/staticdirect.py index 58175881..c6d2b374 100644 --- a/mediagoblin/staticdirect.py +++ b/mediagoblin/staticdirect.py @@ -21,24 +21,24 @@ import urlparse # Staticdirect infrastructure. # Borrowed largely from cc.engine # by Chris Webber & Creative Commons -# +# # This needs documentation! #################################### import pkg_resources import urlparse + class StaticDirect(object): def __init__(self): self.cache = {} def __call__(self, filepath): - if self.cache.has_key(filepath): + if filepath in self.cache: return self.cache[filepath] static_direction = self.cache[filepath] = self.get(filepath) return static_direction - def get(self, filepath): # should be implemented by the individual staticdirector diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 22a13b6d..d450ca21 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -40,7 +40,7 @@ def submit_start(request): submit_form = submit_forms.SubmitStartForm(request.POST) if request.method == 'POST' and submit_form.validate(): - if not (request.POST.has_key('file') + if not ('file' in request.POST and isinstance(request.POST['file'], FieldStorage) and request.POST['file'].file): submit_form.file.errors.append( diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 4132b497..d6ce5930 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -89,7 +89,7 @@ def get_jinja_env(template_loader, locale): # If we have a jinja environment set up with this locale, just # return that one. - if SETUP_JINJA_ENVS.has_key(locale): + if locale in SETUP_JINJA_ENVS: return SETUP_JINJA_ENVS[locale] template_env = jinja2.Environment( @@ -166,7 +166,7 @@ def setup_user_in_request(request): Examine a request and tack on a request.user parameter if that's appropriate. """ - if not request.session.has_key('user_id'): + if not 'user_id' in request.session: request.user = None return @@ -356,7 +356,7 @@ def get_locale_from_request(request): """ request_form = request.GET or request.POST - if request_form.has_key('lang'): + if 'lang' in request_form: return locale_to_lower_upper(request_form['lang']) accept_lang_matches = request.accept_language.best_matches() @@ -364,9 +364,9 @@ def get_locale_from_request(request): # Your routing can explicitly specify a target language matchdict = request.matchdict or {} - if matchdict.has_key('locale'): + if 'locale' in matchdict: target_lang = matchdict['locale'] - elif request.session.has_key('target_lang'): + elif 'target_lang' in request.session: target_lang = request.session['target_lang'] # Pull the first acceptable language elif accept_lang_matches: @@ -393,9 +393,9 @@ HTML_CLEANER = Cleaner( annoying_tags=True, allow_tags=[ 'div', 'b', 'i', 'em', 'strong', 'p', 'ul', 'ol', 'li', 'a', 'br'], - remove_unknown_tags=False, # can't be used with allow_tags + remove_unknown_tags=False, # can't be used with allow_tags safe_attrs_only=True, - add_nofollow=True, # for now + add_nofollow=True, # for now host_whitelist=(), whitelist_tags=set([])) @@ -492,7 +492,7 @@ def setup_gettext(locale): # TODO: fallback nicely on translations from pt_PT to pt if not # available, etc. - if SETUP_GETTEXTS.has_key(locale): + if locale in SETUP_GETTEXTS: this_gettext = SETUP_GETTEXTS[locale] else: this_gettext = gettext.translation( -- cgit v1.2.3 From 84a7e7706c8b1239f8fd52c604afbb10c776ac04 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Sat, 1 Oct 2011 19:49:56 -0400 Subject: Display and error and redirect to login page if unauthenticated user tries to access resend_verification. --- mediagoblin/auth/views.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index b6f38fec..d91a1f25 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -21,7 +21,7 @@ from webob import exc from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.util import render_to_response, redirect, render_404 +from mediagoblin.util import render_to_response, redirect, render_404, setup_user_in_request from mediagoblin.util import pass_to_ugettext as _ from mediagoblin.db.util import ObjectId, InvalidId from mediagoblin.auth import lib as auth_lib @@ -195,9 +195,18 @@ def resend_activation(request): Resend the activation email. """ + + if not request.GET.has_key('userid') or not request.GET.has_key('token'): + messages.add_message( + request, + messages.ERROR, + _('You must be logged in so we know who to send the email to!')) + + return redirect(request, "/auth/login") + request.user[u'verification_key'] = unicode(uuid.uuid4()) request.user.save() - + email_debug_message(request) send_verification_email(request.user, request) -- cgit v1.2.3 From f1360855319612a9af3c03ae4ca04fef6660f6b0 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Sat, 1 Oct 2011 19:52:12 -0400 Subject: Regenerated English .po file to include new string. --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 16a235a2..3c176a14 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-09-25 20:26-0500\n" +"POT-Creation-Date: 2011-10-01 19:51-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -41,33 +41,37 @@ msgstr "" msgid "Email address" msgstr "" -#: mediagoblin/auth/views.py:42 +#: mediagoblin/auth/views.py:55 msgid "Sorry, registration is disabled on this instance." msgstr "" -#: mediagoblin/auth/views.py:60 +#: mediagoblin/auth/views.py:73 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:64 +#: mediagoblin/auth/views.py:77 msgid "Sorry, that email address has already been taken." msgstr "" -#: mediagoblin/auth/views.py:165 +#: mediagoblin/auth/views.py:179 msgid "" "Your email address has been verified. You may now login, edit your " "profile, and submit images!" msgstr "" -#: mediagoblin/auth/views.py:171 +#: mediagoblin/auth/views.py:185 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:192 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:216 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:228 +#: mediagoblin/auth/views.py:257 msgid "" "Could not send password recovery email as your username is inactive or " "your account's email address has not been verified." -- cgit v1.2.3 From 88233cb282ceacd4c9e8cac419faf952627e7fe2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 1 Oct 2011 21:30:41 -0500 Subject: Fixing indentation in start.html --- mediagoblin/templates/mediagoblin/submit/start.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 7bc6ff45..29b01181 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -26,8 +26,8 @@

{% trans %}Submit yer media{% endtrans %}

{{ wtforms_util.render_divs(submit_form) }}
- {{ csrf_token }} - + {{ csrf_token }} +
-- cgit v1.2.3 From 4d7a93a49303344830021bab5a741148b1adb7c3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 1 Oct 2011 21:31:14 -0500 Subject: Adding csrf token fields to the forgot password calls --- mediagoblin/templates/mediagoblin/auth/change_fp.html | 2 ++ mediagoblin/templates/mediagoblin/auth/forgot_password.html | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 4be7e065..53186cec 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -23,6 +23,8 @@
+ {{ csrf_token }} +

{% trans %}Enter your new password{% endtrans %}

diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html index 23fa9eb5..b95a4dcb 100644 --- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html +++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html @@ -23,6 +23,8 @@ + {{ csrf_token }} +

{% trans %}Enter your username or email{% endtrans %}

-- cgit v1.2.3 From 05788ef450cd63da4009cea1825323e10e572e43 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 3 Oct 2011 14:01:13 +0200 Subject: i592: Use full path in various places When running mediagoblin in a sub path on a web server, most things inside mediagoblin need the "inside path", but when generating URLs for the webbrowser, full paths are needed. urlgen and routes already do that. Some (mostly pagination and login) need the URL of the current page. They used request.path_info. But this is the "inside" path, not the full. So now there is request.full_path and its used in various places. --- mediagoblin/app.py | 11 +++++++++++ mediagoblin/decorators.py | 2 +- mediagoblin/templates/mediagoblin/utils/pagination.html | 2 +- mediagoblin/tools/pagination.py | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 0f25a4e5..f052d4a2 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -117,6 +117,17 @@ class MediaGoblinApp(object): path_info = request.path_info route_match = self.routing.match(path_info) + # By using fcgi, mediagoblin can run under a base path + # like /mediagoblin/. request.path_info contains the + # path inside mediagoblin. If the something needs the + # full path of the current page, that should include + # the basepath. + # Note: urlgen and routes are fine! + request.full_path = environ["SCRIPT_NAME"] + request.path_info + # python-routes uses SCRIPT_NAME. So let's use that too. + # The other option would be: + # request.full_path = environ["SCRIPT_URL"] + ## Attach utilities to the request object request.matchdict = route_match request.urlgen = routes.URLGenerator(self.routing, environ) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 19e22bca..6431d67e 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -45,7 +45,7 @@ def require_active_login(controller): return exc.HTTPFound( location="%s?next=%s" % ( request.urlgen("mediagoblin.auth.login"), - request.path_info)) + request.full_path)) return controller(request, *args, **kwargs) diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 0df3bfea..84336103 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -21,7 +21,7 @@ {# only display if {{pagination}} is defined #} {% if pagination and pagination.pages > 1 %} {% if not base_url %} - {% set base_url = request.path_info %} + {% set base_url = request.full_path %} {% endif %} {% if preserve_get_params %} diff --git a/mediagoblin/tools/pagination.py b/mediagoblin/tools/pagination.py index 859b60fb..3ea96e6d 100644 --- a/mediagoblin/tools/pagination.py +++ b/mediagoblin/tools/pagination.py @@ -106,4 +106,4 @@ class Pagination(object): This is a nice wrapper around get_page_url_explicit() """ return self.get_page_url_explicit( - request.path_info, request.GET, page_no) + request.full_path, request.GET, page_no) -- cgit v1.2.3 From 3b74ce94ff90e0bd5b214891becb62a6fc503434 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Mon, 3 Oct 2011 19:59:28 -0400 Subject: Check request.user to determine if user is logged in. --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d91a1f25..fdc5aec8 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -196,7 +196,7 @@ def resend_activation(request): Resend the activation email. """ - if not request.GET.has_key('userid') or not request.GET.has_key('token'): + if request.user is None: messages.add_message( request, messages.ERROR, -- cgit v1.2.3 From 7903a14f986b5bf37a45d5ec3b156c21a1cada72 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Mon, 3 Oct 2011 20:25:11 -0400 Subject: Make sure user isn't already verified before resending verification. --- mediagoblin/auth/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 798fae25..dc4c540b 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -196,6 +196,14 @@ def resend_activation(request): Resend the activation email. """ + if request.user["email_verified"]: + messages.add_message( + request, + messages.ERROR, + _("You've already verified your email address!")) + + return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username']) + if request.user is None: messages.add_message( request, -- cgit v1.2.3 From 2fe6991660cd1a20f9117b0cdc88431085eb7490 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Mon, 3 Oct 2011 20:28:48 -0400 Subject: Reverse order of sanity checks: check email_verified after making sure there's a user in the request. --- mediagoblin/auth/views.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index dc4c540b..d8c441ef 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -196,21 +196,21 @@ def resend_activation(request): Resend the activation email. """ - if request.user["email_verified"]: + if request.user is None: messages.add_message( request, messages.ERROR, - _("You've already verified your email address!")) + _('You must be logged in so we know who to send the email to!')) - return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username']) + return redirect(request, "/auth/login") - if request.user is None: + if request.user["email_verified"]: messages.add_message( request, messages.ERROR, - _('You must be logged in so we know who to send the email to!')) + _("You've already verified your email address!")) - return redirect(request, "/auth/login") + return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username']) request.user[u'verification_key'] = unicode(uuid.uuid4()) request.user.save() -- cgit v1.2.3 From c302bcd918302347f89b2c06c141db89d0c55848 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Mon, 3 Oct 2011 20:47:39 -0400 Subject: Checkbox label is being translated in the form definition -- translating it in the template is redundant and breaks
-- cgit v1.2.3 From 1b36a8e80c09307a2c4ddf8cc8bfe786a9d86f7d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 4 Nov 2011 02:20:26 +0100 Subject: On second thought, let's use this title for forgot_password.html --- mediagoblin/templates/mediagoblin/auth/forgot_password.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html index c7f01678..9b821426 100644 --- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html +++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html @@ -24,7 +24,7 @@ method="POST" enctype="multipart/form-data"> {{ csrf_token }}
-

{% trans %}Forgot your password?{% endtrans %}

+

{% trans %}Recover password{% endtrans %}

{{ wtforms_util.render_divs(fp_form) }}
-- cgit v1.2.3 From 80c9a7ee51590923a3b9f7a07419679af4a368d8 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 4 Nov 2011 02:30:07 +0100 Subject: Small style changes to navigation buttons --- mediagoblin/static/css/base.css | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index b026a819..23a7e6c5 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -290,11 +290,14 @@ img.media_icon{ /* navigation */ .navigation_button{ - width: 139px; + width: 135px; display: block; float: left; text-align: center; - background-color: #222; + background-color: #1d1d1d; + border: 1px solid; + border-color: #2c2c2c #232323 #1a1a1a; + border-radius: 3px; text-decoration: none; padding: 12px 0pt; font-size: 2em; @@ -306,7 +309,7 @@ p.navigation_button{ } .navigation_left{ - margin-right: 2px; + margin-right: 6px; } /* messages */ -- cgit v1.2.3 From da76a8cbaa06ba63533f60051c66f08cd0e7baf4 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 4 Nov 2011 02:34:00 +0100 Subject: Tiny padding change to vertically center navigation button arrows --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 23a7e6c5..afd10207 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -299,7 +299,7 @@ img.media_icon{ border-color: #2c2c2c #232323 #1a1a1a; border-radius: 3px; text-decoration: none; - padding: 12px 0pt; + padding: 8px 0px 14px; font-size: 2em; margin: 0 0 20px } -- cgit v1.2.3 From d871f4e0d107268fab9dc33c648b1a6f7a99a652 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 4 Nov 2011 08:23:28 -0500 Subject: Updating translations --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11089 -> 11119 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 14 +- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 11272 -> 11583 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 92 +++-- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 11051 -> 11067 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 8 +- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 13895 -> 13899 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 10812 bytes mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 498 +++++++++++++++++++++++++ 10 files changed, 568 insertions(+), 50 deletions(-) create mode 100644 mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo create mode 100644 mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index b65212eb..056e3eca 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 5baab62e..5c4ef0d0 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -16,8 +16,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-11-02 15:18+0000\n" +"Last-Translator: piratenpanda \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -259,7 +259,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:38 msgid "Excited to join us?" -msgstr "Neugierig dich uns anzuschliessen?" +msgstr "Neugierig dich uns anzuschließen?" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format @@ -292,8 +292,8 @@ msgstr "Dein Passwort wurde geändert. Versuche dich jetzt einzuloggen." msgid "" "Check your inbox. We sent an email with a URL for changing your password." msgstr "" -"Prüfe deinen Posteingang. Wir haben dir eine Email geschickt mit einer URL, " -"um dein Passwort zu ändern." +"Prüfe deinen Posteingang. Wir haben dir eine Email mit einem Link geschickt," +" mit dem du dein Passwort ändern kannst." #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -539,11 +539,11 @@ msgstr "Ja, wirklich löschen" #: mediagoblin/user_pages/views.py:142 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Leere Kommentare sind nicht erlaubt." #: mediagoblin/user_pages/views.py:148 msgid "Comment posted!" -msgstr "" +msgstr "Kommentar hinzugefügt!" #: mediagoblin/user_pages/views.py:181 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index eaa18426..90e83303 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 16939306..0a6a5a40 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: +# , 2011. # , 2011. # , 2011. # , 2011. @@ -13,8 +14,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-11-04 10:05+0000\n" +"Last-Translator: chesuidayeur \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,7 +43,7 @@ msgstr "Confirmer le mot de passe" #: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." msgstr "" -"Tapez-le à nouveau ici pour vous assurer qu'il n'ya pas de fautes " +"Tapez-le à nouveau ici pour vous assurer qu'il n'y a pas de fautes " "d'orthographe." #: mediagoblin/auth/forms.py:42 @@ -82,6 +83,8 @@ msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +"Impossible d'envoyer un email de récupération de mot de passe : votre compte" +" est inactif ou bien l'email de votre compte n'a pas été vérifiée." #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" @@ -103,6 +106,8 @@ msgstr "La légende ne peut pas être laissée vide." msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"Le nom de ce media dans l'URL. Vous n'avez normalement pas besoin de le " +"changer" #: mediagoblin/edit/forms.py:40 msgid "Bio" @@ -130,7 +135,7 @@ msgstr "" #: mediagoblin/process_media/errors.py:44 msgid "Invalid file given for media type." -msgstr "Invalide fichier donné pour le type de média." +msgstr "Le fichier envoyé ne correspond pas au type de média." #: mediagoblin/submit/forms.py:25 msgid "File" @@ -138,7 +143,7 @@ msgstr "Fichier" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Descriptif pour ce travail" #: mediagoblin/submit/views.py:46 msgid "You must provide a file." @@ -158,7 +163,7 @@ msgstr "Zut!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "Il ne semble pas être une page à cette adresse. Désolé!" +msgstr "Il ne semble pas y avoir de page à cette adresse. Désolé !" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" @@ -166,11 +171,11 @@ msgid "" " been moved or deleted." msgstr "" "Si vous êtes sûr que l'adresse est correcte, peut-être la page que vous " -"recherchez a été déplacé ou supprimé." +"recherchez a été déplacée ou supprimée." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "Image de 404 gobelin stresser" +msgstr "Image de 404 gobelin angoissé" #: mediagoblin/templates/mediagoblin/base.html:22 msgid "GNU MediaGoblin" @@ -199,12 +204,12 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" -"Propulsé par MediaGoblin , un GNU de projet" +"Propulsé par MediaGoblin , un projet " +"GNU" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Explorer" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, media lover! MediaGoblin is..." @@ -219,15 +224,15 @@ msgid "" "A place for people to collaborate and show off original and derived " "creations!" msgstr "" -"Un lieu pour les personnes de collaborer et de montrer des créations " -"originales et dérivées!" +"Un espace de création collaboratif : montrez vos œuvres, originales ou " +"dérivées !" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "" "Free, as in freedom. (We’re a GNU project, " "after all.)" msgstr "" -"Logiciel libre. (Nous sommes une GNU projet, " +"Logiciel libre. (Nous sommes un projet GNU " "après tout.)" #: mediagoblin/templates/mediagoblin/root.html:32 @@ -235,8 +240,8 @@ msgid "" "Aiming to make the world a better place through decentralization and " "(eventually, coming soon!) federation!" msgstr "" -"Visant à rendre le monde meilleur grâce à la décentralisation et " -"(éventuellement, venir bientôt!) fédération!" +"Une tentative de rendre le monde meilleur grâce à la décentralisation et (à " +"terme, et pour bientôt !) la fédération !" #: mediagoblin/templates/mediagoblin/root.html:33 msgid "" @@ -258,7 +263,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:38 msgid "Excited to join us?" -msgstr "" +msgstr "Envi de vous joindre à nous ?" #: mediagoblin/templates/mediagoblin/root.html:39 #, python-format @@ -267,27 +272,33 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Créez gratuitement en compte\n" +" ou\n" +" Installez MediaGoblin sur votre propre serveur" #: mediagoblin/templates/mediagoblin/root.html:53 msgid "Most recent media" -msgstr "" +msgstr "Tout derniers media" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 msgid "Enter your new password" -msgstr "" +msgstr "Entrez un nouveau mot de passe" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 msgid "Enter your username or email" -msgstr "" +msgstr "Entrez votre nom d'utilisateur ou votre email" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." msgstr "" +"Votre mot de passe a été changé. Essayez maintenant de vous identifier." #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" "Check your inbox. We sent an email with a URL for changing your password." msgstr "" +"Verifiez votre boîte de réception. Nous vous avons envoyé un email avec une " +"URL vous permettant de changer votre mot de passe." #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -302,10 +313,19 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Bonjour %(username)s,\n" +"\n" +"Pour changer votre mot de passe GNU MediaGoblin, ouvrez l'URL suivante dans \n" +"votre navigateur internet :\n" +"\n" +"%(verification_url)s\n" +"\n" +"Si vous pensez qu'il s'agit d'une erreur, ignorez simplement cet email et restez\n" +"un goblin heureux !" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" -msgstr "Connexion a échoué!" +msgstr "La connexion a échoué!" #: mediagoblin/templates/mediagoblin/auth/login.html:43 msgid "Don't have an account yet?" @@ -317,11 +337,11 @@ msgstr "Créez-en un ici!" #: mediagoblin/templates/mediagoblin/auth/login.html:49 msgid "Forgot your password?" -msgstr "" +msgstr "Vous avez oublié votre mot de passe ?" #: mediagoblin/templates/mediagoblin/auth/login.html:52 msgid "Change it!" -msgstr "" +msgstr "Changez-le !" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" @@ -396,7 +416,7 @@ msgstr "Voulez-vous vraiment supprimer %(title)s ?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Supprimer définitivement" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" @@ -419,7 +439,7 @@ msgstr "Aucun média en transformation" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "Ces ajouts n'etaient pas processé:" +msgstr "Le traitement de ces ajouts a échoué :" #: mediagoblin/templates/mediagoblin/user_pages/user.html:39 #: mediagoblin/templates/mediagoblin/user_pages/user.html:59 @@ -428,7 +448,7 @@ msgstr "Vérification d'email nécessaire" #: mediagoblin/templates/mediagoblin/user_pages/user.html:42 msgid "Almost done! Your account still needs to be activated." -msgstr "Presque fini! Votre compte a encore besoin d'être activé." +msgstr "Presque fini ! Votre compte a encore besoin d'être activé." #: mediagoblin/templates/mediagoblin/user_pages/user.html:47 msgid "" @@ -479,7 +499,7 @@ msgstr "Modifier le profil" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "This user hasn't filled in their profile (yet)." -msgstr "Cet utilisateur n'a pas rempli leur profil (encore)." +msgstr "Cet utilisateur n'a pas (encore) rempli son profil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:122 #, python-format @@ -491,8 +511,8 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -"C'est là où vos médias apparaît, mais vous ne semblez pas avoir quoi que ce " -"soit encore ajouté." +"C'est là où vos médias apparaîssent, mais vous ne semblez pas avoir encore " +"ajouté quoi que ce soit." #: mediagoblin/templates/mediagoblin/user_pages/user.html:141 msgid "Add media" @@ -500,11 +520,11 @@ msgstr "Ajouter des médias" #: mediagoblin/templates/mediagoblin/user_pages/user.html:147 msgid "There doesn't seem to be any media here yet..." -msgstr "Il ne semble pas être un média encore là ..." +msgstr "Il ne semble pas y avoir de média là, pour l'instant ..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "icon de flux" +msgstr "icone de flux" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" @@ -512,11 +532,11 @@ msgstr "flux Atom" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Nouveaux" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Anciens" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -524,15 +544,15 @@ msgstr "Commentaire" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Je suis sûr de vouloir supprimer cela" #: mediagoblin/user_pages/views.py:142 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Les commentaires vides ne sont pas autorisés." #: mediagoblin/user_pages/views.py:148 msgid "Comment posted!" -msgstr "" +msgstr "Votre commentaire a été posté !" #: mediagoblin/user_pages/views.py:181 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 6e9c8897..2ab9cf8b 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 2598f795..01fe5c48 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-11-02 20:49+0000\n" +"Last-Translator: gap \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -529,11 +529,11 @@ msgstr "Sunt sigur că doresc să șterg" #: mediagoblin/user_pages/views.py:142 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Comentariul trebuie să aibă un conținut." #: mediagoblin/user_pages/views.py:148 msgid "Comment posted!" -msgstr "" +msgstr "Comentariul a fost transmis." #: mediagoblin/user_pages/views.py:181 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 7cfc0b61..4b5481e0 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index aacd5ec8..f4bfbd67 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-11-04 11:13+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -515,7 +515,7 @@ msgstr "Я уверен, что хочу удалить это" #: mediagoblin/user_pages/views.py:142 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Empty comments are not allowed." #: mediagoblin/user_pages/views.py:148 msgid "Comment posted!" diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo new file mode 100644 index 00000000..b0d8d3fc Binary files /dev/null and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..289bddb5 --- /dev/null +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,498 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# వీవెన్ , 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-11-01 23:14-0500\n" +"PO-Revision-Date: 2011-11-03 14:08+0000\n" +"Last-Translator: veeven \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: te\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +msgid "Username" +msgstr "వాడుకరి పేరు" + +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +msgid "Password" +msgstr "సంకేతపదం" + +#: mediagoblin/auth/forms.py:35 +msgid "Passwords must match." +msgstr "" + +#: mediagoblin/auth/forms.py:37 +msgid "Confirm password" +msgstr "" + +#: mediagoblin/auth/forms.py:39 +msgid "Type it again here to make sure there are no spelling mistakes." +msgstr "" + +#: mediagoblin/auth/forms.py:42 +msgid "Email address" +msgstr "ఈమెయిలు చిరునామా" + +#: mediagoblin/auth/views.py:55 +msgid "Sorry, registration is disabled on this instance." +msgstr "" + +#: mediagoblin/auth/views.py:73 +msgid "Sorry, a user with that name already exists." +msgstr "" + +#: mediagoblin/auth/views.py:77 +msgid "Sorry, that email address has already been taken." +msgstr "" + +#: mediagoblin/auth/views.py:179 +msgid "" +"Your email address has been verified. You may now login, edit your profile, " +"and submit images!" +msgstr "" + +#: mediagoblin/auth/views.py:185 +msgid "The verification key or user id is incorrect" +msgstr "" + +#: mediagoblin/auth/views.py:207 +msgid "Resent your verification email." +msgstr "" + +#: mediagoblin/auth/views.py:248 +msgid "" +"Could not send password recovery email as your username is inactive or your " +"account's email address has not been verified." +msgstr "" + +#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +msgid "Title" +msgstr "శీర్షిక" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +msgid "Tags" +msgstr "" + +#: mediagoblin/edit/forms.py:31 +msgid "Slug" +msgstr "" + +#: mediagoblin/edit/forms.py:32 +msgid "The slug can't be empty" +msgstr "" + +#: mediagoblin/edit/forms.py:33 +msgid "" +"The title part of this media's URL. You usually don't need to change this." +msgstr "" + +#: mediagoblin/edit/forms.py:40 +msgid "Bio" +msgstr "" + +#: mediagoblin/edit/forms.py:43 +msgid "Website" +msgstr "" + +#: mediagoblin/edit/views.py:64 +msgid "An entry with that slug already exists for this user." +msgstr "" + +#: mediagoblin/edit/views.py:85 +msgid "You are editing another user's media. Proceed with caution." +msgstr "" + +#: mediagoblin/edit/views.py:155 +msgid "You are editing a user's profile. Proceed with caution." +msgstr "" + +#: mediagoblin/process_media/errors.py:44 +msgid "Invalid file given for media type." +msgstr "" + +#: mediagoblin/submit/forms.py:25 +msgid "File" +msgstr "" + +#: mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/submit/views.py:46 +msgid "You must provide a file." +msgstr "" + +#: mediagoblin/submit/views.py:49 +msgid "The file doesn't seem to be an image!" +msgstr "" + +#: mediagoblin/submit/views.py:121 +msgid "Woohoo! Submitted!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:21 +msgid "Oops!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:24 +msgid "There doesn't seem to be a page at this address. Sorry!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:26 +msgid "" +"If you're sure the address is correct, maybe the page you're looking for has" +" been moved or deleted." +msgstr "" + +#: mediagoblin/templates/mediagoblin/404.html:32 +msgid "Image of 404 goblin stressing out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:22 +msgid "GNU MediaGoblin" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:47 +msgid "MediaGoblin logo" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:52 +msgid "Submit media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:63 +msgid "verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/auth/login.html:27 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 +msgid "Log in" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:89 +msgid "" +"Powered by MediaGoblin, a GNU project" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:24 +msgid "Explore" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:27 +msgid "Hi there, media lover! MediaGoblin is..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:29 +msgid "The perfect place for your media!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:30 +msgid "" +"A place for people to collaborate and show off original and derived " +"creations!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "" +"Free, as in freedom. (We’re a GNU project, " +"after all.)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:32 +msgid "" +"Aiming to make the world a better place through decentralization and " +"(eventually, coming soon!) federation!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:33 +msgid "" +"Built for extensibility. (Multiple media types coming soon to the software," +" including video support!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:34 +msgid "" +"Powered by people like you. (You can help us improve this" +" software!)" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:38 +msgid "Excited to join us?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:39 +#, python-format +msgid "" +"Create a free account\n" +" or\n" +" Set up MediaGoblin on your own server" +msgstr "" + +#: mediagoblin/templates/mediagoblin/root.html:53 +msgid "Most recent media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 +msgid "Enter your new password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 +msgid "Enter your username or email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 +msgid "Your password has been changed. Try to log in now." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 +msgid "" +"Check your inbox. We sent an email with a URL for changing your password." +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to change your GNU MediaGoblin password, open the following URL in \n" +"your web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"If you think this is an error, just ignore this email and continue being\n" +"a happy goblin!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:30 +msgid "Logging in failed!" +msgstr "ప్రవేశం విఫలమయ్యింది!" + +#: mediagoblin/templates/mediagoblin/auth/login.html:43 +msgid "Don't have an account yet?" +msgstr "మీకు ఇంకా ఖాతా లేదా?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:46 +msgid "Create one here!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/login.html:49 +msgid "Forgot your password?" +msgstr "మీ సంకేతపదాన్ని మర్చిపోయారా?" + +#: mediagoblin/templates/mediagoblin/auth/login.html:52 +msgid "Change it!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/register.html:27 +msgid "Create an account!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/register.html:31 +msgid "Create" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 +#, python-format +msgid "" +"Hi %(username)s,\n" +"\n" +"to activate your GNU MediaGoblin account, open the following URL in\n" +"your web browser:\n" +"\n" +"%(verification_url)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:29 +#, python-format +msgid "Editing %(media_title)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:36 +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 +msgid "Cancel" +msgstr "రద్దుచేయి" + +#: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 +msgid "Save changes" +msgstr "మార్పులను భద్రపరచు" + +#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 +#, python-format +msgid "Editing %(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/listings/tag.html:31 +msgid "Media tagged with:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:26 +msgid "Submit yer media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "దాఖలు చెయ్యి" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 +#, python-format +msgid "Really delete %(title)s?" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 +msgid "Delete Permanently" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 +msgid "Media processing panel" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 +msgid "" +"You can track the state of media being processed for your gallery here." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 +msgid "Media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 +msgid "No media in-processing" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 +msgid "These uploads failed to process:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +msgid "Email verification needed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +msgid "Almost done! Your account still needs to be activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +msgid "" +"An email should arrive in a few moments with instructions on how to do so." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +msgid "In case it doesn't:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +msgid "Resend verification email" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +msgid "" +"Someone has registered an account with this username, but it still has to be" +" activated." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#, python-format +msgid "" +"If you are that person but you've lost your verification email, you can log in and resend it." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +msgid "Here's a spot to tell others about yourself." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +msgid "Edit profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +msgid "This user hasn't filled in their profile (yet)." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#, python-format +msgid "View all of %(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +msgid "" +"This is where your media will appear, but you don't seem to have added " +"anything yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +msgid "Add media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +msgid "There doesn't seem to be any media here yet..." +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 +msgid "feed icon" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 +msgid "Atom feed" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 +msgid "Newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 +msgid "Older" +msgstr "" + +#: mediagoblin/user_pages/forms.py:24 +msgid "Comment" +msgstr "వ్యాఖ్య" + +#: mediagoblin/user_pages/forms.py:30 +msgid "I am sure I want to delete this" +msgstr "" + +#: mediagoblin/user_pages/views.py:142 +msgid "Empty comments are not allowed." +msgstr "" + +#: mediagoblin/user_pages/views.py:148 +msgid "Comment posted!" +msgstr "" + +#: mediagoblin/user_pages/views.py:181 +msgid "You are about to delete another user's media. Proceed with caution." +msgstr "" + + -- cgit v1.2.3 From 34b0874d9ad305f4c8d5e892a679bad2f33ed277 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 30 Oct 2011 20:51:55 +0100 Subject: Some docs for the TestingMiddleware To make the TestingMiddleware actually more useful in the future, start to document it. --- mediagoblin/middleware/testing.py | 25 +++++++++++++++++++++++++ mediagoblin/tests/tools.py | 2 ++ 2 files changed, 27 insertions(+) diff --git a/mediagoblin/middleware/testing.py b/mediagoblin/middleware/testing.py index 06714769..99322661 100644 --- a/mediagoblin/middleware/testing.py +++ b/mediagoblin/middleware/testing.py @@ -15,6 +15,23 @@ # along with this program. If not, see . class TestingMiddleware(object): + """ + Middleware for the Unit tests + + It might make sense to perform some tests on all + requests/responses. Or prepare them in a special + manner. For example all html responses could be tested + for being valid html *after* being rendered. + + This module is getting inserted at the front of the + middleware list, which means: requests are handed here + first, responses last. So this wraps up the "normal" + app. + + If you need to add a test, either add it directly to + the appropiate process_request or process_response, or + create a new method and call it from process_*. + """ def __init__(self, mg_app): self.app = mg_app @@ -23,12 +40,20 @@ class TestingMiddleware(object): pass def process_response(self, request, response): + # All following tests should be for html only! if response.content_type != "text/html": # Get out early return + + # If the template contains a reference to + # /mgoblin_static/ instead of using + # /request.staticdirect(), error out here. + # This could probably be implemented as a grep on + # the shipped templates easier... if response.text.find("/mgoblin_static/") >= 0: raise AssertionError( "Response HTML contains reference to /mgoblin_static/ " "instead of staticdirect. Request was for: " + request.full_path) + return diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index e8558240..7f20f6e7 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -107,6 +107,8 @@ def get_test_app(dump_old_app=True): # Insert the TestingMiddleware, which can do some # sanity checks on every request/response. + # Doing it this way is probably not the cleanest way. + # We'll fix it, when we have plugins! mg_globals.app.middleware.insert(0, TestingMiddleware(mg_globals.app)) app = TestApp(test_app) -- cgit v1.2.3 From 33d11e995d183f339597715472e4f6ecc81ba557 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 12 Nov 2011 13:21:41 +0100 Subject: Move TestingMiddleware to tests/tools.py This middleware isn't needed outside of the tests, so let's just put it there. --- mediagoblin/middleware/testing.py | 59 --------------------------------------- mediagoblin/tests/tools.py | 46 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 60 deletions(-) delete mode 100644 mediagoblin/middleware/testing.py diff --git a/mediagoblin/middleware/testing.py b/mediagoblin/middleware/testing.py deleted file mode 100644 index 99322661..00000000 --- a/mediagoblin/middleware/testing.py +++ /dev/null @@ -1,59 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -class TestingMiddleware(object): - """ - Middleware for the Unit tests - - It might make sense to perform some tests on all - requests/responses. Or prepare them in a special - manner. For example all html responses could be tested - for being valid html *after* being rendered. - - This module is getting inserted at the front of the - middleware list, which means: requests are handed here - first, responses last. So this wraps up the "normal" - app. - - If you need to add a test, either add it directly to - the appropiate process_request or process_response, or - create a new method and call it from process_*. - """ - - def __init__(self, mg_app): - self.app = mg_app - - def process_request(self, request): - pass - - def process_response(self, request, response): - # All following tests should be for html only! - if response.content_type != "text/html": - # Get out early - return - - # If the template contains a reference to - # /mgoblin_static/ instead of using - # /request.staticdirect(), error out here. - # This could probably be implemented as a grep on - # the shipped templates easier... - if response.text.find("/mgoblin_static/") >= 0: - raise AssertionError( - "Response HTML contains reference to /mgoblin_static/ " - "instead of staticdirect. Request was for: " - + request.full_path) - - return diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 7f20f6e7..420d9ba8 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -23,7 +23,6 @@ from webtest import TestApp from mediagoblin import mg_globals from mediagoblin.tools import testing -from mediagoblin.middleware.testing import TestingMiddleware from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.decorators import _make_safe from mediagoblin.db.open import setup_connection_and_db_from_config @@ -51,6 +50,51 @@ $ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests""" class BadCeleryEnviron(Exception): pass +class TestingMiddleware(object): + """ + Middleware for the Unit tests + + It might make sense to perform some tests on all + requests/responses. Or prepare them in a special + manner. For example all html responses could be tested + for being valid html *after* being rendered. + + This module is getting inserted at the front of the + middleware list, which means: requests are handed here + first, responses last. So this wraps up the "normal" + app. + + If you need to add a test, either add it directly to + the appropiate process_request or process_response, or + create a new method and call it from process_*. + """ + + def __init__(self, mg_app): + self.app = mg_app + + def process_request(self, request): + pass + + def process_response(self, request, response): + # All following tests should be for html only! + if response.content_type != "text/html": + # Get out early + return + + # If the template contains a reference to + # /mgoblin_static/ instead of using + # /request.staticdirect(), error out here. + # This could probably be implemented as a grep on + # the shipped templates easier... + if response.text.find("/mgoblin_static/") >= 0: + raise AssertionError( + "Response HTML contains reference to /mgoblin_static/ " + "instead of staticdirect. Request was for: " + + request.full_path) + + return + + def suicide_if_bad_celery_environ(): if not os.environ.get('CELERY_CONFIG_MODULE') == \ 'mediagoblin.init.celery.from_tests': -- cgit v1.2.3 From daed11b81263c3841ae23f45ed1bf33aa2e92992 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 12 Nov 2011 14:26:35 +0100 Subject: 640: Configuration files should mention their _local versions Thanks go to Aleksej Serdjukov for bringing this up and providing the patch in the bug! --- mediagoblin.ini | 3 +++ paste.ini | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mediagoblin.ini b/mediagoblin.ini index c22d12d7..728ab2f2 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -1,3 +1,6 @@ +# If you want to make changes to this file, first copy it to +# mediagoblin_local.ini, then make the changes there. + [mediagoblin] direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" diff --git a/paste.ini b/paste.ini index 8866789c..c729e41d 100644 --- a/paste.ini +++ b/paste.ini @@ -1,3 +1,6 @@ +# If you want to make changes to this file, first copy it to +# paste_local.ini, then make the changes there. + [DEFAULT] # Set to true to enable web-based debugging messages and etc. debug = false -- cgit v1.2.3 From 8bb3eb185ab14e8e8f4fc7b3df9eac4e1438d030 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 12 Nov 2011 08:10:46 -0600 Subject: Probably should have MANIFEST.in checked in, for doing python sdists --- MANIFEST.in | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..b1f93dba --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +recursive-include mediagoblin/templates *.html +recursive-include mediagoblin/static *.js *.css *.png *.svg +recursive-include mediagoblin/tests *.ini +recursive-include docs *.rst *.html + -- cgit v1.2.3 From 0cf5b8ad2499a93fdba5ff1202fdc554208ec85f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 12 Nov 2011 13:35:41 -0600 Subject: Don't force-convert resized images to JPEG. That's just not nice for those of us who like transparency! --- mediagoblin/process_media/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 2b9eed6e..85bdcbea 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -136,7 +136,7 @@ def process_image(entry): thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') with thumb_file: - thumb.save(thumb_file, "JPEG", quality=90) + thumb.save(thumb_file) # If the size of the original file exceeds the specified size of a `medium` # file, a `medium.jpg` files is created and later associated with the media @@ -154,7 +154,7 @@ def process_image(entry): medium_file = mgg.public_store.get_file(medium_filepath, 'w') with medium_file: - medium.save(medium_file, "JPEG", quality=90) + medium.save(medium_file) medium_processed = True # we have to re-read because unlike PIL, not everything reads -- cgit v1.2.3 From d0504cfa875b0ac7340fb00a64fc8422faecdc9a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 12 Nov 2011 15:12:39 -0600 Subject: Final step for non-force-conversion to jpeg --- mediagoblin/process_media/__init__.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 85bdcbea..f63fb2b0 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -14,8 +14,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import Image +import os +import Image from celery.task import Task from celery import registry @@ -122,17 +123,16 @@ def process_image(entry): mgg.queue_store, queued_filepath, 'source') + extension = os.path.splitext(queued_filename)[1] + try: thumb = Image.open(queued_filename) except IOError: raise BadMediaFail() thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) - # ensure color mode is compatible with jpg - if thumb.mode != "RGB": - thumb = thumb.convert("RGB") - thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + thumb_filepath = create_pub_filepath(entry, 'thumbnail' + extension) thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') with thumb_file: @@ -147,10 +147,7 @@ def process_image(entry): if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) - if medium.mode != "RGB": - medium = medium.convert("RGB") - - medium_filepath = create_pub_filepath(entry, 'medium.jpg') + medium_filepath = create_pub_filepath(entry, 'medium' + extension) medium_file = mgg.public_store.get_file(medium_filepath, 'w') with medium_file: -- cgit v1.2.3 From efd0a42ca1b81a2dd17aee1626060584a278020c Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 13 Nov 2011 19:51:11 +0100 Subject: Mark two strings for translation --- mediagoblin/edit/views.py | 2 +- mediagoblin/templates/mediagoblin/base.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a6ddb553..17244831 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -170,7 +170,7 @@ def edit_profile(request): messages.add_message(request, messages.SUCCESS, - 'Profile edited!') + _("Profile edited!")) return redirect(request, 'mediagoblin.user_pages.user_home', user=edit_username) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b4c4dcf3..925386e5 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -67,7 +67,7 @@ user= request.user['username']) }}"> {{ request.user['username'] }} - (log out) + ({% trans %}log out{% endtrans %}) {% else %} {% trans %}Log in{% endtrans %} -- cgit v1.2.3 From b97ae0fd7da45c32897a4cb8437c04ddf04fdc95 Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sun, 13 Nov 2011 11:41:43 -0800 Subject: Issue 653: Don't throw exception if response has no vary header. --- mediagoblin/middleware/csrf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index 7a5e352e..6c977f21 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -98,7 +98,7 @@ class CsrfMiddleware(object): httponly=True) # update the Vary header - response.vary = (response.vary or []) + ['Cookie'] + response.vary = getattr(response, 'vary', []) + ['Cookie'] def _make_token(self, request): """Generate a new token to use for CSRF protection.""" -- cgit v1.2.3 From ad3f1233df672688c09ab923d8bb216a351db8cb Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sun, 13 Nov 2011 11:59:24 -0800 Subject: Issue 653: Handle the case where request.vary is None --- mediagoblin/middleware/csrf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index 6c977f21..d0601af8 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -98,7 +98,7 @@ class CsrfMiddleware(object): httponly=True) # update the Vary header - response.vary = getattr(response, 'vary', []) + ['Cookie'] + response.vary = (getattr(response, 'vary') or []) + ['Cookie'] def _make_token(self, request): """Generate a new token to use for CSRF protection.""" -- cgit v1.2.3 From d9ed3aeb402fc66de2a79d145b5a443c9e660c18 Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sun, 13 Nov 2011 12:07:09 -0800 Subject: Issue 653: This time for sure! --- mediagoblin/middleware/csrf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py index d0601af8..8275c18e 100644 --- a/mediagoblin/middleware/csrf.py +++ b/mediagoblin/middleware/csrf.py @@ -98,7 +98,7 @@ class CsrfMiddleware(object): httponly=True) # update the Vary header - response.vary = (getattr(response, 'vary') or []) + ['Cookie'] + response.vary = (getattr(response, 'vary', None) or []) + ['Cookie'] def _make_token(self, request): """Generate a new token to use for CSRF protection.""" -- cgit v1.2.3 From 688f56c2dc579218b35263d0189e5d7c9ba9627f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 13 Nov 2011 14:34:22 -0600 Subject: Improved title block on media page --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 17beffb2..2441ec1b 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -20,6 +20,8 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% from "mediagoblin/utils/pagination.html" import render_pagination %} +{% block title %}{{ media.title }} — {{ super() }}{% endblock %} + {% block mediagoblin_content %} {% if media %}
-- cgit v1.2.3 From 017d6ca3501b157277fc01fb37df2dbbd9ed17ef Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 13 Nov 2011 14:38:40 -0600 Subject: Enhanced title for user profile page --- mediagoblin/templates/mediagoblin/user_pages/user.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index c5beeaaa..d65da055 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -26,6 +26,17 @@ user=user.username) }}"> {% endblock mediagoblin_head %} +{% block title %} + {%- if user -%} + {%- trans username=user.username -%} + {{ username }}'s profile + {%- endtrans %} — {{ super() }} + {%- else -%} + {{ super() }} + {%- endif -%} +{% endblock %} + + {% block mediagoblin_content -%} {# If no user... #} {% if not user %} -- cgit v1.2.3 From 7fc25d27208ef9926e94eeba953160ffbe676942 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 13 Nov 2011 14:40:11 -0600 Subject: If the gallery view makes sure we have a user anyway, do we need this check? Seems like the classic annoying "SHOULD NEVER HAPPEN" else: statement :) --- .../templates/mediagoblin/user_pages/gallery.html | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html index df931d9c..86105493 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html +++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html @@ -27,28 +27,23 @@ {% endblock mediagoblin_head %} {% block mediagoblin_content -%} - {% if user %} -

- {%- trans username=user.username, - user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=user.username) -%} - {{ username }}'s media - {%- endtrans %} -

+

+ {%- trans username=user.username, + user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=user.username) -%} + {{ username }}'s media + {%- endtrans %} +

- + -
- {% set feed_url = request.urlgen( - 'mediagoblin.user_pages.atom_feed', - user=user.username) %} - {% include "mediagoblin/utils/feed_link.html" %} -
- {% else %} - {# This *should* not occur as the view makes sure we pass in a user. #} -

{% trans %}Sorry, no such user found.{% endtrans %}

- {% endif %} +

+ {% set feed_url = request.urlgen( + 'mediagoblin.user_pages.atom_feed', + user=user.username) %} + {% include "mediagoblin/utils/feed_link.html" %} +
{% endblock %} -- cgit v1.2.3 From ab56689017daa985f3938af4710f3c76ad415bda Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 13 Nov 2011 14:42:03 -0600 Subject: Enhanced title on the user's main media gallery --- mediagoblin/templates/mediagoblin/user_pages/gallery.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html index 86105493..b066dd71 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html +++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html @@ -26,6 +26,12 @@ user=user.username) }}"> {% endblock mediagoblin_head %} +{% block title %} + {%- trans username=user.username -%} + {{ username }}'s media + {%- endtrans %} — {{ super() }} +{% endblock %} + {% block mediagoblin_content -%}

{%- trans username=user.username, -- cgit v1.2.3 From 4671fda345394dad9ca4278b1cf7b2cdf7d2b4ee Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 13 Nov 2011 14:48:51 -0600 Subject: Improving on tag page *and* adjusting translation for RTL reasons Basically moving the variable inside the translation to give translators more flexibility --- mediagoblin/templates/mediagoblin/listings/tag.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/listings/tag.html b/mediagoblin/templates/mediagoblin/listings/tag.html index 58863015..f797f72f 100644 --- a/mediagoblin/templates/mediagoblin/listings/tag.html +++ b/mediagoblin/templates/mediagoblin/listings/tag.html @@ -26,9 +26,13 @@ tag=tag_slug) }}"> {% endblock mediagoblin_head %} +{% block title %} + {% trans %}Media tagged with: {{ tag_name }}{% endtrans %} — {{ super() }} +{% endblock %} + {% block mediagoblin_content -%} <h1> - {% trans %}Media tagged with:{% endtrans %} {{ tag_name }} + {% trans %}Media tagged with: {{ tag_name }}{% endtrans %} </h1> <div class="container_16 media_gallery"> -- cgit v1.2.3 From 2b7aa99d3c221e713a95b664491f35612f9023cc Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber <cwebber@dustycloud.org> Date: Sun, 13 Nov 2011 20:39:42 -0600 Subject: Only show "post a comment" link if comments already exist The purpose of the link is to help you jump past comments to the comment box, and so... Even with this new conditional, I'm not entirely sure I like that link ;) --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 2441ec1b..1e495b98 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -62,7 +62,7 @@ {%- endtrans %} </p> <h3></h3> - {% if request.user %} + {% if request.user and comments.count() %} <p><a href="#comment_form">{% trans %}Post a comment{% endtrans %}</a></p> {% endif %} {% if comments %} -- cgit v1.2.3 From b33701b851ef7f848d8d7b47e3654552da32b485 Mon Sep 17 00:00:00 2001 From: Joar Wandborg <git@wandborg.com> Date: Tue, 15 Nov 2011 00:27:21 +0100 Subject: moved from videoscale => ffvideoscale *and* put queus before video and audio pipes --- mediagoblin/media_types/video/transcoders.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 512c7cb6..3a30aedf 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -624,13 +624,16 @@ class VideoTranscoder: self.pipeline.add(self.decoder) # Video elements + self.videoqueue = gst.element_factory_make('queue', 'videoqueue') + self.pipeline.add(self.videoqueue) + self.ffmpegcolorspace = gst.element_factory_make( 'ffmpegcolorspace', 'ffmpegcolorspace') self.pipeline.add(self.ffmpegcolorspace) - self.videoscale = gst.element_factory_make('videoscale', 'videoscale') - self.videoscale.set_property('method', 2) # I'm not sure this works - self.videoscale.set_property('add-borders', 0) + self.videoscale = gst.element_factory_make('ffvideoscale', 'videoscale') + #self.videoscale.set_property('method', 2) # I'm not sure this works + #self.videoscale.set_property('add-borders', 0) self.pipeline.add(self.videoscale) self.capsfilter = gst.element_factory_make('capsfilter', 'capsfilter') @@ -642,6 +645,9 @@ class VideoTranscoder: self.pipeline.add(self.vp8enc) # Audio elements + self.audioqueue = gst.element_factory_make('queue', 'audioqueue') + self.pipeline.add(self.audioqueue) + self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') self.pipeline.add(self.audioconvert) @@ -679,6 +685,7 @@ class VideoTranscoder: self.filesrc.link(self.decoder) # Link all the video elements in a link to webmux + self.videoqueue.link(self.ffmpegcolorspace) self.ffmpegcolorspace.link(self.videoscale) self.videoscale.link(self.capsfilter) #self.capsfilter.link(self.xvimagesink) @@ -688,6 +695,7 @@ class VideoTranscoder: if self.data.is_audio: # Link all the audio elements in a line to webmux #self.audioconvert.link(self.alsasink) + self.audioqueue.link(self.audioconvert) self.audioconvert.link(self.vorbisenc) self.vorbisenc.link(self.webmmux) @@ -707,10 +715,10 @@ class VideoTranscoder: if self.ffmpegcolorspace.get_pad_template('sink')\ .get_caps().intersect(pad.get_caps()).is_empty(): # It is NOT a video src pad. - pad.link(self.audioconvert.get_pad('sink')) + pad.link(self.audioqueue.get_pad('sink')) else: # It IS a video src pad. - pad.link(self.ffmpegcolorspace.get_pad('sink')) + pad.link(self.videoqueue.get_pad('sink')) def _setup_bus(self): self.bus = self.pipeline.get_bus() -- cgit v1.2.3 From a9c7af90408c3537f42763e63862a2ae44bcc368 Mon Sep 17 00:00:00 2001 From: Elrond <elrond+mediagoblin.org@samba-tng.org> Date: Tue, 15 Nov 2011 11:21:15 +0100 Subject: export: Handle Unicode titles better in logging log("ascii %s" % unicode_string) tries to convert unicode to ascii, which might fail. Better use log(u"unicode format %s" % unicode_string) and let the logging framework handle the conversion. This works much better and the exceptions still happening aren't stopping the main app. Also remove one useless import. --- mediagoblin/gmg_commands/import_export.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index a46219a0..30112969 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -16,7 +16,6 @@ from mediagoblin import mg_globals from mediagoblin.db.open import setup_connection_and_db_from_config -from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.storage.filestorage import BasicFileStorage from mediagoblin.init import setup_storage, setup_global_and_app_config @@ -209,7 +208,7 @@ def _export_media(db, args): for entry in db.media_entries.find(): for name, path in entry['media_files'].items(): - _log.info('Exporting {0} - {1}'.format( + _log.info(u'Exporting {0} - {1}'.format( entry['title'], name)) -- cgit v1.2.3 From 7cbddc96a85410c14583b598312e40efe6051a44 Mon Sep 17 00:00:00 2001 From: Elrond <elrond+mediagoblin.org@samba-tng.org> Date: Mon, 14 Nov 2011 14:21:06 +0100 Subject: Enable mongokit's "Dot notation" mongokit documents can allow to use x.FIELD instead of x["FIELD"]. First it looks a lot more pythonic. Second it might allow us an easier migration path towards an sqlalchemy database backend. Docs: http://namlook.github.com/mongokit/tutorial.html#dot-notation --- mediagoblin/db/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index c010cb89..65c15917 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -63,6 +63,7 @@ class User(Document): - bio_html: biography of the user converted to proper HTML. """ __collection__ = 'users' + use_dot_notation = True structure = { 'username': unicode, @@ -177,6 +178,7 @@ class MediaEntry(Document): - fail_metadata: """ __collection__ = 'media_entries' + use_dot_notation = True structure = { 'uploader': ObjectId, @@ -321,6 +323,7 @@ class MediaComment(Document): """ __collection__ = 'media_comments' + use_dot_notation = True structure = { 'media_entry': ObjectId, -- cgit v1.2.3 From eabe6b678a98fd06d9cd8463935a3b842f41485c Mon Sep 17 00:00:00 2001 From: Elrond <elrond+mediagoblin.org@samba-tng.org> Date: Sun, 13 Nov 2011 19:25:06 +0100 Subject: Dot-Notation for "_id" Note: Migrations can't use "Dot Notation"! Migrations run on pymongo, not mongokit. So they can't use the "Dot Notation". This isn't really a big issue, as migrations are anyway quite mongo specific. --- mediagoblin/auth/lib.py | 4 ++-- mediagoblin/auth/views.py | 4 ++-- mediagoblin/db/models.py | 10 +++++----- mediagoblin/decorators.py | 6 +++--- mediagoblin/edit/lib.py | 2 +- mediagoblin/edit/views.py | 6 +++--- mediagoblin/process_media/__init__.py | 4 ++-- mediagoblin/submit/views.py | 10 +++++----- .../templates/mediagoblin/user_pages/media.html | 10 +++++----- mediagoblin/templates/mediagoblin/user_pages/user.html | 6 +++--- mediagoblin/tests/test_auth.py | 12 ++++++------ mediagoblin/tests/test_submission.py | 6 +++--- mediagoblin/tools/pagination.py | 2 +- mediagoblin/user_pages/views.py | 18 +++++++++--------- 14 files changed, 50 insertions(+), 50 deletions(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 653424cc..cf4a2b83 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -109,7 +109,7 @@ def send_verification_email(user, request): 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( host=request.host, uri=request.urlgen('mediagoblin.auth.verify_email'), - userid=unicode(user['_id']), + userid=unicode(user._id), verification_key=user['verification_key'])}) # TODO: There is no error handling in place @@ -144,7 +144,7 @@ def send_fp_verification_email(user, request): 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( host=request.host, uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), - userid=unicode(user['_id']), + userid=unicode(user._id), fp_verification_key=user['fp_verification_key'])}) # TODO: There is no error handling in place diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 8888d23c..8412b81c 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -87,7 +87,7 @@ def register(request): user.save(validate=True) # log the user in - request.session['user_id'] = unicode(user['_id']) + request.session['user_id'] = unicode(user._id) request.session.save() # send verification email @@ -122,7 +122,7 @@ def login(request): if user and user.check_login(request.POST['password']): # set up login in session - request.session['user_id'] = unicode(user['_id']) + request.session['user_id'] = unicode(user._id) request.session.save() if request.POST.get('next'): diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 65c15917..1c1bc2fd 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -219,7 +219,7 @@ class MediaEntry(Document): def get_comments(self): return self.db.MediaComment.find({ - 'media_entry': self['_id']}).sort('created', DESCENDING) + 'media_entry': self._id}).sort('created', DESCENDING) def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): @@ -250,7 +250,7 @@ class MediaEntry(Document): {'slug': self['slug']}) if duplicate: - self['slug'] = "%s-%s" % (self['_id'], self['slug']) + self['slug'] = "%s-%s" % (self._id, self['slug']) def url_for_self(self, urlgen): """ @@ -269,13 +269,13 @@ class MediaEntry(Document): return urlgen( 'mediagoblin.user_pages.media_home', user=uploader['username'], - media=unicode(self['_id'])) + media=unicode(self._id)) def url_to_prev(self, urlgen): """ Provide a url to the previous entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id': {"$gt": self['_id']}, + cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id}, 'uploader': self['uploader'], 'state': 'processed'}).sort( '_id', ASCENDING).limit(1) @@ -288,7 +288,7 @@ class MediaEntry(Document): """ Provide a url to the next entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id': {"$lt": self['_id']}, + cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id}, 'uploader': self['uploader'], 'state': 'processed'}).sort( '_id', DESCENDING).limit(1) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index b247e229..8f7532ec 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -60,7 +60,7 @@ def user_may_delete_media(controller): uploader = request.db.MediaEntry.find_one( {'_id': ObjectId(request.matchdict['media'])}).uploader() if not (request.user['is_admin'] or - request.user['_id'] == uploader['_id']): + request.user._id == uploader._id): return exc.HTTPForbidden() return controller(request, *args, **kwargs) @@ -99,7 +99,7 @@ def get_user_media_entry(controller): media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], 'state': 'processed', - 'uploader': user['_id']}) + 'uploader': user._id}) # no media via slug? Grab it via ObjectId if not media: @@ -107,7 +107,7 @@ def get_user_media_entry(controller): media = request.db.MediaEntry.find_one( {'_id': ObjectId(request.matchdict['media']), 'state': 'processed', - 'uploader': user['_id']}) + 'uploader': user._id}) except InvalidId: return render_404(request) diff --git a/mediagoblin/edit/lib.py b/mediagoblin/edit/lib.py index b722e9c1..458b704e 100644 --- a/mediagoblin/edit/lib.py +++ b/mediagoblin/edit/lib.py @@ -17,7 +17,7 @@ def may_edit_media(request, media): """Check, if the request's user may edit the media details""" - if media['uploader'] == request.user['_id']: + if media['uploader'] == request.user._id: return True if request.user['is_admin']: return True diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index f3ebebe8..5f781552 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -57,7 +57,7 @@ def edit_media(request, media): existing_user_slug_entries = request.db.MediaEntry.find( {'slug': request.POST['slug'], 'uploader': media['uploader'], - '_id': {'$ne': media['_id']}}).count() + '_id': {'$ne': media._id}}).count() if existing_user_slug_entries: form.slug.errors.append( @@ -78,7 +78,7 @@ def edit_media(request, media): location=media.url_for_self(request.urlgen)) if request.user['is_admin'] \ - and media['uploader'] != request.user['_id'] \ + and media['uploader'] != request.user._id \ and request.method != 'POST': messages.add_message( request, messages.WARNING, @@ -104,7 +104,7 @@ def edit_attachments(request, media): attachment_public_filepath \ = mg_globals.public_store.get_unique_filepath( - ['media_entries', unicode(media['_id']), 'attachment', + ['media_entries', unicode(media._id), 'attachment', secure_filename(request.POST['attachment_file'].filename)]) attachment_public_file = mg_globals.public_store.get_file( diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 3d6b418f..34d83e54 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -32,7 +32,7 @@ MEDIUM_SIZE = 640, 640 def create_pub_filepath(entry, filename): return mgg.public_store.get_unique_filepath( ['media_entries', - unicode(entry['_id']), + unicode(entry._id), filename]) @@ -56,7 +56,7 @@ class ProcessMedia(Task): try: process_image(entry) except BaseProcessingFail, exc: - mark_entry_failed(entry[u'_id'], exc) + mark_entry_failed(entry._id, exc) return entry['state'] = u'processed' diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 25f7d79d..bd63bd18 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -52,7 +52,7 @@ def submit_start(request): # create entry and save in database entry = request.db.MediaEntry() - entry['_id'] = ObjectId() + entry._id = ObjectId() entry['title'] = ( unicode(request.POST['title']) or unicode(splitext(filename)[0])) @@ -62,7 +62,7 @@ def submit_start(request): entry['description']) entry['media_type'] = u'image' # heh - entry['uploader'] = request.user['_id'] + entry['uploader'] = request.user._id # Process the user's folksonomy "tags" entry['tags'] = convert_to_tag_list_of_dicts( @@ -74,7 +74,7 @@ def submit_start(request): # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', - unicode(entry['_id']), + unicode(entry._id), secure_filename(filename)]) # queue appropriately @@ -105,7 +105,7 @@ def submit_start(request): # conditions with changes to the document via processing code) try: process_media.apply_async( - [unicode(entry['_id'])], {}, + [unicode(entry._id)], {}, task_id=task_id) except BaseException as exc: # The purpose of this section is because when running in "lazy" @@ -116,7 +116,7 @@ def submit_start(request): # # ... not completely the diaper pattern because the # exception is re-raised :) - mark_entry_failed(entry[u'_id'], exc) + mark_entry_failed(entry._id, exc) # re-raise the exception raise diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 1e495b98..4b02b684 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -69,10 +69,10 @@ {% for comment in comments %} {% set comment_author = comment.author() %} {% if pagination.active_id == comment._id %} - <div class="comment_wrapper comment_active" id="comment-{{ comment['_id'] }}"> + <div class="comment_wrapper comment_active" id="comment-{{ comment._id }}"> <a name="comment" id="comment"></a> {% else %} - <div class="comment_wrapper" id="comment-{{ comment['_id'] }}"> + <div class="comment_wrapper" id="comment-{{ comment._id }}"> {% endif %} <div class="comment_content">{% autoescape False %}{{ comment.content_html }} @@ -83,7 +83,7 @@ {{ comment_author['username'] }}</a> {% trans %}at{% endtrans %} <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment', - comment = comment['_id'], + comment = comment._id, user = media.uploader().username, media = media._id) }}#comment"> {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} @@ -114,7 +114,7 @@ <div class="grid_5 omega"> {% include "mediagoblin/utils/prev_next.html" %} - {% if media['uploader'] == request.user['_id'] or + {% if media['uploader'] == request.user._id or request.user['is_admin'] %} <h3>{% trans %}Actions{% endtrans %}</h3> <p> @@ -151,7 +151,7 @@ {% endif %} {% if app_config['allow_attachments'] - and (media['uploader'] == request.user['_id'] + and (media['uploader'] == request.user._id or request.user['is_admin']) %} <p> <a href="{{ request.urlgen('mediagoblin.edit.attachments', diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index d65da055..1de7f611 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -90,7 +90,7 @@ </h1> {% if not user['url'] and not user['profile'] %} - {% if request.user['_id'] == user['_id'] %} + {% if request.user._id == user._id %} <div class="grid_6 alpha empty_space"> <p> {% trans %}Here's a spot to tell others about yourself.{% endtrans %} @@ -113,7 +113,7 @@ {% else %} <div class="grid_6 alpha"> {% include "mediagoblin/utils/profile.html" %} - {% if request.user['_id'] == user['_id'] or request.user['is_admin'] %} + {% if request.user._id == user._id or request.user['is_admin'] %} <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ user.username }}"> {%- trans %}Edit profile{% endtrans -%} @@ -140,7 +140,7 @@ {% include "mediagoblin/utils/feed_link.html" %} </div> {% else %} - {% if request.user['_id'] == user['_id'] %} + {% if request.user._id == user._id %} <div class="grid_10 omega empty_space"> <p> {% trans -%} diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 40961eca..153c6e53 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -168,7 +168,7 @@ def test_register_views(test_app): ## Make sure user is logged in request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] - assert request.session['user_id'] == unicode(new_user['_id']) + assert request.session['user_id'] == unicode(new_user._id) ## Make sure we get email confirmation, and try verifying assert len(mail.EMAIL_TEST_INBOX) == 1 @@ -185,7 +185,7 @@ def test_register_views(test_app): ### user should have these same parameters assert parsed_get_params['userid'] == [ - unicode(new_user['_id'])] + unicode(new_user._id)] assert parsed_get_params['token'] == [ new_user['verification_key']] @@ -193,7 +193,7 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.get( "/auth/verify_email/?userid=%s&token=total_bs" % unicode( - new_user['_id'])) + new_user._id)) response.follow() context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html'] @@ -269,7 +269,7 @@ def test_register_views(test_app): # user should have matching parameters new_user = mg_globals.database.User.find_one({'username': 'happygirl'}) - assert parsed_get_params['userid'] == [unicode(new_user['_id'])] + assert parsed_get_params['userid'] == [unicode(new_user._id)] assert parsed_get_params['token'] == [new_user['fp_verification_key']] ### The forgotten password token should be set to expire in ~ 10 days @@ -280,7 +280,7 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.get( "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( - new_user['_id']), status=400) + new_user._id), status=400) assert response.status == '400 Bad Request' ## Try using an expired token to change password, shouldn't work @@ -412,7 +412,7 @@ def test_authentication_views(test_app): # Make sure user is in the session context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] session = context['request'].session - assert session['user_id'] == unicode(test_user['_id']) + assert session['user_id'] == unicode(test_user._id) # Successful logout # ----------------- diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 1c657e6c..dec7118b 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -177,7 +177,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media['_id']), + media=media._id), # no value means no confirm {}) @@ -197,7 +197,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media['_id']), + media=media._id), {'confirm': 'y'}) response.follow() @@ -208,7 +208,7 @@ class TestSubmission: # Does media entry still exist? assert_false( request.db.MediaEntry.find( - {'_id': media['_id']}).count()) + {'_id': media._id}).count()) def test_malicious_uploads(self): # Test non-suppoerted file with non-supported extension diff --git a/mediagoblin/tools/pagination.py b/mediagoblin/tools/pagination.py index bc20ec90..5ebc3c5a 100644 --- a/mediagoblin/tools/pagination.py +++ b/mediagoblin/tools/pagination.py @@ -53,7 +53,7 @@ class Pagination(object): cursor = copy.copy(self.cursor) for (doc, increment) in izip(cursor, count(0)): - if doc['_id'] == jump_to_id: + if doc._id == jump_to_id: self.page = 1 + int(floor(increment / self.per_page)) self.active_id = jump_to_id diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2090d6fd..82865bb4 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -45,7 +45,7 @@ def user_home(request, page): {'user': user}) cursor = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) @@ -78,7 +78,7 @@ def user_gallery(request, page): return render_404(request) cursor = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) @@ -135,8 +135,8 @@ def media_post_comment(request, media): assert request.method == 'POST' comment = request.db.MediaComment() - comment['media_entry'] = media['_id'] - comment['author'] = request.user['_id'] + comment['media_entry'] = media._id + comment['author'] = request.user._id comment['content'] = unicode(request.POST['comment_content']) comment['content_html'] = cleaned_markdown_conversion(comment['content']) @@ -179,7 +179,7 @@ def media_confirm_delete(request, media): location=media.url_for_self(request.urlgen)) if ((request.user[u'is_admin'] and - request.user[u'_id'] != media.uploader()[u'_id'])): + request.user._id != media.uploader()._id)): messages.add_message( request, messages.WARNING, _("You are about to delete another user's media. " @@ -207,7 +207,7 @@ def atom_feed(request): return render_404(request) cursor = request.db.MediaEntry.find({ - 'uploader': user['_id'], + 'uploader': user._id, 'state': 'processed'}) \ .sort('created', DESCENDING) \ .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) @@ -251,7 +251,7 @@ def processing_panel(request): # # Make sure we have permission to access this user's panel. Only # admins and this user herself should be able to do so. - if not (user[u'_id'] == request.user[u'_id'] + if not (user._id == request.user._id or request.user.is_admin): # No? Let's simply redirect to this user's homepage then. return redirect( @@ -260,12 +260,12 @@ def processing_panel(request): # Get media entries which are in-processing processing_entries = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processing'}).sort('created', DESCENDING) # Get media entries which have failed to process failed_entries = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'failed'}).sort('created', DESCENDING) # Render to response -- cgit v1.2.3 From 3618a9ac5112c657fd095a0f9cbd346921a4e800 Mon Sep 17 00:00:00 2001 From: Elrond <elrond+mediagoblin.org@samba-tng.org> Date: Mon, 14 Nov 2011 17:11:37 +0100 Subject: Dot-Notation: x._id = ObjectId() doesn't seem to work properly For whatever reason, this does not work as expected: entry._id = ObjectId() Need to go this way: entry['_id'] = ObjectId() --- mediagoblin/submit/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index bd63bd18..139b1d1d 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -52,7 +52,7 @@ def submit_start(request): # create entry and save in database entry = request.db.MediaEntry() - entry._id = ObjectId() + entry['_id'] = ObjectId() entry['title'] = ( unicode(request.POST['title']) or unicode(splitext(filename)[0])) -- cgit v1.2.3 From 64fd0462bdd821d5777d9697e67d951838f87de0 Mon Sep 17 00:00:00 2001 From: Joar Wandborg <git@wandborg.com> Date: Tue, 15 Nov 2011 22:43:05 +0100 Subject: Committing some futile attempts to make GStreamer transcode the audio properly. - Added CPU count detection - Added videorate - Added audiorate --- mediagoblin/media_types/video/transcoders.py | 45 +++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 3a30aedf..de3701f6 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -29,6 +29,18 @@ _log = logging.getLogger(__name__) logging.basicConfig() _log.setLevel(logging.DEBUG) +CPU_COUNT = 2 +try: + import multiprocessing + try: + CPU_COUNT = multiprocessing.cpu_count() + except NotImplementedError: + _log.warning('multiprocessing.cpu_count not implemented') + pass +except ImportError: + _log.warning('Could not import multiprocessing, defaulting to 2 CPU cores') + pass + try: import gtk except: @@ -627,10 +639,13 @@ class VideoTranscoder: self.videoqueue = gst.element_factory_make('queue', 'videoqueue') self.pipeline.add(self.videoqueue) + self.videorate = gst.element_factory_make('videorate', 'videorate') + self.pipeline.add(self.videorate) + self.ffmpegcolorspace = gst.element_factory_make( 'ffmpegcolorspace', 'ffmpegcolorspace') self.pipeline.add(self.ffmpegcolorspace) - + self.videoscale = gst.element_factory_make('ffvideoscale', 'videoscale') #self.videoscale.set_property('method', 2) # I'm not sure this works #self.videoscale.set_property('add-borders', 0) @@ -648,11 +663,22 @@ class VideoTranscoder: self.audioqueue = gst.element_factory_make('queue', 'audioqueue') self.pipeline.add(self.audioqueue) + self.audiorate = gst.element_factory_make('audiorate', 'audiorate') + self.pipeline.add(self.audiorate) + self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') self.pipeline.add(self.audioconvert) + self.audiocapsfilter = gst.element_factory_make('capsfilter', 'audiocapsfilter') + audiocaps = ['audio/x-raw-float'] + self.audiocapsfilter.set_property( + 'caps', + gst.caps_from_string( + ','.join(audiocaps))) + self.pipeline.add(self.audiocapsfilter) + self.vorbisenc = gst.element_factory_make('vorbisenc', 'vorbisenc') - self.vorbisenc.set_property('quality', 0.7) + self.vorbisenc.set_property('quality', 1) self.pipeline.add(self.vorbisenc) # WebMmux & filesink @@ -685,7 +711,8 @@ class VideoTranscoder: self.filesrc.link(self.decoder) # Link all the video elements in a link to webmux - self.videoqueue.link(self.ffmpegcolorspace) + self.videoqueue.link(self.videorate) + self.videorate.link(self.ffmpegcolorspace) self.ffmpegcolorspace.link(self.videoscale) self.videoscale.link(self.capsfilter) #self.capsfilter.link(self.xvimagesink) @@ -695,8 +722,12 @@ class VideoTranscoder: if self.data.is_audio: # Link all the audio elements in a line to webmux #self.audioconvert.link(self.alsasink) - self.audioqueue.link(self.audioconvert) - self.audioconvert.link(self.vorbisenc) + self.audioqueue.link(self.audiorate) + self.audiorate.link(self.audioconvert) + self.audioconvert.link(self.audiocapsfilter) + self.audiocapsfilter.link(self.vorbisenc) + #self.audiocapsfilter.link(self.level) + #self.level.link(self.vorbisenc) self.vorbisenc.link(self.webmmux) self.webmmux.link(self.progressreport) @@ -729,7 +760,7 @@ class VideoTranscoder: ''' Sets up the output format (width, height) for the video ''' - caps = ['video/x-raw-yuv', 'pixel-aspect-ratio=1/1'] + caps = ['video/x-raw-yuv', 'pixel-aspect-ratio=1/1', 'framerate=30/1'] if self.data.videoheight > self.data.videowidth: # Whoa! We have ourselves a portrait video! @@ -743,7 +774,7 @@ class VideoTranscoder: self.capsfilter.set_property( 'caps', gst.caps_from_string( - ', '.join(caps))) + ','.join(caps))) def _on_message(self, bus, message): _log.debug((bus, message, message.type)) -- cgit v1.2.3 From 359781f075f22c6ea677e28756c8046b2f405e63 Mon Sep 17 00:00:00 2001 From: Joar Wandborg <git@wandborg.com> Date: Wed, 16 Nov 2011 14:20:27 +0100 Subject: Fixed video transcoding - Added audiorate with tolerance 80 million - Removed deprecated thumbnailer --- mediagoblin/media_types/video/transcoders.py | 213 +-------------------------- 1 file changed, 1 insertion(+), 212 deletions(-) diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index de3701f6..f6a2eb21 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -340,218 +340,6 @@ class VideoThumbnailer: self.loop.quit() -class DeprecatedVideoThumbnailer: - ''' - Creates a video thumbnail - - - Sets up discoverer & transcoding pipeline. - Discoverer finds out information about the media file - - Launches gobject.MainLoop, this triggers the discoverer to start running - - Once the discoverer is done, it calls the __discovered callback function - - The __discovered callback function launches the transcoding process - - The _on_message callback is called from the transcoding process until it - gets a message of type gst.MESSAGE_EOS, then it calls __stop which shuts - down the gobject.MainLoop - ''' - - WADSWORTH_CONSTANT = 30 # percent - - def __init__(self, src, dst, **kwargs): - _log.info('Initializing VideoThumbnailer...') - - self.loop = gobject.MainLoop() - - self.source_path = src - self.destination_path = dst - - self.destination_dimensions = kwargs.get('dimensions') or (180, 180) - - if not type(self.destination_dimensions) == tuple: - raise Exception('dimensions must be tuple: (width, height)') - - self._setup() - self._run() - - def _setup(self): - self._setup_pipeline() - self._setup_discover() - - def _run(self): - _log.info('Discovering...') - self.discoverer.discover() - _log.info('Done') - - _log.debug('Initializing MainLoop()') - self.loop.run() - - def _setup_discover(self): - self.discoverer = discoverer.Discoverer(self.source_path) - - # Connect self.__discovered to the 'discovered' event - self.discoverer.connect('discovered', self.__discovered) - - def __discovered(self, data, is_media): - ''' - Callback for media discoverer. - ''' - if not is_media: - self.__stop() - raise Exception('Could not discover {0}'.format(self.source_path)) - - _log.debug('__discovered, data: {0}'.format(data)) - - self.data = data - - # Run any tasks that depend on the info from the discovery - self._on_discovered() - - # Tell the transcoding pipeline to start running - _log.info('Transcoding...') - - def _on_discovered(self): - self.__setup_capsfilter() - - def _setup_pipeline(self): - # Create a new pipeline - self.pipeline = gst.Pipeline('VideoThumbnailerPipeline') - - # Create the elements in the pipeline - self.filesrc = gst.element_factory_make('filesrc', 'filesrc') - self.filesrc.set_property('location', self.source_path) - self.pipeline.add(self.filesrc) - - self.decoder = gst.element_factory_make('decodebin2', 'decoder') - self.decoder.connect('new-decoded-pad', self._on_dynamic_pad) - self.pipeline.add(self.decoder) - - self.ffmpegcolorspace = gst.element_factory_make( - 'ffmpegcolorspace', 'ffmpegcolorspace') - self.pipeline.add(self.ffmpegcolorspace) - - self.videoscale = gst.element_factory_make('videoscale', 'videoscale') - self.videoscale.set_property('method', 'bilinear') - self.pipeline.add(self.videoscale) - - self.capsfilter = gst.element_factory_make('capsfilter', 'capsfilter') - self.pipeline.add(self.capsfilter) - - self.jpegenc = gst.element_factory_make('jpegenc', 'jpegenc') - self.pipeline.add(self.jpegenc) - - #self.filesink = gst.element_factory_make('filesink', 'filesink') - #self.filesink.set_property('location', self.destination_path) - #self.pipeline.add(self.filesink) - - self.appsink = gst.element_factory_make('appsink', 'appsink') - self.appsink.set_property('emit-signals', True) - self.appsink.connect('new-preroll', self.__on_sink_preroll) - self.pipeline.add(self.appsink) - - self.progressreport = gst.element_factory_make( - 'progressreport', 'progressreport') - self.progressreport.set_property('update-freq', 1) - self.pipeline.add(self.progressreport) - - self.identity = gst.element_factory_make('identity', 'id') - self.pipeline.add(self.identity) - - # Link all the elements together - self.filesrc.link(self.decoder) - self.ffmpegcolorspace.link(self.videoscale) - self.videoscale.link(self.capsfilter) - self.capsfilter.link(self.jpegenc) - self.jpegenc.link(self.progressreport) - self.progressreport.link(self.identity) - #self.identity.link(self.filesink) - self.identity.link(self.appsink) - - self.pipeline.set_state(gst.STATE_PAUSED) - - self._setup_bus() - - def __on_sink_preroll(self, sink): - _log.debug('SINK PREROLL!!!!') - - def _on_dynamic_pad(self, dbin, pad, islast): - ''' - Callback called when ``decodebin2`` has a pad that we can connect to - ''' - # Intersect the capabilities of the video sink and the pad src - # Then check if they have no common capabilities. - if not self.ffmpegcolorspace.get_pad_template('sink')\ - .get_caps().intersect(pad.get_caps()).is_empty(): - # It IS a video src pad. - pad.link(self.ffmpegcolorspace.get_pad('sink')) - gst.DEBUG_BIN_TO_DOT_FILE( - self.pipeline, - gst.DEBUG_GRAPH_SHOW_ALL, - 'ss') - - def _setup_bus(self): - self.bus = self.pipeline.get_bus() - self.bus.add_signal_watch() - self.bus.connect('message', self._on_message) - - def __setup_capsfilter(self): - caps = ['video/x-raw-rgb', 'pixel-aspect-ratio=1/1'] - - if self.data.videoheight > self.data.videowidth: - # Whoa! We have ourselves a portrait video! - caps.append('height={0}'.format( - self.destination_dimensions[1])) - else: - # It's a landscape, phew, how normal. - caps.append('width={0}'.format( - self.destination_dimensions[0])) - - self.capsfilter.set_property( - 'caps', - gst.caps_from_string( - ', '.join(caps))) - - def __find_wadsworth(self): - if self.decoder.seek_simple( - gst.FORMAT_PERCENT, - gst.SEEK_FLAG_NONE, - 0 * 10000): - _log.info('Found wadsworth') - #pdb.set_trace() - #self.pipeline.set_state(gst.STATE_PLAYING) - self.__get_buffer() - self.__stop() - else: - pdb.set_trace() - - def __get_buffer(self): - buffer = self.appsink.emit('pull-preroll') - open(self.destination_path, 'wb').write(buffer) - - def _on_message(self, bus, message): - t = message.type - - _log.debug(( - t == gst.MESSAGE_ASYNC_DONE, - bus, - message)) - - if t == gst.MESSAGE_EOS: - self.__stop() - _log.info('Got EOS') - elif t == gst.MESSAGE_ASYNC_DONE: - #pdb.set_trace() - self.__find_wadsworth() - elif t == gst.MESSAGE_ERROR: - _log.error((bus, message)) - self.__stop() - - def __stop(self): - _log.debug(self.loop) - - self.pipeline.set_state(gst.STATE_NULL) - - gobject.idle_add(self.loop.quit) - - class VideoTranscoder: ''' Video transcoder @@ -664,6 +452,7 @@ class VideoTranscoder: self.pipeline.add(self.audioqueue) self.audiorate = gst.element_factory_make('audiorate', 'audiorate') + self.audiorate.set_property('tolerance', 80000000) self.pipeline.add(self.audiorate) self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') -- cgit v1.2.3 From 76c6c806caec7af20a3fe11c04bb783baacc3934 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber <cwebber@dustycloud.org> Date: Wed, 16 Nov 2011 17:53:46 -0600 Subject: Accidentally had user['profile'] where it shoulda been user['bio'] --- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index c5beeaaa..6d938262 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -78,7 +78,7 @@ {%- trans username=user.username %}{{ username }}'s profile{% endtrans -%} </h1> - {% if not user['url'] and not user['profile'] %} + {% if not user['url'] and not user['bio'] %} {% if request.user['_id'] == user['_id'] %} <div class="grid_6 alpha empty_space"> <p> -- cgit v1.2.3 From ccca0fbfc3667900d0a5ad3687c27f4fd72db061 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber <cwebber@dustycloud.org> Date: Thu, 17 Nov 2011 08:28:23 -0600 Subject: Beginnings of sqlalchemy models --- mediagoblin/db/sql.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 mediagoblin/db/sql.py diff --git a/mediagoblin/db/sql.py b/mediagoblin/db/sql.py new file mode 100644 index 00000000..31ebfbf4 --- /dev/null +++ b/mediagoblin/db/sql.py @@ -0,0 +1,95 @@ +import datetime + +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import ( + Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint) + + +Base = declarative_base() + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True) + username = Column(Unicode, nullable=False, unique=True) + email = Column(Unicode, nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + pw_hash = Column(Unicode, nullable=False) + email_verified = Column(Boolean) + status = Column(Unicode, default="needs_email_verification", nullable=False) + verification_key = Column(Unicode) + is_admin = Column(Boolean, default=False, nullable=False) + url = Column(Unicode) + bio = Column(UnicodeText) # ?? + bio_html = Column(UnicodeText) # ?? + fp_verification_key = Column(Unicode) + fp_verification_expire = Column(DateTime) + + ## TODO + # plugin data would be in a separate model + + +class MediaEntry(Base): + __tablename__ = "media_entries" + + id = Column(Integer, primary_key=True) + uploader = Column(Integer, ForeignKey('users.id'), nullable=False) + slug = Column(Unicode, nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + description = Column(UnicodeText) # ?? + description_html = Column(UnicodeText) # ?? + media_type = Column(Unicode, nullable=False) + + fail_error = Column(Unicode) + fail_metadata = Column(UnicodeText) + + queued_media_file = Column(Unicode) + + queued_task_id = Column(Unicode) + + __table_args__ = ( + UniqueConstraint('uploader', 'slug'), + {}) + + ## TODO + # media_files + # media_data + # attachment_files + # fail_error + + +class Tag(Base): + __tablename__ = "tags" + + id = Column(Integer, primary_key=True) + slug = Column(Unicode, nullable=False, unique=True) + + +class MediaTag(Base): + __tablename__ = "media_tags" + + id = Column(Integer, primary_key=True) + tag = Column(Integer, ForeignKey('tags.id'), nullable=False) + name = Column(Unicode) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), + nullable=False) + # created = Column(DateTime, nullable=False, default=datetime.datetime.now) + + __table_args__ = ( + UniqueConstraint('tag', 'media_entry'), + {}) + + +class MediaComment(Base): + __tablename__ = "media_comments" + + id = Column(Integer, primary_key=True) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), nullable=False) + author = Column(Integer, ForeignKey('users.id'), nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + content = Column(UnicodeText, nullable=False) + content_html = Column(UnicodeText) -- cgit v1.2.3 From 6950c6c77c2daf4a47810e05a7c3f64f8995059d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber <cwebber@dustycloud.org> Date: Sat, 19 Nov 2011 08:31:37 -0600 Subject: Adding app_config and global_config to the template environment --- mediagoblin/tools/template.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index 905a36df..a0eaabe7 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -55,6 +55,8 @@ def get_jinja_env(template_loader, locale): template_env.globals['fetch_messages'] = messages.fetch_messages template_env.globals['gridify_list'] = gridify_list template_env.globals['gridify_cursor'] = gridify_cursor + template_env.globals['app_config'] = mg_globals.app_config + template_env.globals['global_config'] = mg_globals.global_config if exists(locale): SETUP_JINJA_ENVS[locale] = template_env -- cgit v1.2.3 From 53bc39755bf22fe8eebf06b051018eba111a64e7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber <cwebber@dustycloud.org> Date: Sat, 19 Nov 2011 08:33:29 -0600 Subject: Add app_config and global_config to the template environment --- mediagoblin/tools/template.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index a0eaabe7..0986761b 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -52,6 +52,7 @@ def get_jinja_env(template_loader, locale): # All templates will know how to ... # ... fetch all waiting messages and remove them from the queue # ... construct a grid of thumbnails or other media + # ... have access to the global and app config template_env.globals['fetch_messages'] = messages.fetch_messages template_env.globals['gridify_list'] = gridify_list template_env.globals['gridify_cursor'] = gridify_cursor -- cgit v1.2.3 From 3c0411f51f43ade8c7d47df4f3843fd79d4709b5 Mon Sep 17 00:00:00 2001 From: "Pablo J. Urbano Santos" <flamma@member.fsf.org> Date: Sat, 19 Nov 2011 17:07:41 +0100 Subject: Allow instance owners to customize html titles of page: Added html_title config option. Made base.html template use html_title option as page title. --- mediagoblin/config_spec.ini | 3 +++ mediagoblin/templates/mediagoblin/base.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 900957ce..b804358c 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -1,4 +1,7 @@ [mediagoblin] +# HTML title of the pages +html_title = string(default="GNU MediaGoblin") + # database stuff db_host = string() db_name = string(default="mediagoblin") diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 925386e5..0d6b9e40 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -19,7 +19,7 @@ <html> <head> <meta charset="utf-8"> - <title>{% block title %}{% trans %}GNU MediaGoblin{% endtrans %}{% endblock title %} + {{ app_config['html_title'] }} Date: Sat, 19 Nov 2011 19:11:42 +0100 Subject: Added parameter ascending to MediaEntry::get_comments, if true, comments will be ordered ascending, otherwise descending --- mediagoblin/db/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 1c1bc2fd..f13a4457 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -217,9 +217,14 @@ class MediaEntry(Document): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} - def get_comments(self): + def get_comments(self, ascending=False): + if ascending: + order = ASCENDING + else: + order = DESCENDING + return self.db.MediaComment.find({ - 'media_entry': self._id}).sort('created', DESCENDING) + 'media_entry': self._id}).sort('created', order) def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): -- cgit v1.2.3 From 1a3138addd43d410b03cdd1816e0a62bd217de30 Mon Sep 17 00:00:00 2001 From: "Pablo J. Urbano Santos" Date: Sat, 19 Nov 2011 19:15:41 +0100 Subject: media_home: order comments by ascending date. --- mediagoblin/user_pages/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 82865bb4..98a21bb4 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -106,11 +106,11 @@ def media_home(request, media, page, **kwargs): """ if ObjectId(request.matchdict.get('comment')): pagination = Pagination( - page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE, + page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE, ObjectId(request.matchdict.get('comment'))) else: pagination = Pagination( - page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) + page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE) comments = pagination() -- cgit v1.2.3 From fc5695c538f2b6d230c0e431087e9c10e6deac6c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 19 Nov 2011 10:43:31 -0800 Subject: incorrect path in nginx config --- docs/source/deploying.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index c2ba0c47..b944a3d3 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -207,7 +207,7 @@ this ``nginx.conf`` file should be modeled on the following: :: # Instance specific media: location /mgoblin_media/ { - alias /srv/mediagoblin.example.org/mediagoblin/mediagoblin/user_dev/media/public/; + alias /srv/mediagoblin.example.org/mediagoblin/user_dev/media/public/; } # Mounting MediaGoblin itself via fastcgi. -- cgit v1.2.3 From b4b7b6a57a5ad9a5e52a5d3e05f9ad3d3e8b650a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 19 Nov 2011 13:42:30 -0600 Subject: Added Corey Farwell to the list of contributors --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index c9fc5c8e..b0ef7154 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Thank you! * Alex Camelio * Bernhard Keller * Caleb Forbes Davis V +* Corey Farwell * Chris Moylan * Christopher Allan Webber * Daniel Neel -- cgit v1.2.3 From 7c378f2cd5324a05e709cbada5eb5668ce3a3469 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 19 Nov 2011 14:01:38 -0600 Subject: Allow user to set whether comments are ascending or descending --- mediagoblin/config_spec.ini | 3 +++ mediagoblin/user_pages/views.py | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 900957ce..4d412346 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -27,6 +27,9 @@ allow_registration = boolean(default=True) tags_delimiter = string(default=",") tags_max_length = integer(default=50) +# Whether comments are ascending or descending +comments_ascending = boolean(default=True) + # By default not set, but you might want something like: # "%(here)s/user_dev/templates/" local_templates = string() diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 98a21bb4..25fd2ebb 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -106,11 +106,15 @@ def media_home(request, media, page, **kwargs): """ if ObjectId(request.matchdict.get('comment')): pagination = Pagination( - page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE, + page, media.get_comments( + mg_globals.app_config['comments_ascending']), + MEDIA_COMMENTS_PER_PAGE, ObjectId(request.matchdict.get('comment'))) else: pagination = Pagination( - page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE) + page, media.get_comments( + mg_globals.app_config['comments_ascending']), + MEDIA_COMMENTS_PER_PAGE) comments = pagination() -- cgit v1.2.3 From 1bc231c766c41f61aee6d91c631bd972426b277b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 19 Nov 2011 14:03:01 -0600 Subject: Added Pablo Santos to the AUTHORS file --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index b0ef7154..76e16b86 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,6 +28,7 @@ Thank you! * Nathan Yergler * Odin Hørthe Omdal * Osama Khalid +* Pablo J. Urbano Santos * Rasmus Larsson * Sam Kleinman * Sebastian Spaeth -- cgit v1.2.3 From 7880168526032bc2ddce96257d8f62a01e562832 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 19 Nov 2011 14:06:48 -0600 Subject: Added back the title block --- mediagoblin/templates/mediagoblin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 0d6b9e40..64fafb73 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -19,7 +19,7 @@ - {{ app_config['html_title'] }} + {% block title %}{{ app_config['html_title'] }}{% endblock %} Date: Sat, 19 Nov 2011 23:46:42 +0100 Subject: Change form structure and add relevant CSS rules --- mediagoblin/static/css/base.css | 6 +++++- mediagoblin/templates/mediagoblin/utils/wtforms.html | 12 +++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index afd10207..a7b659c3 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -212,7 +212,11 @@ text-align: center; width: 100%; } -.form_field_label,.form_field_input { +.form_field_input { + margin-bottom: 10px; +} + +.form_field_label { margin-bottom: 4px; } diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 6a86fd24..39dca7cc 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -18,18 +18,16 @@ {# Generically render a field #} {% macro render_field_div(field) %} -
-
{{ _(field.label.text) }}
-
{{ field }}
+

+
+ {{ field }} {%- if field.errors -%} {% for error in field.errors %} -
- {{ error }} -
+

{{ error }}

{% endfor %} {%- endif %} {% if field.description -%} -
{{ _(field.description) }}
+

{{ _(field.description) }}

{%- endif %}
{%- endmacro %} -- cgit v1.2.3 From 2d62e9efd210becd30982e65e06a6ef97029b391 Mon Sep 17 00:00:00 2001 From: lora Date: Sat, 19 Nov 2011 17:00:25 -0600 Subject: issue 582: use media.slug instead of media.id --- mediagoblin/decorators.py | 3 +-- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- .../templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 19e22bca..38f52ced 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -58,7 +58,7 @@ def user_may_delete_media(controller): """ def wrapper(request, *args, **kwargs): uploader = request.db.MediaEntry.find_one( - {'_id': ObjectId(request.matchdict['media'])}).uploader() + {'slug': request.matchdict['media'] }).uploader() if not (request.user['is_admin'] or request.user['_id'] == uploader['_id']): return exc.HTTPForbidden() @@ -95,7 +95,6 @@ def get_user_media_entry(controller): if not user: return render_404(request) - media = request.db.MediaEntry.find_one( {'slug': request.matchdict['media'], 'state': 'processed', diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 433f74dc..5e1b73de 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -124,7 +124,7 @@

{% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.uploader().username, - media= media._id) %} + media= media.slug) %} @@ -133,7 +133,7 @@

{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', user= media.uploader().username, - media= media._id) %} + media= media.slug) %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index dd6923a9..f62082bd 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -23,7 +23,7 @@

-- cgit v1.2.3 From 909dda1f85b27866e0d20343169c91953ca7d8f6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 00:28:19 +0100 Subject: Change button style a bit --- mediagoblin/static/css/base.css | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index a7b659c3..8d9756b9 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -99,20 +99,14 @@ a.mediagoblin_logo{ } .header_submit, .header_submit_highlight{ - color: #272727; - background-color: #aaa; - background-image: -webkit-gradient(linear, left top, left bottom, from(##D2D2D2), to(#aaa)); - background-image: -webkit-linear-gradient(top, #D2D2D2, #aaa); - background-image: -moz-linear-gradient(top, #D2D2D2, #aaa); - background-image: -ms-linear-gradient(top, #D2D2D2, #aaa); - background-image: -o-linear-gradient(top, #D2D2D2, #aaa); - background-image: linear-gradient(top, #D2D2D2, #aaa); - box-shadow: 0px 0px 4px #000; - border-radius: 3px; + color: #c3c3c3; + background-color: #2d2d2d; + border: 1px solid; + border-color: #323232 #232323 #1F1F1F; + border-radius: 4px; margin: 8px; padding: 3px 8px; text-decoration: none; - border: medium none; font-style: normal; font-weight: bold; font-size: 1em; @@ -301,7 +295,7 @@ img.media_icon{ background-color: #1d1d1d; border: 1px solid; border-color: #2c2c2c #232323 #1a1a1a; - border-radius: 3px; + border-radius: 4px; text-decoration: none; padding: 8px 0px 14px; font-size: 2em; -- cgit v1.2.3 From 4837b2f253e7f525eb4eb97a574c8af68c0ff570 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sat, 19 Nov 2011 22:17:21 +0100 Subject: added support for changing the password, issue #643 --- mediagoblin/edit/forms.py | 13 +++++++++++++ mediagoblin/edit/views.py | 34 ++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 7e71722c..ec4e22b3 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -43,6 +43,19 @@ class EditProfileForm(wtforms.Form): _('Website'), [wtforms.validators.Optional(), wtforms.validators.URL(message='Improperly formed URL')]) + old_password = wtforms.PasswordField( + _('Old password'), + [wtforms.validators.Optional()]) + new_password = wtforms.PasswordField( + _('New Password'), + [wtforms.validators.Optional(), + wtforms.validators.Length(min=6, max=30), + wtforms.validators.EqualTo( + 'confirm_password', + 'Passwords must match.')]) + confirm_password = wtforms.PasswordField( + 'Confirm password', + [wtforms.validators.Optional()]) class EditAttachmentsForm(wtforms.Form): diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 5f781552..75bf51bf 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -26,6 +26,7 @@ from werkzeug.utils import secure_filename from mediagoblin import messages from mediagoblin import mg_globals +from mediagoblin.auth import lib as auth_lib from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import require_active_login, get_user_media_entry @@ -161,19 +162,32 @@ def edit_profile(request): bio=user.get('bio')) if request.method == 'POST' and form.validate(): - user['url'] = unicode(request.POST['url']) - user['bio'] = unicode(request.POST['bio']) + user['url'] = unicode(request.POST['url']) + user['bio'] = unicode(request.POST['bio']) - user['bio_html'] = cleaned_markdown_conversion(user['bio']) - - user.save() + password_matches = auth_lib.bcrypt_check_password(request.POST['old_password'], + user['pw_hash']) + if (request.POST['old_password'] or request.POST['new_password']) and not \ + password_matches: messages.add_message(request, - messages.SUCCESS, - _("Profile edited!")) - return redirect(request, - 'mediagoblin.user_pages.user_home', - user=edit_username) + messages.ERROR, + _('Wrong password')) + + if password_matches: + user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + request.POST['new_password']) + + user['bio_html'] = cleaned_markdown_conversion(user['bio']) + + user.save() + + messages.add_message(request, + messages.SUCCESS, + _("Profile edited!")) + return redirect(request, + 'mediagoblin.user_pages.user_home', + user=edit_username) return render_to_response( request, -- cgit v1.2.3 From c8ccd23e8e0d77df3e7382cd6330e0c993bbcc8e Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 20 Nov 2011 00:35:09 +0100 Subject: added unittests, now using form errors and fixed bug when no GET parameter is given for /edit/profile/ --- mediagoblin/edit/views.py | 23 +++++---- mediagoblin/tests/test_edit.py | 112 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 mediagoblin/tests/test_edit.py diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 75bf51bf..673409bd 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -162,17 +162,22 @@ def edit_profile(request): bio=user.get('bio')) if request.method == 'POST' and form.validate(): - user['url'] = unicode(request.POST['url']) - user['bio'] = unicode(request.POST['bio']) - - password_matches = auth_lib.bcrypt_check_password(request.POST['old_password'], - user['pw_hash']) + password_matches = auth_lib.bcrypt_check_password( + request.POST['old_password'], + user['pw_hash']) if (request.POST['old_password'] or request.POST['new_password']) and not \ password_matches: - messages.add_message(request, - messages.ERROR, - _('Wrong password')) + form.old_password.errors.append(_('Wrong password')) + + return render_to_response( + request, + 'mediagoblin/edit/edit_profile.html', + {'user': user, + 'form': form}) + + user['url'] = unicode(request.POST['url']) + user['bio'] = unicode(request.POST['bio']) if password_matches: user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( @@ -187,7 +192,7 @@ def edit_profile(request): _("Profile edited!")) return redirect(request, 'mediagoblin.user_pages.user_home', - user=edit_username) + user=user['username']) return render_to_response( request, diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py new file mode 100644 index 00000000..3637b046 --- /dev/null +++ b/mediagoblin/tests/test_edit.py @@ -0,0 +1,112 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin import mg_globals +from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin.tools import template +from mediagoblin.auth.lib import bcrypt_check_password, \ + bcrypt_gen_password_hash + + +@setup_fresh_app +def test_change_password(test_app): + """Test changing password correctly and incorrectly""" + # set up new user + test_user = mg_globals.database.User() + test_user['username'] = u'chris' + test_user['email'] = u'chris@example.com' + test_user['email_verified'] = True + test_user['status'] = u'active' + test_user['pw_hash'] = bcrypt_gen_password_hash('toast') + test_user.save() + + test_app.post( + '/auth/login/', { + 'username': u'chris', + 'password': 'toast'}) + + # test that the password can be changed + # template.clear_test_template_context() + test_app.post( + '/edit/profile/', { + 'bio': u'', + 'url': u'', + 'old_password': 'toast', + 'new_password': '123456', + 'confirm_password': '123456'}) + + # test_user has to be fetched again in order to have the current values + test_user = mg_globals.database.User.one({'username': 'chris'}) + + assert bcrypt_check_password('123456', test_user['pw_hash']) + + # test that the password cannot be changed if the given old_password + # is wrong + # template.clear_test_template_context() + test_app.post( + '/edit/profile/', { + 'bio': u'', + 'url': u'', + 'old_password': 'toast', + 'new_password': '098765', + 'confirm_password': '098765'}) + + test_user = mg_globals.database.User.one({'username': 'chris'}) + + assert not bcrypt_check_password('098765', test_user['pw_hash']) + + +@setup_fresh_app +def change_bio_url(test_app): + """Test changing bio and URL""" + # set up new user + test_user = mg_globals.database.User() + test_user['username'] = u'chris' + test_user['email'] = u'chris@example.com' + test_user['email_verified'] = True + test_user['status'] = u'active' + test_user['pw_hash'] = bcrypt_gen_password_hash('toast') + test_user.save() + + # test changing the bio and the URL properly + test_app.post( + '/edit/profile/', { + 'bio': u'I love toast!', + 'url': u'http://dustycloud.org/'}) + + test_user = mg_globals.database.User.one({'username': 'chris'}) + + assert test_user['bio'] == u'I love toast!' + assert test_user['url'] == u'http://dustycloud.org/' + + # test changing the bio and the URL inproperly + too_long_bio = 150 * 'T' + 150 * 'o' + 150 * 'a' + 150 * 's' + 150* 't' + + test_app.post( + '/edit/profile/', { + # more than 500 characters + 'bio': too_long_bio, + 'url': 'this-is-no-url'}) + + test_user = mg_globals.database.User.one({'username': 'chris'}) + + context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/edit/edit_profile.html'] + form = context['edit_profile_form'] + + assert form.bio.errors == [u'Field must be between 0 and 500 characters long.'] + assert form.url.errors == [u'Improperly formed URL'] + + # test changing the url inproperly -- cgit v1.2.3 From 5bd523eb23e7c30b52e41cdb0f02053d8573ce63 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 01:12:10 +0100 Subject: Change to background of "empty_space", it now uses an image --- mediagoblin/static/css/base.css | 2 +- mediagoblin/static/images/empty_back.png | Bin 0 -> 191 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 mediagoblin/static/images/empty_back.png diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 8d9756b9..d61292a2 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -177,7 +177,7 @@ text-align: center; } .empty_space{ - background-color: #222; + background-image: url("../images/empty_back.png"); font-style: italic; text-align: center; height: 160px; diff --git a/mediagoblin/static/images/empty_back.png b/mediagoblin/static/images/empty_back.png new file mode 100644 index 00000000..3522ddd3 Binary files /dev/null and b/mediagoblin/static/images/empty_back.png differ -- cgit v1.2.3 From 13423daae28f759a24ba645fecc3e01cdfa92d9c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 01:43:48 +0100 Subject: Another change to button style. Renamed header_submit, header_submit_highlight and button classes, correct all references to these --- mediagoblin/static/css/base.css | 39 +++++++++++----------- .../templates/mediagoblin/auth/change_fp.html | 2 +- .../mediagoblin/auth/forgot_password.html | 2 +- mediagoblin/templates/mediagoblin/auth/login.html | 4 +-- .../templates/mediagoblin/auth/register.html | 2 +- mediagoblin/templates/mediagoblin/base.html | 6 ++-- .../templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- .../templates/mediagoblin/edit/edit_profile.html | 2 +- mediagoblin/templates/mediagoblin/root.html | 4 +-- .../templates/mediagoblin/submit/start.html | 2 +- mediagoblin/templates/mediagoblin/test_submit.html | 2 +- .../templates/mediagoblin/user_pages/media.html | 2 +- .../user_pages/media_confirm_delete.html | 2 +- .../templates/mediagoblin/user_pages/user.html | 6 ++-- 15 files changed, 40 insertions(+), 39 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d61292a2..cec236f4 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -98,24 +98,6 @@ a.mediagoblin_logo{ font-weight: bold; } -.header_submit, .header_submit_highlight{ - color: #c3c3c3; - background-color: #2d2d2d; - border: 1px solid; - border-color: #323232 #232323 #1F1F1F; - border-radius: 4px; - margin: 8px; - padding: 3px 8px; - text-decoration: none; - font-style: normal; - font-weight: bold; - font-size: 1em; -} - -.header_submit_highlight{ -background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, 173, 144)); -} - .mediagoblin_footer { height: 30px; border-top: 1px solid #333; @@ -135,7 +117,26 @@ background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, /* common website elements */ -.button, .cancel_link { +.button_action, .button_action_highlight{ + color: #c3c3c3; + background-color: #363636; + border: 1px solid; + border-color: #464646 #2B2B2B #252525; + border-radius: 4px; + margin: 8px; + padding: 3px 8px; + text-decoration: none; + font-style: normal; + font-weight: bold; + font-size: 1em; +} + +.button_action_highlight{ +background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, 173, 144)); +} + + +.button_form, .cancel_link { height: 32px; min-width: 99px; background-color: #86d4b1; diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 53186cec..fa972085 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -30,7 +30,7 @@ {{ wtforms_util.render_divs(cp_form) }}
- +

diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html index 9b821426..41940742 100644 --- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html +++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html @@ -27,7 +27,7 @@

{% trans %}Recover password{% endtrans %}

{{ wtforms_util.render_divs(fp_form) }}
- +
diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 756f67c0..c3807e5f 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -42,10 +42,10 @@ {% trans %}Forgot your password?{% endtrans %}

- +
{% if next %} - {% endif %}

diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index 25b68058..a0d0a277 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -29,7 +29,7 @@ {{ csrf_token }}
+ class="button_form" />
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 64fafb73..ede5f5c6 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -47,7 +47,7 @@ alt="{% trans %}MediaGoblin logo{% endtrans %}" /> {% endblock %} {% if request.user and request.user['status'] == 'active' %} - {% trans %}Submit media{% endtrans %} @@ -59,8 +59,8 @@ {% if request.user.status == "needs_email_verification" %} - {% trans %}verify your email!{% endtrans %} + class="button_action_highlight"> + {% trans %}Verify your email!{% endtrans %} {% endif %} Cancel - + {{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index b4b3be85..73c2bada 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -34,7 +34,7 @@ {{ wtforms_util.render_divs(form) }}
{% trans %}Cancel{% endtrans %} - + {{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index 93b2a792..bf8fe5c1 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -32,7 +32,7 @@ {{ wtforms_util.render_divs(form) }}
- + {{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 43d973d1..25ce9e96 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -30,9 +30,9 @@ {% if allow_registration %}

{% trans %}Don't have one yet? It's easy!{% endtrans %}

{% trans register_url=request.urlgen('mediagoblin.auth.register') -%} - Create an account at this site + Create an account at this site or - Set up MediaGoblin on your own server + Set up MediaGoblin on your own server {%- endtrans %} {% endif %} diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 29b01181..1a0dd4b7 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -27,7 +27,7 @@ {{ wtforms_util.render_divs(submit_form) }}
{{ csrf_token }} - +
diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 190b9ac3..38be8efc 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -25,7 +25,7 @@ {{ wtforms_util.render_table(image_form) }} - + {{ csrf_token }} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 4b02b684..c8a9650f 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -98,7 +98,7 @@ media=media._id) }}" method="POST"> {{ wtforms_util.render_divs(comment_form) }}
- + {{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 8da90f79..c3a9d622 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -47,7 +47,7 @@
{# TODO: This isn't a button really... might do unexpected things :) #} {% trans %}Cancel{% endtrans %} - + {{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index d6a9fe1f..91dd2369 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -62,7 +62,7 @@

{% trans %}In case it doesn't:{% endtrans %}

{% trans %}Resend verification email{% endtrans %} + class="button_form">{% trans %}Resend verification email{% endtrans %} {% else %} {# if the user is not you, but still needs to verify their email #} @@ -97,7 +97,7 @@

+ class="button_action"> {%- trans %}Edit profile{% endtrans -%} @@ -147,7 +147,7 @@ This is where your media will appear, but you don't seem to have added anything yet. {%- endtrans %}

- {%- trans %}Add media{% endtrans -%} -- cgit v1.2.3 From 5ab3855e1f8fd94058ccea76ef2d5a1d795cc93a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 01:46:21 +0100 Subject: Slight change to error wording --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 8412b81c..54cb1ab5 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -74,7 +74,7 @@ def register(request): extra_validation_passes = False if users_with_email: register_form.email.errors.append( - _(u'Sorry, that email address has already been taken.')) + _(u'Sorry, a user with that email address already exists.')) extra_validation_passes = False if extra_validation_passes: -- cgit v1.2.3 From c6c08a2f296be16dbde4a5041bd6adc0d215d29d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 01:57:02 +0100 Subject: Small correction, this button should be button_action, not button_form --- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 91dd2369..5a39aaa5 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -62,7 +62,7 @@

{% trans %}In case it doesn't:{% endtrans %}

{% trans %}Resend verification email{% endtrans %} + class="button_action_highlight">{% trans %}Resend verification email{% endtrans %} {% else %} {# if the user is not you, but still needs to verify their email #} -- cgit v1.2.3 From 88f20b58b29a4edbfbc24378a991d82de8e7b975 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 01:57:29 +0100 Subject: Slight style changes to button_action_highlight --- mediagoblin/static/css/base.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index cec236f4..c26e11af 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -132,7 +132,9 @@ a.mediagoblin_logo{ } .button_action_highlight{ -background-image: -moz-linear-gradient(center top , rgb(134, 212, 177), rgb(109, 173, 144)); + background-color: #86D4B1; + border-color: #A2DEC3 #6CAA8E #5C9179; + color: #283F35; } -- cgit v1.2.3 From cee794a8f7ac82ee7681f749e56411c910e281a6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 15:34:40 +0100 Subject: Fix for bug #467, "Add explanatory copy to add/edit picture pages saying that tags are comma-separated" --- mediagoblin/edit/forms.py | 4 +++- mediagoblin/submit/forms.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index ec4e22b3..93934be7 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -26,7 +26,9 @@ class EditForm(wtforms.Form): description = wtforms.TextAreaField('Description of this work') tags = wtforms.TextField( _('Tags'), - [tag_length_validator]) + [tag_length_validator], + description=_( + "Seperate tags by commas or spaces.")) slug = wtforms.TextField( _('Slug'), [wtforms.validators.Required(message=_("The slug can't be empty"))], diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 25d6e304..48a21f02 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -30,4 +30,6 @@ class SubmitStartForm(wtforms.Form): _('Description of this work')) tags = wtforms.TextField( _('Tags'), - [tag_length_validator]) + [tag_length_validator], + description=_( + "Seperate tags by commas or spaces.")) -- cgit v1.2.3 From 16a444444ab42f88f1654054050b7dcd64bf960e Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 16:18:27 +0100 Subject: Change tag list from a list to a paragraph. Wrap text for translation. --- mediagoblin/templates/mediagoblin/utils/tags.html | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index b3211bd9..19ca8d2a 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,13 +17,20 @@ #} {% block tags_content -%} -

Tags

- +

{% endblock %} -- cgit v1.2.3 From 7807f5a513f2d5e510916e00dc276d0cd33de66a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 16:45:45 +0100 Subject: Remove Edit/Delete icons, since they are not required yet. --- mediagoblin/static/images/icon_delete.png | Bin 472 -> 0 bytes mediagoblin/static/images/icon_edit.png | Bin 297 -> 0 bytes mediagoblin/templates/mediagoblin/user_pages/media.html | 11 ++--------- 3 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 mediagoblin/static/images/icon_delete.png delete mode 100644 mediagoblin/static/images/icon_edit.png diff --git a/mediagoblin/static/images/icon_delete.png b/mediagoblin/static/images/icon_delete.png deleted file mode 100644 index 9d76a5db..00000000 Binary files a/mediagoblin/static/images/icon_delete.png and /dev/null differ diff --git a/mediagoblin/static/images/icon_edit.png b/mediagoblin/static/images/icon_edit.png deleted file mode 100644 index 480c73ad..00000000 Binary files a/mediagoblin/static/images/icon_edit.png and /dev/null differ diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index c8a9650f..7ef64c76 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -116,24 +116,17 @@ {% if media['uploader'] == request.user._id or request.user['is_admin'] %} -

{% trans %}Actions{% endtrans %}

{% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.uploader().username, media= media._id) %} - - {% trans %}edit{% endtrans %} + {% trans %}Edit{% endtrans %}

{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', user= media.uploader().username, media= media._id) %} - - {% trans %}delete{% endtrans %} + {% trans %}Delete{% endtrans %}

{% endif %} -- cgit v1.2.3 From 0b3cdd6a25f8aaa74beecb7fed32a20cc13587a8 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 20 Nov 2011 17:01:23 +0100 Subject: Navigation buttons edits. Removed images as they are no longer needed. Related: bug #504 --- mediagoblin/static/css/base.css | 8 ++------ mediagoblin/static/images/navigation_end.png | Bin 718 -> 0 bytes mediagoblin/static/images/navigation_left.png | Bin 406 -> 0 bytes mediagoblin/static/images/navigation_right.png | Bin 383 -> 0 bytes mediagoblin/templates/mediagoblin/utils/prev_next.html | 8 ++++---- 5 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 mediagoblin/static/images/navigation_end.png delete mode 100644 mediagoblin/static/images/navigation_left.png delete mode 100644 mediagoblin/static/images/navigation_right.png diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index c26e11af..12d88ffa 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -300,15 +300,11 @@ img.media_icon{ border-color: #2c2c2c #232323 #1a1a1a; border-radius: 4px; text-decoration: none; - padding: 8px 0px 14px; - font-size: 2em; + padding: 12px 0 16px; + font-size: 1.4em; margin: 0 0 20px } -p.navigation_button{ - color: #272727; -} - .navigation_left{ margin-right: 6px; } diff --git a/mediagoblin/static/images/navigation_end.png b/mediagoblin/static/images/navigation_end.png deleted file mode 100644 index b2f27296..00000000 Binary files a/mediagoblin/static/images/navigation_end.png and /dev/null differ diff --git a/mediagoblin/static/images/navigation_left.png b/mediagoblin/static/images/navigation_left.png deleted file mode 100644 index d1645120..00000000 Binary files a/mediagoblin/static/images/navigation_left.png and /dev/null differ diff --git a/mediagoblin/static/images/navigation_right.png b/mediagoblin/static/images/navigation_right.png deleted file mode 100644 index d4caa7b8..00000000 Binary files a/mediagoblin/static/images/navigation_right.png and /dev/null differ diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 75903076..3363891b 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -25,23 +25,23 @@ {# There are no previous entries for the very first media entry #} {% if prev_entry_url %} - Previous image + ← newer {% else %} {# This is the first entry. display greyed-out 'previous' image #} {% endif %} {# Likewise, this could be the very last media entry #} {% if next_entry_url %} - Next image + older → {% else %} {# This is the last entry. display greyed-out 'next' image #} {% endif %} -- cgit v1.2.3 From 5dbeda8a0f2953aed13521b6e87376327e8302e0 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 20 Nov 2011 20:15:21 +0100 Subject: Fix redirect to logical path redirects should in nearly all cases go to a logical path like 'mediagoblin.auth.login' and not to an absolute path like "/auth/login". --- mediagoblin/auth/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index b3a70d46..d01861d1 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -202,7 +202,7 @@ def resend_activation(request): messages.ERROR, _('You must be logged in so we know who to send the email to!')) - return redirect(request, "/auth/login") + return redirect(request, 'mediagoblin.auth.login') if request.user["email_verified"]: messages.add_message( -- cgit v1.2.3 From 9404a9fed23bfe27144da4f8e692df1f692a25b5 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 20 Nov 2011 21:15:07 +0100 Subject: don't use 'and' anymore, if there is only one tag --- mediagoblin/templates/mediagoblin/utils/tags.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 19ca8d2a..20c50f6e 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -20,7 +20,10 @@

{% trans %}Tagged with{% endtrans %} {% for tag in media.tags %} {% if loop.last %} - {% trans %}and{% endtrans %} {{ tag['name'] }}. {% elif loop.revindex==2 %} -- cgit v1.2.3 From a00f1c1e1cecb8f127b6a064e2cd90c8f613660d Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 20 Nov 2011 21:30:46 +0100 Subject: eyecandy for programmers --- mediagoblin/templates/mediagoblin/utils/tags.html | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 20c50f6e..49bc3cee 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -20,19 +20,21 @@

{% trans %}Tagged with{% endtrans %} {% for tag in media.tags %} {% if loop.last %} + {# the 'and' should only appear if there is more than one tag #} {% if media.tags|length > 1 %} - {% trans %}and{% endtrans %} + {% trans %}and{% endtrans %} {% endif %} - {{ tag['name'] }}. - {% elif loop.revindex==2 %} - {{ tag['name'] }} - {% else %}{{ tag['name'] }}, + + {{ tag['name'] }}. + {% elif loop.revindex==2 %} + {{ tag['name'] }} + {% else %}{{ tag['name'] }}, {% endif %} {% endfor %}

-- cgit v1.2.3 From fe0a8f53e251aae93bee5f4dee79d462fad751e8 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 20 Nov 2011 21:40:51 +0100 Subject: fixed identation --- mediagoblin/templates/mediagoblin/utils/tags.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 49bc3cee..c7dfc8eb 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -24,15 +24,15 @@ {% if media.tags|length > 1 %} {% trans %}and{% endtrans %} {% endif %} - {{ tag['name'] }}. - {% elif loop.revindex==2 %} + {% elif loop.revindex == 2 %} {{ tag['name'] }} - {% else %}{{ tag['name'] }}, {% endif %} -- cgit v1.2.3 From a63b640f12896a873ebf96f9fe0ef62d0794bfe7 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 21 Nov 2011 00:06:59 +0100 Subject: Stashing changes --- mediagoblin/init/celery/__init__.py | 3 -- mediagoblin/media_types/__init__.py | 26 ++++++------ mediagoblin/media_types/video/processing.py | 49 ++++------------------ mediagoblin/media_types/video/transcoders.py | 1 - mediagoblin/process_media/__init__.py | 3 ++ mediagoblin/templates/mediagoblin/base.html | 7 ++++ .../mediagoblin/media_displays/video.html | 18 +++++--- setup.py | 1 - 8 files changed, 43 insertions(+), 65 deletions(-) diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index 05c54b05..c5d37420 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -17,11 +17,8 @@ import os import sys -from mediagoblin.media_types import get_media_types - MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media'] -MANDATORY_CELERY_IMPORTS = [i for i in get_media_types()] print(MANDATORY_CELERY_IMPORTS) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 49d3ab9d..2d13f5a6 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -26,31 +26,33 @@ class FileTypeNotSupported(Exception): class InvalidFileType(Exception): pass +# This should be more dynamic in the future. Perhaps put it in the .ini? +# -- Joar MEDIA_TYPES = [ 'mediagoblin.media_types.image', 'mediagoblin.media_types.video'] def get_media_types(): + ''' + Generator that returns the available media types + ''' for media_type in MEDIA_TYPES: yield media_type def get_media_managers(): + ''' + Generator that returns all available media managers + ''' for media_type in get_media_types(): - ''' - FIXME - __import__ returns the lowest-level module. If the plugin is located - outside the conventional plugin module tree, it will not be loaded - properly because of the [...]ugin.media_types. - - We need this if we want to support a separate site-specific plugin - folder. - ''' try: __import__(media_type) except ImportError as e: - raise Exception('ERROR: Could not import {0}: {1}'.format(media_type, e)) + raise Exception( + _('ERROR: Could not import {media_type}: {exception}').format( + media_type=media_type, + exception=e)) yield media_type, sys.modules[media_type].MEDIA_MANAGER @@ -67,8 +69,8 @@ def get_media_type_and_manager(filename): ext = os.path.splitext(filename)[1].lower() else: raise InvalidFileType( - 'Could not find any file extension in "{0}"'.format( - filename)) + _('Could not find any file extension in "{filename}"').format( + filename=filename)) if ext[1:] in manager['accepted_extensions']: return media_type, manager diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 027f527b..4e05a71c 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -15,25 +15,21 @@ # along with this program. If not, see . import tempfile -import pkg_resources -import os import logging +import os from celery.task import Task from celery import registry from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg -from mediagoblin.util import lazy_pass_to_ugettext as _ -from mediagoblin.process_media.errors import BaseProcessingFail, BadMediaFail +from mediagoblin.process_media import BaseProcessingFail from mediagoblin.process_media import mark_entry_failed from . import transcoders THUMB_SIZE = 180, 180 MEDIUM_SIZE = 640, 640 -loop = None # Is this even used? - logger = logging.getLogger(__name__) logging.basicConfig() logger.setLevel(logging.DEBUG) @@ -59,7 +55,11 @@ def process_video(entry): 'source') medium_filepath = create_pub_filepath( - entry, '640p.webm') + entry, + '{original}-640p.webm'.format( + original=os.path.splitext( + queued_filepath[-1])[0] # Select the + )) thumbnail_filepath = create_pub_filepath( entry, 'thumbnail.jpg') @@ -163,38 +163,3 @@ class ProcessMedia(Task): process_media = registry.tasks[ProcessMedia.name] - - -def mark_entry_failed(entry_id, exc): - """ - Mark a media entry as having failed in its conversion. - - Uses the exception that was raised to mark more information. If the - exception is a derivative of BaseProcessingFail then we can store extra - information that can be useful for users telling them why their media failed - to process. - - Args: - - entry_id: The id of the media entry - - """ - # Was this a BaseProcessingFail? In other words, was this a - # type of error that we know how to handle? - if isinstance(exc, BaseProcessingFail): - # Looks like yes, so record information about that failure and any - # metadata the user might have supplied. - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': exc.exception_path, - u'fail_metadata': exc.metadata}}) - else: - # Looks like no, so just mark it as failed and don't record a - # failure_error (we'll assume it wasn't handled) and don't record - # metadata (in fact overwrite it if somehow it had previous info - # here) - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': None, - u'fail_metadata': {}}}) diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index f6a2eb21..8d80beda 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -56,7 +56,6 @@ try: import pygst pygst.require('0.10') import gst - from gst import pbutils from gst.extend import discoverer except: raise Exception('gst/pygst 0.10 could not be found') diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 2b9eed6e..96fe49fe 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -53,10 +53,13 @@ class ProcessMedia(Task): # Try to process, and handle expected errors. try: + __import__(entry['media_type']) process_image(entry) except BaseProcessingFail, exc: mark_entry_failed(entry[u'_id'], exc) return + except ImportError, exc: + mark_entry_failed(entry[u'_id'], exc) entry['state'] = u'processed' entry.save() diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b4c4dcf3..bad22e7e 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -28,8 +28,15 @@ href="{{ request.staticdirect('/css/extlib/960_16_col.css') }}"/> + + + + {% block mediagoblin_head %} {% endblock mediagoblin_head %} diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index bff9889a..5b8ec789 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -1,11 +1,17 @@ {% extends 'mediagoblin/user_pages/media.html' %} {% block mediagoblin_media %} - +
+ +
{% if 'original' in media.media_files %}

1: + directory = self._resolve_filepath(filepath[:-1]) + if not os.path.exists(directory): + os.makedirs(directory) + + shutil.copy( + filename, self.get_local_path(filepath)) -- cgit v1.2.3 From 2e8fbc8fab47930f1de7e20e0072eaefafc898a6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 20 Nov 2011 22:02:02 -0600 Subject: Slightly clearer docs on copy_local_to_storage --- mediagoblin/storage/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py index b76e18af..0840614b 100644 --- a/mediagoblin/storage/__init__.py +++ b/mediagoblin/storage/__init__.py @@ -172,6 +172,10 @@ class StorageInterface(object): def copy_local_to_storage(self, filename, filepath): """ Copy this file from locally to the storage system. + + This is kind of the opposite of copy_locally. It's likely you + could override this method with something more appropriate to + your storage system. """ with self.get_file(filepath, 'wb') as dest_file: with file(filename, 'rb') as source_file: -- cgit v1.2.3 From 61c5306d247a4403032e4e37bbdf32db1e6d8aa8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 20 Nov 2011 22:03:38 -0600 Subject: Made the image processing use intermediary conversion file. This should fix the problem with PIL and the cloudfiles storage system fighting. --- mediagoblin/process_media/__init__.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 34d83e54..54c0c493 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -118,6 +118,10 @@ def process_image(entry): Code to process an image """ workbench = mgg.workbench_manager.create_workbench() + # Conversions subdirectory to avoid collisions + conversions_subdir = os.path.join( + workbench.dir, 'conversions') + os.mkdir(conversions_subdir) queued_filepath = entry['queued_media_file'] queued_filename = workbench.localized_file( @@ -133,11 +137,15 @@ def process_image(entry): thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) - thumb_filepath = create_pub_filepath(entry, 'thumbnail' + extension) - thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - - with thumb_file: + # Copy the thumb to the conversion subdir, then remotely. + thumb_filename = 'thumbnail' + extension + thumb_filepath = create_pub_filepath(entry, thumb_filename) + tmp_thumb_filename = os.path.join( + conversions_subdir, thumb_filename) + with file(tmp_thumb_filename, 'w') as thumb_file: thumb.save(thumb_file) + mgg.public_store.copy_local_to_storage( + tmp_thumb_filename, thumb_filepath) # If the size of the original file exceeds the specified size of a `medium` # file, a `medium.jpg` files is created and later associated with the media @@ -148,12 +156,18 @@ def process_image(entry): if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) - medium_filepath = create_pub_filepath(entry, 'medium' + extension) - medium_file = mgg.public_store.get_file(medium_filepath, 'w') + medium_filename = 'medium' + extension + medium_filepath = create_pub_filepath(entry, medium_filename) + tmp_medium_filename = os.path.join( + conversions_subdir, medium_filename) - with medium_file: + with file(tmp_medium_filename, 'w') as medium_file: medium.save(medium_file) - medium_processed = True + + mgg.public_store.copy_local_to_storage( + tmp_medium_filename, medium_filepath) + + medium_processed = True # we have to re-read because unlike PIL, not everything reads # things in string representation :) -- cgit v1.2.3 From e56e5f8c5c3dc7909aa68a1543ed04ddb18e27f6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 20 Nov 2011 22:25:22 -0600 Subject: Tests for StorageInterface*.copy_local_to_storage() --- mediagoblin/tests/test_storage.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index 46ecb2ec..eab4d032 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -57,6 +57,10 @@ class FakeRemoteStorage(storage.filestorage.BasicFileStorage): # should force copying to the workbench local_storage = False + def copy_local_to_storage(self, *args, **kwargs): + return storage.StorageInterface.copy_local_to_storage( + self, *args, **kwargs) + def test_storage_system_from_config(): this_storage = storage.storage_system_from_config( @@ -252,3 +256,26 @@ def test_basic_storage_copy_locally(): this_storage.copy_locally(filepath, new_file_dest) assert file(new_file_dest).read() == 'Testing this file' + + +def _test_copy_local_to_storage_works(tmpdir, this_storage): + local_filename = tempfile.mktemp() + with file(local_filename, 'w') as tmpfile: + tmpfile.write('haha') + + this_storage.copy_local_to_storage( + local_filename, ['dir1', 'dir2', 'copiedto.txt']) + + assert file( + os.path.join(tmpdir, 'dir1/dir2/copiedto.txt'), + 'r').read() == 'haha' + + +def test_basic_storage_copy_local_to_storage(): + tmpdir, this_storage = get_tmp_filestorage() + _test_copy_local_to_storage_works(tmpdir, this_storage) + + +def test_general_storage_copy_local_to_storage(): + tmpdir, this_storage = get_tmp_filestorage(fake_remote=True) + _test_copy_local_to_storage_works(tmpdir, this_storage) -- cgit v1.2.3 From c875bb74a8245b39b6985f37cb8ab838c22efa7e Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 21 Nov 2011 21:47:00 +0100 Subject: Refractored GStreamer element linking --- mediagoblin/media_types/video/transcoders.py | 43 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 8d80beda..8b220891 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -17,7 +17,6 @@ from __future__ import division import os -os.environ["GST_DEBUG_DUMP_DOT_DIR"] = "/tmp" os.putenv('GST_DEBUG_DUMP_DOT_DIR', '/tmp') import sys @@ -498,28 +497,30 @@ class VideoTranscoder: # or audio sink self.filesrc.link(self.decoder) - # Link all the video elements in a link to webmux - self.videoqueue.link(self.videorate) - self.videorate.link(self.ffmpegcolorspace) - self.ffmpegcolorspace.link(self.videoscale) - self.videoscale.link(self.capsfilter) - #self.capsfilter.link(self.xvimagesink) - self.capsfilter.link(self.vp8enc) - self.vp8enc.link(self.webmmux) + # Link all the video elements in a row to webmmux + gst.element_link_many( + self.videoqueue, + self.videorate, + self.ffmpegcolorspace, + self.videoscale, + self.capsfilter, + self.vp8enc, + self.webmmux) if self.data.is_audio: - # Link all the audio elements in a line to webmux - #self.audioconvert.link(self.alsasink) - self.audioqueue.link(self.audiorate) - self.audiorate.link(self.audioconvert) - self.audioconvert.link(self.audiocapsfilter) - self.audiocapsfilter.link(self.vorbisenc) - #self.audiocapsfilter.link(self.level) - #self.level.link(self.vorbisenc) - self.vorbisenc.link(self.webmmux) - - self.webmmux.link(self.progressreport) - self.progressreport.link(self.filesink) + # Link all the audio elements in a row to webmux + gst.element_link_many( + self.audioqueue, + self.audiorate, + self.audioconvert, + self.audiocapsfilter, + self.vorbisenc, + self.webmmux) + + gst.element_link_many( + self.webmmux, + self.progressreport, + self.filesink) # Setup the message bus and connect _on_message to the pipeline self._setup_bus() -- cgit v1.2.3 From 58dd8d9e6326013528cdfdfeea375c4eade54b92 Mon Sep 17 00:00:00 2001 From: "Pablo J. Urbano Santos" Date: Mon, 21 Nov 2011 22:42:55 +0100 Subject: Filename extensions are lowercased before uploading the image. --- mediagoblin/process_media/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 54c0c493..dcf21b81 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -128,7 +128,9 @@ def process_image(entry): mgg.queue_store, queued_filepath, 'source') - extension = os.path.splitext(queued_filename)[1] + filename_bits = os.path.splitext(queued_filename) + basename = os.path.split(filename_bits[0])[1] + extension = filename_bits[1].lower() try: thumb = Image.open(queued_filename) @@ -174,7 +176,8 @@ def process_image(entry): queued_file = file(queued_filename, 'rb') with queued_file: - original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + #create_pub_filepath(entry, queued_filepath[-1]) + original_filepath = create_pub_filepath(entry, basename + extension) with mgg.public_store.get_file(original_filepath, 'wb') \ as original_file: -- cgit v1.2.3 From 8e5f974684ce4e329a5022459f2e536fa4e15edd Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 21 Nov 2011 23:18:40 +0100 Subject: Fixes after merging video branch into master - Removed debug output from init/celery - Moved process_media/__init__ to processing.py - Centralized the processing.ProcessMedia task class - Updated media managers to reference the processing function instead of the ProcessMedia instance - Updated new-style image processing to previous, newer old-style image processing - Updated video transcoding - Changed method in progress output, sometimes message.structure['percent'] raises KeyError --- mediagoblin/init/celery/__init__.py | 4 +- mediagoblin/media_types/image/__init__.py | 8 +- mediagoblin/media_types/image/processing.py | 95 +++++-------- mediagoblin/media_types/video/__init__.py | 7 +- mediagoblin/media_types/video/processing.py | 69 ++-------- mediagoblin/media_types/video/transcoders.py | 17 +-- mediagoblin/process_media/__init__.py | 195 --------------------------- mediagoblin/process_media/errors.py | 45 ------- mediagoblin/processing.py | 143 ++++++++++++++++++++ mediagoblin/submit/views.py | 7 +- 10 files changed, 200 insertions(+), 390 deletions(-) delete mode 100644 mediagoblin/process_media/__init__.py delete mode 100644 mediagoblin/process_media/errors.py create mode 100644 mediagoblin/processing.py diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index a62d40e3..1eb21d7a 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -18,9 +18,7 @@ import os import sys -MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media'] - -print(MANDATORY_CELERY_IMPORTS) +MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing'] DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module' diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py index 0cd0383f..3b63d8eb 100644 --- a/mediagoblin/media_types/image/__init__.py +++ b/mediagoblin/media_types/image/__init__.py @@ -14,15 +14,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.media_types.image.processing import process_media +from mediagoblin.media_types.image.processing import process_image MEDIA_MANAGER = { "human_readable": "Image", - "processor": process_media, # alternately a string, + "processor": process_image, # alternately a string, # 'mediagoblin.media_types.image.processing'? "display_template": "mediagoblin/media_displays/image.html", "default_thumb": "images/media_thumbs/image.jpg", - "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"], - "accepted_mimetypes": [ - "image/jpeg", "image/png", "image/gif", "image/tiff"]} + "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"]} diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 57eb75db..5e8e4e0a 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import Image +import os from celery.task import Task from celery import registry @@ -22,19 +23,9 @@ from celery import registry from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg -from mediagoblin.util import lazy_pass_to_ugettext as _ - -from mediagoblin.process_media.errors import * - -THUMB_SIZE = 180, 180 -MEDIUM_SIZE = 640, 640 - - -def create_pub_filepath(entry, filename): - return mgg.public_store.get_unique_filepath( - ['media_entries', - unicode(entry['_id']), - filename]) +from mediagoblin.processing import BaseProcessingFail, \ + mark_entry_failed, BadMediaFail, create_pub_filepath, THUMB_SIZE, \ + MEDIUM_SIZE ################################ # Media processing initial steps @@ -77,67 +68,39 @@ class ProcessMedia(Task): process_media = registry.tasks[ProcessMedia.name] -def mark_entry_failed(entry_id, exc): - """ - Mark a media entry as having failed in its conversion. - - Uses the exception that was raised to mark more information. If the - exception is a derivative of BaseProcessingFail then we can store extra - information that can be useful for users telling them why their media failed - to process. - - Args: - - entry_id: The id of the media entry - - """ - # Was this a BaseProcessingFail? In other words, was this a - # type of error that we know how to handle? - if isinstance(exc, BaseProcessingFail): - # Looks like yes, so record information about that failure and any - # metadata the user might have supplied. - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': exc.exception_path, - u'fail_metadata': exc.metadata}}) - else: - # Looks like no, so just mark it as failed and don't record a - # failure_error (we'll assume it wasn't handled) and don't record - # metadata (in fact overwrite it if somehow it had previous info - # here) - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': None, - u'fail_metadata': {}}}) - - def process_image(entry): """ Code to process an image """ workbench = mgg.workbench_manager.create_workbench() + # Conversions subdirectory to avoid collisions + conversions_subdir = os.path.join( + workbench.dir, 'conversions') + os.mkdir(conversions_subdir) queued_filepath = entry['queued_media_file'] queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') + extension = os.path.splitext(queued_filename)[1] + try: thumb = Image.open(queued_filename) except IOError: raise BadMediaFail() thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) - # ensure color mode is compatible with jpg - if thumb.mode != "RGB": - thumb = thumb.convert("RGB") - - thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') - thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with thumb_file: - thumb.save(thumb_file, "JPEG", quality=90) + # Copy the thumb to the conversion subdir, then remotely. + thumb_filename = 'thumbnail' + extension + thumb_filepath = create_pub_filepath(entry, thumb_filename) + tmp_thumb_filename = os.path.join( + conversions_subdir, thumb_filename) + with file(tmp_thumb_filename, 'w') as thumb_file: + thumb.save(thumb_file) + mgg.public_store.copy_local_to_storage( + tmp_thumb_filename, thumb_filepath) # If the size of the original file exceeds the specified size of a `medium` # file, a `medium.jpg` files is created and later associated with the media @@ -148,15 +111,18 @@ def process_image(entry): if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) - if medium.mode != "RGB": - medium = medium.convert("RGB") + medium_filename = 'medium' + extension + medium_filepath = create_pub_filepath(entry, medium_filename) + tmp_medium_filename = os.path.join( + conversions_subdir, medium_filename) + + with file(tmp_medium_filename, 'w') as medium_file: + medium.save(medium_file) - medium_filepath = create_pub_filepath(entry, 'medium.jpg') - medium_file = mgg.public_store.get_file(medium_filepath, 'w') + mgg.public_store.copy_local_to_storage( + tmp_medium_filename, medium_filepath) - with medium_file: - medium.save(medium_file, "JPEG", quality=90) - medium_processed = True + medium_processed = True # we have to re-read because unlike PIL, not everything reads # things in string representation :) @@ -165,7 +131,8 @@ def process_image(entry): with queued_file: original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + with mgg.public_store.get_file(original_filepath, 'wb') \ + as original_file: original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py index c1910ee2..a970ab01 100644 --- a/mediagoblin/media_types/video/__init__.py +++ b/mediagoblin/media_types/video/__init__.py @@ -14,13 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.media_types.video.processing import process_media +from mediagoblin.media_types.video.processing import process_video MEDIA_MANAGER = { "human_readable": "Video", - "processor": process_media, # alternately a string, + "processor": process_video, # alternately a string, # 'mediagoblin.media_types.image.processing'? "display_template": "mediagoblin/media_displays/video.html", "default_thumb": "images/media_thumbs/video.jpg", - "accepted_extensions": ["mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "ogg"]} + "accepted_extensions": [ + "mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "ogg"]} diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 4e05a71c..6125e49c 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -18,21 +18,15 @@ import tempfile import logging import os -from celery.task import Task -from celery import registry - -from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg -from mediagoblin.process_media import BaseProcessingFail -from mediagoblin.process_media import mark_entry_failed +from mediagoblin.processing import mark_entry_failed, \ + THUMB_SIZE, MEDIUM_SIZE, create_pub_filepath from . import transcoders -THUMB_SIZE = 180, 180 -MEDIUM_SIZE = 640, 640 - -logger = logging.getLogger(__name__) logging.basicConfig() -logger.setLevel(logging.DEBUG) + +_log = logging.getLogger(__name__) +_log.setLevel(logging.DEBUG) def process_video(entry): @@ -73,8 +67,10 @@ def process_video(entry): transcoder = transcoders.VideoTranscoder(queued_filename, tmp_dst.name) # Push transcoded video to public storage + _log.debug('Saving medium...') mgg.public_store.get_file(medium_filepath, 'wb').write( tmp_dst.read()) + _log.debug('Saved medium') entry['media_files']['webm_640'] = medium_filepath @@ -91,8 +87,10 @@ def process_video(entry): transcoders.VideoThumbnailer(queued_filename, tmp_thumb.name) # Push the thumbnail to public storage + _log.debug('Saving thumbnail...') mgg.public_store.get_file(thumbnail_filepath, 'wb').write( tmp_thumb.read()) + _log.debug('Saved thumbnail') entry['media_files']['thumb'] = thumbnail_filepath @@ -107,7 +105,9 @@ def process_video(entry): with mgg.public_store.get_file(original_filepath, 'wb') as \ original_file: + _log.debug('Saving original...') original_file.write(queued_file.read()) + _log.debug('Saved original') entry['media_files']['original'] = original_filepath @@ -116,50 +116,3 @@ def process_video(entry): # Save the MediaEntry entry.save() - -def create_pub_filepath(entry, filename): - return mgg.public_store.get_unique_filepath( - ['media_entries', - unicode(entry['_id']), - filename]) - - -################################ -# Media processing initial steps -################################ - -class ProcessMedia(Task): - """ - Pass this entry off for processing. - """ - def run(self, media_id): - """ - Pass the media entry off to the appropriate processing function - (for now just process_image...) - """ - entry = mgg.database.MediaEntry.one( - {'_id': ObjectId(media_id)}) - - # Try to process, and handle expected errors. - try: - process_video(entry) - except BaseProcessingFail, exc: - mark_entry_failed(entry[u'_id'], exc) - return - - entry['state'] = u'processed' - entry.save() - - def on_failure(self, exc, task_id, args, kwargs, einfo): - """ - If the processing failed we should mark that in the database. - - Assuming that the exception raised is a subclass of BaseProcessingFail, - we can use that to get more information about the failure and store that - for conveying information to users about the failure, etc. - """ - entry_id = args[0] - mark_entry_failed(entry_id, exc) - - -process_media = registry.tasks[ProcessMedia.name] diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 8b220891..493a837f 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -195,7 +195,6 @@ class VideoThumbnailer: _log.debug('seek amount: {0}'.format(seek_amount)) - seek_result = self.thumbnail_pipeline.seek( 1.0, gst.FORMAT_TIME, @@ -204,14 +203,6 @@ class VideoThumbnailer: seek_amount, gst.SEEK_TYPE_NONE, 0) - ''' - - seek_result = self.thumbnail_pipeline.seek_simple( - gst.FORMAT_TIME, - gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE, - seek_amount) - - ''' if not seek_result: self.errors.append('COULD_NOT_SEEK') @@ -576,17 +567,13 @@ class VideoTranscoder: elif t == gst.MESSAGE_ELEMENT: if message.structure.get_name() == 'progress': - data = { - 'structure': message.structure, - 'percent': message.structure['percent'], - 'total': message.structure['total'], - 'current': message.structure['current']} + data = dict(message.structure) if self._progress_callback: self._progress_callback(data) _log.info('{percent}% done...'.format( - percent=data['percent'])) + percent=data.get('percent'))) _log.debug(data) elif t == gst.MESSAGE_ERROR: diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py deleted file mode 100644 index 346bb479..00000000 --- a/mediagoblin/process_media/__init__.py +++ /dev/null @@ -1,195 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import os - -import Image -from celery.task import Task -from celery import registry - -from mediagoblin.db.util import ObjectId -from mediagoblin import mg_globals as mgg -from mediagoblin.process_media.errors import BaseProcessingFail, BadMediaFail - - -THUMB_SIZE = 180, 180 -MEDIUM_SIZE = 640, 640 - - -def create_pub_filepath(entry, filename): - return mgg.public_store.get_unique_filepath( - ['media_entries', - unicode(entry._id), - filename]) - - -################################ -# Media processing initial steps -################################ - -class ProcessMedia(Task): - """ - Pass this entry off for processing. - """ - def run(self, media_id): - """ - Pass the media entry off to the appropriate processing function - (for now just process_image...) - """ - entry = mgg.database.MediaEntry.one( - {'_id': ObjectId(media_id)}) - - # Try to process, and handle expected errors. - try: - __import__(entry['media_type']) - process_image(entry) - except BaseProcessingFail, exc: - mark_entry_failed(entry._id, exc) - return - except ImportError, exc: - mark_entry_failed(entry[u'_id'], exc) - - entry['state'] = u'processed' - entry.save() - - def on_failure(self, exc, task_id, args, kwargs, einfo): - """ - If the processing failed we should mark that in the database. - - Assuming that the exception raised is a subclass of - BaseProcessingFail, we can use that to get more information - about the failure and store that for conveying information to - users about the failure, etc. - """ - entry_id = args[0] - mark_entry_failed(entry_id, exc) - - -process_media = registry.tasks[ProcessMedia.name] - - -def mark_entry_failed(entry_id, exc): - """ - Mark a media entry as having failed in its conversion. - - Uses the exception that was raised to mark more information. If - the exception is a derivative of BaseProcessingFail then we can - store extra information that can be useful for users telling them - why their media failed to process. - - Args: - - entry_id: The id of the media entry - - """ - # Was this a BaseProcessingFail? In other words, was this a - # type of error that we know how to handle? - if isinstance(exc, BaseProcessingFail): - # Looks like yes, so record information about that failure and any - # metadata the user might have supplied. - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': exc.exception_path, - u'fail_metadata': exc.metadata}}) - else: - # Looks like no, so just mark it as failed and don't record a - # failure_error (we'll assume it wasn't handled) and don't record - # metadata (in fact overwrite it if somehow it had previous info - # here) - mgg.database['media_entries'].update( - {'_id': entry_id}, - {'$set': {u'state': u'failed', - u'fail_error': None, - u'fail_metadata': {}}}) - - -def process_image(entry): - """ - Code to process an image - """ - workbench = mgg.workbench_manager.create_workbench() - # Conversions subdirectory to avoid collisions - conversions_subdir = os.path.join( - workbench.dir, 'conversions') - os.mkdir(conversions_subdir) - - queued_filepath = entry['queued_media_file'] - queued_filename = workbench.localized_file( - mgg.queue_store, queued_filepath, - 'source') - - extension = os.path.splitext(queued_filename)[1] - - try: - thumb = Image.open(queued_filename) - except IOError: - raise BadMediaFail() - - thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) - - # Copy the thumb to the conversion subdir, then remotely. - thumb_filename = 'thumbnail' + extension - thumb_filepath = create_pub_filepath(entry, thumb_filename) - tmp_thumb_filename = os.path.join( - conversions_subdir, thumb_filename) - with file(tmp_thumb_filename, 'w') as thumb_file: - thumb.save(thumb_file) - mgg.public_store.copy_local_to_storage( - tmp_thumb_filename, thumb_filepath) - - # If the size of the original file exceeds the specified size of a `medium` - # file, a `medium.jpg` files is created and later associated with the media - # entry. - medium = Image.open(queued_filename) - medium_processed = False - - if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: - medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) - - medium_filename = 'medium' + extension - medium_filepath = create_pub_filepath(entry, medium_filename) - tmp_medium_filename = os.path.join( - conversions_subdir, medium_filename) - - with file(tmp_medium_filename, 'w') as medium_file: - medium.save(medium_file) - - mgg.public_store.copy_local_to_storage( - tmp_medium_filename, medium_filepath) - - medium_processed = True - - # we have to re-read because unlike PIL, not everything reads - # things in string representation :) - queued_file = file(queued_filename, 'rb') - - with queued_file: - original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - - with mgg.public_store.get_file(original_filepath, 'wb') \ - as original_file: - original_file.write(queued_file.read()) - - mgg.queue_store.delete_file(queued_filepath) - entry['queued_media_file'] = [] - media_files_dict = entry.setdefault('media_files', {}) - media_files_dict['thumb'] = thumb_filepath - media_files_dict['original'] = original_filepath - if medium_processed: - media_files_dict['medium'] = medium_filepath - - # clean up workbench - workbench.destroy_self() diff --git a/mediagoblin/process_media/errors.py b/mediagoblin/process_media/errors.py deleted file mode 100644 index 4224a3e1..00000000 --- a/mediagoblin/process_media/errors.py +++ /dev/null @@ -1,45 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ - - -class BaseProcessingFail(Exception): - """ - Base exception that all other processing failure messages should - subclass from. - - You shouldn't call this itself; instead you should subclass it - and provid the exception_path and general_message applicable to - this error. - """ - general_message = u'' - - @property - def exception_path(self): - return u"%s:%s" % ( - self.__class__.__module__, self.__class__.__name__) - - def __init__(self, **metadata): - self.metadata = metadata or {} - - -class BadMediaFail(BaseProcessingFail): - """ - Error that should be raised when an inappropriate file was given - for the media type specified. - """ - general_message = _(u'Invalid file given for media type.') diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py new file mode 100644 index 00000000..8738cbe2 --- /dev/null +++ b/mediagoblin/processing.py @@ -0,0 +1,143 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from celery.task import Task + +from mediagoblin.db.util import ObjectId +from mediagoblin import mg_globals as mgg + +from mediagoblin.util import lazy_pass_to_ugettext as _ + +from mediagoblin.media_types import get_media_manager + + +THUMB_SIZE = 180, 180 +MEDIUM_SIZE = 640, 640 + + +def create_pub_filepath(entry, filename): + return mgg.public_store.get_unique_filepath( + ['media_entries', + unicode(entry._id), + filename]) + + +################################ +# Media processing initial steps +################################ + +class ProcessMedia(Task): + """ + DEPRECATED -- This now resides in the individual media plugins + + Pass this entry off for processing. + """ + def run(self, media_id): + """ + Pass the media entry off to the appropriate processing function + (for now just process_image...) + """ + entry = mgg.database.MediaEntry.one( + {'_id': ObjectId(media_id)}) + + # Try to process, and handle expected errors. + try: + #__import__(entry['media_type']) + manager = get_media_manager(entry['media_type']) + manager['processor'](entry) + except BaseProcessingFail, exc: + mark_entry_failed(entry._id, exc) + return + except ImportError, exc: + mark_entry_failed(entry[u'_id'], exc) + + entry['state'] = u'processed' + entry.save() + + def on_failure(self, exc, task_id, args, kwargs, einfo): + """ + If the processing failed we should mark that in the database. + + Assuming that the exception raised is a subclass of + BaseProcessingFail, we can use that to get more information + about the failure and store that for conveying information to + users about the failure, etc. + """ + entry_id = args[0] + mark_entry_failed(entry_id, exc) + + +def mark_entry_failed(entry_id, exc): + """ + Mark a media entry as having failed in its conversion. + + Uses the exception that was raised to mark more information. If + the exception is a derivative of BaseProcessingFail then we can + store extra information that can be useful for users telling them + why their media failed to process. + + Args: + - entry_id: The id of the media entry + + """ + # Was this a BaseProcessingFail? In other words, was this a + # type of error that we know how to handle? + if isinstance(exc, BaseProcessingFail): + # Looks like yes, so record information about that failure and any + # metadata the user might have supplied. + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': exc.exception_path, + u'fail_metadata': exc.metadata}}) + else: + # Looks like no, so just mark it as failed and don't record a + # failure_error (we'll assume it wasn't handled) and don't record + # metadata (in fact overwrite it if somehow it had previous info + # here) + mgg.database['media_entries'].update( + {'_id': entry_id}, + {'$set': {u'state': u'failed', + u'fail_error': None, + u'fail_metadata': {}}}) + + +class BaseProcessingFail(Exception): + """ + Base exception that all other processing failure messages should + subclass from. + + You shouldn't call this itself; instead you should subclass it + and provid the exception_path and general_message applicable to + this error. + """ + general_message = u'' + + @property + def exception_path(self): + return u"%s:%s" % ( + self.__class__.__module__, self.__class__.__name__) + + def __init__(self, **metadata): + self.metadata = metadata or {} + + +class BadMediaFail(BaseProcessingFail): + """ + Error that should be raised when an inappropriate file was given + for the media type specified. + """ + general_message = _(u'Invalid file given for media type.') diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index dd1c3d1b..21381e39 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -19,6 +19,8 @@ import uuid from os.path import splitext from cgi import FieldStorage +from celery import registry + from werkzeug.utils import secure_filename from mediagoblin.db.util import ObjectId @@ -27,7 +29,7 @@ from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security -from mediagoblin.process_media import mark_entry_failed +from mediagoblin.processing import mark_entry_failed, ProcessMedia from mediagoblin.messages import add_message, SUCCESS from mediagoblin.media_types import get_media_type_and_manager @@ -104,8 +106,9 @@ def submit_start(request): # # (... don't change entry after this point to avoid race # conditions with changes to the document via processing code) + process_media = registry.tasks[ProcessMedia.name] try: - media_manager['processor'].apply_async( + process_media.apply_async( [unicode(entry._id)], {}, task_id=task_id) except BaseException as exc: -- cgit v1.2.3 From 0bce749b21595fb0e33e2a109902b71e4611d483 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 21 Nov 2011 23:38:31 +0100 Subject: Fixes after merging video into master - part 2 - Added handling of InvalidFileType to submit.views - Updated test_celery_setup and test_submission tests to reflect the changes to the media procesing infrastructure --- mediagoblin/submit/views.py | 135 +++++++++++++++++---------------- mediagoblin/tests/test_celery_setup.py | 4 +- mediagoblin/tests/test_submission.py | 6 +- 3 files changed, 74 insertions(+), 71 deletions(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 21381e39..3def44ce 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -31,7 +31,7 @@ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.processing import mark_entry_failed, ProcessMedia from mediagoblin.messages import add_message, SUCCESS -from mediagoblin.media_types import get_media_type_and_manager +from mediagoblin.media_types import get_media_type_and_manager, InvalidFileType @require_active_login @@ -48,86 +48,89 @@ def submit_start(request): submit_form.file.errors.append( _(u'You must provide a file.')) else: - filename = request.POST['file'].filename + try: + filename = request.POST['file'].filename + media_type, media_manager = get_media_type_and_manager(filename) - media_type, media_manager = get_media_type_and_manager(filename) + # create entry and save in database + entry = request.db.MediaEntry() + entry['_id'] = ObjectId() + entry['media_type'] = unicode(media_type) + entry['title'] = ( + unicode(request.POST['title']) + or unicode(splitext(filename)[0])) - # create entry and save in database - entry = request.db.MediaEntry() - entry['_id'] = ObjectId() - entry['media_type'] = unicode(media_type) - entry['title'] = ( - unicode(request.POST['title']) - or unicode(splitext(filename)[0])) + entry['description'] = unicode(request.POST.get('description')) + entry['description_html'] = cleaned_markdown_conversion( + entry['description']) - entry['description'] = unicode(request.POST.get('description')) - entry['description_html'] = cleaned_markdown_conversion( - entry['description']) - - entry['uploader'] = request.user['_id'] + entry['uploader'] = request.user['_id'] - # Process the user's folksonomy "tags" - entry['tags'] = convert_to_tag_list_of_dicts( - request.POST.get('tags')) + # Process the user's folksonomy "tags" + entry['tags'] = convert_to_tag_list_of_dicts( + request.POST.get('tags')) - # Generate a slug from the title - entry.generate_slug() + # Generate a slug from the title + entry.generate_slug() - # Now store generate the queueing related filename - queue_filepath = request.app.queue_store.get_unique_filepath( - ['media_entries', - unicode(entry._id), - secure_filename(filename)]) + # Now store generate the queueing related filename + queue_filepath = request.app.queue_store.get_unique_filepath( + ['media_entries', + unicode(entry._id), + secure_filename(filename)]) - # queue appropriately - queue_file = request.app.queue_store.get_file( - queue_filepath, 'wb') + # queue appropriately + queue_file = request.app.queue_store.get_file( + queue_filepath, 'wb') - with queue_file: - queue_file.write(request.POST['file'].file.read()) + with queue_file: + queue_file.write(request.POST['file'].file.read()) - # Add queued filename to the entry - entry['queued_media_file'] = queue_filepath + # Add queued filename to the entry + entry['queued_media_file'] = queue_filepath - # We generate this ourselves so we know what the taks id is for - # retrieval later. + # We generate this ourselves so we know what the taks id is for + # retrieval later. - # (If we got it off the task's auto-generation, there'd be - # a risk of a race condition when we'd save after sending - # off the task) - task_id = unicode(uuid.uuid4()) - entry['queued_task_id'] = task_id + # (If we got it off the task's auto-generation, there'd be + # a risk of a race condition when we'd save after sending + # off the task) + task_id = unicode(uuid.uuid4()) + entry['queued_task_id'] = task_id - # Save now so we have this data before kicking off processing - entry.save(validate=True) + # Save now so we have this data before kicking off processing + entry.save(validate=True) - # Pass off to processing - # - # (... don't change entry after this point to avoid race - # conditions with changes to the document via processing code) - process_media = registry.tasks[ProcessMedia.name] - try: - process_media.apply_async( - [unicode(entry._id)], {}, - task_id=task_id) - except BaseException as exc: - # The purpose of this section is because when running in "lazy" - # or always-eager-with-exceptions-propagated celery mode that - # the failure handling won't happen on Celery end. Since we - # expect a lot of users to run things in this way we have to - # capture stuff here. + # Pass off to processing # - # ... not completely the diaper pattern because the - # exception is re-raised :) - mark_entry_failed(entry._id, exc) - # re-raise the exception - raise - - add_message(request, SUCCESS, _('Woohoo! Submitted!')) - - return redirect(request, "mediagoblin.user_pages.user_home", - user=request.user['username']) + # (... don't change entry after this point to avoid race + # conditions with changes to the document via processing code) + process_media = registry.tasks[ProcessMedia.name] + try: + process_media.apply_async( + [unicode(entry._id)], {}, + task_id=task_id) + except BaseException as exc: + # The purpose of this section is because when running in "lazy" + # or always-eager-with-exceptions-propagated celery mode that + # the failure handling won't happen on Celery end. Since we + # expect a lot of users to run things in this way we have to + # capture stuff here. + # + # ... not completely the diaper pattern because the + # exception is re-raised :) + mark_entry_failed(entry._id, exc) + # re-raise the exception + raise + + add_message(request, SUCCESS, _('Woohoo! Submitted!')) + + return redirect(request, "mediagoblin.user_pages.user_home", + user=request.user['username']) + except InvalidFileType, exc: + submit_form.file.errors.append( + _(u'Invalid file type.')) return render_to_response( request, diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index 348a4357..19a9b899 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -50,7 +50,7 @@ def test_setup_celery_from_config(): assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) assert fake_celery_module.CELERY_RESULT_PERSISTENT is True assert fake_celery_module.CELERY_IMPORTS == [ - 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.process_media'] + 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing'] assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { 'database': 'mediagoblin'} assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' @@ -74,7 +74,7 @@ def test_setup_celery_from_config(): assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) assert fake_celery_module.CELERY_RESULT_PERSISTENT is False assert fake_celery_module.CELERY_IMPORTS == [ - 'baz.bar.foo', 'import.is.a.this', 'mediagoblin.process_media'] + 'baz.bar.foo', 'import.is.a.this', 'mediagoblin.processing'] assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { 'database': 'captain_lollerskates', 'host': 'mongodb.example.org', diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index dec7118b..eea5747f 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -222,7 +222,7 @@ class TestSubmission: context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] - assert form.file.errors == ['The file doesn\'t seem to be an image!'] + assert form.file.errors == [u'Invalid file type.'] # NOTE: The following 2 tests will ultimately fail, but they # *will* pass the initial form submission step. Instead, @@ -246,7 +246,7 @@ class TestSubmission: assert_equal(entry['state'], 'failed') assert_equal( entry['fail_error'], - u'mediagoblin.process_media.errors:BadMediaFail') + u'mediagoblin.processing:BadMediaFail') # Test non-supported file with .png extension # ------------------------------------------- @@ -266,4 +266,4 @@ class TestSubmission: assert_equal(entry['state'], 'failed') assert_equal( entry['fail_error'], - u'mediagoblin.process_media.errors:BadMediaFail') + u'mediagoblin.processing:BadMediaFail') -- cgit v1.2.3 From 8aeb6738774f6428312bd0889e2aaf4fc9445da0 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 22 Nov 2011 00:09:41 +0100 Subject: Video support is disabled by default, set enable_video to true to enable --- mediagoblin/config_spec.ini | 3 +++ mediagoblin/media_types/__init__.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index eef6f6e0..e5e059c9 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -50,6 +50,9 @@ allow_attachments = boolean(default=False) # Cookie stuff csrf_cookie_name = string(default='mediagoblin_csrftoken') +# Media types +enable_video = boolean(default=False) + [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/public") diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 2d13f5a6..a2ea6bcb 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -17,6 +17,7 @@ import os import sys +from mediagoblin import mg_globals from mediagoblin.util import lazy_pass_to_ugettext as _ @@ -29,8 +30,10 @@ class InvalidFileType(Exception): # This should be more dynamic in the future. Perhaps put it in the .ini? # -- Joar MEDIA_TYPES = [ - 'mediagoblin.media_types.image', - 'mediagoblin.media_types.video'] + 'mediagoblin.media_types.image'] + +if mg_globals.app_config['enable_video']: + MEDIA_TYPES.append('mediagoblin.media_types.video') def get_media_types(): -- cgit v1.2.3 From d0ba62e2e773dbd3cc89bf6f446da45370652360 Mon Sep 17 00:00:00 2001 From: "Pablo J. Urbano Santos" Date: Tue, 22 Nov 2011 20:29:33 +0100 Subject: Fixes #597. Add a visible error when user tries to delete an image without cheking the "I'm sure" checkbox. --- mediagoblin/user_pages/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 25fd2ebb..2ccb453b 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -179,6 +179,9 @@ def media_confirm_delete(request, media): return redirect(request, "mediagoblin.user_pages.user_home", user=username) else: + messages.add_message( + request, messages.ERROR, + _("The file was not deleted because you didn't check that you were sure.")) return exc.HTTPFound( location=media.url_for_self(request.urlgen)) -- cgit v1.2.3 From 6506b1e22c70b55a73ee4cb391aebaf73db79ef9 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 22 Nov 2011 21:06:08 +0100 Subject: Fixes for video branch - Removed superfluous code from media_types.image - Updated lazy_pass_to_ugettext imports --- mediagoblin/media_types/__init__.py | 10 ++------ mediagoblin/media_types/image/processing.py | 36 ---------------------------- mediagoblin/media_types/video/transcoders.py | 4 ++-- mediagoblin/processing.py | 2 +- 4 files changed, 5 insertions(+), 47 deletions(-) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index a2ea6bcb..f56fd942 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -18,7 +18,7 @@ import os import sys from mediagoblin import mg_globals -from mediagoblin.util import lazy_pass_to_ugettext as _ +from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ class FileTypeNotSupported(Exception): @@ -49,13 +49,7 @@ def get_media_managers(): Generator that returns all available media managers ''' for media_type in get_media_types(): - try: - __import__(media_type) - except ImportError as e: - raise Exception( - _('ERROR: Could not import {media_type}: {exception}').format( - media_type=media_type, - exception=e)) + __import__(media_type) yield media_type, sys.modules[media_type].MEDIA_MANAGER diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 5e8e4e0a..2932c455 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -31,42 +31,6 @@ from mediagoblin.processing import BaseProcessingFail, \ # Media processing initial steps ################################ -class ProcessMedia(Task): - """ - Pass this entry off for processing. - """ - def run(self, media_id): - """ - Pass the media entry off to the appropriate processing function - (for now just process_image...) - """ - entry = mgg.database.MediaEntry.one( - {'_id': ObjectId(media_id)}) - - # Try to process, and handle expected errors. - try: - process_image(entry) - except BaseProcessingFail, exc: - mark_entry_failed(entry[u'_id'], exc) - return - - entry['state'] = u'processed' - entry.save() - - def on_failure(self, exc, task_id, args, kwargs, einfo): - """ - If the processing failed we should mark that in the database. - - Assuming that the exception raised is a subclass of BaseProcessingFail, - we can use that to get more information about the failure and store that - for conveying information to users about the failure, etc. - """ - entry_id = args[0] - mark_entry_failed(entry_id, exc) - - -process_media = registry.tasks[ProcessMedia.name] - def process_image(entry): """ diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 493a837f..d7ed14ca 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -94,8 +94,8 @@ class VideoThumbnailer: self.videosink = gst.element_factory_make('fakesink', 'videosink') self.playbin.set_property('video-sink', self.videosink) - #self.audiosink = gst.element_factory_make('fakesink', 'audiosink') - #self.playbin.set_property('audio-sink', self.audiosink) + self.audiosink = gst.element_factory_make('fakesink', 'audiosink') + self.playbin.set_property('audio-sink', self.audiosink) self.bus = self.playbin.get_bus() self.bus.add_signal_watch() diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index 8738cbe2..89c4ac89 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -19,7 +19,7 @@ from celery.task import Task from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg -from mediagoblin.util import lazy_pass_to_ugettext as _ +from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from mediagoblin.media_types import get_media_manager -- cgit v1.2.3 From 56bfd91ab45c5160bcd65ebe15f44b08f880ed72 Mon Sep 17 00:00:00 2001 From: "Pablo J. Urbano Santos" Date: Tue, 22 Nov 2011 21:07:09 +0100 Subject: Added a message noticing the user the image has been successfully deleted. --- mediagoblin/user_pages/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2ccb453b..b28b68e1 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -175,13 +175,14 @@ def media_confirm_delete(request, media): delete_media_files(media) media.delete() + messages.add_message(request, messages.SUCCESS, _('You deleted the media.')) return redirect(request, "mediagoblin.user_pages.user_home", user=username) else: messages.add_message( request, messages.ERROR, - _("The file was not deleted because you didn't check that you were sure.")) + _("The media was not deleted because you didn't check that you were sure.")) return exc.HTTPFound( location=media.url_for_self(request.urlgen)) -- cgit v1.2.3 From ea33f63635ca0b57f0bc7eca6eb941a9ee99b596 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 22 Nov 2011 21:48:56 +0100 Subject: Wrap long line. Nothing else. --- mediagoblin/user_pages/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index b28b68e1..f679be9c 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -175,7 +175,8 @@ def media_confirm_delete(request, media): delete_media_files(media) media.delete() - messages.add_message(request, messages.SUCCESS, _('You deleted the media.')) + messages.add_message( + request, messages.SUCCESS, _('You deleted the media.')) return redirect(request, "mediagoblin.user_pages.user_home", user=username) -- cgit v1.2.3 From 4d4e5b435b54fcf0920786a40e190c1748cc2ed1 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 18 Nov 2011 23:37:25 +0100 Subject: 652: Don't show empty field labels. If the label for a field is empty, don't show it at all. And don't translate it! --- mediagoblin/templates/mediagoblin/utils/wtforms.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 39dca7cc..cc30388f 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -18,7 +18,9 @@ {# Generically render a field #} {% macro render_field_div(field) %} -

+ {% if field.label.text -%} +

+ {%- endif %}
{{ field }} {%- if field.errors -%} -- cgit v1.2.3 From 30188321531e1b0d3c78166498702bbd8c7dc2bc Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 21 Nov 2011 21:40:48 +0100 Subject: Rename MediaEntry.uploader() to .get_uploader() The .uploader() method conflicts with the uploader database field. As we're moving to .FIELD for db field access, this is a relevant conflict. So renaming .uploader() to .get_uploader() --- mediagoblin/db/models.py | 8 ++++---- mediagoblin/decorators.py | 2 +- mediagoblin/listings/views.py | 2 +- mediagoblin/templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 16 ++++++++-------- .../mediagoblin/user_pages/media_confirm_delete.html | 2 +- mediagoblin/user_pages/views.py | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index f13a4457..265fe36d 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -263,7 +263,7 @@ class MediaEntry(Document): Use a slug if we have one, else use our '_id'. """ - uploader = self.uploader() + uploader = self.get_uploader() if self.get('slug'): return urlgen( @@ -286,7 +286,7 @@ class MediaEntry(Document): '_id', ASCENDING).limit(1) if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', - user=self.uploader()['username'], + user=self.get_uploader()['username'], media=unicode(cursor[0]['slug'])) def url_to_next(self, urlgen): @@ -300,10 +300,10 @@ class MediaEntry(Document): if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', - user=self.uploader()['username'], + user=self.get_uploader()['username'], media=unicode(cursor[0]['slug'])) - def uploader(self): + def get_uploader(self): return self.db.User.find_one({'_id': self['uploader']}) def get_fail_exception(self): diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 8f7532ec..1cdce23a 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -58,7 +58,7 @@ def user_may_delete_media(controller): """ def wrapper(request, *args, **kwargs): uploader = request.db.MediaEntry.find_one( - {'_id': ObjectId(request.matchdict['media'])}).uploader() + {'_id': ObjectId(request.matchdict['media'])}).get_uploader() if not (request.user['is_admin'] or request.user._id == uploader._id): return exc.HTTPForbidden() diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index 12e539e7..5a09de43 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -86,7 +86,7 @@ def tag_atom_feed(request): feed.add(entry.get('title'), entry.get('description_html'), content_type='html', - author=entry.uploader()['username'], + author=entry.get_uploader()['username'], updated=entry.get('created'), url=entry.url_for_self(request.urlgen)) diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html index 576642cf..6a5ab896 100644 --- a/mediagoblin/templates/mediagoblin/edit/attachments.html +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -20,7 +20,7 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %}
diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index 73c2bada..aa46af3d 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -22,7 +22,7 @@ {% block mediagoblin_content %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 7ef64c76..adbb66db 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -56,8 +56,8 @@ {% trans date=media.created.strftime("%Y-%m-%d"), user_url=request.urlgen( 'mediagoblin.user_pages.user_home', - user=media.uploader().username), - username=media.uploader().username -%} + user=media.get_uploader().username), + username=media.get_uploader().username -%} By {{ username }} on {{ date }} {%- endtrans %}

@@ -84,7 +84,7 @@ {% trans %}at{% endtrans %} {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} @@ -94,7 +94,7 @@ {% if request.user %} {{ wtforms_util.render_divs(comment_form) }}
@@ -106,7 +106,7 @@ {{ render_pagination(request, pagination, request.urlgen('mediagoblin.user_pages.media_home', - user = media.uploader().username, + user = media.get_uploader().username, media = media._id)) }}
{% endif %} @@ -118,13 +118,13 @@ request.user['is_admin'] %}

{% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.uploader().username, + user= media.get_uploader().username, media= media._id) %} {% trans %}Edit{% endtrans %}

{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.uploader().username, + user= media.get_uploader().username, media= media._id) %} {% trans %}Delete{% endtrans %}

@@ -148,7 +148,7 @@ or request.user['is_admin']) %}

Add attachment

{% endif %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index c3a9d622..058351a5 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -22,7 +22,7 @@ {% block mediagoblin_content %}
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index f679be9c..61cae775 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -169,7 +169,7 @@ def media_confirm_delete(request, media): if request.method == 'POST' and form.validate(): if form.confirm.data is True: - username = media.uploader()['username'] + username = media.get_uploader()['username'] # Delete all files on the public storage delete_media_files(media) @@ -188,7 +188,7 @@ def media_confirm_delete(request, media): location=media.url_for_self(request.urlgen)) if ((request.user[u'is_admin'] and - request.user._id != media.uploader()._id)): + request.user._id != media.get_uploader()._id)): messages.add_message( request, messages.WARNING, _("You are about to delete another user's media. " -- cgit v1.2.3 From cfa96da734e633856282fcefb04e1fb231d85053 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Nov 2011 11:41:24 -0600 Subject: Load multiple media types based on the media_types section of the config file --- mediagoblin.ini | 3 +++ mediagoblin/config_spec.ini | 5 +++-- mediagoblin/media_types/__init__.py | 14 +++----------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index 728ab2f2..dbde6e51 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -11,6 +11,9 @@ email_debug_mode = true # Set to false to disable registrations allow_registration = true +## Uncomment this to turn on video or enable other media types +# media_types = mediagoblin.media_types.image, mediagoblin.media_types.video + ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index e5e059c9..a17e30f0 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -2,16 +2,17 @@ # HTML title of the pages html_title = string(default="GNU MediaGoblin") +# Enabled media types +media_types = string_list(default=list("mediagoblin.media_types.image")) + # database stuff db_host = string() db_name = string(default="mediagoblin") db_port = integer() - # Where temporary files used in processing and etc are kept workbench_path = string(default="%(here)s/user_dev/media/workbench") - # Where mediagoblin-builtin static assets are kept direct_remote_path = string(default="/mgoblin_static/") diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index f56fd942..61786562 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -27,20 +27,12 @@ class FileTypeNotSupported(Exception): class InvalidFileType(Exception): pass -# This should be more dynamic in the future. Perhaps put it in the .ini? -# -- Joar -MEDIA_TYPES = [ - 'mediagoblin.media_types.image'] - -if mg_globals.app_config['enable_video']: - MEDIA_TYPES.append('mediagoblin.media_types.video') - def get_media_types(): - ''' + """ Generator that returns the available media types - ''' - for media_type in MEDIA_TYPES: + """ + for media_type in mg_globals.app_config['media_types']: yield media_type -- cgit v1.2.3 From f47a7a8c92936dfedd73716a69ba3f0978481aca Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Nov 2011 11:42:03 -0600 Subject: Remove old enable_video config option --- mediagoblin/config_spec.ini | 2 -- 1 file changed, 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index a17e30f0..c057f432 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -51,8 +51,6 @@ allow_attachments = boolean(default=False) # Cookie stuff csrf_cookie_name = string(default='mediagoblin_csrftoken') -# Media types -enable_video = boolean(default=False) [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") -- cgit v1.2.3 From 4da6efb45956321d831339da0fcdbbb6553c6846 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Nov 2011 11:43:34 -0600 Subject: Removing these video javascript files, which are currently unused --- mediagoblin/templates/mediagoblin/base.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 3dd9c8ff..29639026 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -32,11 +32,6 @@ href="{{ request.staticdirect('/css/video-js.css') }}"/> - - - {% block mediagoblin_head %} {% endblock mediagoblin_head %} -- cgit v1.2.3 From ce5ae8da19707019cd62d42533e591d71071f4fe Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Nov 2011 12:13:56 -0600 Subject: Rename MediaGoblin middleware to meddleware to avoid confusion w/ wsgi middleware hehehehehe, "meddleware" --- mediagoblin/app.py | 16 ++--- mediagoblin/meddleware/__init__.py | 20 ++++++ mediagoblin/meddleware/csrf.py | 132 +++++++++++++++++++++++++++++++++++++ mediagoblin/meddleware/noop.py | 27 ++++++++ mediagoblin/middleware/__init__.py | 20 ------ mediagoblin/middleware/csrf.py | 132 ------------------------------------- mediagoblin/middleware/noop.py | 27 -------- mediagoblin/tests/tools.py | 10 +-- mediagoblin/tools/template.py | 2 +- 9 files changed, 193 insertions(+), 193 deletions(-) create mode 100644 mediagoblin/meddleware/__init__.py create mode 100644 mediagoblin/meddleware/csrf.py create mode 100644 mediagoblin/meddleware/noop.py delete mode 100644 mediagoblin/middleware/__init__.py delete mode 100644 mediagoblin/middleware/csrf.py delete mode 100644 mediagoblin/middleware/noop.py diff --git a/mediagoblin/app.py b/mediagoblin/app.py index ce4b0bec..aafadd97 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -20,7 +20,7 @@ import urllib import routes from webob import Request, exc -from mediagoblin import routing, middleware +from mediagoblin import routing, meddleware from mediagoblin.tools import common, translate, template from mediagoblin.tools.response import render_404 from mediagoblin.tools import request as mg_request @@ -100,15 +100,15 @@ class MediaGoblinApp(object): # matters in always eager mode :) setup_workbench() - # instantiate application middleware - self.middleware = [common.import_component(m)(self) - for m in middleware.ENABLED_MIDDLEWARE] + # instantiate application meddleware + self.meddleware = [common.import_component(m)(self) + for m in meddleware.ENABLED_MEDDLEWARE] def __call__(self, environ, start_response): request = Request(environ) - # pass the request through our middleware classes - for m in self.middleware: + # pass the request through our meddleware classes + for m in self.meddleware: response = m.process_request(request) if response is not None: return response(environ, start_response) @@ -169,8 +169,8 @@ class MediaGoblinApp(object): # get the response from the controller response = controller(request) - # pass the response through the middleware - for m in self.middleware[::-1]: + # pass the response through the meddleware + for m in self.meddleware[::-1]: m.process_response(request, response) return response(environ, start_response) diff --git a/mediagoblin/meddleware/__init__.py b/mediagoblin/meddleware/__init__.py new file mode 100644 index 00000000..3addc937 --- /dev/null +++ b/mediagoblin/meddleware/__init__.py @@ -0,0 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +ENABLED_MEDDLEWARE = ( + 'mediagoblin.meddleware.noop:NoOpMeddleware', + 'mediagoblin.meddleware.csrf:CsrfMeddleware', + ) diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py new file mode 100644 index 00000000..051afe58 --- /dev/null +++ b/mediagoblin/meddleware/csrf.py @@ -0,0 +1,132 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import hashlib +import random + +from webob.exc import HTTPForbidden +from wtforms import Form, HiddenField, validators + +from mediagoblin import mg_globals + +# Use the system (hardware-based) random number generator if it exists. +# -- this optimization is lifted from Django +if hasattr(random, 'SystemRandom'): + getrandbits = random.SystemRandom().getrandbits +else: + getrandbits = random.getrandbits + + +class CsrfForm(Form): + """Simple form to handle rendering a CSRF token and confirming it + is included in the POST.""" + + csrf_token = HiddenField("", + [validators.Required()]) + + +def render_csrf_form_token(request): + """Render the CSRF token in a format suitable for inclusion in a + form.""" + + form = CsrfForm(csrf_token=request.environ['CSRF_TOKEN']) + + return form.csrf_token + + +class CsrfMeddleware(object): + """CSRF Protection Meddleware + + Adds a CSRF Cookie to responses and verifies that it is present + and matches the form token for non-safe requests. + """ + + CSRF_KEYLEN = 64 + SAFE_HTTP_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE") + + def __init__(self, mg_app): + self.app = mg_app + + def process_request(self, request): + """For non-safe requests, confirm that the tokens are present + and match. + """ + + # get the token from the cookie + try: + request.environ['CSRF_TOKEN'] = \ + request.cookies[mg_globals.app_config['csrf_cookie_name']] + + except KeyError, e: + # if it doesn't exist, make a new one + request.environ['CSRF_TOKEN'] = self._make_token(request) + + # if this is a non-"safe" request (ie, one that could have + # side effects), confirm that the CSRF tokens are present and + # valid + if request.method not in self.SAFE_HTTP_METHODS \ + and ('gmg.verify_csrf' in request.environ or + 'paste.testing' not in request.environ): + + return self.verify_tokens(request) + + def process_response(self, request, response): + """Add the CSRF cookie to the response if needed and set Vary + headers. + """ + + # set the CSRF cookie + response.set_cookie( + mg_globals.app_config['csrf_cookie_name'], + request.environ['CSRF_TOKEN'], + path=request.environ['SCRIPT_NAME'], + domain=mg_globals.app_config.get('csrf_cookie_domain'), + secure=(request.scheme.lower() == 'https'), + httponly=True) + + # update the Vary header + response.vary = (getattr(response, 'vary', None) or []) + ['Cookie'] + + def _make_token(self, request): + """Generate a new token to use for CSRF protection.""" + + return "%s" % (getrandbits(self.CSRF_KEYLEN),) + + def verify_tokens(self, request): + """Verify that the CSRF Cookie exists and that it matches the + form value.""" + + # confirm the cookie token was presented + cookie_token = request.cookies.get( + mg_globals.app_config['csrf_cookie_name'], + None) + + if cookie_token is None: + # the CSRF cookie must be present in the request + return HTTPForbidden() + + # get the form token and confirm it matches + form = CsrfForm(request.POST) + if form.validate(): + form_token = form.csrf_token.data + + if form_token == cookie_token: + # all's well that ends well + return + + # either the tokens didn't match or the form token wasn't + # present; either way, the request is denied + return HTTPForbidden() diff --git a/mediagoblin/meddleware/noop.py b/mediagoblin/meddleware/noop.py new file mode 100644 index 00000000..d11a5b9e --- /dev/null +++ b/mediagoblin/meddleware/noop.py @@ -0,0 +1,27 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +class NoOpMeddleware(object): + + def __init__(self, mg_app): + self.app = mg_app + + def process_request(self, request): + pass + + def process_response(self, request, response): + pass diff --git a/mediagoblin/middleware/__init__.py b/mediagoblin/middleware/__init__.py deleted file mode 100644 index 05325ee5..00000000 --- a/mediagoblin/middleware/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -ENABLED_MIDDLEWARE = ( - 'mediagoblin.middleware.noop:NoOpMiddleware', - 'mediagoblin.middleware.csrf:CsrfMiddleware', - ) diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py deleted file mode 100644 index 8275c18e..00000000 --- a/mediagoblin/middleware/csrf.py +++ /dev/null @@ -1,132 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import hashlib -import random - -from webob.exc import HTTPForbidden -from wtforms import Form, HiddenField, validators - -from mediagoblin import mg_globals - -# Use the system (hardware-based) random number generator if it exists. -# -- this optimization is lifted from Django -if hasattr(random, 'SystemRandom'): - getrandbits = random.SystemRandom().getrandbits -else: - getrandbits = random.getrandbits - - -class CsrfForm(Form): - """Simple form to handle rendering a CSRF token and confirming it - is included in the POST.""" - - csrf_token = HiddenField("", - [validators.Required()]) - - -def render_csrf_form_token(request): - """Render the CSRF token in a format suitable for inclusion in a - form.""" - - form = CsrfForm(csrf_token=request.environ['CSRF_TOKEN']) - - return form.csrf_token - - -class CsrfMiddleware(object): - """CSRF Protection Middleware - - Adds a CSRF Cookie to responses and verifies that it is present - and matches the form token for non-safe requests. - """ - - CSRF_KEYLEN = 64 - SAFE_HTTP_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE") - - def __init__(self, mg_app): - self.app = mg_app - - def process_request(self, request): - """For non-safe requests, confirm that the tokens are present - and match. - """ - - # get the token from the cookie - try: - request.environ['CSRF_TOKEN'] = \ - request.cookies[mg_globals.app_config['csrf_cookie_name']] - - except KeyError, e: - # if it doesn't exist, make a new one - request.environ['CSRF_TOKEN'] = self._make_token(request) - - # if this is a non-"safe" request (ie, one that could have - # side effects), confirm that the CSRF tokens are present and - # valid - if request.method not in self.SAFE_HTTP_METHODS \ - and ('gmg.verify_csrf' in request.environ or - 'paste.testing' not in request.environ): - - return self.verify_tokens(request) - - def process_response(self, request, response): - """Add the CSRF cookie to the response if needed and set Vary - headers. - """ - - # set the CSRF cookie - response.set_cookie( - mg_globals.app_config['csrf_cookie_name'], - request.environ['CSRF_TOKEN'], - path=request.environ['SCRIPT_NAME'], - domain=mg_globals.app_config.get('csrf_cookie_domain'), - secure=(request.scheme.lower() == 'https'), - httponly=True) - - # update the Vary header - response.vary = (getattr(response, 'vary', None) or []) + ['Cookie'] - - def _make_token(self, request): - """Generate a new token to use for CSRF protection.""" - - return "%s" % (getrandbits(self.CSRF_KEYLEN),) - - def verify_tokens(self, request): - """Verify that the CSRF Cookie exists and that it matches the - form value.""" - - # confirm the cookie token was presented - cookie_token = request.cookies.get( - mg_globals.app_config['csrf_cookie_name'], - None) - - if cookie_token is None: - # the CSRF cookie must be present in the request - return HTTPForbidden() - - # get the form token and confirm it matches - form = CsrfForm(request.POST) - if form.validate(): - form_token = form.csrf_token.data - - if form_token == cookie_token: - # all's well that ends well - return - - # either the tokens didn't match or the form token wasn't - # present; either way, the request is denied - return HTTPForbidden() diff --git a/mediagoblin/middleware/noop.py b/mediagoblin/middleware/noop.py deleted file mode 100644 index 820b5d9e..00000000 --- a/mediagoblin/middleware/noop.py +++ /dev/null @@ -1,27 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -class NoOpMiddleware(object): - - def __init__(self, mg_app): - self.app = mg_app - - def process_request(self, request): - pass - - def process_response(self, request, response): - pass diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 420d9ba8..1a26c6e9 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -50,9 +50,9 @@ $ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests""" class BadCeleryEnviron(Exception): pass -class TestingMiddleware(object): +class TestingMeddleware(object): """ - Middleware for the Unit tests + Meddleware for the Unit tests It might make sense to perform some tests on all requests/responses. Or prepare them in a special @@ -60,7 +60,7 @@ class TestingMiddleware(object): for being valid html *after* being rendered. This module is getting inserted at the front of the - middleware list, which means: requests are handed here + meddleware list, which means: requests are handed here first, responses last. So this wraps up the "normal" app. @@ -149,11 +149,11 @@ def get_test_app(dump_old_app=True): test_app = loadapp( 'config:' + TEST_SERVER_CONFIG) - # Insert the TestingMiddleware, which can do some + # Insert the TestingMeddleware, which can do some # sanity checks on every request/response. # Doing it this way is probably not the cleanest way. # We'll fix it, when we have plugins! - mg_globals.app.middleware.insert(0, TestingMiddleware(mg_globals.app)) + mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app)) app = TestApp(test_app) MGOBLIN_APP = app diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index 0986761b..f48b7c2e 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -21,7 +21,7 @@ from mediagoblin import mg_globals from mediagoblin import messages from mediagoblin.tools import common from mediagoblin.tools.translate import setup_gettext -from mediagoblin.middleware.csrf import render_csrf_form_token +from mediagoblin.meddleware.csrf import render_csrf_form_token SETUP_JINJA_ENVS = {} -- cgit v1.2.3 From 1b7662012f4f0827d01cc8747ce710b3e4dc6b81 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 25 Nov 2011 12:33:34 -0600 Subject: Uncommenting requires=['gst'] till I figure out why Joar added it there :) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c3c2f86f..ec672dd2 100644 --- a/setup.py +++ b/setup.py @@ -66,7 +66,7 @@ setup( ## their package managers. # 'lxml', ], - requires=['gst'], + # requires=['gst'], test_suite='nose.collector', entry_points="""\ [console_scripts] -- cgit v1.2.3 From 56dc1c9d3eb73b86bf8e165ffc79ad4929239603 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 25 Nov 2011 22:16:18 +0100 Subject: Add base class for Meddleware Created a BaseMeddleware which all Meddleware should derive from. This is not strictly needed, but will greatly help. The base class has the common __init__ of all the other Meddlwares and fall backs for all hooks. That way a new Meddlware only needs to override what it actually wants to implement. --- mediagoblin/meddleware/__init__.py | 12 ++++++++++++ mediagoblin/meddleware/csrf.py | 6 ++---- mediagoblin/meddleware/noop.py | 5 ++--- mediagoblin/tests/tools.py | 9 ++------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/mediagoblin/meddleware/__init__.py b/mediagoblin/meddleware/__init__.py index 3addc937..729a020d 100644 --- a/mediagoblin/meddleware/__init__.py +++ b/mediagoblin/meddleware/__init__.py @@ -18,3 +18,15 @@ ENABLED_MEDDLEWARE = ( 'mediagoblin.meddleware.noop:NoOpMeddleware', 'mediagoblin.meddleware.csrf:CsrfMeddleware', ) + + +class BaseMeddleware(object): + + def __init__(self, mg_app): + self.app = mg_app + + def process_request(self, request): + pass + + def process_response(self, request, response): + pass diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py index 051afe58..ca2eca5f 100644 --- a/mediagoblin/meddleware/csrf.py +++ b/mediagoblin/meddleware/csrf.py @@ -21,6 +21,7 @@ from webob.exc import HTTPForbidden from wtforms import Form, HiddenField, validators from mediagoblin import mg_globals +from mediagoblin.meddleware import BaseMeddleware # Use the system (hardware-based) random number generator if it exists. # -- this optimization is lifted from Django @@ -47,7 +48,7 @@ def render_csrf_form_token(request): return form.csrf_token -class CsrfMeddleware(object): +class CsrfMeddleware(BaseMeddleware): """CSRF Protection Meddleware Adds a CSRF Cookie to responses and verifies that it is present @@ -57,9 +58,6 @@ class CsrfMeddleware(object): CSRF_KEYLEN = 64 SAFE_HTTP_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE") - def __init__(self, mg_app): - self.app = mg_app - def process_request(self, request): """For non-safe requests, confirm that the tokens are present and match. diff --git a/mediagoblin/meddleware/noop.py b/mediagoblin/meddleware/noop.py index d11a5b9e..b43053de 100644 --- a/mediagoblin/meddleware/noop.py +++ b/mediagoblin/meddleware/noop.py @@ -15,11 +15,10 @@ # along with this program. If not, see . -class NoOpMeddleware(object): +from mediagoblin.meddleware import BaseMeddleware - def __init__(self, mg_app): - self.app = mg_app +class NoOpMeddleware(BaseMeddleware): def process_request(self, request): pass diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 1a26c6e9..01813e96 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -26,6 +26,7 @@ from mediagoblin.tools import testing from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.decorators import _make_safe from mediagoblin.db.open import setup_connection_and_db_from_config +from mediagoblin.meddleware import BaseMeddleware MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__' @@ -50,7 +51,7 @@ $ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests""" class BadCeleryEnviron(Exception): pass -class TestingMeddleware(object): +class TestingMeddleware(BaseMeddleware): """ Meddleware for the Unit tests @@ -69,12 +70,6 @@ class TestingMeddleware(object): create a new method and call it from process_*. """ - def __init__(self, mg_app): - self.app = mg_app - - def process_request(self, request): - pass - def process_response(self, request, response): # All following tests should be for html only! if response.content_type != "text/html": -- cgit v1.2.3 From 5568a014195fa9f39021033a6ba2706125bb13ed Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 23 Oct 2011 23:29:15 +0200 Subject: Use setup_global_and_app_config in gmg's migrate. Instead of using read_mediagoblin_config, forgetting to check the validation report and then finding the main app section by hand, just use setup_global_and_app_config. --- mediagoblin/gmg_commands/migrate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/gmg_commands/migrate.py b/mediagoblin/gmg_commands/migrate.py index beea109d..bd3bcb20 100644 --- a/mediagoblin/gmg_commands/migrate.py +++ b/mediagoblin/gmg_commands/migrate.py @@ -18,7 +18,7 @@ import sys from mediagoblin.db import util as db_util from mediagoblin.db.open import setup_connection_and_db_from_config -from mediagoblin.init.config import read_mediagoblin_config +from mediagoblin.init import setup_global_and_app_config # This MUST be imported so as to set up the appropriate migrations! from mediagoblin.db import migrations @@ -41,9 +41,9 @@ def _print_finished_migration(migration_number, migration_func): def migrate(args): - config, validation_result = read_mediagoblin_config(args.conf_file) + global_config, app_config = setup_global_and_app_config(args.conf_file) connection, db = setup_connection_and_db_from_config( - config['mediagoblin'], use_pymongo=True) + app_config, use_pymongo=True) migration_manager = db_util.MigrationManager(db) # Clear old indexes -- cgit v1.2.3 From 91cf67385a78a59af7874df327b96f7ea0b4259b Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 26 Nov 2011 14:34:36 -0800 Subject: Issue 680: Dispatch meddleware request processing post-routing --- mediagoblin/app.py | 13 +++++++------ mediagoblin/meddleware/__init__.py | 2 +- mediagoblin/meddleware/csrf.py | 2 +- mediagoblin/meddleware/noop.py | 3 ++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index aafadd97..7f087ed9 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -107,12 +107,6 @@ class MediaGoblinApp(object): def __call__(self, environ, start_response): request = Request(environ) - # pass the request through our meddleware classes - for m in self.meddleware: - response = m.process_request(request) - if response is not None: - return response(environ, start_response) - ## Routing / controller loading stuff path_info = request.path_info route_match = self.routing.match(path_info) @@ -164,6 +158,13 @@ class MediaGoblinApp(object): return render_404(request)(environ, start_response) controller = common.import_component(route_match['controller']) + + # pass the request through our meddleware classes + for m in self.meddleware: + response = m.process_request(request, controller) + if response is not None: + return response(environ, start_response) + request.start_response = start_response # get the response from the controller diff --git a/mediagoblin/meddleware/__init__.py b/mediagoblin/meddleware/__init__.py index 729a020d..7ba70d87 100644 --- a/mediagoblin/meddleware/__init__.py +++ b/mediagoblin/meddleware/__init__.py @@ -25,7 +25,7 @@ class BaseMeddleware(object): def __init__(self, mg_app): self.app = mg_app - def process_request(self, request): + def process_request(self, request, controller): pass def process_response(self, request, response): diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py index ca2eca5f..961fa7a6 100644 --- a/mediagoblin/meddleware/csrf.py +++ b/mediagoblin/meddleware/csrf.py @@ -58,7 +58,7 @@ class CsrfMeddleware(BaseMeddleware): CSRF_KEYLEN = 64 SAFE_HTTP_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE") - def process_request(self, request): + def process_request(self, request, controller): """For non-safe requests, confirm that the tokens are present and match. """ diff --git a/mediagoblin/meddleware/noop.py b/mediagoblin/meddleware/noop.py index b43053de..f5376494 100644 --- a/mediagoblin/meddleware/noop.py +++ b/mediagoblin/meddleware/noop.py @@ -19,7 +19,8 @@ from mediagoblin.meddleware import BaseMeddleware class NoOpMeddleware(BaseMeddleware): - def process_request(self, request): + + def process_request(self, request, controller): pass def process_response(self, request, response): -- cgit v1.2.3 From ca9ebfe2e05c83248d647b442ff29a9758a6a05c Mon Sep 17 00:00:00 2001 From: Nathan Yergler Date: Sat, 26 Nov 2011 15:32:35 -0800 Subject: Issue 680 Allow decorating views to prevent CSRF protection. --- mediagoblin/meddleware/csrf.py | 15 ++++++++++++--- mediagoblin/tests/test_csrf_middleware.py | 21 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py index 961fa7a6..16541bee 100644 --- a/mediagoblin/meddleware/csrf.py +++ b/mediagoblin/meddleware/csrf.py @@ -31,6 +31,13 @@ else: getrandbits = random.getrandbits +def csrf_exempt(func): + """Decorate a Controller to exempt it from CSRF protection.""" + + func.csrf_enabled = False + return func + + class CsrfForm(Form): """Simple form to handle rendering a CSRF token and confirming it is included in the POST.""" @@ -75,9 +82,11 @@ class CsrfMeddleware(BaseMeddleware): # if this is a non-"safe" request (ie, one that could have # side effects), confirm that the CSRF tokens are present and # valid - if request.method not in self.SAFE_HTTP_METHODS \ - and ('gmg.verify_csrf' in request.environ or - 'paste.testing' not in request.environ): + if (getattr(controller, 'csrf_enabled', True) and + request.method not in self.SAFE_HTTP_METHODS and + ('gmg.verify_csrf' in request.environ or + 'paste.testing' not in request.environ) + ): return self.verify_tokens(request) diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py index 691f10b9..c8fca23a 100644 --- a/mediagoblin/tests/test_csrf_middleware.py +++ b/mediagoblin/tests/test_csrf_middleware.py @@ -27,7 +27,7 @@ from mediagoblin import mg_globals def test_csrf_cookie_set(test_app): cookie_name = mg_globals.app_config['csrf_cookie_name'] - + # get login page response = test_app.get('/auth/login/') @@ -69,3 +69,22 @@ def test_csrf_token_must_match(test_app): mg_globals.app_config['csrf_cookie_name'])}, extra_environ={'gmg.verify_csrf': True}).\ status_int == 200 + +@setup_fresh_app +def test_csrf_exempt(test_app): + + # monkey with the views to decorate a known endpoint + import mediagoblin.auth.views + from mediagoblin.meddleware.csrf import csrf_exempt + + mediagoblin.auth.views.login = csrf_exempt( + mediagoblin.auth.views.login + ) + + # construct a request with no cookie or form token + assert test_app.post('/auth/login/', + extra_environ={'gmg.verify_csrf': True}, + expect_errors=False).status_int == 200 + + # restore the CSRF protection in case other tests expect it + mediagoblin.auth.views.login.csrf_enabled = True -- cgit v1.2.3 From 3038ba87e4fdc5612f57affeedb643a614e0c9a2 Mon Sep 17 00:00:00 2001 From: Manuel Urbano Santos Date: Sun, 27 Nov 2011 13:49:47 +0100 Subject: * Bug #671: Tags list on Edit page is not seperated by spaces and hard to read : Make 'media_tags_as_string' function put a space after each comma. * Feature #678: Drop custom delimiters in tags : I declare a constant in the begining of text.py file. --- mediagoblin/config_spec.ini | 1 - mediagoblin/tools/text.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index eef6f6e0..544f0321 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -27,7 +27,6 @@ email_smtp_pass = string(default=None) allow_registration = boolean(default=True) # tag parsing -tags_delimiter = string(default=",") tags_max_length = integer(default=50) # Whether comments are ascending or descending diff --git a/mediagoblin/tools/text.py b/mediagoblin/tools/text.py index be1adb00..d576224d 100644 --- a/mediagoblin/tools/text.py +++ b/mediagoblin/tools/text.py @@ -43,6 +43,7 @@ HTML_CLEANER = Cleaner( host_whitelist=(), whitelist_tags=set([])) +TAGS_DELIMITER=','; def clean_html(html): # clean_html barfs on an empty string @@ -67,7 +68,7 @@ def convert_to_tag_list_of_dicts(tag_string): # Split the tag string into a list of tags for tag in stripped_tag_string.split( - mg_globals.app_config['tags_delimiter']): + TAGS_DELIMITER): # Ignore empty or duplicate tags if tag.strip() and tag.strip() not in [t['name'] for t in taglist]: @@ -85,7 +86,7 @@ def media_tags_as_string(media_entry_tags): """ media_tag_string = '' if media_entry_tags: - media_tag_string = mg_globals.app_config['tags_delimiter'].join( + media_tag_string = (TAGS_DELIMITER+u' ').join( [tag['name'] for tag in media_entry_tags]) return media_tag_string -- cgit v1.2.3 From d5bb51f9d4871d8b758875fb18be5d8a9fbdb260 Mon Sep 17 00:00:00 2001 From: Manuel Urbano Santos Date: Sun, 27 Nov 2011 13:55:07 +0100 Subject: * Feature #678: Drop custom delimiters in tags * Eliminate the definition of the tag delimiter for tests. * Remove a test that was related to custom tags delimiter. * Bug #671: Tags list on Edit page is not seperated by spaces and hard to read * Modify a test to include this space. --- mediagoblin/tests/test_mgoblin_app.ini | 1 - mediagoblin/tests/test_tags.py | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index f979e810..2525a4f9 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -5,7 +5,6 @@ email_debug_mode = true db_name = __mediagoblin_tests__ # tag parsing -tags_delimiter = "," tags_max_length = 50 # Celery shouldn't be set up by the application as it's setup via diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py index a05831c9..583c1a55 100644 --- a/mediagoblin/tests/test_tags.py +++ b/mediagoblin/tests/test_tags.py @@ -39,11 +39,4 @@ def test_list_of_dicts_conversion(test_app): # Make sure converting the list of dicts to a string works assert text.media_tags_as_string([{'name': u'yin', 'slug': u'yin'}, {'name': u'yang', 'slug': u'yang'}]) == \ - u'yin,yang' - - # If the tag delimiter is a space then we expect different results - mg_globals.app_config['tags_delimiter'] = u' ' - assert text.convert_to_tag_list_of_dicts('unicorn ceramic nazi') == [ - {'name': u'unicorn', 'slug': u'unicorn'}, - {'name': u'ceramic', 'slug': u'ceramic'}, - {'name': u'nazi', 'slug': u'nazi'}] + u'yin, yang' -- cgit v1.2.3 From 9382221fe2d3e69b7900cfb7461abfdb443b4d10 Mon Sep 17 00:00:00 2001 From: Manuel Urbano Santos Date: Sun, 27 Nov 2011 14:31:20 +0100 Subject: Fix the text "Seperate tags by commas and spaces" since spaces are not used to seperate anymore. --- mediagoblin/edit/forms.py | 2 +- mediagoblin/submit/forms.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 93934be7..dd339e08 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -28,7 +28,7 @@ class EditForm(wtforms.Form): _('Tags'), [tag_length_validator], description=_( - "Seperate tags by commas or spaces.")) + "Seperate tags by commas.")) slug = wtforms.TextField( _('Slug'), [wtforms.validators.Required(message=_("The slug can't be empty"))], diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 48a21f02..ad420771 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -32,4 +32,4 @@ class SubmitStartForm(wtforms.Form): _('Tags'), [tag_length_validator], description=_( - "Seperate tags by commas or spaces.")) + "Seperate tags by commas.")) -- cgit v1.2.3 From 19e2668b77427a1157984480231023661792fca8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 27 Nov 2011 15:31:42 -0600 Subject: Updating translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 268 ++++++++++--------- mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po | 290 +++++++++++--------- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 310 ++++++++++++---------- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 234 ++++++++-------- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 278 ++++++++++--------- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 278 ++++++++++--------- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 280 ++++++++++--------- mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po | 246 +++++++++-------- mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 272 ++++++++++--------- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 254 ++++++++++-------- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 256 ++++++++++-------- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 282 +++++++++++--------- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 278 ++++++++++--------- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 279 ++++++++++--------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 290 +++++++++++--------- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 280 ++++++++++--------- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 271 ++++++++++--------- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 246 +++++++++-------- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 282 ++++++++++---------- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 248 +++++++++-------- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 275 ++++++++++--------- 21 files changed, 3125 insertions(+), 2572 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index 548e971f..40e8b1cd 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -21,6 +21,10 @@ msgstr "" "Language: ar\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "اسم المستخدم" @@ -54,8 +58,8 @@ msgid "Sorry, a user with that name already exists." msgstr "عذرًا، لقد اختار مستخدم آخر هذا الاسم." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "عفوًا، هذا العنوان البريدي مستخدم." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -69,11 +73,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "مفتاح التحقق أو معرف المستخدم خاطئ" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "أعدنا إرسال رسالة التحقق." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -89,43 +101,63 @@ msgstr "العنوان" msgid "Tags" msgstr "الوسوم" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "المسار" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "لا يمكن ترك المسار فارغًا" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "الجزء الذي يمثل عنوان الملف في المسار. لا حاجة إلى تغيير محتوى هذه الخانة " "عادةً." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "السيرة" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "الموقع الإلكتروني" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "يوجد ملف آخر بهذا المسار لدى هذى المستخدم." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "أنت تحرّر وسائط مستخدم آخر. كن حذرًا أثناء العملية." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "أنت تحرّر ملف مستخدم آخر. كن حذرًا أثناء العملية." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -136,18 +168,18 @@ msgstr "الملف" msgid "Description of this work" msgstr "وصف هذا العمل." -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "يجب أن تضع ملفًا." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "لا يبدو أن هذا الملف صورة!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "يا سلام! نُشرَت!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "ويحي!" @@ -167,29 +199,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "صورة قزم مرتبك" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "غنو ميدياغوبلن" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "شعار ميدياغوبلن" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "أرسل وسائط" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "أكّد بريدك" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "لِج" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -200,61 +232,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "مرحبًا بكم يا محبي الوسائط! ميدياغوبلن هو..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "المكان الأنسب لوسائطك!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "مكان يجتمع فيه الناس ليتعاونوا ويعرضوا إبداعاتهم الأصلية والمقتبسة!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" -msgstr "مشروع حر، فنحن أحد مشاريع غنو." - -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "مشروع يحاول جعل عالمنا أفضل عن طريق اللامركزية (قريبًا!)." +msgid "Hi there, welcome to this MediaGoblin site!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"جاهز للتمدد. (سيُضاف دعم أنساق كثيرة من الوسائط قريبًا، كما سندعم الفيديو!)." -#: mediagoblin/templates/mediagoblin/root.html:34 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"أنشئ حسابًا مجانيًا\n" -" أو\n" -" ركّب ميدياغوبلن على خادومك الخاص" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "أحدث الوسائط" @@ -262,9 +265,13 @@ msgstr "أحدث الوسائط" msgid "Enter your new password" msgstr "أدخل كلمة سرك الجديدة" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "أدخل اسم المستخدم أو بريدك الإلكتروني" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -300,22 +307,18 @@ msgstr "" msgid "Logging in failed!" msgstr "فشل الولوج!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "ألا تملك حسابًا بعد؟" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "أنشئ حسابًا هنا!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "أنسيت كلمة سرك؟" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "غيّرها!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "أنشئ حسابًا!" @@ -361,9 +364,15 @@ msgstr "احفظ التغييرات" msgid "Editing %(username)s's profile" msgstr "تحرير ملف %(username)s الشخصي" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "الوسائط الموسومة ب‍" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -373,16 +382,16 @@ msgstr "انشر وسائطك" msgid "Submit" msgstr "أرسل" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "عذرًا، تعذر العثور على مستخدم بهذا الاسم." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -413,35 +422,45 @@ msgstr "لا توجد وسائط تحت المعالجة" msgid "These uploads failed to process:" msgstr "فشلت معالجة هذه الملفات:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "ملف %(username)s الشخصي" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "عذرًا، تعذر العثور على مستخدم بهذا الاسم." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "يجب التحقق من البريد الإلكتروني" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "أوشكنا على الانتهاء! ما زال حسابك بحاجة إلى التفعيل." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "ستصلك رسالة إلكترونية خلال لحظات بها التعليمات." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "إن لم تصل." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "أعد إرسال رسالة التحقق" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "سجّل أحدهم حسابًا بهذا الاسم، ولكننا بانتظار التفعيل حتى الآن." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can الولوج وإعادة إرسالها." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "ملف %(username)s الشخصي" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "هذه زاوية لتخبر الآخرين فيها عن نفسك." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "حرِّر الملف الشخصي" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "لم يعبئ هذا العضو بيانات ملفه بعد." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "أظهِر كل وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "هنا ستظهر وسائطك، ولكن يبدو أنك لم تضف شيئًا بعد." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "أضف وسائط" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "لا يبدو أنه توجد أي وسائط هنا حتى الآن..." @@ -503,6 +517,14 @@ msgstr "الأحدث" msgid "Older" msgstr "الأقدم" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "علِّق" @@ -511,15 +533,23 @@ msgstr "علِّق" msgid "I am sure I want to delete this" msgstr "أنا متأكد من رغبتي بحذف هذا العمل" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "أنت على وشك حذف وسائط مستخدم آخر. كن حذرًا أثناء العملية." diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po index e2cd8342..f07ab2d6 100644 --- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po @@ -3,13 +3,14 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: +# Al fred , 2011. # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +20,10 @@ msgstr "" "Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Aquest tipus de fitxer no és vàlid." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nom d'usuari" @@ -52,8 +57,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Lamentablement aquest usuari ja existeix." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Disculpeu, aquesta adreça electrònica ja s'està utilitzant." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -68,11 +73,19 @@ msgid "The verification key or user id is incorrect" msgstr "" "La clau de verificació o la identificació de l'usuari no són correctes." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Torna'm a enviar el correu de verificació" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -86,42 +99,62 @@ msgstr "Títol" msgid "Tags" msgstr "Etiquetes" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Lloc web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Esteu editant fitxers d'un altre usuari. Aneu amb compte." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Esteu editant el perfil d'un usuari. Aneu amb compte" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Aquest tipus de fitxer no és vàlid." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -131,18 +164,18 @@ msgstr "Fitxer" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Heu d'escollir un fitxer." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "El fitxer no és una imatge" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Visca! S'ha enviat!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Ups!" @@ -161,31 +194,31 @@ msgstr "" #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" +msgstr "Imatge de la pantalla 404, el goblin no sap què fer..." -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Logo de mediagoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Envia fitxers" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "verifiqueu el correu electrònic" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entra" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -196,66 +229,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Ei, fanàtic multimèdia! MediaGoblin és..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "El lloc fitxer pels teus fitxers!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Un lloc en el qual les persones poden col·laborar i mostrar les seves " -"creacions originals o obres derivades." - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" -"Amb l'objectiu de fer del món un lloc millor a través de la " -"descentralització i (eventualment, aviat disponible!) La federació!" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Construït per l'ampliació. (Múltiples tipus de fitxers en breu amb el " -"programari, incloent el suport de vídeo!)" -#: mediagoblin/templates/mediagoblin/root.html:34 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Desenvolupat per persones com vostè. ( Podeu ajudar a millorar " -"aquest programari! )" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -263,8 +262,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -294,22 +297,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Inici de sessió ha fallat!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Encara no teniu un compte?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Creeu-ne un aquí!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Creeu un compte!" @@ -355,9 +354,15 @@ msgstr "Desa els canvis" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Etiquetat amb:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -367,16 +372,16 @@ msgstr "Envieu els vostres fitxers" msgid "Submit" msgstr "Envia" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Lamentablement no s'ha trobat l'usuari que cercàveu." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -397,7 +402,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "S'està processant el fitxer" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" @@ -405,37 +410,49 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" +msgstr "No s'han pogut penjar els següents fitxers:" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Lamentablement no s'ha trobat l'usuari que cercàveu." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" -msgstr "" +msgstr "Cal que verifiqueu l'adreça electrònica" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Gairebé esteu! Tan sols falta que activeu el vostre compte" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Us hauria d'arribar un correu amb les instruccions per a fer-ho." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" -msgstr "" +msgstr "Per si no hi fos:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Torna'm a enviar el correu de verificació" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Algú ja ha registrat un compte amb aquest nom d'usuari, però encara l'ha " +"d'activar." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can entrar i tornar-lo a enviar." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Edita el perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Aquest usuari encara no ha escrit res al seu perfil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "View all of %(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" -msgstr "" +msgstr "Tots els fitxers" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "Icona RSS" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" @@ -497,6 +509,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Comentari" @@ -505,15 +525,23 @@ msgstr "Comentari" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 5c4ef0d0..f5907eda 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -6,6 +6,7 @@ # , 2011. # , 2011. # Elrond , 2011. +# , 2011. # Jan-Christoph Borchardt , 2011. # , 2011. # , 2011. @@ -15,9 +16,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 15:18+0000\n" -"Last-Translator: piratenpanda \n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -26,6 +27,10 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Benutzername" @@ -48,43 +53,52 @@ msgstr "Hier nochmal eintragen, um Tippfehler zu verhindern." #: mediagoblin/auth/forms.py:42 msgid "Email address" -msgstr "Email-Adresse" +msgstr "E-Mail-Adresse" #: mediagoblin/auth/views.py:55 msgid "Sorry, registration is disabled on this instance." -msgstr "Registrierung ist auf dieser Instanz leider deaktiviert." +msgstr "Das Registrieren ist auf dieser Instanz leider deaktiviert." #: mediagoblin/auth/views.py:73 msgid "Sorry, a user with that name already exists." msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Tut und Leid, aber diese Email-Adresse wird bereits verwendet." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Deine Email-Adresse wurde bestätigt. Du kannst dich nun anmelden, Dein " +"Deine E-Mail-Adresse wurde bestätigt. Du kannst dich nun anmelden, Dein " "Profil bearbeiten und Bilder hochladen!" #: mediagoblin/auth/views.py:185 msgid "The verification key or user id is incorrect" -msgstr "Der Bestätigungssschlüssel oder die Nutzernummer ist falsch." +msgstr "Der Bestätigungsschlüssel oder die Nutzernummer ist falsch." + +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." -msgstr "Bestätigungs-Email wurde erneut versandt." +msgstr "Bestätigungs-E-Mail wurde erneut versandt." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" -"Konnte Email zur Wiederherstellung des Passworts nicht senden, weil dein " -"Benutzername inaktiv oder deine Email-Adresse noch nicht verifiziert ist." +"E-Mail zur Wiederherstellung des Passworts konnte nicht gesendet werden, " +"weil dein Benutzername inaktiv oder deine E-Mail-Adresse noch nicht " +"verifiziert ist." #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" @@ -94,44 +108,64 @@ msgstr "Titel" msgid "Tags" msgstr "Markierungen" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Kurztitel" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Bitte gib einen Kurztitel ein" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "Der Titelteil der Medienadresse. Normalerweise muss hier nichts geändert " "werden." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biographie" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Webseite" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Diesen Kurztitel hast du bereits vergeben." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -141,18 +175,18 @@ msgstr "Datei" msgid "Description of this work" msgstr "Beschreibung des Werkes" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Du musst eine Datei angeben." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Diese Datei scheint kein Bild zu sein!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Yeeeaaah! Geschafft!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Hoppla!" @@ -173,29 +207,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Bild eines angespannten Goblins" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin-Logo" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Medien hochladen" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Bitte bestätige deine Email-Adresse!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Anmelden" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -208,71 +242,32 @@ msgid "Explore" msgstr "Entdecke" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Hallo Medien-Liebhaber! MediaGoblin ist …" - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Der perfekte Platz für deine Medien!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Ein Platz für Zusammenarbeit und um Originale und abgeleitete Werke zu " -"präsentieren!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Frei, wie in Freiheit. (Wir sind schließlich ein GNU-Projekt.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Weltverbesserer durch Dezentralisierung und (hoffentlich bald!) unabhängige " -"Kommunikation!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Gebaut für Erweiterungen. (Bald mit Unterstützung für verschiedene " -"Medientypen inklusive Videos!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Betrieben von Leuten wie dir. (Du kannst uns dabei helfen, " -"die Software zu verbessern!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Neugierig dich uns anzuschließen?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Gratis ein Konto einrichten\n" -" or\n" -" MediaGoblin auf deinem eigenen Server einrichten" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Neuste Medien" @@ -280,9 +275,13 @@ msgstr "Neuste Medien" msgid "Enter your new password" msgstr "Neues Passwort eingeben" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Benutzername oder Email-Adresse eingeben" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -292,8 +291,8 @@ msgstr "Dein Passwort wurde geändert. Versuche dich jetzt einzuloggen." msgid "" "Check your inbox. We sent an email with a URL for changing your password." msgstr "" -"Prüfe deinen Posteingang. Wir haben dir eine Email mit einem Link geschickt," -" mit dem du dein Passwort ändern kannst." +"Überprüfe deinen Posteingang. Wir haben dir eine E-Mail mit einem Link " +"geschickt, mit dem du dein Passwort ändern kannst." #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -314,28 +313,24 @@ msgstr "" "\n" "%(verification_url)s\n" "\n" -"Wenn du denkst, dass das ein Fehler ist, ignoriere einfach diese Email und bleib ein glücklicher Goblin!" +"Wenn du denkst, dass das ein Fehler ist, ignoriere einfach diese E-Mail und bleib ein glücklicher Goblin!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" msgstr "Anmeldevorgang fehlgeschlagen!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Hast du noch kein Konto?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Registriere dich hier!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Passwort vergessen?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Wechsle es!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Neues Konto registrieren!" @@ -356,7 +351,7 @@ msgid "" msgstr "" "Hallo %(username)s,\n" "\n" -"um dein Konto bei GNU MediaGoblin zu aktivieren, musst du folgende Adresse in einem Webbrowser öffnen:\n" +"um dein Konto bei GNU MediaGoblin zu aktivieren, musst du folgende Adresse in deinem Webbrowser öffnen:\n" "\n" "%(verification_url)s" @@ -380,9 +375,15 @@ msgstr "Änderungen speichern" msgid "Editing %(username)s's profile" msgstr "%(username)ss Profil bearbeiten" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Medien markiert mit:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -392,16 +393,16 @@ msgstr "Medien hochladen" msgid "Submit" msgstr "Bestätigen" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)ss Medien" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Dieser Benutzer wurde leider nicht gefunden." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -434,31 +435,41 @@ msgstr "Keine Medien in Bearbeitung" msgid "These uploads failed to process:" msgstr "Die folgenden Uploads sind fehlgeschlagen:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)ss Profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Dieser Benutzer konnte leider nicht gefunden werden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" -msgstr "Email-Bestätigung benötigt" +msgstr "E-Mail-Bestätigung benötigt" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Fast fertig! Dein Konto muss noch freigeschaltet werden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -"Gleich solltest du eine Email bekommen, die dir sagt, was du noch machen " -"musst." +"Gleich solltest du eine E-Mail erhalten, die dir erklärt, was du noch machen" +" musst." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Wenn sie nicht ankommt:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Bestätigung erneut senden" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -466,7 +477,7 @@ msgstr "" "Jemand hat bereits ein Konto mit diesem Benutzernamen registriert, aber es " "muss noch aktiviert werden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can anmelden und sie erneut " "senden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "%(username)ss Profil" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Hier kannst du Anderen etwas über dich erzählen." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Profil bearbeiten" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Dieser Benutzer hat (noch) keine Daten in seinem Profil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Alle Medien von %(username)s anschauen" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Hier erscheinen deine Medien. Sobald du etwas hochgeladen hast." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Medien hinzufügen" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Scheinbar gibt es hier noch nichts …" @@ -529,6 +535,14 @@ msgstr "Neuere" msgid "Older" msgstr "Ältere" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Kommentar" @@ -537,15 +551,23 @@ msgstr "Kommentar" msgid "I am sure I want to delete this" msgstr "Ja, wirklich löschen" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "Leere Kommentare sind nicht erlaubt." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "Kommentar hinzugefügt!" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Du versuchst Medien eines anderen Nutzers zu löschen. Sei vorsichtig." diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index f3e0c100..c1f3fd7f 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "" @@ -50,7 +54,7 @@ msgid "Sorry, a user with that name already exists." msgstr "" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." +msgid "Sorry, a user with that email address already exists." msgstr "" #: mediagoblin/auth/views.py:179 @@ -89,40 +93,60 @@ msgstr "" msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -133,16 +157,16 @@ msgstr "" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" +#: mediagoblin/submit/views.py:127 +msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:121 -msgid "Woohoo! Submitted!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." msgstr "" #: mediagoblin/templates/mediagoblin/404.html:21 @@ -163,29 +187,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -196,60 +220,35 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you" +" can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project," -" after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the " -"software, including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve " -"this software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a " -"free account\n" +"Create an " +"account at this site\n" " or\n" -" Set up MediaGoblin on " "your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -257,8 +256,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -287,22 +290,18 @@ msgstr "" msgid "Logging in failed!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "" @@ -342,8 +341,14 @@ msgstr "" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 @@ -354,14 +359,14 @@ msgstr "" msgid "Submit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format -msgid "%(username)s's media" +msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 +#, python-format +msgid "%(username)s's media" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -393,74 +398,79 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "An email should arrive in a few moments with instructions on how to do so." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to" " be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can " "log in and resend it." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -480,6 +490,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" @@ -488,15 +506,23 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index f6bb1cce..2cffe874 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -21,6 +21,10 @@ msgstr "" "Language: eo\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "La provizita dosiero ne konformas al la informtipo." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Uzantnomo" @@ -54,8 +58,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Tiu retpoŝtadreso jam estas uzata." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -69,11 +73,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "La kontrol-kodo aŭ la uzantonomo ne estas korekta" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Resendi vian kontrol-mesaĝon." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -89,44 +101,64 @@ msgstr "Titolo" msgid "Tags" msgstr "Etikedoj" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "La distingiga adresparto" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La distingiga adresparto ne povas esti malplena" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "La parto de la dosieradreso, bazita sur la dosiertitolo. Ordinare ne necesas" " ĝin ŝanĝi." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Retejo" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "La provizita dosiero ne konformas al la informtipo." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -136,18 +168,18 @@ msgstr "Dosiero" msgid "Description of this work" msgstr "Priskribo de ĉi tiu verko" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Vi devas provizi dosieron." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "La dosiero ŝajnas ne esti bildo!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Hura! Alŝutitas!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Oj!" @@ -168,29 +200,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Bildo de 404-koboldo penŝvitanta." -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Emblemo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Alŝuti aŭd-vid-dosieron" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "konfirmu vian retpoŝtadreson! " +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Ensaluti" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -203,69 +235,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Saluton, artemulo! MediaGoblin estas…" - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "La perfekta loko por viaj aŭd-vid-dosieroj!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Loko, kie homoj povas kunlabori, kaj elmeti originalajn kreaĵojn kaj " -"derivaĵojn!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Libera verko. (Ni ja estas projekto de GNU.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Celanta plibonigi la mondon per sencentreco kaj (iam, baldaŭ!) federateco!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Kreita por etendado. (Baldaŭ en la programo aperos subteno de pluraj " -"informspecoj, inkluzive de filmoj!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Vivanta per homoj kiel vi. (Vi povas helpi al ni " -"plibonigi la programon!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Ĉu vi deziregas aliĝi nin?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Kreu senpagan" -" konton⏎ aŭ⏎ Kreu senpagan konton" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Plej nove aldonitaj dosieroj" @@ -273,9 +268,13 @@ msgstr "Plej nove aldonitaj dosieroj" msgid "Enter your new password" msgstr "Enigu vian novan pasvorton" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Enigu vian salutnomon aŭ retpoŝtadreson" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -313,22 +312,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Ensaluto malsukcesis!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Ĉu ankoraŭ sen konto?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Kreu ĝin ĉi tie!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Ĉu vi forgesis vian pasvorton?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Ŝanĝu ĝin!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Kreu konton!" @@ -373,9 +368,15 @@ msgstr "Konservi ŝanĝojn" msgid "Editing %(username)s's profile" msgstr "Redaktado de l’profilo de %(username)s'" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Dosieroj markitaj per:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -385,16 +386,16 @@ msgstr "Alŝutu vian aŭd-vid-dosieron" msgid "Submit" msgstr "Alŝuti" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Dosieroj de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Uzanto ne trovita." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -427,30 +428,40 @@ msgstr "Neniu dosieroj preparatas" msgid "These uploads failed to process:" msgstr "Preparado de ĉi tiuj alŝutaĵoj malsukcesis:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profilo de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Uzanto ne trovita." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Necesas konfirmo de retpoŝtadreso" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Preskaŭ finite! Restas nur validigi vian konton." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "Post kelkaj momentoj devas veni retletero kun instrukcio pri kiel tion fari." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Se tio ne okazas:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Resendi kontrolmesaĝon" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -458,7 +469,7 @@ msgstr "" "Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti " "aktivigita." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can ensaluti kaj resendi ĝin." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profilo de %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Jen estas spaceto por rakonti pri vi al aliaj." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Redakti profilon" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Ĉi tiu uzanto ne jam aldonis informojn pri si." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Rigardi ĉiujn dosierojn de %(username)s'" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Ĝuste ĉi tie aperos viaj dosieroj, sed vi ŝajne ankoraŭ nenion alŝutis." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Aldoni dosieron" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Ĉi tie ŝajne estas ankoraŭ neniuj dosieroj…" @@ -521,6 +527,14 @@ msgstr "Plinovaj" msgid "Older" msgstr "Malplinovaj" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Komento" @@ -529,15 +543,23 @@ msgstr "Komento" msgid "I am sure I want to delete this" msgstr "Mi estas certa, ke mi volas forigi ĉi tion" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Malplenaj komentoj ne estas afiŝeblaj." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" +msgstr "La komento estas afiŝita!" + +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Vi estas forigonta dosieron de alia uzanto. Estu singardema." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index a3c9939b..6ab070af 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -25,6 +25,10 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Archivo inválido para el formato seleccionado." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nombre de usuario" @@ -59,8 +63,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Lo sentimos, ya existe un usuario con ese nombre." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Lo sentimos, esa dirección de correo electrónico ya ha sido tomada." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -75,11 +79,19 @@ msgid "The verification key or user id is incorrect" msgstr "" "La clave de verificación o la identificación de usuario son incorrectas" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Se reenvió tu correo electrónico de verificación." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -96,44 +108,64 @@ msgstr "Título" msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Ficha" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La ficha no puede estar vacía" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "La parte del título de la URL de este contenido. Normalmente no necesitas " "cambiar esto." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sitio web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Una entrada con esa ficha ya existe para este usuario." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Estás editando el contenido de otro usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Estás editando un perfil de usuario. Proceder con precaución." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Archivo inválido para el formato seleccionado." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -143,18 +175,18 @@ msgstr "Archivo" msgid "Description of this work" msgstr "Descripción de esta obra" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Debes proporcionar un archivo." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "¡El archivo no parece ser una imagen!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "¡Woohoo! ¡Enviado!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Ups!" @@ -175,29 +207,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Imagen de 404 goblin estresándose" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Logo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Enviar contenido" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "¡Verifica tu correo electrónico!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Conectarse" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -210,71 +242,32 @@ msgid "Explore" msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "¡Hola, amante de los contenidos! MediaGoblin es ..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "¡El lugar ideal para tus contenidos!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"¡Un lugar para colaborar y exhibir tus creaciones originales y derivadas!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Libre, como en la libertad. (Somos parte del proyecto GNU después de todo.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Queriendo hacer del mundo un mejor lugar a través de la descentralización y " -"(eventualmente, muy pronto!) la federalización!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Pensado para ser extensible. (Prontamente soporte para multiples formatos, " -"incluyendo video!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Impulsado por gente como vos. ( Vos podés ayudarnos a " -"mejorar este programa)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Te gustaría unirte a nosotros?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Crea una " -"cuenta gratuita o Establece MediaGoblin en " -"tu propio servidor" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "El contenido más reciente" @@ -282,9 +275,13 @@ msgstr "El contenido más reciente" msgid "Enter your new password" msgstr "Ingrese su nueva contraseña" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Introduzca su nombre de usuario o correo electrónico" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -319,22 +316,18 @@ msgstr "" msgid "Logging in failed!" msgstr "¡Falló el inicio de sesión!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "¿No tienes una cuenta?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "¡Crea una aquí!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "¿Olvidaste tu contraseña?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Cambiarlo!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "¡Crea una cuenta!" @@ -379,9 +372,15 @@ msgstr "Guardar cambios" msgid "Editing %(username)s's profile" msgstr "Editando el perfil de %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Contenido etiquetado con:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -391,16 +390,16 @@ msgstr "Envía tu contenido" msgid "Submit" msgstr "Enviar" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Contenido de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Lo sentimos, no se encontró ese usuario." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -433,31 +432,41 @@ msgstr "No hay contenido siendo procesado." msgid "These uploads failed to process:" msgstr "Estos archivos no pudieron ser procesados:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Perfil de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Lo sentimos, no se encontró ese usuario." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Es necesario un correo electrónico de verificación" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Casi terminas! Solo falta activar la cuenta." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "En unos momentos te debería llegar un correo electrónico con las " "instrucciones para hacerlo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "En caso de que no:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Reenviar correo electrónico de verificación" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -465,7 +474,7 @@ msgstr "" "Alguien ya registró una cuenta con ese nombre de usuario, pero todavía no " "fue activada." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can acceder y reenviarlo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Perfil de %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Aquí hay un lugar para que le cuentes a los demás sobre tí." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Este usuario (todavia) no ha completado su perfil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Ver todo el contenido de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Aquí es donde tú contenido estará, pero parece que aún no has agregado nada." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Añadir contenido" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Parece que aún no hay ningún contenido aquí..." @@ -528,6 +532,14 @@ msgstr "Recientes" msgid "Older" msgstr "Antiguas" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Comentario" @@ -536,15 +548,23 @@ msgstr "Comentario" msgid "I am sure I want to delete this" msgstr "Estoy seguro de que quiero borrar esto" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Estás a punto de eliminar un contenido de otro usuario. Proceder con " diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 0a6a5a40..b37f5217 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -13,9 +13,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-04 10:05+0000\n" -"Last-Translator: chesuidayeur \n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,6 +24,10 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Le fichier envoyé ne correspond pas au type de média." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nom d'utilisateur" @@ -59,8 +63,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Un utilisateur existe déjà avec ce nom, désolé." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Désolé, cette adresse courriel a déjà été prise." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -74,11 +78,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "La clé de vérification ou le nom d'utilisateur est incorrect." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "E-mail de vérification renvoyé." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -94,48 +106,68 @@ msgstr "Titre" msgid "Tags" msgstr "Tags" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Légende" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "La légende ne peut pas être laissée vide." -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "Le nom de ce media dans l'URL. Vous n'avez normalement pas besoin de le " "changer" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Site web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Une entrée existe déjà pour cet utilisateur avec la même légende." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " "prendre garde." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " "garde." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Le fichier envoyé ne correspond pas au type de média." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -145,18 +177,18 @@ msgstr "Fichier" msgid "Description of this work" msgstr "Descriptif pour ce travail" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Il vous faut fournir un fichier." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Ce fichier ne semble pas être une image !" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Youhou, c'est envoyé !" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Zut!" @@ -177,29 +209,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Image de 404 gobelin angoissé" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Soumettre un média" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "vérifiez votre adresse e-mail !" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "S'identifier" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -212,71 +244,32 @@ msgid "Explore" msgstr "Explorer" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Salut à tous, amateur de médias! MediaGoblin est ..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "L'endroit idéal pour vos médias!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Un espace de création collaboratif : montrez vos œuvres, originales ou " -"dérivées !" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Logiciel libre. (Nous sommes un projet GNU " -"après tout.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Une tentative de rendre le monde meilleur grâce à la décentralisation et (à " -"terme, et pour bientôt !) la fédération !" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Construit pour l'extensibilité. (Plusieurs types de médias à venir au " -"logiciel, y compris le support vidéo!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Propulsé par des gens comme vous. (Vous pouvez nous aider à " -"améliorer ce logiciel!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Envi de vous joindre à nous ?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Créez gratuitement en compte\n" -" ou\n" -" Installez MediaGoblin sur votre propre serveur" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Tout derniers media" @@ -284,9 +277,13 @@ msgstr "Tout derniers media" msgid "Enter your new password" msgstr "Entrez un nouveau mot de passe" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Entrez votre nom d'utilisateur ou votre email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -327,22 +324,18 @@ msgstr "" msgid "Logging in failed!" msgstr "La connexion a échoué!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Pas encore de compte?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Créez-en un ici!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Vous avez oublié votre mot de passe ?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Changez-le !" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Créer un compte!" @@ -387,9 +380,15 @@ msgstr "Enregistrer les modifications" msgid "Editing %(username)s's profile" msgstr "Modification du profil de %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Média comportant les tags suivants :" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -399,16 +398,16 @@ msgstr "Soumettez ce média" msgid "Submit" msgstr "Soumettre" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Impossible de trouver cet utilisateur, désolé." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -441,31 +440,41 @@ msgstr "Aucun média en transformation" msgid "These uploads failed to process:" msgstr "Le traitement de ces ajouts a échoué :" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "profil de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Impossible de trouver cet utilisateur, désolé." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Vérification d'email nécessaire" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Presque fini ! Votre compte a encore besoin d'être activé." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "Un e-mail devrait vous parvenir dans quelques instants ; il vous indiquera " "comment procéder." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Si la vérification n'est pas arrivée à bon port :" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Renvoyer l'e-mail de vérification" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -473,7 +482,7 @@ msgstr "" "Quelqu'un a enregistré un compte avec ce nom, mais il doit encore être " "activé." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can identifier et " "le renvoyer." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "profil de %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Voici un endroit pour parler aux autres de vous-même." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Modifier le profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Cet utilisateur n'a pas (encore) rempli son profil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Voir tous les médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -514,11 +518,11 @@ msgstr "" "C'est là où vos médias apparaîssent, mais vous ne semblez pas avoir encore " "ajouté quoi que ce soit." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Ajouter des médias" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Il ne semble pas y avoir de média là, pour l'instant ..." @@ -538,6 +542,14 @@ msgstr "Nouveaux" msgid "Older" msgstr "Anciens" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commentaire" @@ -546,15 +558,23 @@ msgstr "Commentaire" msgid "I am sure I want to delete this" msgstr "Je suis sûr de vouloir supprimer cela" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "Les commentaires vides ne sont pas autorisés." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "Votre commentaire a été posté !" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Vous êtes sur le point de supprimer des médias d'un autre utilisateur. " diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po index d9fdf8d6..a4f1f8d7 100644 --- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: ia\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nomine de usator" @@ -52,7 +56,7 @@ msgid "Sorry, a user with that name already exists." msgstr "" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." +msgid "Sorry, a user with that email address already exists." msgstr "" #: mediagoblin/auth/views.py:179 @@ -65,11 +69,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -83,41 +95,61 @@ msgstr "Titulo" msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -128,16 +160,16 @@ msgstr "" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" +#: mediagoblin/submit/views.py:127 +msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:121 -msgid "Woohoo! Submitted!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." msgstr "" #: mediagoblin/templates/mediagoblin/404.html:21 @@ -158,29 +190,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Initiar session" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -191,57 +223,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -249,8 +256,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -280,22 +291,18 @@ msgstr "" msgid "Logging in failed!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Crear un conto!" @@ -335,8 +342,14 @@ msgstr "" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 @@ -347,14 +360,14 @@ msgstr "" msgid "Submit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format -msgid "%(username)s's media" +msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 +#, python-format +msgid "%(username)s's media" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -387,75 +400,80 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profilo de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profilo de %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -475,6 +493,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commento" @@ -483,15 +509,23 @@ msgstr "Commento" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po index 183d09ed..25700f8f 100644 --- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: it\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "documento non valido come tipo multimediale." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nome utente" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Spiacente, esiste già un utente con quel nome" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Spiacente, quell'indirizzo email è già stato preso." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "La chiave di verifica o l'id utente è sbagliato" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Rispedisci email di verifica" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -85,44 +97,64 @@ msgstr "Titolo" msgid "Tags" msgstr "Tags" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Stai modificando documenti multimediale di un altro utente. Procedi con " "attenzione." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Stai modificando il profilo di un utente. Procedi con attenzione." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "documento non valido come tipo multimediale." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -132,18 +164,18 @@ msgstr "Documento" msgid "Description of this work" msgstr "Descrizione di questo lavoro" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Devi specificare un documento." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Il documento non sembra essere un'immagine!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Evviva! " +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Oops!" @@ -164,29 +196,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Immagine di 404 folletti che stressano" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Inoltra file multimediale" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "verifica il tuo indirizzo email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Accedi" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -199,65 +231,32 @@ msgid "Explore" msgstr "Esplora" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Ciao, amante del multimedia! MediaGoblin è..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Il posto perfetto per i tuoi documenti multimediali!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Un posto per collaborare con altri e mostrare le proprie creazioni originali" -" e derivate!" -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Libero, come in libertà. (Siamo un progetto GNU, dopotutto.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" -"Con l'obbiettivo di rendere il mondo un posto migliore attraverso la " -"decentrelizzazione e (finalmente, presto!) federazione!" - -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Fatto per estensibilità. (Numerosi tipi multimediali saranno presto aggiunti" -" al programma, incluso il supporto video!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Eccitato di unirti a noi?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Documenti multimediali più recenti" @@ -265,9 +264,13 @@ msgstr "Documenti multimediali più recenti" msgid "Enter your new password" msgstr "Inserisci la tua nuova password" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Inserisci il tuo nome utente o email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -296,22 +299,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Accesso fallito!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Non hai ancora un account?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Creane uno qui!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Hai dimenticato la password?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Crea un account!" @@ -356,9 +355,15 @@ msgstr "Salva i cambiamenti" msgid "Editing %(username)s's profile" msgstr "Stai modificando il profilo di %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Media taggata con:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -368,16 +373,16 @@ msgstr "Inoltra documento multimediale" msgid "Submit" msgstr "Conferma" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Documenti multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Mi dispiace, utente non trovato" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -408,30 +413,40 @@ msgstr "Nessun documento multimediale in elaborazione" msgid "These uploads failed to process:" msgstr "L'elaborazione di questi upload è fallita:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "profilo di %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Mi dispiace, utente non trovato" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "è necessario verificare email" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Quasi finito! Il tuo account deve ancora essere attivato." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "In breve dovresti ricevere un email contenente istruzioni su come fare." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Nel caso non fosse:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Rispedisci email di verifica" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -439,7 +454,7 @@ msgstr "" "Qualcuno ha registrato un account con questo nome utente, ma deve ancora " "essere attivato." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can accedere e rispedirlo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "profilo di %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Ecco un posto dove raccontare agli altri di te." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Modifica profilo" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Questo utente non ha (ancora) compilato il proprio profilo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Visualizza tutti i file multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -479,11 +489,11 @@ msgstr "" "Questo è dove i tuoi documenti multimediali appariranno, ma sembra che tu " "non abbia ancora aggiunto niente." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Aggiungi documenti multimediali" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Non sembra ci sia ancora nessun documento multimediali qui.." @@ -503,6 +513,14 @@ msgstr "Più nuovo" msgid "Older" msgstr "Più vecchio" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commento" @@ -511,15 +529,23 @@ msgstr "Commento" msgid "I am sure I want to delete this" msgstr "Sono sicuro di volerlo cancellare" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Stai cancellando un documento multimediale di un altro utente. Procedi con " diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 59262d82..f2989e0e 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: ja\n" "Plural-Forms: nplurals=1; plural=0\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "ユーザネーム" @@ -52,7 +56,7 @@ msgid "Sorry, a user with that name already exists." msgstr "申し訳ありませんが、その名前を持つユーザーがすでに存在しています。" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." +msgid "Sorry, a user with that email address already exists." msgstr "" #: mediagoblin/auth/views.py:179 @@ -65,11 +69,19 @@ msgstr "メアドが確認されています。これで、ログインしてプ msgid "The verification key or user id is incorrect" msgstr "検証キーまたはユーザーIDが間違っています" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "検証メールを再送しました。" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -83,41 +95,61 @@ msgstr "タイトル" msgid "Tags" msgstr "タグ" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "スラグ" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "スラグは必要です。" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "自己紹介" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "URL" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "そのスラグを持つエントリは、このユーザーは既に存在します。" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -128,18 +160,18 @@ msgstr "ファイル" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "ファイルを提供する必要があります。" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "ファイルが画像ではないようです!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "投稿終了!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "" @@ -158,29 +190,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "コンテンツを投稿" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "メアドを確認してください!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "ログイン" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -191,57 +223,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -249,8 +256,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -280,22 +291,18 @@ msgstr "" msgid "Logging in failed!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "まだアカウントを持っていませんか?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "ここで作成!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "アカウントを作成!" @@ -340,9 +347,15 @@ msgstr "投稿する" msgid "Editing %(username)s's profile" msgstr "%(username)sさんのプロフィールを編集中" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "タグ付けされたコンテンツ:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -352,16 +365,16 @@ msgstr "コンテンツを投稿" msgid "Submit" msgstr "送信" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "申し訳ありませんが、そのユーザーは見つかりませんでした。" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -392,75 +405,80 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)sさんのプロフィール" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "申し訳ありませんが、そのユーザーは見つかりませんでした。" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "メールは、その方法の指示でいくつかの瞬間に到着します。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "到着しない場合は、" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "確認メールを再送信" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "あなたの確認メールを紛失した場合、ログインして再送できます。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "%(username)sさんのプロフィール" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "プロフィールを編集" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "%(username)sさんのコンテンツをすべて見る" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -480,6 +498,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" @@ -488,15 +514,23 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index 618daf6f..84957014 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Gebruikersnaam" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Sorry, er bestaat al een gebruiker met die naam." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Sorry, dat e-mailadres is al ingenomen." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "De verificatie sleutel of gebruikers-ID is onjuist" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Verificatie e-mail opnieuw opgestuurd." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -85,44 +97,64 @@ msgstr "Titel" msgid "Tags" msgstr "Etiket" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Website" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" "U bent de media van een andere gebruiker aan het aanpassen. Ga voorzichtig " "te werk." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -133,18 +165,18 @@ msgstr "Bestand" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "U moet een bestand aangeven." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Het lijkt erop dat dit bestand geen afbeelding is!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Mooizo! Toegevoegd!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "" @@ -163,29 +195,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Voeg media toe" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Controleer uw e-mail!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Inloggen" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -196,57 +228,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -254,8 +261,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -285,22 +296,18 @@ msgstr "" msgid "Logging in failed!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Heeft u nog geen account?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Maak er hier een!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Maak een account aan!" @@ -342,9 +349,15 @@ msgstr "Wijzigingen opslaan" msgid "Editing %(username)s's profile" msgstr "Het profiel aanpassen van %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Media met het etiket:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -354,16 +367,16 @@ msgstr "Voeg media toe" msgid "Submit" msgstr "Voeg toe" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Media van %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Sorry, die gebruiker kon niet worden gevonden." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -394,37 +407,47 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profiel van %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Sorry, die gebruiker kon niet worden gevonden." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "Een e-mail zou in een paar ogenblikken aan moeten komen met instructies " "hiertoe." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Zoniet:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Stuur de verificatie e-mail opnieuw op." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can inloggen en hem nogmaals verzenden." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profiel van %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Profiel aanpassen." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Bekijk alle media van %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -486,6 +504,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Commentaar" @@ -494,15 +520,23 @@ msgstr "Commentaar" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index c74e1dd0..21cfdda5 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: nn_NO\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Ugyldig fil for mediatypen." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Brukarnamn" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Ein konto med dette brukarnamnet finst allereide." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Den epostadressa er allereide teken." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Send ein ny stadfestingsepost." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -86,42 +98,62 @@ msgstr "Tittel" msgid "Tags" msgstr "Merkelappar" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Nettnamn" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Nettnamnet kan ikkje vera tomt" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "Nettnamnet (adressetittel) for mediefila di. Trengst ikkje endrast." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Presentasjon" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Heimeside" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Eit innlegg med denne adressetittelen finst allereie." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Trå varsamt, du endrar nokon andre sine mediefiler." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Trå varsamt, du endrar nokon andre sin profil." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Ugyldig fil for mediatypen." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -131,18 +163,18 @@ msgstr "Fil" msgid "Description of this work" msgstr "Skildring av mediefila" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Du må velja ei fil." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Fila verkar ikkje å vera ei gyldig biletefil." - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Johoo! Opplasta!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Oops." @@ -163,29 +195,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Bilete av stressa 404-tusse." -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Last opp" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Stadfest epostadressa di" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logg inn" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -198,69 +230,32 @@ msgid "Explore" msgstr "Utforsk" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Hei der mediaentusiast, MediaGoblin..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Er ein perfekt plass for mediet ditt!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Er ein plass for folk å samarbeida og visa fram sjølvlaga og vidarebygde " -"verk." - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" -msgstr "Fri som i fridom (me er eit GNU-prosjekt)." -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Arbeidar for å gjera verda ein betre stad gjennom desentralisering og (til " -"slutt, kjem snart!) federering, enkelt forklart deling og sending av " -"mediefiler og kommentarar over fleire nettstader." - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "Bygd for utviding (fleire medietypar kjem snart, m.a. video)." -#: mediagoblin/templates/mediagoblin/root.html:34 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Driven av folk som deg. (Du kan hjelpa med å forbetra" -" MediaGoblin)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Lyst til å bli med oss?" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Opprett ein " -"gratis konto eller installer MediaGoblin på " -"eigen tenar" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Nyaste mediefiler" @@ -268,9 +263,13 @@ msgstr "Nyaste mediefiler" msgid "Enter your new password" msgstr "Fyll inn passord" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Fyll inn brukarnamn eller epost" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -308,22 +307,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Innlogging feila" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Har du ingen konto?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Lag ein!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Gløymd passordet?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Endra" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Lag ein konto." @@ -368,9 +363,15 @@ msgstr "Lagra" msgid "Editing %(username)s's profile" msgstr "Endrar profilen til %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Merkelappar:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -380,16 +381,16 @@ msgstr "Last opp" msgid "Submit" msgstr "Send" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Fann ingen slik brukar" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -420,35 +421,45 @@ msgstr "Ingen media under handsaming" msgid "These uploads failed to process:" msgstr "Klarte ikkje handsama desse opplasta filene:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s sin profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Fann ingen slik brukar" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Epostverifisering trengst." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Nesten ferdig. Du treng berre aktivera kontoen." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Ein epost med instruksjonar kjem straks." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "I tilfelle det ikkje skjer:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Send ein ny epost" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "Dette brukarnamnet finst allereie, men det er ikkje aktivert." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can logga inn for å få " "tilsendt ny epost med stadfestingslenkje." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "%(username)s sin profil" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Her kan du fortelja om deg sjølv." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Endra profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Brukaren har ikkje fylt ut profilen sin (enno)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Sjå alle %(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "Her kjem mediefilene dine. Ser ikkje ut til at du har lagt til noko." +msgstr "Her kjem mediefilene dine." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Legg til mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Ser ikkje ut til at det finst nokon mediefiler her nett no." @@ -510,6 +516,14 @@ msgstr "Nyare" msgid "Older" msgstr "Eldre" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Innspel" @@ -518,15 +532,23 @@ msgstr "Innspel" msgid "I am sure I want to delete this" msgstr "Eg er sikker eg vil sletta dette" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Du må skriva noko i innspelet." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" +msgstr "Innspel lagt til." + +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Du er i ferd med å sletta ein annan brukar sine mediefiler. Trå varsamt." diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 047e598b..c4f77f8a 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -20,6 +20,10 @@ msgstr "" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Arquivo inválido para esse tipo de mídia" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nome de Usuário" @@ -54,8 +58,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Desculpe, um usuário com este nome já existe." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Desculpe, esse endereço de email já está em uso." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -69,11 +73,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "A chave de verificação ou nome usuário estão incorretos." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "O email de verificação foi reenviado." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -89,43 +101,63 @@ msgstr "Título" msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Arquivo" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "O arquivo não pode estar vazio" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "A parte título da URL dessa mídia. Geralmente não é necessário alterar isso." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Website" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Uma entrada com esse arquivo já existe para esse usuário" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Você está editando a mídia de outro usuário. Tenha cuidado." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Você está editando um perfil de usuário. Tenha cuidado." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Arquivo inválido para esse tipo de mídia" +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -135,18 +167,18 @@ msgstr "Arquivo" msgid "Description of this work" msgstr "Descrição desse trabalho" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Você deve fornecer um arquivo." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "O arquivo não parece ser uma imagem!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Eba! Enviado!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Oops" @@ -167,29 +199,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Imagem do goblin 404 aparecendo" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Enviar mídia" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Verifique seu email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entrar" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -202,71 +234,32 @@ msgid "Explore" msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Olá amante de mídias. MediaGoblin é..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "O lugar perfeito para sua mídia!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Um lugar para as pessoas colaborarem e mostrarem suas criações originais e " -"derivadas!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Livre como a liberdade. (Afinal, somos um projeto GNU)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Com o objetivo de fazer um mundo melhor através da descentralização e " -"(eventualmente, em breve) federação!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Construído para extensibilidade. (Múltiplos tipos de mídia em breve, " -"incluindo suporte a vídeo) " -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Desenvolvido por pessoas como você. (Você pode ajudar a melhorar " -"esse software)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Animado para juntar-se a nós?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -" Crie uma conta grátis \n" -" ou Configure seu próprio servidor MediaGoblin\n" -" " -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Mídia mais recente" @@ -274,9 +267,13 @@ msgstr "Mídia mais recente" msgid "Enter your new password" msgstr "Digite sua nova senha" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Digite seu nome de usuário ou email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -315,22 +312,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Autenticação falhou" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Ainda não tem conta?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Crie uma aqui!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Esqueceu sua senha?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Altere-a" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Criar uma conta!" @@ -375,9 +368,15 @@ msgstr "Salvar mudanças" msgid "Editing %(username)s's profile" msgstr "Editando perfil de %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Mídia marcada como:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -387,16 +386,16 @@ msgstr "Envie sua mídia" msgid "Submit" msgstr "Enviar" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Mídia de %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Desculpe, esse usuário não foi encontrado." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -428,29 +427,39 @@ msgstr "Nenhuma mídia em processo" msgid "These uploads failed to process:" msgstr "Esses envios não foram processados:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Perfil de %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Desculpe, esse usuário não foi encontrado." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Verificação de email necessária" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Quase pronto! Sua conta ainda precisa ser ativada" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Um email deve chegar em instantes com instruções de como fazê-lo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Caso contrário:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Reenviar email de verificação" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -458,7 +467,7 @@ msgstr "" "Alguém registrou uma conta com esse nome de usuário, mas ainda precisa ser " "ativada." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can efetuar login e reenviá-la." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Perfil de %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Aqui é o lugar onde você fala de si para os outros." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Esse usuário não preencheu seu perfil (ainda)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Ver todas as mídias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -498,11 +502,11 @@ msgstr "" "Aqui é onde sua mídia vai aparecer, mas parece que você não adicionou nada " "ainda." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Adicionar mídia" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Aparentemente não há nenhuma mídia aqui ainda..." @@ -522,6 +526,14 @@ msgstr "Mais novo" msgid "Older" msgstr "Mais velho" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Comentário" @@ -530,15 +542,23 @@ msgstr "Comentário" msgid "I am sure I want to delete this" msgstr "Eu tenho certeza de que quero pagar isso" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Você vai apagar uma mídia de outro usuário. Tenha cuidado." diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 01fe5c48..96fd46d8 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 20:49+0000\n" -"Last-Translator: gap \n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,10 @@ msgstr "" "Language: ro\n" "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1))\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Formatul fișierului nu corespunde cu tipul de media selectat." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Nume de utilizator" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Ne pare rău, există deja un utilizator cu același nume." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Ne pare rău, această adresă de e-mail este deja rezervată." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Cheie de verificare sau user ID incorect." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "E-mail-ul de verificare a fost retrimis." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -87,45 +99,65 @@ msgstr "Titlu" msgid "Tags" msgstr "Etichete" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Identificator" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Identificatorul nu poate să lipsească" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "Partea din adresa acestui fișier corespunzătoare titlului. De regulă nu " "trebuie modificată." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografie" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Sit Web" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" "Există deja un entry cu același identificator pentru acest utilizator." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Editezi fișierul unui alt utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Editezi profilul unui utilizator. Se recomandă prudență." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Formatul fișierului nu corespunde cu tipul de media selectat." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -135,18 +167,18 @@ msgstr "Fișier" msgid "Description of this work" msgstr "Descrierea acestui fișier" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Trebuie să selectezi un fișier." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Fișierul nu pare a fi o imagine!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Gata, trimis!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Oops!" @@ -167,29 +199,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Imagine cu elful 404 stresat." -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Transmite un fișier media" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "verifică e-mail-ul!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Autentificare" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -202,70 +234,32 @@ msgid "Explore" msgstr "Explorează" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Bună! MediaGoblin este..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Locul perfect pentru fișierele tale media!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Un loc unde oamenii colaborează și își expun creațiile originale și " -"derivate!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Liber. (Suntem un proiect GNU, până la urmă.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Un pas spre o lume mai bună prin descentralizare și (în curând) " -"federalizare!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Proiectat să fie extensibil. (Software-ul va avea în curând suport pentru " -"mai multe formate de media, inclusiv pentru video!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Animat de oameni ca tine. (Ne poți ajuta să îmbunătățim" -" acest software!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Vrei să ni te alături?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Creează gratuit un cont\n" -" sau\n" -" instalează MediaGoblin pe serverul tău" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Cele mai recente fișiere" @@ -273,9 +267,13 @@ msgstr "Cele mai recente fișiere" msgid "Enter your new password" msgstr "Introdu noua parolă" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Introdu numele de utilizator sau adresa de e-mail" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -313,22 +311,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Autentificare eșuată!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Nu ai un cont?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Creează-l aici!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Ai uitat parola?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Schimb-o!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Creează un cont!" @@ -373,9 +367,15 @@ msgstr "Salvează modificările" msgid "Editing %(username)s's profile" msgstr "Editare profil %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Etichete:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -385,16 +385,16 @@ msgstr "Trimite fișierele tale media" msgid "Submit" msgstr "Trimite" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Ne pare rău, nu am găsit utilizatorul căutat." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -425,29 +425,39 @@ msgstr "Niciun fișier în curs de procesare" msgid "These uploads failed to process:" msgstr "Aceste fișiere nu au putut fi procesate:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profil %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Ne pare rău, nu am găsit utilizatorul căutat." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Este necesară confirmarea adresei de e-mail" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Aproape gata! Mai trebuie doar să activezi contul." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "Vei primi în scurt timp un e-mail cu instrucțiuni." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Dacă nu-l primești:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Retrimite mesajul de verificare" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -455,7 +465,7 @@ msgstr "" "Cineva a înregistrat un cont cu acest nume de utilizator, dar contul nu a " "fost încă activat." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can autentifici pentru a-l retrimite." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profil %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Aici poți spune altora ceva despre tine." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Editare profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Acest utilizator nu și-a completat (încă) profilul." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Vezi toate fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -495,11 +500,11 @@ msgstr "" "Aici vor apărea fișierele tale media, dar se pare că încă nu ai trimis " "nimic." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Trimite fișier" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Nu pare să existe niciun fișier media deocamdată..." @@ -519,6 +524,14 @@ msgstr "Mai noi" msgid "Older" msgstr "Mai vechi" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Scrie un comentariu" @@ -527,15 +540,23 @@ msgstr "Scrie un comentariu" msgid "I am sure I want to delete this" msgstr "Sunt sigur că doresc să șterg" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "Comentariul trebuie să aibă un conținut." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "Comentariul a fost transmis." -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" "Urmează să ștergi fișierele media ale unui alt utilizator. Se recomandă " diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index f4bfbd67..9fb1ce08 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-04 11:13+0000\n" -"Last-Translator: aleksejrs \n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,10 @@ msgstr "" "Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Неправильный формат файла." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Логин" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Извините, пользователь с этим именем уже зарегистрирован." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Извините, этот адрес электронной почты уже занят." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Неверный ключ проверки или идентификатор пользователя" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Переслать сообщение с подтверждением аккаунта." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -88,45 +100,65 @@ msgstr "Название" msgid "Tags" msgstr "Метки" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Отличительная часть адреса" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Отличительная часть адреса необходима" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" "Часть адреса этого файла, производная от его названия. Её обычно не нужно " "изменять." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Биография" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Сайт" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" "У этого пользователя уже есть файл с такой отличительной частью адреса." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Вы редактируете файлы другого пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Вы редактируете профиль пользователя. Будьте осторожны." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Неправильный формат файла." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -136,18 +168,18 @@ msgstr "Файл" msgid "Description of this work" msgstr "Описание этого произведения" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Вы должны загрузить файл." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Файл, похоже, не является картинкой!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Ура! Файл загружен!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Ой!" @@ -160,35 +192,35 @@ msgstr "Кажется, такой страницы не существует. msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." -msgstr "Возможно, страница которую вы ищете была удалена или переехала." +msgstr "Возможно, страница, которую вы ищете, была удалена или переехала." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" msgstr "Изображение 404 нервничающего гоблина" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Символ MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Загрузить файл" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "подтвердите ваш адрес электронной почты!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Войти" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -201,66 +233,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Привет, любитель мультимедиа! MediaGoblin…" - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Отличное место для ваших файлов!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Место для того, чтобы совместно работать или просто показать свои " -"оригинальные и/или заимствованные создания!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" -msgstr "Свободное ПО. (Мы же проект GNU.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" -"Попытка сделать мир лучше с помощью децентрализации и (надеемся, что скоро!)" -" интеграции!" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Рассчитан на расширяемость. (В программе скоро должна появиться поддержка " -"других видов мультимедиа, таких как видео!)" -#: mediagoblin/templates/mediagoblin/root.html:34 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Поддерживается такими же, как и ты. (Ты можешь помочь сделать это" -" ПО лучше!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Самые новые файлы" @@ -268,18 +266,24 @@ msgstr "Самые новые файлы" msgid "Enter your new password" msgstr "Введите свой новый пароль" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Введите Ваше имя пользователя или адрес электронной почты" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." -msgstr "" +msgstr "Ваш пароль изменён. Теперь попробуйте представиться." #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" "Check your inbox. We sent an email with a URL for changing your password." msgstr "" +"Проверьте свой электронный почтовый ящик. Мы отправили сообщение с адресом " +"для изменения Вашего пароля." #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -294,27 +298,32 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Привет, %(username)s,\n" +"\n" +"чтобы сменить свой пароль от GNU MediaGoblin, откройте\n" +"следующий URL вашим веб‐браузером:\n" +"\n" +"%(verification_url)s\n" +"\n" +"Если вы думаете, что это какая‐то ошибка, то игнорируйте\n" +"это сообщение и продолжайте быть счастливым гоблином!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" msgstr "Авторизация неуспешна!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Ещё нету аккаунта?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Создайте здесь!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Забыли свой пароль?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Смените его!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Создать аккаунт!" @@ -359,9 +368,15 @@ msgstr "Сохранить изменения" msgid "Editing %(username)s's profile" msgstr "Редактирование профиля %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Файлы с меткой:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -371,16 +386,16 @@ msgstr "Загрузить файл(ы)" msgid "Submit" msgstr "Подтвердить" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Файлы пользователя %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Извините, но такой пользователь не найден." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -412,38 +427,48 @@ msgstr "Нету файлов для обработки" msgid "These uploads failed to process:" msgstr "Обработка этих файлов вызвала ошибку:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Профиль пользователя %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Извините, но такой пользователь не найден." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Нужно подтверждение почтового адреса" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Почти закончили! Теперь надо активировать ваш аккаунт." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "Через пару мгновений на адрес вашей электронной почты должно прийти " "сообщение с дальнейшими инструкциями." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "А если нет, то:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "" "Повторно отправить сообщение для подверждения адреса электронной почты" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "Кто‐то создал аккаунт с этим именем, но его еще надо активировать." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can войти и отправить его повторно." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Профиль пользователя %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Здесь вы можете рассказать о себе." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Редактировать профиль" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Это пользователь не заполнил свой профайл (пока)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Смотреть все файлы %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Ваши файлы появятся здесь, когда вы их добавите." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Добавить файлы" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Пока что тут файлов нет…" @@ -505,6 +525,14 @@ msgstr "Более новые" msgid "Older" msgstr "Более старые" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Комментарий" @@ -513,15 +541,23 @@ msgstr "Комментарий" msgid "I am sure I want to delete this" msgstr "Я уверен, что хочу удалить это" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "Empty comments are not allowed." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" +msgstr "Комментарий размещён!" + +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Вы на пороге удаления файла другого пользователя. Будьте осторожны." diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index d3196b9c..bee7b3b5 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: sk\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Odovzdaný nesprávny súbor pre daný typ média." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Prihlasovacie meno" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Prepáč, rovnaké prihlasovacie meno už niekto používa." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Prepáč, daná e-mailová adresa už bola pri registrácii využitá." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Nesprávny overovací kľúč alebo používateľské ID" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Opätovne zaslať overovaciu správu." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -87,42 +99,62 @@ msgstr "Nadpis" msgid "Tags" msgstr "Štítky" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Unikátna časť adresy" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Unikátna časť adresy musí byť vyplnená" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "Titulná časť URL odkazu média. Zvyčajne to meniť nemusíš." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Webstránka" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Položku s rovnakou unikátnou časťou adresy už niekde máš." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Upravuješ médiá niekoho iného. Pristupuj opatrne." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Upravuješ používateľský profil. Pristupuj opatrne." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Odovzdaný nesprávny súbor pre daný typ média." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -132,18 +164,18 @@ msgstr "Súbor" msgid "Description of this work" msgstr "Charakteristika diela" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Poskytni súbor." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Súbor najskôr nie je obrázkom!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Juchú! Úspešne vložené!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Ajaj!" @@ -164,29 +196,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Obrázok stresujúceho goblina pri chybovom kóde č. 404" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Vložiť výtvor" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "over si svoj e-mail!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prihlásenie" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -199,71 +231,32 @@ msgid "Explore" msgstr "Preskúmať" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Vitaj medzi nami, kreatívne stvorenie! MediaGoblin je..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Parádne miesto pre tvoje výtvory!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "" -"Miesto pre ľudí, vhodné na spoluprácu a vystavovanie tak originálnych, ako " -"aj odvodených kreácií!" - -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Voľné, vo význame slobody. (Koniec-koncov, sme predsa GNU projekt.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Zo snahou spraviť svet lepším miestom vďaka decentralizácii a (eventuálne, " -"už čoskoro!) federácii!" -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"S dôrazom na rozšíriteľnosť. (Podpora pre rozličné typy médií v tomto " -"softvéri už čoskoro, nevynímajúc videá!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Existujeme aj vďaka ľudom ako si ty. (Môžeš nám pomôcť softvér " -"vylepšiť!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Tak čo, chceš sa pridať?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Vytvoriť bezplatný účet\n" -" alebo\n" -" Sprevádzkovať MediaGoblin na vlastnom serveri" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Najčerstvejšie výtvory" @@ -271,9 +264,13 @@ msgstr "Najčerstvejšie výtvory" msgid "Enter your new password" msgstr "Vlož svoje nové heslo" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Vlož svoje používateľské meno alebo e-mailovú adresu" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -312,22 +309,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Prihlásenie zlyhalo!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Ešte nemáš účet?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Vytvoriť jeden tu!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Zabudnuté heslo?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Zmeniť ho!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Vytvoriť účet!" @@ -373,9 +366,15 @@ msgstr "Uložiť zmeny" msgid "Editing %(username)s's profile" msgstr "Úprava profilu, ktorý vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Výtvor značený štítkami:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -385,16 +384,16 @@ msgstr "Vlož svoj výtvor" msgid "Submit" msgstr "Vložiť" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Prepáč, používateľské meno nenájdené." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -425,29 +424,39 @@ msgstr "Žiadne médiá v procese spracovania" msgid "These uploads failed to process:" msgstr "Nasledovné vloženia neprešli spracovaním:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profil, ktorý vlastní %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Prepáč, používateľské meno nenájdené." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Potrebné overenie e-mailovej adresy" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Takmer hotovo! Ešte ti musí byť aktivovaný účet." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "E-mailová správa s popisom ako to spraviť, by mala onedlho doraziť." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "V prípade, že sa tak nestalo:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Opätovne zaslať overovaciu správu" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -455,7 +464,7 @@ msgstr "" "Účet s týmto prihlasovacím menom je už registrovaný, avšak ešte stále " "neaktívny." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can prihlásiť a preposlať si ju." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profil, ktorý vlastní %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Povedz tu o sebe ostatným." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Upraviť profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Dotyčná osoba ešte nevyplnila svoj profil (zatiaľ)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Zhliadnuť všetky výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Všetky tvoje výtvory sa objavia práve tu, ale zatiaľ nemáš nič pridané." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Pridať výtvor" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Najskôr tu ešte nebudú žiadne výtvory..." @@ -518,6 +522,14 @@ msgstr "Novšie" msgid "Older" msgstr "Staršie" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Komentár" @@ -526,15 +538,23 @@ msgstr "Komentár" msgid "I am sure I want to delete this" msgstr "Jednoznačne to chcem odstrániť" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." -msgstr "" +msgstr "Komentáre bez obsahu nepovolené." -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" +msgstr "Komentár odoslaný!" + +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Chystáš sa odstrániť výtvory niekoho iného. Pristupuj opatrne." diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index cba4fdd0..77273ebe 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,6 +19,10 @@ msgstr "" "Language: sl\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Za vrsto vsebine je bila podana napačna datoteka." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Uporabniško ime" @@ -52,8 +56,8 @@ msgid "Sorry, a user with that name already exists." msgstr "Oprostite, uporabnik s tem imenom že obstaja." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Oprostite, ta e-poštni naslov je že v uporabi." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -67,11 +71,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Potrditveni ključ ali uporabniška identifikacija je napačna" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Ponovno pošiljanje potrditvene e-pošte." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -85,42 +97,62 @@ msgstr "Naslov" msgid "Tags" msgstr "Oznake" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Oznaka" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Oznaka ne sme biti prazna" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Biografija" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Spletna stran" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Vnos s to oznako za tega uporabnika že obstaja." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Za vrsto vsebine je bila podana napačna datoteka." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -130,18 +162,18 @@ msgstr "Datoteka" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Podati morate datoteko." -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Kot kaže datoteka ni slika." - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Juhej! Poslano." +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Opa!" @@ -162,29 +194,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Slika napake 404 s paničnim škratom" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "Logotip MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Pošlji vsebino" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Preverite svojo e-pošto." +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prijava" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -195,66 +227,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Pozdravljen, ljubitelj večpredstavnostnih vsebin! MediaGoblin je ..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Popolno mesto za vaše večpredstavnostne vsebine." - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Mesto, kjer ljudje lahko sodelujejo in razkazujejo originalne in predelane " -"stvaritve." -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" -"Ustvarjen z namenom izboljšati svet, s pomočjo decentralizacije in (kmalu) " -"federacije." - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" -"Zgrajen za razširjanje. (Kmalu bodo na voljo dodatne vrste vsebin, vključno " -"podpora za video)" - -#: mediagoblin/templates/mediagoblin/root.html:34 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Sad dela ljudi, kot ste vi. (Pri izboljševanju nam lahko " -"pomagate tudi vi.)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -262,8 +260,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -293,22 +295,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Prijava ni uspela." -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Še nimate računa?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Ustvarite si ga." -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Ustvarite račun." @@ -354,9 +352,15 @@ msgstr "Shrani spremembe" msgid "Editing %(username)s's profile" msgstr "Urejanje profila – %(username)s" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Vsebina označena z:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -366,16 +370,16 @@ msgstr "Pošljite svojo vsebino" msgid "Submit" msgstr "Pošlji" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Oprostite, tega uporabnika ni bilo moč najti." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -406,29 +410,39 @@ msgstr "V obdelavi ni nobene vsebine" msgid "These uploads failed to process:" msgstr "Teh vsebin ni bilo moč obdelati:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "Profil – %(username)s" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Oprostite, tega uporabnika ni bilo moč najti." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "Potrebna je potrditev prek e-pošte" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Skoraj ste zaključili. Svoj račun morate le še aktivirati." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "V kratkem bi morali prejeti e-pošto z navodili, kako to storiti." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Če je ne prejmete:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Ponovno pošlji potrditveno e-pošto" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -436,7 +450,7 @@ msgstr "" "Nekdo je s tem uporabniškim imenom že registriral račun, vendar mora biti še" " aktiviran." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can prijavite in jo ponovno pošljete." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "Profil – %(username)s" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Na tem mestu lahko drugim poveste nekaj o sebi." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Uredi profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Ta uporabnik še ni izpolnil svojega profila." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Prikaži vso vsebino uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Tu bo prikazana vaša vsebina, a trenutno še niste dodali nič." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Dodaj vsebino" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Videti je, da tu še ni nobene vsebine ..." @@ -498,6 +507,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Komentar" @@ -506,15 +523,23 @@ msgstr "Komentar" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index b4b2fb7b..0bdfc21c 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -18,6 +18,10 @@ msgstr "" "Language: sr\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "" @@ -51,7 +55,7 @@ msgid "Sorry, a user with that name already exists." msgstr "" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." +msgid "Sorry, a user with that email address already exists." msgstr "" #: mediagoblin/auth/views.py:179 @@ -64,11 +68,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -82,41 +94,61 @@ msgstr "" msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -127,16 +159,16 @@ msgstr "" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" +#: mediagoblin/submit/views.py:127 +msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:121 -msgid "Woohoo! Submitted!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." msgstr "" #: mediagoblin/templates/mediagoblin/404.html:21 @@ -157,29 +189,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -190,57 +222,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -248,8 +255,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -279,22 +290,18 @@ msgstr "" msgid "Logging in failed!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "" @@ -334,8 +341,14 @@ msgstr "" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 @@ -346,14 +359,14 @@ msgstr "" msgid "Submit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format -msgid "%(username)s's media" +msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 +#, python-format +msgid "%(username)s's media" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -386,75 +399,80 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -474,6 +492,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "" @@ -482,15 +508,23 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index 3ee44b18..37bd36c1 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -20,6 +20,10 @@ msgstr "" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "Ogiltig fil för mediatypen." + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "Användarnamn" @@ -53,8 +57,8 @@ msgid "Sorry, a user with that name already exists." msgstr "En användare med det användarnamnet finns redan." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "Den e-postadressen är redan tagen." +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -68,11 +72,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "Verifieringsnyckeln eller användar-IDt är fel." -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "Skickade ett nytt verifierings-email." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -88,42 +100,62 @@ msgstr "Titel" msgid "Tags" msgstr "Taggar" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "Sökvägsnamn" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "Sökvägsnamnet kan inte vara tomt" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "Sökvägstitlen för din media. Du brukar inte behöva ändra denna." -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "Presentation" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "Hemsida" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "Ett inlägg med det sökvägsnamnet existerar redan." -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "Var försiktig, du redigerar någon annans inlägg." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "Ogiltig fil för mediatypen." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -133,18 +165,18 @@ msgstr "Fil" msgid "Description of this work" msgstr "Beskrivning av verket" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "Du måste ange en fil" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "Filen verkar inte vara en giltig bildfil!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "Tjohoo! Upladdat!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "Ojoj!" @@ -165,29 +197,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "Bild av stressat 404-troll." -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin-logotyp" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "Ladda upp" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "Verifiera din e-postadress!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logga in" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -200,75 +232,32 @@ msgid "Explore" msgstr "Utforska" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "Hej där mediaentusiast, MediaGoblin..." - -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "Är ett perfekt ställe för din media!" - -#: mediagoblin/templates/mediagoblin/root.html:30 -msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -"Är ett ställe för människor att samarbeta och visa upp originella och " -"härrörande verk." -#: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -"Är fritt som i frihet. (Vi är ju ett GNU-projekt.)" -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" -"Arbetar för att göra världen till ett bättre ställe genom decentralisering " -"och (så småningom, kommer snart!) -- Google Translate säger " -"\"sammanslutning\", en: federation" -" " - -#: mediagoblin/templates/mediagoblin/root.html:33 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" -"Byggd för utbyggbarhet. (Flera mediatyper kommer snart till MediaGoblin, " -"bland annat video!)" -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +#: mediagoblin/templates/mediagoblin/root.html:31 +msgid "Don't have one yet? It's easy!" msgstr "" -"Drivs av människor som du. (Du kan hjälpa os forbättra " -"MediaGoblin!)" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "Nyfiken att gå med oss?" -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"Skapa ett konto gratis\n" -"\n" -" or\n" -" Installera MediaGoblin på din egen server" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "Senast medier" @@ -276,9 +265,13 @@ msgstr "Senast medier" msgid "Enter your new password" msgstr "Fyll i ditt lösenord" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "Fyll i ditt användarnamn eller lösenord" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -317,22 +310,18 @@ msgstr "" msgid "Logging in failed!" msgstr "Inloggning misslyckades!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "Har du inget konto än?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "Skapa ett här!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Glömt ditt lösenord?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "Ändra!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "Skapa ett konto!" @@ -377,9 +366,15 @@ msgstr "Spara ändringar" msgid "Editing %(username)s's profile" msgstr "Redigerar %(username)ss profil" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "Media taggat med:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -389,16 +384,16 @@ msgstr "Ladda upp" msgid "Submit" msgstr "Skicka" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)ss media" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "Ledsen, hittar ingen sådan användare." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -429,30 +424,40 @@ msgstr "Ingen media under behandling" msgid "These uploads failed to process:" msgstr "De här behandlingarna misslyckades:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)ss profil" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "Ledsen, hittar ingen sådan användare." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "E-postadressverifiering krävs." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "Nästan klar! Ditt konto behöver bara aktiveras." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" "Ett e-postmeddelande med instruktioner kommer att hamna hos dig inom kort." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "Om det inte skulle göra det:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "Skicka ett nytt e-postmeddelande" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." @@ -460,7 +465,7 @@ msgstr "" "Någon har redan registrerat ett konto med det här användarnamnet men det har" " inte aktiverats." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can logga in och begära ett nytt." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "%(username)ss profil" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "Här kan du berätta för andra om dig själv." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "Redigera profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "Den här användaren har inte fyllt i sin profilsida ännu." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "Se all media från %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -501,11 +501,11 @@ msgstr "" "Här kommer din media att dyka upp, du verkar inte ha lagt till någonting " "ännu." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "Lägg till media" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "Det verkar inte finnas någon media här ännu." @@ -525,6 +525,14 @@ msgstr "Nyare" msgid "Older" msgstr "Äldre" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "Kommentar" @@ -533,15 +541,23 @@ msgstr "Kommentar" msgid "I am sure I want to delete this" msgstr "Jag är säker på att jag vill radera detta" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Du tänker radera en annan användares media. Var försiktig." diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po index 289bddb5..064fa7d1 100644 --- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-03 14:08+0000\n" -"Last-Translator: veeven \n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,10 @@ msgstr "" "Language: te\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "వాడుకరి పేరు" @@ -52,7 +56,7 @@ msgid "Sorry, a user with that name already exists." msgstr "" #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." +msgid "Sorry, a user with that email address already exists." msgstr "" #: mediagoblin/auth/views.py:179 @@ -65,11 +69,19 @@ msgstr "" msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -83,41 +95,61 @@ msgstr "శీర్షిక" msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" msgstr "" #: mediagoblin/submit/forms.py:25 @@ -128,16 +160,16 @@ msgstr "" msgid "Description of this work" msgstr "" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" +#: mediagoblin/submit/views.py:127 +msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:121 -msgid "Woohoo! Submitted!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." msgstr "" #: mediagoblin/templates/mediagoblin/404.html:21 @@ -158,29 +190,29 @@ msgstr "" msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -191,57 +223,32 @@ msgid "Explore" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." +msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" +msgid "Don't have one yet? It's easy!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "" - -#: mediagoblin/templates/mediagoblin/root.html:39 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "" @@ -249,8 +256,12 @@ msgstr "" msgid "Enter your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 @@ -280,22 +291,18 @@ msgstr "" msgid "Logging in failed!" msgstr "ప్రవేశం విఫలమయ్యింది!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "మీకు ఇంకా ఖాతా లేదా?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "మీ సంకేతపదాన్ని మర్చిపోయారా?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "" @@ -335,8 +342,14 @@ msgstr "మార్పులను భద్రపరచు" msgid "Editing %(username)s's profile" msgstr "" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 @@ -347,14 +360,14 @@ msgstr "" msgid "Submit" msgstr "దాఖలు చెయ్యి" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format -msgid "%(username)s's media" +msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 +#, python-format +msgid "%(username)s's media" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -387,75 +400,80 @@ msgstr "" msgid "These uploads failed to process:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -475,6 +493,14 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "వ్యాఖ్య" @@ -483,15 +509,23 @@ msgstr "వ్యాఖ్య" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." msgstr "" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." +msgstr "" + +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index c664adbe..5e406b41 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-01 23:14-0500\n" -"PO-Revision-Date: 2011-11-02 04:13+0000\n" +"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"PO-Revision-Date: 2011-11-27 21:28+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -20,6 +20,10 @@ msgstr "" "Language: zh_TW\n" "Plural-Forms: nplurals=1; plural=0\n" +#: mediagoblin/processing.py:143 +msgid "Invalid file given for media type." +msgstr "指定錯誤的媒體類別!" + #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" msgstr "使用者名稱" @@ -53,8 +57,8 @@ msgid "Sorry, a user with that name already exists." msgstr "抱歉, 這個使用者名稱已經存在." #: mediagoblin/auth/views.py:77 -msgid "Sorry, that email address has already been taken." -msgstr "抱歉,這個電子郵件已經被其他人使用了。" +msgid "Sorry, a user with that email address already exists." +msgstr "" #: mediagoblin/auth/views.py:179 msgid "" @@ -66,11 +70,19 @@ msgstr "你的電子郵件位址已被認證. 你現在就可以登入, 編輯 msgid "The verification key or user id is incorrect" msgstr "認證碼或是使用者帳號錯誤" -#: mediagoblin/auth/views.py:207 +#: mediagoblin/auth/views.py:203 +msgid "You must be logged in so we know who to send the email to!" +msgstr "" + +#: mediagoblin/auth/views.py:211 +msgid "You've already verified your email address!" +msgstr "" + +#: mediagoblin/auth/views.py:224 msgid "Resent your verification email." msgstr "重送認證信." -#: mediagoblin/auth/views.py:248 +#: mediagoblin/auth/views.py:265 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -84,42 +96,62 @@ msgstr "標題" msgid "Tags" msgstr "標籤" -#: mediagoblin/edit/forms.py:31 +#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 +msgid "Seperate tags by commas or spaces." +msgstr "" + +#: mediagoblin/edit/forms.py:33 msgid "Slug" msgstr "自訂字串" -#: mediagoblin/edit/forms.py:32 +#: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" msgstr "自訂字串不能空白" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "此媒體網址的名稱。你通常不需要變動這個的。" -#: mediagoblin/edit/forms.py:40 +#: mediagoblin/edit/forms.py:42 msgid "Bio" msgstr "自我介紹" -#: mediagoblin/edit/forms.py:43 +#: mediagoblin/edit/forms.py:45 msgid "Website" msgstr "網站" -#: mediagoblin/edit/views.py:64 +#: mediagoblin/edit/forms.py:49 +msgid "Old password" +msgstr "" + +#: mediagoblin/edit/forms.py:52 +msgid "New Password" +msgstr "" + +#: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." msgstr "這個自訂字串已經被其他人用了" -#: mediagoblin/edit/views.py:85 +#: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:155 +#: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." msgstr "你正在編輯一位用戶的檔案. 請謹慎處理." -#: mediagoblin/process_media/errors.py:44 -msgid "Invalid file given for media type." -msgstr "指定錯誤的媒體類別!" +#: mediagoblin/edit/views.py:171 +msgid "Wrong password" +msgstr "" + +#: mediagoblin/edit/views.py:192 +msgid "Profile edited!" +msgstr "" + +#: mediagoblin/media_types/__init__.py:61 +msgid "Could not find any file extension in \"{filename}\"" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -129,18 +161,18 @@ msgstr "檔案" msgid "Description of this work" msgstr "這個作品的描述" -#: mediagoblin/submit/views.py:46 +#: mediagoblin/submit/views.py:49 msgid "You must provide a file." msgstr "你必須提供一個檔案" -#: mediagoblin/submit/views.py:49 -msgid "The file doesn't seem to be an image!" -msgstr "檔案似乎不是一個圖片喔!" - -#: mediagoblin/submit/views.py:121 +#: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" msgstr "呼呼! 送出去嚕!" +#: mediagoblin/submit/views.py:133 +msgid "Invalid file type." +msgstr "" + #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" msgstr "糟糕!" @@ -159,29 +191,29 @@ msgstr "如果你確定這個位址是正確的,或許你在找的網頁已經 msgid "Image of 404 goblin stressing out" msgstr "Image of 404 goblin stressing out" -#: mediagoblin/templates/mediagoblin/base.html:22 -msgid "GNU MediaGoblin" -msgstr "GNU MediaGoblin" - -#: mediagoblin/templates/mediagoblin/base.html:47 +#: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" msgstr "MediaGoblin 標誌" -#: mediagoblin/templates/mediagoblin/base.html:52 +#: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" msgstr "遞交媒體" -#: mediagoblin/templates/mediagoblin/base.html:63 -msgid "verify your email!" -msgstr "確認您的電子郵件!" +#: mediagoblin/templates/mediagoblin/base.html:65 +msgid "Verify your email!" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:73 +#: mediagoblin/templates/mediagoblin/base.html:72 +msgid "log out" +msgstr "" + +#: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 -#: mediagoblin/templates/mediagoblin/auth/login.html:35 +#: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "登入" -#: mediagoblin/templates/mediagoblin/base.html:89 +#: mediagoblin/templates/mediagoblin/base.html:91 msgid "" "Powered by MediaGoblin, a GNU project" @@ -194,62 +226,32 @@ msgid "Explore" msgstr "探索" #: mediagoblin/templates/mediagoblin/root.html:27 -msgid "Hi there, media lover! MediaGoblin is..." -msgstr "嗨!多媒體檔案愛好者!MediaGoblin是..." +msgid "Hi there, welcome to this MediaGoblin site!" +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:29 -msgid "The perfect place for your media!" -msgstr "你的媒體檔案的最佳所在!" +#: mediagoblin/templates/mediagoblin/root.html:28 +msgid "Your finest source for all goblin-related media." +msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:30 +#: mediagoblin/templates/mediagoblin/root.html:29 msgid "" -"A place for people to collaborate and show off original and derived " -"creations!" -msgstr "這是一個可以讓人們共同展示他們的創作、衍生作品的地方!" +"To add your own media, place comments, save your favourites and more, you " +"can log in with your MediaGoblin account." +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 -msgid "" -"Free, as in freedom. (We’re a GNU project, " -"after all.)" -msgstr "免費但是我們更重視自由 (畢竟我們是個 GNU 專案)" - -#: mediagoblin/templates/mediagoblin/root.html:32 -msgid "" -"Aiming to make the world a better place through decentralization and " -"(eventually, coming soon!) federation!" -msgstr "目的是要透過分散式且自由的方式讓這個世界更美好!(總有一天,它很快會到來的!)" - -#: mediagoblin/templates/mediagoblin/root.html:33 -msgid "" -"Built for extensibility. (Multiple media types coming soon to the software," -" including video support!)" -msgstr "天生的擴充性。(軟體將支援多種多媒體格式, 也支援影音檔案!)" - -#: mediagoblin/templates/mediagoblin/root.html:34 -msgid "" -"Powered by people like you. (You can help us improve this" -" software!)" +msgid "Don't have one yet? It's easy!" msgstr "" -"由像你一樣的人們製作 (你可以幫我們改進軟體!)" -#: mediagoblin/templates/mediagoblin/root.html:38 -msgid "Excited to join us?" -msgstr "迫不亟待想要加入我們?" - -#: mediagoblin/templates/mediagoblin/root.html:39 +#: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" -"Create a free account\n" +"Create an account at this site\n" " or\n" -" Set up MediaGoblin on your own server" +" Set up MediaGoblin on your own server" msgstr "" -"建立一個免費帳號\n" -" 或是\n" -" 在你的伺服器上設立 MediaGoblin" -#: mediagoblin/templates/mediagoblin/root.html:53 +#: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" msgstr "最新的媒體" @@ -257,9 +259,13 @@ msgstr "最新的媒體" msgid "Enter your new password" msgstr "輸入你的新密碼" -#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29 -msgid "Enter your username or email" -msgstr "輸入你的帳號或是電子郵件" +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 +msgid "Recover password" +msgstr "" + +#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 +msgid "Send instructions" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -295,22 +301,18 @@ msgstr "" msgid "Logging in failed!" msgstr "登入失敗!" -#: mediagoblin/templates/mediagoblin/auth/login.html:43 +#: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" msgstr "還沒有帳號嗎?" -#: mediagoblin/templates/mediagoblin/auth/login.html:46 +#: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" msgstr "在這裡建立一個吧!" -#: mediagoblin/templates/mediagoblin/auth/login.html:49 +#: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "忘了密碼嗎?" -#: mediagoblin/templates/mediagoblin/auth/login.html:52 -msgid "Change it!" -msgstr "變更!" - #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" msgstr "建立一個帳號!" @@ -355,9 +357,15 @@ msgstr "儲存變更" msgid "Editing %(username)s's profile" msgstr "編輯 %(username)s'的檔案中" -#: mediagoblin/templates/mediagoblin/listings/tag.html:31 -msgid "Media tagged with:" -msgstr "媒體檔案被標籤為:" +#: mediagoblin/templates/mediagoblin/listings/tag.html:30 +#: mediagoblin/templates/mediagoblin/listings/tag.html:35 +#, python-format +msgid "Media tagged with: %(tag_name)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +msgid "Original" +msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -367,16 +375,16 @@ msgstr "遞交你的媒體檔案" msgid "Submit" msgstr "送出" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32 +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 +#, python-format +msgid "%(username)s's media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)s的媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:32 -msgid "Sorry, no such user found." -msgstr "抱歉,找不到這個使用者." - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -407,75 +415,80 @@ msgstr "沒有正在處理中的媒體" msgid "These uploads failed to process:" msgstr "無法處理這些更新" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:39 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:59 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:31 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:89 +#, python-format +msgid "%(username)s's profile" +msgstr "%(username)s的個人檔案" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:43 +msgid "Sorry, no such user found." +msgstr "抱歉,找不到這個使用者." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:50 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" msgstr "需要認證電子郵件" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:42 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." msgstr "幾乎完成了!但你的帳號仍然需要被啟用。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:47 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." msgstr "馬上會有一封電子郵件告訴你如何做." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" msgstr "假設它無法:" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:54 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" msgstr "重送認證信" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:62 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "有人用了這個帳號登錄了,但是這個帳號仍需要被啟用。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "如果你就是那個人, 但是遺失了認證信, 你可以登入 然後重送一次." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:78 -#, python-format -msgid "%(username)s's profile" -msgstr "%(username)s的個人檔案" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:85 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." msgstr "這是一個地方,能讓你向他人介紹自己。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:90 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:108 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:101 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 msgid "Edit profile" msgstr "編輯個人檔案" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:96 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." msgstr "這個使用者還沒(來得及)填寫個人檔案。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:122 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format msgid "View all of %(username)s's media" msgstr "查看%(username)s的全部媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:135 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "這個地方是你的媒體檔案會出現的地方,但是你似乎還沒有加入任何東西。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" msgstr "新增媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:147 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." msgstr "似乎還沒有任何的媒體檔案..." @@ -495,6 +508,14 @@ msgstr "新一點" msgid "Older" msgstr "舊一點" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "Tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "and" +msgstr "" + #: mediagoblin/user_pages/forms.py:24 msgid "Comment" msgstr "評論" @@ -503,15 +524,23 @@ msgstr "評論" msgid "I am sure I want to delete this" msgstr "我確定我想要刪除" -#: mediagoblin/user_pages/views.py:142 +#: mediagoblin/user_pages/views.py:155 msgid "Empty comments are not allowed." -msgstr "" +msgstr "評論不能空白。" -#: mediagoblin/user_pages/views.py:148 +#: mediagoblin/user_pages/views.py:161 msgid "Comment posted!" +msgstr "評論已經張貼!" + +#: mediagoblin/user_pages/views.py:183 +msgid "You deleted the media." +msgstr "" + +#: mediagoblin/user_pages/views.py:190 +msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:181 +#: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "你在刪除其他人的媒體檔案。請小心處理喔。" -- cgit v1.2.3 From a3663b407997cb8e2d45086641b7eb9f4efd476c Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 28 Nov 2011 09:45:15 +0100 Subject: Mark two strings for translation 1. "Go to page:" in pagination 2. "Submit" in the forget password form --- mediagoblin/templates/mediagoblin/auth/change_fp.html | 2 +- mediagoblin/templates/mediagoblin/utils/pagination.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index fa972085..5677949c 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -30,7 +30,7 @@ {{ wtforms_util.render_divs(cp_form) }}
- +
diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 84336103..3c12f93c 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -47,7 +47,7 @@ Next page {% endif %}
- Go to page: + {% trans %}Go to page:{% endtrans %} {%- for page in pagination.iter_pages() %} {% if page %} {% if page != pagination.page %} -- cgit v1.2.3 From 813be2938ae8036573b04cd6ab7beac06efe8f16 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 1 Dec 2011 15:21:15 -0600 Subject: Don't barf on templates that use the autoescaping extension --- babel.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/babel.ini b/babel.ini index a4e3267a..1a8231f5 100644 --- a/babel.ini +++ b/babel.ini @@ -4,9 +4,12 @@ [jinja2: mediagoblin/templates/**.html] # Extract jinja templates (html) encoding = utf-8 +extensions = jinja2.ext.autoescape + [jinja2: mediagoblin/templates/**.txt] # Extract jinja templates (text) encoding = utf-8 +extensions = jinja2.ext.autoescape # # Extraction from JavaScript files # [javascript: mediagoblin/static/js/**.js] -- cgit v1.2.3 From 9754802d4bca036b8fb0b50db948dd2eb8f64bd6 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 1 Dec 2011 23:33:47 +0100 Subject: fixture_add_user: Factoring a unit test tool Some unit tests need a user in the database, especially to act as that user. Some routines did that on their own. So factored this whole thing into a new function and use it around. --- mediagoblin/tests/test_auth.py | 8 ++------ mediagoblin/tests/test_edit.py | 21 ++++----------------- mediagoblin/tests/test_submission.py | 12 +++--------- mediagoblin/tests/tools.py | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 153c6e53..acef3d26 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -20,7 +20,7 @@ import datetime from nose.tools import assert_equal from mediagoblin.auth import lib as auth_lib -from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin.tests.tools import setup_fresh_app, fixture_add_user from mediagoblin import mg_globals from mediagoblin.tools import template, mail @@ -332,11 +332,7 @@ def test_authentication_views(test_app): Test logging in and logging out """ # Make a new user - test_user = mg_globals.database.User() - test_user['username'] = u'chris' - test_user['email'] = u'chris@example.com' - test_user['pw_hash'] = auth_lib.bcrypt_gen_password_hash('toast') - test_user.save() + test_user = fixture_add_user(active_user=False) # Get login # --------- diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index 3637b046..c29ddfe9 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -15,23 +15,16 @@ # along with this program. If not, see . from mediagoblin import mg_globals -from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin.tests.tools import setup_fresh_app, fixture_add_user from mediagoblin.tools import template -from mediagoblin.auth.lib import bcrypt_check_password, \ - bcrypt_gen_password_hash +from mediagoblin.auth.lib import bcrypt_check_password @setup_fresh_app def test_change_password(test_app): """Test changing password correctly and incorrectly""" # set up new user - test_user = mg_globals.database.User() - test_user['username'] = u'chris' - test_user['email'] = u'chris@example.com' - test_user['email_verified'] = True - test_user['status'] = u'active' - test_user['pw_hash'] = bcrypt_gen_password_hash('toast') - test_user.save() + test_user = fixture_add_user() test_app.post( '/auth/login/', { @@ -73,13 +66,7 @@ def test_change_password(test_app): def change_bio_url(test_app): """Test changing bio and URL""" # set up new user - test_user = mg_globals.database.User() - test_user['username'] = u'chris' - test_user['email'] = u'chris@example.com' - test_user['email_verified'] = True - test_user['status'] = u'active' - test_user['pw_hash'] = bcrypt_gen_password_hash('toast') - test_user.save() + test_user = fixture_add_user() # test changing the bio and the URL properly test_app.post( diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index eea5747f..7ea6c4bc 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -19,8 +19,8 @@ import pkg_resources from nose.tools import assert_equal, assert_true, assert_false -from mediagoblin.auth import lib as auth_lib -from mediagoblin.tests.tools import setup_fresh_app, get_test_app +from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \ + fixture_add_user from mediagoblin import mg_globals from mediagoblin.tools import template, common @@ -45,13 +45,7 @@ class TestSubmission: # TODO: Possibly abstract into a decorator like: # @as_authenticated_user('chris') - test_user = mg_globals.database.User() - test_user['username'] = u'chris' - test_user['email'] = u'chris@example.com' - test_user['email_verified'] = True - test_user['status'] = u'active' - test_user['pw_hash'] = auth_lib.bcrypt_gen_password_hash('toast') - test_user.save() + test_user = fixture_add_user() self.test_user = test_user diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 01813e96..49a3d33e 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -27,6 +27,7 @@ from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.decorators import _make_safe from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.meddleware import BaseMeddleware +from mediagoblin.auth.lib import bcrypt_gen_password_hash MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__' @@ -200,3 +201,19 @@ def assert_db_meets_expected(db, expected): document = collection.find_one({'_id': expected_document['_id']}) assert document is not None # make sure it exists assert document == expected_document # make sure it matches + + +def fixture_add_user(username = u'chris', password = 'toast', + active_user = True): + test_user = mg_globals.database.User() + test_user.username = username + test_user.email = username + u'@example.com' + if password is not None: + test_user.pw_hash = bcrypt_gen_password_hash(password) + if active_user: + test_user.email_verified = True + test_user.status = u'active' + + test_user.save() + + return test_user -- cgit v1.2.3 From c7e1fee1b8eab3c01266c9a349812db598ca8f07 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 1 Dec 2011 16:58:56 -0600 Subject: Should be 404 for 404s, not 400 :) --- mediagoblin/tools/response.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py index b01d31a2..c905097c 100644 --- a/mediagoblin/tools/response.py +++ b/mediagoblin/tools/response.py @@ -30,7 +30,7 @@ def render_404(request): Render a 404. """ return render_to_response( - request, 'mediagoblin/404.html', {}, status=400) + request, 'mediagoblin/404.html', {}, status=404) def redirect(request, *args, **kwargs): -- cgit v1.2.3 From 93e4622491ff6bed339267cea2a0a98a7af3c8d8 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 2 Dec 2011 00:09:13 +0100 Subject: Expect 404 in unit tests, if we now use 404. Our unit tests for auth were expecting a 400. Well, now we give a 404. So expect that! I'm not completely sure, if the 404 is the right thing here, but that's another topic. --- mediagoblin/tests/test_auth.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 153c6e53..ee085761 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -280,16 +280,16 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.get( "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( - new_user._id), status=400) - assert response.status == '400 Bad Request' + new_user._id), status=404) + assert_equal(response.status, '404 Not Found') ## Try using an expired token to change password, shouldn't work template.clear_test_template_context() real_token_expiration = new_user['fp_token_expire'] new_user['fp_token_expire'] = datetime.datetime.now() new_user.save() - response = test_app.get("%s?%s" % (path, get_params), status=400) - assert response.status == '400 Bad Request' + response = test_app.get("%s?%s" % (path, get_params), status=404) + assert_equal(response.status, '404 Not Found') new_user['fp_token_expire'] = real_token_expiration new_user.save() -- cgit v1.2.3 From 92417fc535c32d905957b4f5ef0fd2cfd8d78609 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 2 Dec 2011 21:17:55 +0100 Subject: First push with jQuery library --- extlib/jquery/MIT.txt | 20 ++++++++++++++++++++ extlib/jquery/jquery.js | 4 ++++ mediagoblin/static/js/extlib/jquery.js | 1 + 3 files changed, 25 insertions(+) create mode 100644 extlib/jquery/MIT.txt create mode 100644 extlib/jquery/jquery.js create mode 120000 mediagoblin/static/js/extlib/jquery.js diff --git a/extlib/jquery/MIT.txt b/extlib/jquery/MIT.txt new file mode 100644 index 00000000..5a2aeb47 --- /dev/null +++ b/extlib/jquery/MIT.txt @@ -0,0 +1,20 @@ +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extlib/jquery/jquery.js b/extlib/jquery/jquery.js new file mode 100644 index 00000000..198b3ff0 --- /dev/null +++ b/extlib/jquery/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/mediagoblin/static/js/extlib/jquery.js b/mediagoblin/static/js/extlib/jquery.js new file mode 120000 index 00000000..d78f5cc3 --- /dev/null +++ b/mediagoblin/static/js/extlib/jquery.js @@ -0,0 +1 @@ +../../../../extlib/jquery/jquery.js \ No newline at end of file -- cgit v1.2.3 From 1e9d1acc03aa42ff979c8d15162d51441b81ec5d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 2 Dec 2011 16:13:14 -0600 Subject: We should use the variable local_templates instead of user_template_path --- mediagoblin/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 7f087ed9..04eb2acc 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -63,7 +63,7 @@ class MediaGoblinApp(object): # Get the template environment self.template_loader = get_jinja_loader( - app_config.get('user_template_path')) + app_config.get('local_templates')) # Set up storage systems self.public_store, self.queue_store = setup_storage() -- cgit v1.2.3 From 0d6e5dddeb38f6af7972485ae186532449719243 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 2 Dec 2011 23:48:40 +0100 Subject: Add show-password checkbox and make it work --- mediagoblin/auth/forms.py | 10 +--------- mediagoblin/templates/mediagoblin/auth/register.html | 20 ++++++++++++++++++++ mediagoblin/templates/mediagoblin/base.html | 3 ++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index dcb6766c..4cd3e9d8 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -29,15 +29,7 @@ class RegistrationForm(wtforms.Form): password = wtforms.PasswordField( _('Password'), [wtforms.validators.Required(), - wtforms.validators.Length(min=6, max=30), - wtforms.validators.EqualTo( - 'confirm_password', - _('Passwords must match.'))]) - confirm_password = wtforms.PasswordField( - _('Confirm password'), - [wtforms.validators.Required()], - description=_( - u"Type it again here to make sure there are no spelling mistakes.")) + wtforms.validators.Length(min=6, max=30)]) email = wtforms.TextField( _('Email address'), [wtforms.validators.Required(), diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index a0d0a277..bded1d7e 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -19,6 +19,26 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} +{% block mediagoblin_head %} + +{% endblock mediagoblin_head %} + {% block mediagoblin_content %} + {% block mediagoblin_head %} {% endblock mediagoblin_head %} - {% block mediagoblin_body %}
-- cgit v1.2.3 From eae7d0585fc0348a47087919c04e2372d15d244c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 3 Dec 2011 01:19:15 +0100 Subject: Changed comment error message wording slightly. Btw, should we translate these things? --- mediagoblin/user_pages/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 3d9735f7..779394c7 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -152,13 +152,13 @@ def media_post_comment(request, media): messages.add_message( request, messages.ERROR, - _("Empty comments are not allowed.")) + _("Oops, your comment was empty.")) else: comment.save() messages.add_message( request, messages.SUCCESS, - _('Comment posted!')) + _('Your comment has been posted!')) return exc.HTTPFound( location=media.url_for_self(request.urlgen)) -- cgit v1.2.3 From d463055317e5518adf7c5a99b4724f4e66830b3c Mon Sep 17 00:00:00 2001 From: Manuel Urbano Santos Date: Sat, 3 Dec 2011 14:29:28 +0100 Subject: Change adduser arguments from positional to --keyword style. --- mediagoblin/gmg_commands/users.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 4c4b0c1b..a4d85aa4 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -21,14 +21,14 @@ from mediagoblin import mg_globals def adduser_parser_setup(subparser): subparser.add_argument( - 'username', + '--username','-u', help="Username used to login") subparser.add_argument( - 'password', - help="Your supersecret word to login") + '--password','-p', + help="Your supersecret word to login, beware of storing it in bash history") subparser.add_argument( - 'email', - help="Email to recieve notifications") + '--email','-e', + help="Email to receive notifications") def adduser(args): -- cgit v1.2.3 From 7d98005a6b2469134adcf84b7a7417a24968bd8d Mon Sep 17 00:00:00 2001 From: Manuel Urbano Santos Date: Sat, 3 Dec 2011 15:36:02 +0100 Subject: Prompt for arguments in adduser if not present (I created a function in util.py to check and prompt for arguments). --- mediagoblin/gmg_commands/users.py | 5 ++++- mediagoblin/gmg_commands/util.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index a4d85aa4..b437e839 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -18,7 +18,6 @@ from mediagoblin.gmg_commands import util as commands_util from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals - def adduser_parser_setup(subparser): subparser.add_argument( '--username','-u', @@ -35,6 +34,10 @@ def adduser(args): #TODO: Lets trust admins this do not validate Emails :) commands_util.setup_app(args) + args.username = commands_util.prompt_if_not_set(args.username, "Username:") + args.password = commands_util.prompt_if_not_set(args.password, "Password:",True) + args.email = commands_util.prompt_if_not_set(args.email, "Email:") + db = mg_globals.database users_with_username = \ db.User.find({ diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py index 168a0760..af172105 100644 --- a/mediagoblin/gmg_commands/util.py +++ b/mediagoblin/gmg_commands/util.py @@ -16,6 +16,7 @@ from mediagoblin import app +import getpass def setup_app(args): @@ -25,3 +26,15 @@ def setup_app(args): mgoblin_app = app.MediaGoblinApp(args.conf_file) return mgoblin_app + +def prompt_if_not_set(variable,text,password=False): + """ + Checks if the variable is None and prompt for a value if it is + """ + if (variable==None): + if not password: + variable=raw_input(text+' ') + else: + variable=getpass.getpass(text) + + return variable -- cgit v1.2.3 From 968dd9e735eeeee9da0d1c10735e9bba2817e7c0 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 3 Dec 2011 16:45:33 +0100 Subject: Bug #685: Add failing unit test The simplest way to reproduce Bug #685 is to ask for a non existent page. This should return a proper 404. It currently doesn't. So add a unit test exactly for this. This unit test fails currently! It will fail until the bug gets fixed. --- mediagoblin/tests/test_misc.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 mediagoblin/tests/test_misc.py diff --git a/mediagoblin/tests/test_misc.py b/mediagoblin/tests/test_misc.py new file mode 100644 index 00000000..09623355 --- /dev/null +++ b/mediagoblin/tests/test_misc.py @@ -0,0 +1,26 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from nose.tools import assert_equal + +from mediagoblin.tests.tools import setup_fresh_app + + +@setup_fresh_app +def test_404_for_non_existent(test_app): + assert_equal(test_app.get('/does-not-exist/', + expect_errors=True).status_int, + 404) -- cgit v1.2.3 From 71c6c432a5fe8fe0f96dac284562a8e1b981d669 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 3 Dec 2011 21:20:11 +0100 Subject: Bug #685: only provide CSRF token if it exists This was suggested by Nathan Yergler in the bug logs. Just implementing it. - Let render_csrf_form_token return None, if the CSRF_TOKEN is not available in the environ, because the process_request part of the meddleware has not yet run. - In render_template: If the returned value from above is None, then do not add the csrf_token to the templates context. --- mediagoblin/meddleware/csrf.py | 3 +++ mediagoblin/tools/template.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py index 16541bee..a4e4e5c6 100644 --- a/mediagoblin/meddleware/csrf.py +++ b/mediagoblin/meddleware/csrf.py @@ -50,6 +50,9 @@ def render_csrf_form_token(request): """Render the CSRF token in a format suitable for inclusion in a form.""" + if 'CSRF_TOKEN' not in request.environ: + return None + form = CsrfForm(csrf_token=request.environ['CSRF_TOKEN']) return form.csrf_token diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index f48b7c2e..d0400347 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -79,7 +79,9 @@ def render_template(request, template_path, context): template = request.template_env.get_template( template_path) context['request'] = request - context['csrf_token'] = render_csrf_form_token(request) + rendered_csrf_token = render_csrf_form_token(request) + if rendered_csrf_token is not None: + context['csrf_token'] = render_csrf_form_token(request) rendered = template.render(context) if common.TESTS_ENABLED: -- cgit v1.2.3 From a6f065632a8410dc7e032267fd3ef16ae5d9576c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 3 Dec 2011 16:59:20 -0600 Subject: Updated translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 12268 -> 12629 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo | Bin 10826 -> 11417 bytes mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11119 -> 11684 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 70 +++++++++---- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 50 +++++++-- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 10809 -> 11489 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 70 +++++++++---- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 11329 -> 11967 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 103 ++++++++++++------ mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 11583 -> 12215 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 114 +++++++++++++------- mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo | Bin 10530 -> 11150 bytes mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo | Bin 11026 -> 11534 bytes mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 11224 -> 11791 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 10695 -> 11306 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 10287 -> 10845 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 56 ++++++++-- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 10945 -> 11508 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 11067 -> 11761 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 121 ++++++++++++++-------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 13899 -> 14235 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 56 ++++++++-- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo | Bin 11267 -> 11701 bytes mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 56 ++++++++-- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 10764 -> 11351 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 10627 -> 11247 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 11015 -> 11450 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 10812 -> 11439 bytes mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 52 ++++++++-- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 10509 -> 11108 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 107 ++++++++++++------- 41 files changed, 1056 insertions(+), 319 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index 4e4e8863..aa6eacac 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index 40e8b1cd..e1188ac9 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -102,7 +102,7 @@ msgid "Tags" msgstr "الوسوم" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -265,6 +265,11 @@ msgstr "أحدث الوسائط" msgid "Enter your new password" msgstr "أدخل كلمة سرك الجديدة" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "أرسل" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -378,10 +383,6 @@ msgstr "" msgid "Submit yer media" msgstr "انشر وسائطك" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "أرسل" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -392,6 +393,35 @@ msgstr "" msgid "%(username)s's media" msgstr "وسائط %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -517,6 +547,10 @@ msgstr "الأحدث" msgid "Older" msgstr "الأقدم" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -534,11 +568,11 @@ msgid "I am sure I want to delete this" msgstr "أنا متأكد من رغبتي بحذف هذا العمل" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo index 9b9e7e3b..203114fc 100644 Binary files a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po index f07ab2d6..a05dc5c0 100644 --- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -100,7 +100,7 @@ msgid "Tags" msgstr "Etiquetes" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -262,6 +262,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Envia" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -368,10 +373,6 @@ msgstr "" msgid "Submit yer media" msgstr "Envieu els vostres fitxers" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Envia" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -382,6 +383,35 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s's media" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -509,6 +539,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -526,11 +560,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 056e3eca..4747bd76 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index f5907eda..fc78ed7c 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -109,7 +109,7 @@ msgid "Tags" msgstr "Markierungen" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -137,11 +137,11 @@ msgstr "Webseite" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Altes Passwort" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Neues Passwort" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -157,7 +157,7 @@ msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Falsches Passwort" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" @@ -217,11 +217,11 @@ msgstr "Medien hochladen" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Bitte bestätige deine E-Mail-Adresse!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "Abmelden" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -275,6 +275,11 @@ msgstr "Neuste Medien" msgid "Enter your new password" msgstr "Neues Passwort eingeben" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Bestätigen" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -389,20 +394,45 @@ msgstr "" msgid "Submit yer media" msgstr "Medien hochladen" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Bestätigen" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "%(username)ss Medien" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)ss Medien" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -535,13 +565,17 @@ msgstr "Neuere" msgid "Older" msgstr "Ältere" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "und" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -552,12 +586,12 @@ msgid "I am sure I want to delete this" msgstr "Ja, wirklich löschen" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Leere Kommentare sind nicht erlaubt." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Kommentar hinzugefügt!" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index c1f3fd7f..3732705c 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -94,7 +94,7 @@ msgid "Tags" msgstr "" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -256,6 +256,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -355,10 +360,6 @@ msgstr "" msgid "Submit yer media" msgstr "" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -369,6 +370,35 @@ msgstr "" msgid "%(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -490,6 +520,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -507,11 +541,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index c537c65e..02d09486 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 2cffe874..cfc81d11 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -102,7 +102,7 @@ msgid "Tags" msgstr "Etikedoj" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -130,11 +130,11 @@ msgstr "Retejo" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "La malnova pasvorto" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "La nova pasvorto" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -150,7 +150,7 @@ msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Malĝusta pasvorto" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" @@ -214,7 +214,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "elsaluti" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -236,7 +236,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaĝaro!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "Your finest source for all goblin-related media." @@ -268,6 +268,11 @@ msgstr "Plej nove aldonitaj dosieroj" msgid "Enter your new password" msgstr "Enigu vian novan pasvorton" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Alŝuti" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -376,16 +381,12 @@ msgstr "" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Originalo" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Alŝutu vian aŭd-vid-dosieron" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Alŝuti" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -396,6 +397,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Dosieroj de %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -527,13 +557,17 @@ msgstr "Plinovaj" msgid "Older" msgstr "Malplinovaj" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "kaj" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -544,12 +578,12 @@ msgid "I am sure I want to delete this" msgstr "Mi estas certa, ke mi volas forigi ĉi tion" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Malplenaj komentoj ne estas afiŝeblaj." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "La komento estas afiŝita!" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index 2d2b9243..dba37f0a 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 6ab070af..88bd4da7 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -64,7 +64,7 @@ msgstr "Lo sentimos, ya existe un usuario con ese nombre." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Lo sentimos, ya existe un usuario con esa dirección de email." #: mediagoblin/auth/views.py:179 msgid "" @@ -82,10 +82,12 @@ msgstr "" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" msgstr "" +"Debes iniciar sesión para que podamos saber a quién le enviamos el correo " +"electrónico!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Ya haz verificado tu dirección de email!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -109,7 +111,7 @@ msgid "Tags" msgstr "Etiquetas" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -137,11 +139,11 @@ msgstr "Sitio web" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Vieja contraseña" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Nueva contraseña" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -157,15 +159,15 @@ msgstr "Estás editando un perfil de usuario. Proceder con precaución." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Contraseña incorrecta" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Perfil editado!" #: mediagoblin/media_types/__init__.py:61 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "No se pudo encontrar la extensión del archivo en \"{filename}\"" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -185,7 +187,7 @@ msgstr "¡Woohoo! ¡Enviado!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Tipo de archivo inválido." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -217,11 +219,11 @@ msgstr "Enviar contenido" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Verifica tu email!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "Cerrar sesión" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -243,21 +245,23 @@ msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Hola, bienvenido a este sitio de MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "Your finest source for all goblin-related media." -msgstr "" +msgstr "Tu mejor fuente de contenidos relacionados con goblins." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Para añadir tus propios contenidos, dejar comentarios, guardar tus favoritos" +" y más, puedes iniciar sesión con tu cuenta de MediaGoblin." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Aún no tienes una? Es fácil!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -266,6 +270,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Crea una cuenta en este sitio\n" +" o\n" +" Instala MediaGoblin en tu propio servidor" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -275,13 +282,18 @@ msgstr "El contenido más reciente" msgid "Enter your new password" msgstr "Ingrese su nueva contraseña" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Enviar" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Recuperar contraseña" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Enviar instrucciones" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -376,30 +388,55 @@ msgstr "Editando el perfil de %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Contenido etiquetado con: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Original" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Envía tu contenido" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Enviar" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Contenidos de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Contenido de %(username)s's" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -532,13 +569,17 @@ msgstr "Recientes" msgid "Older" msgstr "Antiguas" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Etiquetado con" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "y" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -549,20 +590,20 @@ msgid "I am sure I want to delete this" msgstr "Estoy seguro de que quiero borrar esto" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Eliminaste el contenido" #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" +msgstr "El contenido no se eliminó porque no marcaste que estabas seguro." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index 90e83303..c7f5701f 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index b37f5217..0bff6c37 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -13,8 +13,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -64,7 +64,7 @@ msgstr "Un utilisateur existe déjà avec ce nom, désolé." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Désolé, il existe déjà un utilisateur ayant cette adresse e-mail." #: mediagoblin/auth/views.py:179 msgid "" @@ -81,10 +81,11 @@ msgstr "La clé de vérification ou le nom d'utilisateur est incorrect." #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" msgstr "" +"Vous devez être authentifié afin que nous sachions à qui envoyer l'e-mail !" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Votre adresse e-mail a déjà été vérifiée !" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -107,7 +108,7 @@ msgid "Tags" msgstr "Tags" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -135,11 +136,11 @@ msgstr "Site web" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Ancien mot de passe." #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Nouveau mot de passe" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -159,15 +160,15 @@ msgstr "" #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Mauvais mot de passe" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Profile mis à jour !" #: mediagoblin/media_types/__init__.py:61 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "Impossible d'extraire une extension de fichier de \"{nomfichier}\"" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -187,11 +188,11 @@ msgstr "Youhou, c'est envoyé !" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Type de fichier invalide." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "Zut!" +msgstr "Zut !" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" @@ -219,11 +220,11 @@ msgstr "Soumettre un média" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Vérifiez votre adresse e-mail !" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "déconnexion" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -245,21 +246,23 @@ msgstr "Explorer" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Bonjour, et bienvenu sur ce site MediaGoblin !" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "Your finest source for all goblin-related media." -msgstr "" +msgstr "Là où ce trouve tout vos \"goblinesque\" media." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Ajoutez vos propres medias, commentez ceux des autres, sauvegardez vos " +"préférés et plus encore ! Faites tout cela depuis votre compte MediaGoblin." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Vous n'en avez pas ? C'est facile !" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -268,6 +271,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Créez un compte sur ce site\n" +" ou\n" +" Déployez MediaGoblin sur votre propre serveur" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -277,13 +283,18 @@ msgstr "Tout derniers media" msgid "Enter your new password" msgstr "Entrez un nouveau mot de passe" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Soumettre" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Récupérer le mot de passe" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Envoyer les instructions" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -326,11 +337,11 @@ msgstr "La connexion a échoué!" #: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" -msgstr "Pas encore de compte?" +msgstr "Pas encore de compte ?" #: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" -msgstr "Créez-en un ici!" +msgstr "Créez-en un ici !" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" @@ -338,7 +349,7 @@ msgstr "Vous avez oublié votre mot de passe ?" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" -msgstr "Créer un compte!" +msgstr "Créer un compte !" #: mediagoblin/templates/mediagoblin/auth/register.html:31 msgid "Create" @@ -384,30 +395,55 @@ msgstr "Modification du profil de %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Médias taggés avec : %(tag_name)s " #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Original" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Soumettez ce média" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Soumettre" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Medias de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Médias de %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -542,13 +578,17 @@ msgstr "Nouveaux" msgid "Older" msgstr "Anciens" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Taggé avec" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "et" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -559,20 +599,22 @@ msgid "I am sure I want to delete this" msgstr "Je suis sûr de vouloir supprimer cela" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Les commentaires vides ne sont pas autorisés." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Votre commentaire a été posté !" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Vous avez supprimé le media." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" +"Ce media n'a pas été supprimé car vous n'avez pas confirmer que vous étiez " +"sur." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo index feb156ff..55802ee2 100644 Binary files a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po index a4f1f8d7..7dd3a4f1 100644 --- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -96,7 +96,7 @@ msgid "Tags" msgstr "" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -256,6 +256,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -356,10 +361,6 @@ msgstr "" msgid "Submit yer media" msgstr "" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -370,6 +371,35 @@ msgstr "" msgid "%(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -493,6 +523,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -510,11 +544,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo index cc0ccbfa..77bfbee9 100644 Binary files a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po index 25700f8f..dc9ec274 100644 --- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -98,7 +98,7 @@ msgid "Tags" msgstr "Tags" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -264,6 +264,11 @@ msgstr "Documenti multimediali più recenti" msgid "Enter your new password" msgstr "Inserisci la tua nuova password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Conferma" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -369,10 +374,6 @@ msgstr "" msgid "Submit yer media" msgstr "Inoltra documento multimediale" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Conferma" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -383,6 +384,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Documenti multimediali di %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -513,6 +543,10 @@ msgstr "Più nuovo" msgid "Older" msgstr "Più vecchio" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -530,11 +564,11 @@ msgid "I am sure I want to delete this" msgstr "Sono sicuro di volerlo cancellare" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 5267eddc..e2a241a8 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index f2989e0e..5dcf7377 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -96,7 +96,7 @@ msgid "Tags" msgstr "タグ" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -256,6 +256,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "送信" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -361,10 +366,6 @@ msgstr "" msgid "Submit yer media" msgstr "コンテンツを投稿" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "送信" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -375,6 +376,35 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -498,6 +528,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -515,11 +549,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index e6d1976b..d7ba8ef6 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index 84957014..dad00867 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -98,7 +98,7 @@ msgid "Tags" msgstr "Etiket" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -261,6 +261,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Voeg toe" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -363,10 +368,6 @@ msgstr "" msgid "Submit yer media" msgstr "Voeg media toe" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Voeg toe" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -377,6 +378,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Media van %(username)s " +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -504,6 +534,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -521,11 +555,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index ba427c29..a75d86a7 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index 21cfdda5..10fad192 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -99,7 +99,7 @@ msgid "Tags" msgstr "Merkelappar" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -263,6 +263,11 @@ msgstr "Nyaste mediefiler" msgid "Enter your new password" msgstr "Fyll inn passord" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Send" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -377,10 +382,6 @@ msgstr "" msgid "Submit yer media" msgstr "Last opp" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Send" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -391,6 +392,35 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s sine mediefiler" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -516,6 +546,10 @@ msgstr "Nyare" msgid "Older" msgstr "Eldre" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -533,12 +567,12 @@ msgid "I am sure I want to delete this" msgstr "Eg er sikker eg vil sletta dette" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Du må skriva noko i innspelet." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Innspel lagt til." +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 31cb860c..e78b8e3b 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index c4f77f8a..0512f43d 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -102,7 +102,7 @@ msgid "Tags" msgstr "Etiquetas" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -267,6 +267,11 @@ msgstr "Mídia mais recente" msgid "Enter your new password" msgstr "Digite sua nova senha" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Enviar" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -382,10 +387,6 @@ msgstr "" msgid "Submit yer media" msgstr "Envie sua mídia" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Enviar" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -396,6 +397,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Mídia de %(username)s " +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -526,6 +556,10 @@ msgstr "Mais novo" msgid "Older" msgstr "Mais velho" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -543,11 +577,11 @@ msgid "I am sure I want to delete this" msgstr "Eu tenho certeza de que quero pagar isso" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 2ab9cf8b..c2044ccb 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 96fd46d8..5401c046 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -57,14 +57,14 @@ msgstr "Ne pare rău, există deja un utilizator cu același nume." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Există deja un utilizator înregistrat cu această adresă de e-mail." #: mediagoblin/auth/views.py:179 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -"Adresa ta de e-mail a fost confirmată. Poți să te autentifici, să îți " +"Adresa ta de e-mail a fost verificată. Poți să te autentifici, să îți " "completezi profilul și să trimiți imagini!" #: mediagoblin/auth/views.py:185 @@ -73,11 +73,11 @@ msgstr "Cheie de verificare sau user ID incorect." #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "Trebuie să fii autentificat ca să știm cui să trimitem mesajul!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Adresa ta de e-mail a fost deja verificată!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -89,7 +89,7 @@ msgid "" "account's email address has not been verified." msgstr "" "E-mailul pentru recuperarea parolei nu a putut fi trimis deoarece contul tău" -" e inactiv sau adresa ta de e-mail nu a fost confirmată." +" e inactiv sau adresa ta de e-mail nu a fost verificată." #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" @@ -97,10 +97,10 @@ msgstr "Titlu" #: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 msgid "Tags" -msgstr "Etichete" +msgstr "Tag-uri" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -128,11 +128,11 @@ msgstr "Sit Web" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Vechea parolă" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Noua parolă" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -149,15 +149,15 @@ msgstr "Editezi profilul unui utilizator. Se recomandă prudență." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Parolă incorectă" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Profilul a fost modificat!" #: mediagoblin/media_types/__init__.py:61 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "Nu pot extrage extensia din „{filename}”" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -173,19 +173,19 @@ msgstr "Trebuie să selectezi un fișier." #: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" -msgstr "Gata, trimis!" +msgstr "Ura! Trimis!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Tip de fișier incompatibil." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "Oops!" +msgstr "Hopa!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "Ne pare rău, nu există nicio pagină la această adresă." +msgstr "Nu există nicio pagină la această adresă. Ne pare rău!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" @@ -209,11 +209,11 @@ msgstr "Transmite un fișier media" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Verifică adresa de e-mail!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "ieșire" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -235,21 +235,23 @@ msgstr "Explorează" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Salut, bine ai venit pe acest site MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "Your finest source for all goblin-related media." -msgstr "" +msgstr "Locul unde elfii își transmit fișierele media." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Ca să adăugi propriile tale fișiere, să scrii comentarii, să salvezi " +"favoritele tale și multe altele, autentifică-te cu contul tău MediaGoblin." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Încă nu ai unul? E simplu!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -258,6 +260,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Creează un cont pe acest site\n" +" sau\n" +" Instalează MediaGoblin pe propriul tău server" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -267,13 +272,18 @@ msgstr "Cele mai recente fișiere" msgid "Enter your new password" msgstr "Introdu noua parolă" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Trimite" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Recuperează parola" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Trimite instrucțiuni" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -371,30 +381,55 @@ msgstr "Editare profil %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Fișier etichetat cu tag-urile: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Original" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "Trimite fișierele tale media" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Trimite" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Fișierele lui %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Fișierele media ale lui %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -438,7 +473,7 @@ msgstr "Ne pare rău, nu am găsit utilizatorul căutat." #: mediagoblin/templates/mediagoblin/user_pages/user.html:50 #: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" -msgstr "Este necesară confirmarea adresei de e-mail" +msgstr "Este necesară verificarea adresei de e-mail" #: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." @@ -524,13 +559,17 @@ msgstr "Mai noi" msgid "Older" msgstr "Mai vechi" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Tag-uri" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "și" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -541,20 +580,20 @@ msgid "I am sure I want to delete this" msgstr "Sunt sigur că doresc să șterg" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Comentariul trebuie să aibă un conținut." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Comentariul a fost transmis." +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Ai șters acest fișier" #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" +msgstr "Fișierul nu a fost șters deoarece nu ai confirmat că ești sigur." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 4b5481e0..19765967 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 9fb1ce08..cee135ca 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -101,7 +101,7 @@ msgid "Tags" msgstr "Метки" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -266,6 +266,11 @@ msgstr "Самые новые файлы" msgid "Enter your new password" msgstr "Введите свой новый пароль" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Подтвердить" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -382,10 +387,6 @@ msgstr "" msgid "Submit yer media" msgstr "Загрузить файл(ы)" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Подтвердить" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -396,6 +397,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Файлы пользователя %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -525,6 +555,10 @@ msgstr "Более новые" msgid "Older" msgstr "Более старые" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -542,12 +576,12 @@ msgid "I am sure I want to delete this" msgstr "Я уверен, что хочу удалить это" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Empty comments are not allowed." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Комментарий размещён!" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo index 684c850a..10699d0b 100644 Binary files a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index bee7b3b5..30622dee 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -100,7 +100,7 @@ msgid "Tags" msgstr "Štítky" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -264,6 +264,11 @@ msgstr "Najčerstvejšie výtvory" msgid "Enter your new password" msgstr "Vlož svoje nové heslo" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Vložiť" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -380,10 +385,6 @@ msgstr "" msgid "Submit yer media" msgstr "Vlož svoj výtvor" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Vložiť" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -394,6 +395,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Výtvory, ktoré vlastní %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -522,6 +552,10 @@ msgstr "Novšie" msgid "Older" msgstr "Staršie" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -539,12 +573,12 @@ msgid "I am sure I want to delete this" msgstr "Jednoznačne to chcem odstrániť" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "Komentáre bez obsahu nepovolené." +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "Komentár odoslaný!" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 52e3d632..5d6a0fe2 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index 77273ebe..568a5f73 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -98,7 +98,7 @@ msgid "Tags" msgstr "Oznake" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -260,6 +260,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Pošlji" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -366,10 +371,6 @@ msgstr "" msgid "Submit yer media" msgstr "Pošljite svojo vsebino" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Pošlji" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -380,6 +381,35 @@ msgstr "" msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -507,6 +537,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -524,11 +558,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index d2649938..deb56104 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index 0bdfc21c..63f92fdc 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -95,7 +95,7 @@ msgid "Tags" msgstr "" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -255,6 +255,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -355,10 +360,6 @@ msgstr "" msgid "Submit yer media" msgstr "" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -369,6 +370,35 @@ msgstr "" msgid "%(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -492,6 +522,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -509,11 +543,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index 2ae7c510..b2194da9 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index 37bd36c1..0e48dc53 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -101,7 +101,7 @@ msgid "Tags" msgstr "Taggar" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -265,6 +265,11 @@ msgstr "Senast medier" msgid "Enter your new password" msgstr "Fyll i ditt lösenord" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "Skicka" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -380,10 +385,6 @@ msgstr "" msgid "Submit yer media" msgstr "Ladda upp" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Skicka" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -394,6 +395,35 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)ss media" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -525,6 +555,10 @@ msgstr "Nyare" msgid "Older" msgstr "Äldre" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -542,11 +576,11 @@ msgid "I am sure I want to delete this" msgstr "Jag är säker på att jag vill radera detta" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo index b0d8d3fc..2ac4c41c 100644 Binary files a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po index 064fa7d1..816f2580 100644 --- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -96,7 +96,7 @@ msgid "Tags" msgstr "" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -256,6 +256,11 @@ msgstr "" msgid "Enter your new password" msgstr "" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "దాఖలు చెయ్యి" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" msgstr "" @@ -356,10 +361,6 @@ msgstr "" msgid "Submit yer media" msgstr "" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "దాఖలు చెయ్యి" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -370,6 +371,35 @@ msgstr "" msgid "%(username)s's media" msgstr "" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -493,6 +523,10 @@ msgstr "" msgid "Older" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" msgstr "" @@ -510,11 +544,11 @@ msgid "I am sure I want to delete this" msgstr "" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." +msgid "Oops, your comment was empty." msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" +msgid "Your comment has been posted!" msgstr "" #: mediagoblin/user_pages/views.py:183 diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index e3751aeb..33400cef 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 5e406b41..6bc7a717 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-11-27 15:25-0600\n" -"PO-Revision-Date: 2011-11-27 21:28+0000\n" +"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"PO-Revision-Date: 2011-12-03 22:56+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -58,7 +58,7 @@ msgstr "抱歉, 這個使用者名稱已經存在." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "抱歉,此電子郵件已被註冊了。" #: mediagoblin/auth/views.py:179 msgid "" @@ -72,11 +72,11 @@ msgstr "認證碼或是使用者帳號錯誤" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "你必須登入,我們才知道信要送給誰!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "你的電子郵件已經確認了!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -97,7 +97,7 @@ msgid "Tags" msgstr "標籤" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas or spaces." +msgid "Seperate tags by commas." msgstr "" #: mediagoblin/edit/forms.py:33 @@ -123,11 +123,11 @@ msgstr "網站" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "舊的密碼" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "新的密碼" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -143,15 +143,15 @@ msgstr "你正在編輯一位用戶的檔案. 請謹慎處理." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "密碼錯誤" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "個人資料已被編輯了!" #: mediagoblin/media_types/__init__.py:61 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "找不到任何 \"{filename}\" 的附檔名。" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -171,7 +171,7 @@ msgstr "呼呼! 送出去嚕!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "不正確的檔案格式" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -201,11 +201,11 @@ msgstr "遞交媒體" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "確認你的電子郵件" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "登出" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -227,21 +227,21 @@ msgstr "探索" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "嘿!歡迎來到 媒體怪獸(MediaGoblin) 網站" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "Your finest source for all goblin-related media." -msgstr "" +msgstr "你是媒體怪獸的相關媒體最珍貴的來源。" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." -msgstr "" +msgstr "你可以用 媒體怪獸 帳號登入,加入你自己的媒體檔案,加入評語,把你的最愛儲存起來。" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "還沒有嗎?其實非常簡單!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -250,6 +250,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"在這網站建立帳號\n" +" 或是\n" +" 建立一個自己的媒體怪獸(MedaiGoblin)" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -259,13 +262,18 @@ msgstr "最新的媒體" msgid "Enter your new password" msgstr "輸入你的新密碼" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Submit" +msgstr "送出" + #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "找回密碼" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "送出指示" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -361,30 +369,55 @@ msgstr "編輯 %(username)s'的檔案中" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "此媒體被標識為:%(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "原始的" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" msgstr "遞交你的媒體檔案" -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "送出" - #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "%(username)s的媒體" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)s的媒體檔案" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#, python-format +msgid "By %(username)s on %(date)s" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +msgid "Post a comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Post comment!" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +msgid "Edit" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 +msgid "Sorry, no such media found." +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -508,13 +541,17 @@ msgstr "新一點" msgid "Older" msgstr "舊一點" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +msgid "Go to page:" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "被標籤為" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "且" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -525,20 +562,20 @@ msgid "I am sure I want to delete this" msgstr "我確定我想要刪除" #: mediagoblin/user_pages/views.py:155 -msgid "Empty comments are not allowed." -msgstr "評論不能空白。" +msgid "Oops, your comment was empty." +msgstr "" #: mediagoblin/user_pages/views.py:161 -msgid "Comment posted!" -msgstr "評論已經張貼!" +msgid "Your comment has been posted!" +msgstr "" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "你已刪除此媒體檔案。" #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" +msgstr "此媒體檔案尚未被刪除因為你還沒有確認你真的要刪除。" #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." -- cgit v1.2.3 From cc4f83faabda361301210a6ba66c3ae5c7305a6a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 3 Dec 2011 21:38:45 -0600 Subject: Raise a slightly useful exception when we can't find the media type. --- mediagoblin/media_types/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 61786562..25f3d255 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -51,6 +51,10 @@ def get_media_manager(_media_type = None): if media_type in _media_type: return manager + # Nope? Then raise an error + raise FileTypeNotSupported( + "MediaManager not in enabled types. Check media_types in config?") + def get_media_type_and_manager(filename): for media_type, manager in get_media_managers(): -- cgit v1.2.3 From bbac7663f4b05430592ac5d39f056029dc11db92 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 3 Dec 2011 21:56:30 -0600 Subject: PEP-8'ifying prompt_if_not_set --- mediagoblin/gmg_commands/util.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py index af172105..004f9e49 100644 --- a/mediagoblin/gmg_commands/util.py +++ b/mediagoblin/gmg_commands/util.py @@ -27,13 +27,13 @@ def setup_app(args): return mgoblin_app -def prompt_if_not_set(variable,text,password=False): +def prompt_if_not_set(variable, text, password=False): """ Checks if the variable is None and prompt for a value if it is """ - if (variable==None): + if variable is None: if not password: - variable=raw_input(text+' ') + variable=raw_input(text + u' ') else: variable=getpass.getpass(text) -- cgit v1.2.3 From bb20c179c43cc9aec2cb7a3160dc734e58961609 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 3 Dec 2011 21:59:52 -0600 Subject: Most users won't see this but having space after prompt still nice for passwords. --- mediagoblin/gmg_commands/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py index 004f9e49..3e26c53f 100644 --- a/mediagoblin/gmg_commands/util.py +++ b/mediagoblin/gmg_commands/util.py @@ -35,6 +35,6 @@ def prompt_if_not_set(variable, text, password=False): if not password: variable=raw_input(text + u' ') else: - variable=getpass.getpass(text) + variable=getpass.getpass(text + u' ') return variable -- cgit v1.2.3 From 21e84329569a356deab73ed2b98d16b91af16b0f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 10:21:58 -0600 Subject: Change "Your finest source of goblin related media" to something else We don't want to insist everyone hold a goblin-related gallery :) --- mediagoblin/templates/mediagoblin/root.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 25ce9e96..0f769f2f 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -25,7 +25,7 @@ {% else %}

{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}

-

{% trans %}Your finest source for all goblin-related media.{% endtrans %}

+

{% trans %}This site is running MediaGoblin, an extraordinarily great piece of media hosting software.{% endtrans %}

{% trans %}To add your own media, place comments, save your favourites and more, you can log in with your MediaGoblin account.{% endtrans %}

{% if allow_registration %}

{% trans %}Don't have one yet? It's easy!{% endtrans %}

-- cgit v1.2.3 From f80f5b58a818dfcbbf984fc3e580df5fbf04917b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 10:24:42 -0600 Subject: Removing the conditional that checks if there's a media in media.html If there isn't a media, we shouldn't hit that template! The view should ensure that. --- .../templates/mediagoblin/user_pages/media.html | 246 ++++++++++----------- 1 file changed, 121 insertions(+), 125 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 7434664c..caa99eb7 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -23,143 +23,139 @@ {% block title %}{{ media.title }} — {{ super() }}{% endblock %} {% block mediagoblin_content %} - {% if media %} -
-
- {% block mediagoblin_media %} - {% set display_media = request.app.public_store.file_url( - media.get_display_media(media.media_files)) %} +
+
+ {% block mediagoblin_media %} + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} - {# if there's a medium file size, that means the medium size - # isn't the original... so link to the original! - #} - {% if media['media_files'].has_key('medium') %} - - Image for {{ media.title }} - - {% else %} + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media['media_files'].has_key('medium') %} + Image for {{ media.title }} - {% endif %} - {% endblock %} -
+ + {% else %} + Image for {{ media.title }} + {% endif %} + {% endblock %} +
-

- {{ media.title }} -

- {% autoescape False %} -

{{ media.description_html }}

- {% endautoescape %} -

- {% trans date=media.created.strftime("%Y-%m-%d"), - user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader().username), - username=media.get_uploader().username -%} - By {{ username }} on {{ date }} - {%- endtrans %} -

-

- {% if request.user and comments.count() %} -

{% trans %}Post a comment{% endtrans %}

- {% endif %} - {% if comments %} - {% for comment in comments %} - {% set comment_author = comment.author() %} - {% if pagination.active_id == comment._id %} -
- - {% else %} -
- {% endif %} +

+ {{ media.title }} +

+ {% autoescape False %} +

{{ media.description_html }}

+ {% endautoescape %} +

+ {% trans date=media.created.strftime("%Y-%m-%d"), + user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader().username), + username=media.get_uploader().username -%} + By {{ username }} on {{ date }} + {%- endtrans %} +

+

+ {% if request.user and comments.count() %} +

{% trans %}Post a comment{% endtrans %}

+ {% endif %} + {% if comments %} + {% for comment in comments %} + {% set comment_author = comment.author() %} + {% if pagination.active_id == comment._id %} +
+ + {% else %} +
+ {% endif %} -
{% autoescape False %}{{ comment.content_html }} - {% endautoescape %} - - - {{ comment_author['username'] }} - {% trans %}at{% endtrans %} - - {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} - -
+
{% autoescape False %}{{ comment.content_html }} + {% endautoescape %} + + + {{ comment_author['username'] }} + {% trans %}at{% endtrans %} + + {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} +
- {% endfor %} +
+ {% endfor %} - {% if request.user %} - - {{ wtforms_util.render_divs(comment_form) }} -
- - {{ csrf_token }} -
- - {% endif %} + {% if request.user %} +
+ {{ wtforms_util.render_divs(comment_form) }} +
+ + {{ csrf_token }} +
+ + {% endif %} - {{ render_pagination(request, pagination, - request.urlgen('mediagoblin.user_pages.media_home', - user = media.get_uploader().username, - media = media._id)) }} -
- {% endif %} + {{ render_pagination(request, pagination, + request.urlgen('mediagoblin.user_pages.media_home', + user = media.get_uploader().username, + media = media._id)) }} +
+ {% endif %} -
- {% include "mediagoblin/utils/prev_next.html" %} +
+ {% include "mediagoblin/utils/prev_next.html" %} - {% if media['uploader'] == request.user._id or - request.user['is_admin'] %} -

- {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader().username, - media= media._id) %} - {% trans %}Edit{% endtrans %} -

-

- {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader().username, - media= media._id) %} - {% trans %}Delete{% endtrans %} -

- {% endif %} + {% if media['uploader'] == request.user._id or + request.user['is_admin'] %} +

+ {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', + user= media.get_uploader().username, + media= media._id) %} + {% trans %}Edit{% endtrans %} +

+

+ {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', + user= media.get_uploader().username, + media= media._id) %} + {% trans %}Delete{% endtrans %} +

+ {% endif %} - {% if media.attachment_files|count %} -

Attachments

- - {% endif %} + {% if media.attachment_files|count %} +

Attachments

+ + {% endif %} - {% if app_config['allow_attachments'] - and (media['uploader'] == request.user._id - or request.user['is_admin']) %} -

- Add attachment -

- {% endif %} + {% if app_config['allow_attachments'] + and (media['uploader'] == request.user._id + or request.user['is_admin']) %} +

+ Add attachment +

+ {% endif %} - {% if media.tags %} - {% include "mediagoblin/utils/tags.html" %} - {% endif %} -
- {% else %} -

{% trans %}Sorry, no such media found.{% endtrans %}

- {% endif %} + {% if media.tags %} + {% include "mediagoblin/utils/tags.html" %} + {% endif %} +

{% endblock %} -- cgit v1.2.3 From b25b00d26e41158591822f5570c15f1baf2bc30b Mon Sep 17 00:00:00 2001 From: tycho garen Date: Sun, 4 Dec 2011 14:51:00 -0500 Subject: DOCS: update to deployment documentation and new production deployments doc --- docs/source/deploying.rst | 10 +++---- docs/source/production-deployments.rst | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 docs/source/production-deployments.rst diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index b944a3d3..9c0acf30 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -244,7 +244,7 @@ Production MediaGoblin Deployments with Paste The instance configured with ``lazyserver`` is not ideal for a production MediaGoblin deployment. Ideally, you should be able to use -a a control script (i.e. init script.) to launch and restart the +a control script (i.e. init script.) to launch and restart the MediaGoblin process. Use the following command as the basis for such a script: :: @@ -252,13 +252,13 @@ Use the following command as the basis for such a script: :: CELERY_ALWAYS_EAGER=true \ /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ /srv/mediagoblin.example.org/mediagoblin/paste.ini \ - --pid-file=/tmp/mediagoblin.pid \ + --pid-file=/var/run/mediagoblin.pid \ --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ .. note:: The above configuration places MediaGoblin in "always eager" mode with Celery. This is fine for development and smaller - deployments. However, if you're getting into the really large - deployment category, consider reading the section of this manual on - Celery. + deployments. However, for larger production deployments with larger + processing requirements, see the ":doc:`production-deployments`" + documentation. diff --git a/docs/source/production-deployments.rst b/docs/source/production-deployments.rst new file mode 100644 index 00000000..37251734 --- /dev/null +++ b/docs/source/production-deployments.rst @@ -0,0 +1,48 @@ +========================================= +Considerations for Production Deployments +========================================= + +This document contains a number of suggestions for deploying +MediaGoblin in actual production environments. Consider +":doc:`deploying`" for a basic overview of how to deploy Media +Goblin. + +Celery +------ + +While the ``./lazyserer.sh`` configuration provides an efficient way to +start using a MediaGoblin instance, it is not suitable for production +deployments for several reasons: + +1. In nearly every scenario, work on the Celery queue will need to + balance with the demands of other processes, and cannot proceed + synchronously. This is a particularly relevant problem if you use + MediaGoblin to host Video content. + +2. Processing with Celery ought to be operationally separate from the + MediaGoblin application itself, this simplifies management and + support better workload distribution. + +3. ... additional reason here. .... + +Build an :ref:`init script ` around the following +command. + + CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd + +Modify your existing MediaGoblin and application init scripts, if +necessary, to prevent them from starting their own ``celeryd`` +processes. + +.. _init-script: + +Use an Init Script +------------------- + +TODO insert init script here + +Other Concerns +-------------- + +TODO What are they? + -- cgit v1.2.3 From b3efea3c79097ab5ea080f4c39ea59c2994fca5c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 13:56:55 -0600 Subject: Updated translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 42 +++++---- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 24 +++-- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 88 ++++++++++--------- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 54 ++++++------ mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 28 +++--- mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 53 +++++------ mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 102 ++++++++++++---------- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 26 +++--- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 28 +++--- 21 files changed, 371 insertions(+), 386 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index e1188ac9..61abc63f 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -156,7 +156,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -236,7 +236,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -393,35 +395,31 @@ msgstr "" msgid "%(username)s's media" msgstr "وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po index a05dc5c0..9609cb34 100644 --- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -152,7 +152,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -233,7 +233,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -383,35 +385,31 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index fc78ed7c..7d7e0ee9 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -16,9 +16,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" -"Last-Translator: cwebber \n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:26+0000\n" +"Last-Translator: elrond \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -65,7 +65,7 @@ msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Leider gibt es bereits einen Benutzer mit dieser E-Mail-Adresse." #: mediagoblin/auth/views.py:179 msgid "" @@ -85,7 +85,7 @@ msgstr "" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Deine E-Mail-Adresse wurde bereits bestätigt." #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -161,9 +161,9 @@ msgstr "Falsches Passwort" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Das Profil wurde aktualisiert" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -246,7 +246,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -384,7 +386,7 @@ msgstr "%(username)ss Profil bearbeiten" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr ": %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" @@ -404,34 +406,30 @@ msgstr "%(username)ss Medien" msgid "%(username)s's media" msgstr "%(username)ss Medien" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Bearbeiten" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" +msgstr "Löschen" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -571,7 +569,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Markiert mit" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 3732705c..17e6873c 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -145,7 +145,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -224,7 +224,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, " +"an extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -370,35 +372,31 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index cfc81d11..e5c6356e 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" -"Last-Translator: cwebber \n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 19:15+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -59,7 +59,7 @@ msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Ni bedaŭras, sed konto kun tiu retpoŝtadreso jam ekzistas." #: mediagoblin/auth/views.py:179 msgid "" @@ -75,11 +75,11 @@ msgstr "La kontrol-kodo aŭ la uzantonomo ne estas korekta" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "Vi devas esti ensalutita, por ke ni sciu, al kiu sendi la retleteron!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Vi jam konfirmis vian retpoŝtadreson!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -103,7 +103,7 @@ msgstr "Etikedoj" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Dividu la etikedojn per komoj." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -154,11 +154,11 @@ msgstr "Malĝusta pasvorto" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "La profilŝanĝo faritas!" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "Ŝajnas, ke en «{filename}» mankas dosiernoma finaĵo" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -178,7 +178,7 @@ msgstr "Hura! Alŝutitas!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Netaŭga dosiertipo." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -210,7 +210,7 @@ msgstr "Alŝuti aŭd-vid-dosieron" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Konfirmu viecon de la retpoŝtadreso!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" @@ -232,25 +232,32 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Ĉirkaŭrigardi" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaĝaro!" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" +"Ĉi tiu retpaĝaro funkcias per MediaGoblin, eksterordinare bonega " +"programaro por gastigado de aŭd‐vid‐dosieroj." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Por aldoni viajn proprajn dosierojn, fari liston de plej plaĉantaj por vi, " +"ks, vi povas ensaluti je via MediaGoblina konto." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Ĉu vi ankoraŭ ne havas tian? Ne malĝoju!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -259,6 +266,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Kreu konton en ĉi tiu retejo\n" +" aŭ\n" +" Ekfunkciigu MediaGoblin’on en via propra servilo" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -275,11 +285,11 @@ msgstr "Alŝuti" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Ekhavo de nova pasvorto" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Sendi instrukcion" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -377,7 +387,7 @@ msgstr "Redaktado de l’profilo de %(username)s'" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Dosieroj kun etikedo: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" @@ -390,41 +400,37 @@ msgstr "Alŝutu vian aŭd-vid-dosieron" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Dosieroj de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Dosieroj de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Afiŝita de %(username)s je %(date)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Afiŝi komenton" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "je" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Afiŝi la komenton!" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Ŝanĝi" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" +msgstr "Forigi" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -559,11 +565,11 @@ msgstr "Malplinovaj" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Iri al paĝo:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Markita per: " #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" @@ -579,19 +585,21 @@ msgstr "Mi estas certa, ke mi volas forigi ĉi tion" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Oj, via komento estis malplena." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Via komento estis afiŝita!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Vi forigis la dosieron." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" +"La dosiero ne estis forigita, ĉar vi ne konfirmis vian certecon per la " +"markilo." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 88bd4da7..460c074c 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -10,13 +10,14 @@ # , 2011. # , 2011. # Mario Rodriguez , 2011. +# , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" -"Last-Translator: cwebber \n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:49+0000\n" +"Last-Translator: manolinux \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -112,7 +113,7 @@ msgstr "Etiquetas" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Separar etiquetas por comas." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -165,7 +166,7 @@ msgstr "Contraseña incorrecta" msgid "Profile edited!" msgstr "Perfil editado!" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "No se pudo encontrar la extensión del archivo en \"{filename}\"" @@ -248,8 +249,13 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Hola, bienvenido a este sitio de MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." -msgstr "Tu mejor fuente de contenidos relacionados con goblins." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." +msgstr "" +"Este sitio está montado con MediaGoblin, un programa libre buenísimo" +" para gestionar contenido multimedia." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -408,34 +414,30 @@ msgstr "Contenidos de %(username)s" msgid "%(username)s's media" msgstr "Contenido de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Por %(username)s en %(date)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Pon un comentario." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "en" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "¡Pon un comentario!" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Editar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" +msgstr "Borrar" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -571,7 +573,7 @@ msgstr "Antiguas" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Ir a la página:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" @@ -591,11 +593,11 @@ msgstr "Estoy seguro de que quiero borrar esto" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Ups, tu comentario estaba vacío." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "¡Tu comentario ha sido publicado!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 0bff6c37..8d1e2711 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -13,8 +13,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -166,7 +166,7 @@ msgstr "Mauvais mot de passe" msgid "Profile edited!" msgstr "Profile mis à jour !" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "Impossible d'extraire une extension de fichier de \"{nomfichier}\"" @@ -249,8 +249,10 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Bonjour, et bienvenu sur ce site MediaGoblin !" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." -msgstr "Là où ce trouve tout vos \"goblinesque\" media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -415,35 +417,31 @@ msgstr "Medias de %(username)s" msgid "%(username)s's media" msgstr "Médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po index 7dd3a4f1..512635e3 100644 --- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -148,7 +148,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -227,7 +227,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -371,35 +373,31 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po index dc9ec274..96d1f0a2 100644 --- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -152,7 +152,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -235,7 +235,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -384,35 +386,31 @@ msgstr "" msgid "%(username)s's media" msgstr "Documenti multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 5dcf7377..3198eed9 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -148,7 +148,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -227,7 +227,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -376,35 +378,31 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index dad00867..c1778676 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -153,7 +153,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -232,7 +232,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -378,35 +380,31 @@ msgstr "" msgid "%(username)s's media" msgstr "Media van %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index 10fad192..0b0c2a27 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -151,7 +151,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -234,7 +234,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -392,35 +394,31 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 0512f43d..daa65e0f 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" @@ -155,7 +155,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -238,7 +238,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -397,35 +399,31 @@ msgstr "" msgid "%(username)s's media" msgstr "Mídia de %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 5401c046..b747fc3a 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -4,13 +4,14 @@ # # Translators: # , 2011. +# George Pop , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" -"Last-Translator: cwebber \n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 18:41+0000\n" +"Last-Translator: gap \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -101,7 +102,7 @@ msgstr "Tag-uri" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Desparte tag-urile prin virgulă." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -155,7 +156,7 @@ msgstr "Parolă incorectă" msgid "Profile edited!" msgstr "Profilul a fost modificat!" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "Nu pot extrage extensia din „{filename}”" @@ -238,8 +239,12 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Salut, bine ai venit pe acest site MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." -msgstr "Locul unde elfii își transmit fișierele media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." +msgstr "" +"Acest site folosește MediaGoblin, un " +"software excepțional pentru găzduirea fișierelor media." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -401,34 +406,30 @@ msgstr "Fișierele lui %(username)s" msgid "%(username)s's media" msgstr "Fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "De %(username)s la %(date)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Scrie un comentariu" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "la" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Trimite comentariul" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Editare" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" +msgstr "Șterge" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -561,7 +562,7 @@ msgstr "Mai vechi" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Salt la pagina:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" @@ -581,11 +582,11 @@ msgstr "Sunt sigur că doresc să șterg" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Hopa, ai uitat să scrii comentariul." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Comentariul tău a fost trimis!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index cee135ca..c615cde2 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" -"Last-Translator: cwebber \n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 17:53+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -58,6 +58,8 @@ msgstr "Извините, пользователь с этим именем уж #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." msgstr "" +"Сожалеем, но на этот адрес электронной почты уже зарегистрирована другая " +"учётная запись." #: mediagoblin/auth/views.py:179 msgid "" @@ -73,11 +75,11 @@ msgstr "Неверный ключ проверки или идентификат #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "Вам надо представиться, чтобы мы знали, кому отправлять сообщение!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Вы уже потвердили свой адрес электронной почты!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -102,7 +104,7 @@ msgstr "Метки" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Разделяйте метки запятыми." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -129,11 +131,11 @@ msgstr "Сайт" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Старый пароль" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Новый пароль" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -150,15 +152,15 @@ msgstr "Вы редактируете профиль пользователя. #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Неправильный пароль" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Профиль изменён!" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "В «{filename}» не обнаружено расширение имени файла" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -178,7 +180,7 @@ msgstr "Ура! Файл загружен!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Неподходящий тип файла." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -208,11 +210,11 @@ msgstr "Загрузить файл" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Подтвердите ваш адрес электронной почты!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "завершение сеанса" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -230,25 +232,32 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Смотреть" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Привет! Добро пожаловать на наш MediaGoblin’овый сайт!" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" +"Этот сайт работает на MediaGoblin, " +"необыкновенно замечательном ПО для хостинга мультимедийных файлов." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Для добавления собственных файлов, комментирования, ведения списка любиых " +"файлов и т. п. вы можете представиться с помощью вашей MediaGoblin’овой " +"учётной записи." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "У вас её ещё нет? Не проблема!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -257,6 +266,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Создайте учётную запись на этом сайте\n" +" или\n" +" Установите MediaGoblin на собственный сервер" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -273,11 +285,11 @@ msgstr "Подтвердить" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Сброс пароля" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Отправить инструкцию" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -377,11 +389,11 @@ msgstr "Редактирование профиля %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Файлы с меткой: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Оригинал" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -390,41 +402,37 @@ msgstr "Загрузить файл(ы)" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Файлы %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Файлы пользователя %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Загружено %(username)s %(date)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Оставить комментарий" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "в" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Разместить комментарий!" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Изменить" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" +msgstr "Удалить" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -557,15 +565,15 @@ msgstr "Более старые" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Перейти к странице:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Метки:" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "и" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -577,19 +585,19 @@ msgstr "Я уверен, что хочу удалить это" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Ой, ваш комментарий был пуст." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Ваш комментарий размещён!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Вы удалили файл." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" +msgstr "Файл не удалён, так как вы не подтвердили свою уверенность галочкой." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index 30622dee..a44f7866 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -152,7 +152,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -235,7 +235,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -395,35 +397,31 @@ msgstr "" msgid "%(username)s's media" msgstr "Výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index 568a5f73..ffd2c04c 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -150,7 +150,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -231,7 +231,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -381,35 +383,31 @@ msgstr "" msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index 63f92fdc..942f7203 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -147,7 +147,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -226,7 +226,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -370,35 +372,31 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index 0e48dc53..e195ad70 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -153,7 +153,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -236,7 +236,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -395,35 +397,31 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)ss media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po index 816f2580..f7bbd6ac 100644 --- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -148,7 +148,7 @@ msgstr "" msgid "Profile edited!" msgstr "" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "" @@ -227,7 +227,9 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 @@ -371,35 +373,31 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 6bc7a717..70622590 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-03 16:57-0600\n" -"PO-Revision-Date: 2011-12-03 22:56+0000\n" +"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"PO-Revision-Date: 2011-12-04 16:23+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -149,7 +149,7 @@ msgstr "密碼錯誤" msgid "Profile edited!" msgstr "個人資料已被編輯了!" -#: mediagoblin/media_types/__init__.py:61 +#: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" msgstr "找不到任何 \"{filename}\" 的附檔名。" @@ -230,8 +230,10 @@ msgid "Hi there, welcome to this MediaGoblin site!" msgstr "嘿!歡迎來到 媒體怪獸(MediaGoblin) 網站" #: mediagoblin/templates/mediagoblin/root.html:28 -msgid "Your finest source for all goblin-related media." -msgstr "你是媒體怪獸的相關媒體最珍貴的來源。" +msgid "" +"This site is running MediaGoblin, an " +"extraordinarily great piece of media hosting software." +msgstr "" #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -389,35 +391,31 @@ msgstr "%(username)s的媒體" msgid "%(username)s's media" msgstr "%(username)s的媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:58 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:68 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:86 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:125 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:131 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:163 -msgid "Sorry, no such media found." -msgstr "" - #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -- cgit v1.2.3 From 5b972a192e923dffde4660ca44e8bfbc74aa0c2f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 13:57:35 -0600 Subject: Compiled the .mo files too --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 12629 -> 12717 bytes mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo | Bin 11417 -> 11505 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11684 -> 11805 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 11489 -> 11754 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 11967 -> 12093 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 12215 -> 12304 bytes mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo | Bin 11150 -> 11238 bytes mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo | Bin 11534 -> 11622 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 11791 -> 11879 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 11306 -> 11394 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 10845 -> 10933 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 11508 -> 11596 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 11761 -> 11882 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 14235 -> 15455 bytes mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo | Bin 11701 -> 11789 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 11351 -> 11439 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 11247 -> 11335 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 11450 -> 11538 bytes mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 11439 -> 11527 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 11108 -> 11190 bytes 20 files changed, 0 insertions(+), 0 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index aa6eacac..02dfa29a 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo index 203114fc..34179a53 100644 Binary files a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 4747bd76..f7562eaa 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 02d09486..8f37922f 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index dba37f0a..bed6aab8 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index c7f5701f..ed1ea35d 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo index 55802ee2..c0a1ecb6 100644 Binary files a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo index 77bfbee9..1319a605 100644 Binary files a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index e2a241a8..39f3595b 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index d7ba8ef6..842bfb9b 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index a75d86a7..c07f42be 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index e78b8e3b..95d6d0ae 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index c2044ccb..e0a70ea9 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 19765967..0e34144d 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo index 10699d0b..4e71eaa7 100644 Binary files a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 5d6a0fe2..9ad54a83 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index deb56104..ece8989f 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index b2194da9..c6cf0df9 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo index 2ac4c41c..cd9fab9f 100644 Binary files a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index 33400cef..6dda94b7 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ -- cgit v1.2.3 From 2ef0679790ca6ee15fea2c8e25449d5c54cf5036 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 14:39:42 -0600 Subject: Fix button word-wrapping issue --- mediagoblin/static/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 12d88ffa..961a51fc 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -129,6 +129,7 @@ a.mediagoblin_logo{ font-style: normal; font-weight: bold; font-size: 1em; + display: inline-block; } .button_action_highlight{ -- cgit v1.2.3 From 4752fdcf06764965d2f926d99f3831a968d8ea8d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 15:27:00 -0600 Subject: Filled in reason #3 to submit separate out celery. --- docs/source/production-deployments.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/source/production-deployments.rst b/docs/source/production-deployments.rst index 37251734..75acf9cf 100644 --- a/docs/source/production-deployments.rst +++ b/docs/source/production-deployments.rst @@ -23,7 +23,16 @@ deployments for several reasons: MediaGoblin application itself, this simplifies management and support better workload distribution. -3. ... additional reason here. .... +3. If your user submits something complex and it needs to process, + that's extra time your user has to sit around waiting when they + could get back immediately to doing things on the site. + Furthermore, if that processing step takes a long time, as it + certainly will for video, your user won't just be left waiting, + their connection will probably time out. + +Basically, if you're doing anything other than trivial images for a +small set of users (or something similarly trivial, like ascii art), +you want to switch over to doing a separate celery process. Build an :ref:`init script ` around the following command. -- cgit v1.2.3 From a085dda5d29a1353eaf7df3ddfc3a7c500af9186 Mon Sep 17 00:00:00 2001 From: tycho garen Date: Sun, 4 Dec 2011 17:06:54 -0500 Subject: DOCS:: #675 revision to deployment and production documents --- docs/source/deploying.rst | 25 ++-------- docs/source/index.rst | 1 + docs/source/production-deployments.rst | 83 ++++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index 9c0acf30..70b1a6af 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -239,26 +239,9 @@ example: :: Visit the site you've set up in your browser by visiting . You should see MediaGoblin! -Production MediaGoblin Deployments with Paste -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The instance configured with ``lazyserver`` is not ideal for a -production MediaGoblin deployment. Ideally, you should be able to use -a control script (i.e. init script.) to launch and restart the -MediaGoblin process. - -Use the following command as the basis for such a script: :: - - CELERY_ALWAYS_EAGER=true \ - /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ - /srv/mediagoblin.example.org/mediagoblin/paste.ini \ - --pid-file=/var/run/mediagoblin.pid \ - --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ - .. note:: - The above configuration places MediaGoblin in "always eager" mode - with Celery. This is fine for development and smaller - deployments. However, for larger production deployments with larger - processing requirements, see the ":doc:`production-deployments`" - documentation. + The configuration described above is sufficient for development and + smaller deployments. However, for larger production deployments + with larger processing requirements, see the + ":doc:`production-deployments`" documentation. diff --git a/docs/source/index.rst b/docs/source/index.rst index e9f3993e..6ffe0974 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,6 +14,7 @@ Table of Contents: foreword about deploying + production-deployments configuration help theming diff --git a/docs/source/production-deployments.rst b/docs/source/production-deployments.rst index 75acf9cf..7bf26169 100644 --- a/docs/source/production-deployments.rst +++ b/docs/source/production-deployments.rst @@ -7,32 +7,54 @@ MediaGoblin in actual production environments. Consider ":doc:`deploying`" for a basic overview of how to deploy Media Goblin. -Celery ------- +Deploy with Paste +----------------- + +The instance configured with ``./lazyserver.sh`` is not ideal for a +production MediaGoblin deployment. Ideally, you should be able to use +an "init" or "control" script to launch and restart the MediaGoblin +process. + +Use the following command as the basis for such a script: :: + + CELERY_ALWAYS_EAGER=true \ + /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ + /srv/mediagoblin.example.org/mediagoblin/paste.ini \ + --pid-file=/var/run/mediagoblin.pid \ + --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ + +The above configuration places MediaGoblin in "always eager" mode +with Celery, this means that submissions of content will be processed +synchronously, and the user will advance to the next page only after +processing is complete. If we take Celery out of "always eager mode," +the user will be able to immediately return to the MediaGoblin site +while processing is ongoing. In these cases, use the following command +as the basis for your script: :: + + CELERY_ALWAYS_EAGER=false \ + /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ + /srv/mediagoblin.example.org/mediagoblin/paste.ini \ + --pid-file=/var/run/mediagoblin.pid \ + --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ + +Separate Celery +--------------- While the ``./lazyserer.sh`` configuration provides an efficient way to start using a MediaGoblin instance, it is not suitable for production deployments for several reasons: -1. In nearly every scenario, work on the Celery queue will need to - balance with the demands of other processes, and cannot proceed - synchronously. This is a particularly relevant problem if you use - MediaGoblin to host Video content. +In nearly every scenario, work on the Celery queue will need to +balance with the demands of other processes, and cannot proceed +synchronously. This is a particularly relevant problem if you use +MediaGoblin to host video content. Processing with Celery ought to be +operationally separate from the MediaGoblin application itself, this +simplifies management and support better workload distribution. -2. Processing with Celery ought to be operationally separate from the - MediaGoblin application itself, this simplifies management and - support better workload distribution. - -3. If your user submits something complex and it needs to process, - that's extra time your user has to sit around waiting when they - could get back immediately to doing things on the site. - Furthermore, if that processing step takes a long time, as it - certainly will for video, your user won't just be left waiting, - their connection will probably time out. - -Basically, if you're doing anything other than trivial images for a -small set of users (or something similarly trivial, like ascii art), -you want to switch over to doing a separate celery process. +Basically, if you're doing anything beyond a trivial workload, such as +image hosting for a small set of users, or have limited media types +such as "ASCII art" or icon sharing, you will need to run ``celeryd`` +as a separate process. Build an :ref:`init script ` around the following command. @@ -46,12 +68,15 @@ processes. .. _init-script: Use an Init Script -------------------- - -TODO insert init script here - -Other Concerns --------------- - -TODO What are they? - +------------------ + +Look in your system's ``/etc/init.d/`` or ``/etc/rc.d/`` directory for +examples of how to build scripts that will start, stop, and restart +MediaGoblin and Celery. These scripts will vary by +distribution/operating system. In the future, MediaGoblin will provide +example scripts as examples. + +.. TODO insert init script here +.. TODO are additional concernts ? + .. Other Concerns + .. -------------- -- cgit v1.2.3 From 38f102515a84c1da25a9dab56d2fe7731412f4f5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 4 Dec 2011 23:58:58 -0600 Subject: Cloudfiles not actually a dependency, removing from setup.py If users want cloudfiles, they can always ./bin/easy_install it. --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index ec672dd2..293f3f03 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,6 @@ setup( 'webtest', 'ConfigObj', 'Markdown', - 'python-cloudfiles', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', -- cgit v1.2.3 From bcc9ee3205dfc6bc2b5e5dacb09de89121eb3782 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Dec 2011 08:35:42 -0600 Subject: Update the delete item to use the _id after all... it's the safest way. See http://bugs.foocorp.net/issues/695 --- mediagoblin/decorators.py | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- .../templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +- mediagoblin/tests/test_submission.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 56dddb44..269b0c2e 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -58,7 +58,7 @@ def user_may_delete_media(controller): """ def wrapper(request, *args, **kwargs): uploader = request.db.MediaEntry.find_one( - {'slug': request.matchdict['media']}).get_uploader() + {'_id': ObjectId(request.matchdict['media'])}).get_uploader() if not (request.user['is_admin'] or request.user._id == uploader._id): return exc.HTTPForbidden() diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index c7818012..5039fb30 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -126,7 +126,7 @@

{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', user= media.get_uploader().username, - media= media.slug) %} + media= media._id) %} {% trans %}Delete{% endtrans %}

{% endif %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index e36891d6..058351a5 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -23,7 +23,7 @@

diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index a3453f2f..7ea6c4bc 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -171,7 +171,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media.slug), + media=media._id), # no value means no confirm {}) @@ -191,7 +191,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media.slug), + media=media._id), {'confirm': 'y'}) response.follow() -- cgit v1.2.3 From 5b5b67cd5c82e743f7c656616c92841fae31b36f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 5 Dec 2011 08:37:20 -0600 Subject: Update comment URLs to use the media slug. --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 5039fb30..b811d161 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -86,7 +86,7 @@ + media = media.slug) }}#comment"> {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }}

-- cgit v1.2.3 From 5a4e3ff1e2a0f2ed451bc191c1d44bcd694b8e75 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 15:39:57 +0100 Subject: Dot-Notation for Users.username --- mediagoblin/auth/lib.py | 4 ++-- mediagoblin/auth/views.py | 10 +++++----- mediagoblin/db/models.py | 8 ++++---- mediagoblin/decorators.py | 2 +- mediagoblin/edit/views.py | 2 +- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/listings/views.py | 2 +- mediagoblin/submit/views.py | 2 +- mediagoblin/templates/mediagoblin/base.html | 6 +++--- mediagoblin/templates/mediagoblin/edit/edit_profile.html | 4 ++-- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- mediagoblin/tests/test_submission.py | 4 ++-- mediagoblin/tests/test_tests.py | 2 +- mediagoblin/user_pages/views.py | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index cf4a2b83..ee1ce12d 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -105,7 +105,7 @@ def send_verification_email(user, request): """ rendered_email = render_template( request, 'mediagoblin/auth/verification_email.txt', - {'username': user['username'], + {'username': user.username, 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( host=request.host, uri=request.urlgen('mediagoblin.auth.verify_email'), @@ -140,7 +140,7 @@ def send_fp_verification_email(user, request): """ rendered_email = render_template( request, 'mediagoblin/auth/fp_verification_email.txt', - {'username': user['username'], + {'username': user.username, 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( host=request.host, uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d01861d1..dab95b17 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -80,7 +80,7 @@ def register(request): if extra_validation_passes: # Create the user user = request.db.User() - user['username'] = username + user.username = username user['email'] = email user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) @@ -98,7 +98,7 @@ def register(request): # message waiting for them to verify their email return redirect( request, 'mediagoblin.user_pages.user_home', - user=user['username']) + user=user.username) return render_to_response( request, @@ -186,7 +186,7 @@ def verify_email(request): return redirect( request, 'mediagoblin.user_pages.user_home', - user=user['username']) + user=user.username) def resend_activation(request): @@ -224,7 +224,7 @@ def resend_activation(request): _('Resent your verification email.')) return redirect( request, 'mediagoblin.user_pages.user_home', - user=request.user['username']) + user=request.user.username) def forgot_password(request): @@ -268,7 +268,7 @@ def forgot_password(request): return redirect( request, 'mediagoblin.user_pages.user_home', - user=user['username']) + user=user.username) # do not reveal whether or not there is a matching user return redirect(request, 'mediagoblin.auth.fp_email_sent') diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 265fe36d..4af996b8 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -268,12 +268,12 @@ class MediaEntry(Document): if self.get('slug'): return urlgen( 'mediagoblin.user_pages.media_home', - user=uploader['username'], + user=uploader.username, media=self['slug']) else: return urlgen( 'mediagoblin.user_pages.media_home', - user=uploader['username'], + user=uploader.username, media=unicode(self._id)) def url_to_prev(self, urlgen): @@ -286,7 +286,7 @@ class MediaEntry(Document): '_id', ASCENDING).limit(1) if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader()['username'], + user=self.get_uploader().username, media=unicode(cursor[0]['slug'])) def url_to_next(self, urlgen): @@ -300,7 +300,7 @@ class MediaEntry(Document): if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader()['username'], + user=self.get_uploader().username, media=unicode(cursor[0]['slug'])) def get_uploader(self): diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 269b0c2e..d6a054f8 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -40,7 +40,7 @@ def require_active_login(controller): request.user.get('status') == u'needs_email_verification': return redirect( request, 'mediagoblin.user_pages.user_home', - user=request.user['username']) + user=request.user.username) elif not request.user or request.user.get('status') != u'active': return exc.HTTPFound( location="%s?next=%s" % ( diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 673409bd..61a61d4c 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -147,7 +147,7 @@ def edit_attachments(request, media): def edit_profile(request): # admins may edit any user profile given a username in the querystring edit_username = request.GET.get('username') - if request.user['is_admin'] and request.user['username'] != edit_username: + if request.user['is_admin'] and request.user.username != edit_username: user = request.db.User.find_one({'username': edit_username}) # No need to warn again if admin just submitted an edited profile if request.method != 'POST': diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index b437e839..e8426272 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -50,7 +50,7 @@ def adduser(args): else: # Create the user entry = db.User() - entry['username'] = unicode(args.username.lower()) + entry.username = unicode(args.username.lower()) entry['email'] = unicode(args.email) entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash(args.password) entry['status'] = u'active' diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index 5a09de43..6b83ffcf 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -86,7 +86,7 @@ def tag_atom_feed(request): feed.add(entry.get('title'), entry.get('description_html'), content_type='html', - author=entry.get_uploader()['username'], + author=entry.get_uploader().username, updated=entry.get('created'), url=entry.url_for_self(request.urlgen)) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 3def44ce..6beb6b18 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -127,7 +127,7 @@ def submit_start(request): add_message(request, SUCCESS, _('Woohoo! Submitted!')) return redirect(request, "mediagoblin.user_pages.user_home", - user=request.user['username']) + user=request.user.username) except InvalidFileType, exc: submit_form.file.errors.append( _(u'Invalid file type.')) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 29639026..c06addd0 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -60,14 +60,14 @@ {# the following link should only appear when verification is needed #} {% if request.user.status == "needs_email_verification" %} {% trans %}Verify your email!{% endtrans %} {% endif %} - {{ request.user['username'] }} + user= request.user.username) }}"> + {{ request.user.username }} ({% trans %}log out{% endtrans %}) {% else %} diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index bf8fe5c1..2d5daa95 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -22,11 +22,11 @@ {% block mediagoblin_content %}

- {%- trans username=user['username'] -%} + {%- trans username=user.username -%} Editing {{ username }}'s profile {%- endtrans %}

diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index b811d161..7fc60c3f 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -80,8 +80,8 @@ {% endautoescape %} - {{ comment_author['username'] }} + user = comment_author.username) }}"> + {{ comment_author.username }} {% trans %}at{% endtrans %} Date: Mon, 14 Nov 2011 18:54:52 +0100 Subject: Dot-Notation for Users.email_verified --- mediagoblin/auth/views.py | 6 +++--- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/tests/test_auth.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 63bf9a91..2d29d0a5 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -168,7 +168,7 @@ def verify_email(request): if user and user['verification_key'] == unicode(request.GET['token']): user[u'status'] = u'active' - user[u'email_verified'] = True + user.email_verified = True user[u'verification_key'] = None user.save() @@ -249,7 +249,7 @@ def forgot_password(request): {'email': request.POST['username']}) if user: - if user['email_verified'] and user['status'] == 'active': + if user.email_verified and user['status'] == 'active': user[u'fp_verification_key'] = unicode(uuid.uuid4()) user[u'fp_token_expire'] = datetime.datetime.now() + \ datetime.timedelta(days=10) @@ -304,7 +304,7 @@ def verify_forgot_password(request): if ((user and user['fp_verification_key'] and user['fp_verification_key'] == unicode(formdata_token) and datetime.datetime.now() < user['fp_token_expire'] - and user['email_verified'] and user['status'] == 'active')): + and user.email_verified and user['status'] == 'active')): cp_form = auth_forms.ChangePassForm(formdata_vars) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 6084f9d7..88895661 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -54,7 +54,7 @@ def adduser(args): entry.email = unicode(args.email) entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password) entry['status'] = u'active' - entry['email_verified'] = True + entry.email_verified = True entry.save(validate=True) print "User created (and email marked as verified)" diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 2faf0f25..ad9a5bca 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -163,7 +163,7 @@ def test_register_views(test_app): {'username': 'happygirl'}) assert new_user assert new_user['status'] == u'needs_email_verification' - assert new_user['email_verified'] == False + assert new_user.email_verified == False ## Make sure user is logged in request = template.TEMPLATE_TEST_CONTEXT[ @@ -203,7 +203,7 @@ def test_register_views(test_app): {'username': 'happygirl'}) assert new_user assert new_user['status'] == u'needs_email_verification' - assert new_user['email_verified'] == False + assert new_user.email_verified == False ## Verify the email activation works template.clear_test_template_context() @@ -217,7 +217,7 @@ def test_register_views(test_app): {'username': 'happygirl'}) assert new_user assert new_user['status'] == u'active' - assert new_user['email_verified'] == True + assert new_user.email_verified == True # Uniqueness checks # ----------------- -- cgit v1.2.3 From 7a3d00ec217cc3fd44788b9d8c63ab9f7b1d05a7 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:01:26 +0100 Subject: Dot-Notation for Users.status --- mediagoblin/auth/views.py | 6 +++--- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/templates/mediagoblin/base.html | 2 +- mediagoblin/tests/test_auth.py | 6 +++--- mediagoblin/user_pages/views.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 2d29d0a5..caf9835a 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -167,7 +167,7 @@ def verify_email(request): {'_id': ObjectId(unicode(request.GET['userid']))}) if user and user['verification_key'] == unicode(request.GET['token']): - user[u'status'] = u'active' + user.status = u'active' user.email_verified = True user[u'verification_key'] = None @@ -249,7 +249,7 @@ def forgot_password(request): {'email': request.POST['username']}) if user: - if user.email_verified and user['status'] == 'active': + if user.email_verified and user.status == 'active': user[u'fp_verification_key'] = unicode(uuid.uuid4()) user[u'fp_token_expire'] = datetime.datetime.now() + \ datetime.timedelta(days=10) @@ -304,7 +304,7 @@ def verify_forgot_password(request): if ((user and user['fp_verification_key'] and user['fp_verification_key'] == unicode(formdata_token) and datetime.datetime.now() < user['fp_token_expire'] - and user.email_verified and user['status'] == 'active')): + and user.email_verified and user.status == 'active')): cp_form = auth_forms.ChangePassForm(formdata_vars) diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 88895661..7b23ba34 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -53,7 +53,7 @@ def adduser(args): entry.username = unicode(args.username.lower()) entry.email = unicode(args.email) entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password) - entry['status'] = u'active' + entry.status = u'active' entry.email_verified = True entry.save(validate=True) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index c06addd0..16569f03 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -48,7 +48,7 @@ >{% trans %}MediaGoblin logo{% endtrans %} {% endblock %} - {% if request.user and request.user['status'] == 'active' %} + {% if request.user and request.user.status == 'active' %} {% trans %}Submit media{% endtrans %} diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index ad9a5bca..bd79a407 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -162,7 +162,7 @@ def test_register_views(test_app): new_user = mg_globals.database.User.find_one( {'username': 'happygirl'}) assert new_user - assert new_user['status'] == u'needs_email_verification' + assert new_user.status == u'needs_email_verification' assert new_user.email_verified == False ## Make sure user is logged in @@ -202,7 +202,7 @@ def test_register_views(test_app): new_user = mg_globals.database.User.find_one( {'username': 'happygirl'}) assert new_user - assert new_user['status'] == u'needs_email_verification' + assert new_user.status == u'needs_email_verification' assert new_user.email_verified == False ## Verify the email activation works @@ -216,7 +216,7 @@ def test_register_views(test_app): new_user = mg_globals.database.User.find_one( {'username': 'happygirl'}) assert new_user - assert new_user['status'] == u'active' + assert new_user.status == u'active' assert new_user.email_verified == True # Uniqueness checks diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index ad33479b..4b311822 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -40,7 +40,7 @@ def user_home(request, page): 'username': request.matchdict['user']}) if not user: return render_404(request) - elif user['status'] != u'active': + elif user.status != u'active': return render_to_response( request, 'mediagoblin/user_pages/user.html', @@ -254,7 +254,7 @@ def processing_panel(request): # Make sure the user exists and is active if not user: return render_404(request) - elif user['status'] != u'active': + elif user.status != u'active': return render_to_response( request, 'mediagoblin/user_pages/user.html', -- cgit v1.2.3 From 00bb95502e01f8c8fcaa5652889a5ed423051d7c Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:04:13 +0100 Subject: Dot-Notation for Users.verification_key --- mediagoblin/auth/lib.py | 2 +- mediagoblin/auth/views.py | 6 +++--- mediagoblin/tests/test_auth.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index 24992094..d03f7af0 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -110,7 +110,7 @@ def send_verification_email(user, request): host=request.host, uri=request.urlgen('mediagoblin.auth.verify_email'), userid=unicode(user._id), - verification_key=user['verification_key'])}) + verification_key=user.verification_key)}) # TODO: There is no error handling in place send_email( diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index caf9835a..d7e8d1bf 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -166,10 +166,10 @@ def verify_email(request): user = request.db.User.find_one( {'_id': ObjectId(unicode(request.GET['userid']))}) - if user and user['verification_key'] == unicode(request.GET['token']): + if user and user.verification_key == unicode(request.GET['token']): user.status = u'active' user.email_verified = True - user[u'verification_key'] = None + user.verification_key = None user.save() @@ -212,7 +212,7 @@ def resend_activation(request): return redirect(request, "mediagoblin.user_pages.user_home", user=request.user['username']) - request.user[u'verification_key'] = unicode(uuid.uuid4()) + request.user.verification_key = unicode(uuid.uuid4()) request.user.save() email_debug_message(request) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index bd79a407..7cb867d7 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -187,7 +187,7 @@ def test_register_views(test_app): assert parsed_get_params['userid'] == [ unicode(new_user._id)] assert parsed_get_params['token'] == [ - new_user['verification_key']] + new_user.verification_key] ## Try verifying with bs verification key, shouldn't work template.clear_test_template_context() -- cgit v1.2.3 From bec591d85b1e4695024b54bbd902559ec7727ea6 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:08:43 +0100 Subject: Dot-Notation for Users.is_admin --- mediagoblin/decorators.py | 2 +- mediagoblin/edit/lib.py | 2 +- mediagoblin/edit/views.py | 4 ++-- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- mediagoblin/user_pages/views.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index d6a054f8..229664d7 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -59,7 +59,7 @@ def user_may_delete_media(controller): def wrapper(request, *args, **kwargs): uploader = request.db.MediaEntry.find_one( {'_id': ObjectId(request.matchdict['media'])}).get_uploader() - if not (request.user['is_admin'] or + if not (request.user.is_admin or request.user._id == uploader._id): return exc.HTTPForbidden() diff --git a/mediagoblin/edit/lib.py b/mediagoblin/edit/lib.py index 458b704e..4ce2d42f 100644 --- a/mediagoblin/edit/lib.py +++ b/mediagoblin/edit/lib.py @@ -19,6 +19,6 @@ def may_edit_media(request, media): """Check, if the request's user may edit the media details""" if media['uploader'] == request.user._id: return True - if request.user['is_admin']: + if request.user.is_admin: return True return False diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 61a61d4c..e766b6d8 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -78,7 +78,7 @@ def edit_media(request, media): return exc.HTTPFound( location=media.url_for_self(request.urlgen)) - if request.user['is_admin'] \ + if request.user.is_admin \ and media['uploader'] != request.user._id \ and request.method != 'POST': messages.add_message( @@ -147,7 +147,7 @@ def edit_attachments(request, media): def edit_profile(request): # admins may edit any user profile given a username in the querystring edit_username = request.GET.get('username') - if request.user['is_admin'] and request.user.username != edit_username: + if request.user.is_admin and request.user.username != edit_username: user = request.db.User.find_one({'username': edit_username}) # No need to warn again if admin just submitted an edited profile if request.method != 'POST': diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 7b23ba34..4bfe30a5 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -73,7 +73,7 @@ def makeadmin(args): user = db.User.one({'username': unicode(args.username.lower())}) if user: - user['is_admin'] = True + user.is_admin = True user.save() print 'The user is now Admin' else: diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 7fc60c3f..89fd104d 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -116,7 +116,7 @@ {% include "mediagoblin/utils/prev_next.html" %} {% if media['uploader'] == request.user._id or - request.user['is_admin'] %} + request.user.is_admin %}

{% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.get_uploader().username, @@ -146,7 +146,7 @@ {% if app_config['allow_attachments'] and (media['uploader'] == request.user._id - or request.user['is_admin']) %} + or request.user.is_admin) %}

{% include "mediagoblin/utils/profile.html" %} - {% if request.user._id == user._id or request.user['is_admin'] %} + {% if request.user._id == user._id or request.user.is_admin %} {%- trans %}Edit profile{% endtrans -%} diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 4b311822..dc549567 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -191,7 +191,7 @@ def media_confirm_delete(request, media): return exc.HTTPFound( location=media.url_for_self(request.urlgen)) - if ((request.user[u'is_admin'] and + if ((request.user.is_admin and request.user._id != media.get_uploader()._id)): messages.add_message( request, messages.WARNING, -- cgit v1.2.3 From a24e5133ed9ee0845e854478da9a88f85e755f70 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:16:02 +0100 Subject: Dot-Notation for Users.url --- mediagoblin/edit/views.py | 2 +- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index e766b6d8..cbae9cc3 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -176,7 +176,7 @@ def edit_profile(request): {'user': user, 'form': form}) - user['url'] = unicode(request.POST['url']) + user.url = unicode(request.POST['url']) user['bio'] = unicode(request.POST['bio']) if password_matches: diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index d0f3bced..b952e88c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -89,7 +89,7 @@ {%- trans username=user.username %}{{ username }}'s profile{% endtrans -%} - {% if not user['url'] and not user['bio'] %} + {% if not user.url and not user.bio %} {% if request.user._id == user._id %}

-- cgit v1.2.3 From 4b77f86ab46c54a41a250ad1d8cec82214b67545 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:19:54 +0100 Subject: Dot-Notation for Users.bio and .bio_html --- mediagoblin/edit/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index cbae9cc3..4e8c3686 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -177,13 +177,13 @@ def edit_profile(request): 'form': form}) user.url = unicode(request.POST['url']) - user['bio'] = unicode(request.POST['bio']) + user.bio = unicode(request.POST['bio']) if password_matches: user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['new_password']) - user['bio_html'] = cleaned_markdown_conversion(user['bio']) + user.bio_html = cleaned_markdown_conversion(user['bio']) user.save() -- cgit v1.2.3 From dc39e4555c9e104ae9d7b38f231a848fe106d1a0 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:21:33 +0100 Subject: Dot-Notation for Users.fp_verification_key --- mediagoblin/auth/lib.py | 2 +- mediagoblin/auth/views.py | 8 ++++---- mediagoblin/tests/test_auth.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index d03f7af0..c0af3b5b 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -145,7 +145,7 @@ def send_fp_verification_email(user, request): host=request.host, uri=request.urlgen('mediagoblin.auth.verify_forgot_password'), userid=unicode(user._id), - fp_verification_key=user['fp_verification_key'])}) + fp_verification_key=user.fp_verification_key)}) # TODO: There is no error handling in place send_email( diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index d7e8d1bf..633ceef4 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -250,7 +250,7 @@ def forgot_password(request): if user: if user.email_verified and user.status == 'active': - user[u'fp_verification_key'] = unicode(uuid.uuid4()) + user.fp_verification_key = unicode(uuid.uuid4()) user[u'fp_token_expire'] = datetime.datetime.now() + \ datetime.timedelta(days=10) user.save() @@ -301,8 +301,8 @@ def verify_forgot_password(request): return render_404(request) # check if we have a real user and correct token - if ((user and user['fp_verification_key'] and - user['fp_verification_key'] == unicode(formdata_token) and + if ((user and user.fp_verification_key and + user.fp_verification_key == unicode(formdata_token) and datetime.datetime.now() < user['fp_token_expire'] and user.email_verified and user.status == 'active')): @@ -311,7 +311,7 @@ def verify_forgot_password(request): if request.method == 'POST' and cp_form.validate(): user.pw_hash = auth_lib.bcrypt_gen_password_hash( request.POST['password']) - user[u'fp_verification_key'] = None + user.fp_verification_key = None user[u'fp_token_expire'] = None user.save() diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 7cb867d7..2dcb5c14 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -270,7 +270,7 @@ def test_register_views(test_app): # user should have matching parameters new_user = mg_globals.database.User.find_one({'username': 'happygirl'}) assert parsed_get_params['userid'] == [unicode(new_user._id)] - assert parsed_get_params['token'] == [new_user['fp_verification_key']] + assert parsed_get_params['token'] == [new_user.fp_verification_key] ### The forgotten password token should be set to expire in ~ 10 days # A few ticks have expired so there are only 9 full days left... -- cgit v1.2.3 From 2d540fed8b511c76819a836da3d62875d20b6547 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 19:24:15 +0100 Subject: Dot-Notation for Users.fp_token_expire --- mediagoblin/auth/views.py | 6 +++--- mediagoblin/tests/test_auth.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 633ceef4..919aa3cd 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -251,7 +251,7 @@ def forgot_password(request): if user: if user.email_verified and user.status == 'active': user.fp_verification_key = unicode(uuid.uuid4()) - user[u'fp_token_expire'] = datetime.datetime.now() + \ + user.fp_token_expire = datetime.datetime.now() + \ datetime.timedelta(days=10) user.save() @@ -303,7 +303,7 @@ def verify_forgot_password(request): # check if we have a real user and correct token if ((user and user.fp_verification_key and user.fp_verification_key == unicode(formdata_token) and - datetime.datetime.now() < user['fp_token_expire'] + datetime.datetime.now() < user.fp_token_expire and user.email_verified and user.status == 'active')): cp_form = auth_forms.ChangePassForm(formdata_vars) @@ -312,7 +312,7 @@ def verify_forgot_password(request): user.pw_hash = auth_lib.bcrypt_gen_password_hash( request.POST['password']) user.fp_verification_key = None - user[u'fp_token_expire'] = None + user.fp_token_expire = None user.save() return redirect(request, 'mediagoblin.auth.fp_changed_success') diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 2dcb5c14..d3b8caf1 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -274,7 +274,7 @@ def test_register_views(test_app): ### The forgotten password token should be set to expire in ~ 10 days # A few ticks have expired so there are only 9 full days left... - assert (new_user['fp_token_expire'] - datetime.datetime.now()).days == 9 + assert (new_user.fp_token_expire - datetime.datetime.now()).days == 9 ## Try using a bs password-changing verification key, shouldn't work template.clear_test_template_context() @@ -285,12 +285,12 @@ def test_register_views(test_app): ## Try using an expired token to change password, shouldn't work template.clear_test_template_context() - real_token_expiration = new_user['fp_token_expire'] - new_user['fp_token_expire'] = datetime.datetime.now() + real_token_expiration = new_user.fp_token_expire + new_user.fp_token_expire = datetime.datetime.now() new_user.save() response = test_app.get("%s?%s" % (path, get_params), status=404) assert_equal(response.status, '404 Not Found') - new_user['fp_token_expire'] = real_token_expiration + new_user.fp_token_expire = real_token_expiration new_user.save() ## Verify step 1 of password-change works -- can see form to change password -- cgit v1.2.3 From 4ec5717a173803e6ccebf7fced1e5127c8b52caa Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 21 Nov 2011 12:56:26 +0100 Subject: Dot-Notation: tests/test_edit.py convert tests/test_edit.py over to Dot-Notation. It only accesses the User object. --- mediagoblin/tests/test_edit.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index c29ddfe9..0cf71e9b 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -44,7 +44,7 @@ def test_change_password(test_app): # test_user has to be fetched again in order to have the current values test_user = mg_globals.database.User.one({'username': 'chris'}) - assert bcrypt_check_password('123456', test_user['pw_hash']) + assert bcrypt_check_password('123456', test_user.pw_hash) # test that the password cannot be changed if the given old_password # is wrong @@ -59,7 +59,7 @@ def test_change_password(test_app): test_user = mg_globals.database.User.one({'username': 'chris'}) - assert not bcrypt_check_password('098765', test_user['pw_hash']) + assert not bcrypt_check_password('098765', test_user.pw_hash) @setup_fresh_app @@ -76,8 +76,8 @@ def change_bio_url(test_app): test_user = mg_globals.database.User.one({'username': 'chris'}) - assert test_user['bio'] == u'I love toast!' - assert test_user['url'] == u'http://dustycloud.org/' + assert test_user.bio == u'I love toast!' + assert test_user.url == u'http://dustycloud.org/' # test changing the bio and the URL inproperly too_long_bio = 150 * 'T' + 150 * 'o' + 150 * 'a' + 150 * 's' + 150* 't' -- cgit v1.2.3 From 0547843020643febbdcbfa33377fd48f92c568c8 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 14 Nov 2011 18:39:18 +0100 Subject: Dot-Notation for MediaEntry.created --- mediagoblin/templates/mediagoblin/user_pages/processing_panel.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html index 9b4adeb5..307a0027 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html +++ b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html @@ -37,7 +37,7 @@ {% for media_entry in processing_entries %}

- + {% endfor %} -- cgit v1.2.3 From 1ceb4fc8682dd00c15376b75a3d9222cac6fb5bd Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 21 Nov 2011 20:18:38 +0100 Subject: Dot-Notation for MediaEntry.uploader --- mediagoblin/db/models.py | 6 +++--- mediagoblin/edit/lib.py | 2 +- mediagoblin/edit/views.py | 4 ++-- mediagoblin/submit/views.py | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 795cba6a..f1f56dd1 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -281,7 +281,7 @@ class MediaEntry(Document): Provide a url to the previous entry from this user, if there is one """ cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id}, - 'uploader': self['uploader'], + 'uploader': self.uploader, 'state': 'processed'}).sort( '_id', ASCENDING).limit(1) if cursor.count(): @@ -294,7 +294,7 @@ class MediaEntry(Document): Provide a url to the next entry from this user, if there is one """ cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id}, - 'uploader': self['uploader'], + 'uploader': self.uploader, 'state': 'processed'}).sort( '_id', DESCENDING).limit(1) @@ -304,7 +304,7 @@ class MediaEntry(Document): media=unicode(cursor[0]['slug'])) def get_uploader(self): - return self.db.User.find_one({'_id': self['uploader']}) + return self.db.User.find_one({'_id': self.uploader}) def get_fail_exception(self): """ diff --git a/mediagoblin/edit/lib.py b/mediagoblin/edit/lib.py index 4ce2d42f..a199cbf7 100644 --- a/mediagoblin/edit/lib.py +++ b/mediagoblin/edit/lib.py @@ -17,7 +17,7 @@ def may_edit_media(request, media): """Check, if the request's user may edit the media details""" - if media['uploader'] == request.user._id: + if media.uploader == request.user._id: return True if request.user.is_admin: return True diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 4e8c3686..0b84f639 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -57,7 +57,7 @@ def edit_media(request, media): # and userid. existing_user_slug_entries = request.db.MediaEntry.find( {'slug': request.POST['slug'], - 'uploader': media['uploader'], + 'uploader': media.uploader, '_id': {'$ne': media._id}}).count() if existing_user_slug_entries: @@ -79,7 +79,7 @@ def edit_media(request, media): location=media.url_for_self(request.urlgen)) if request.user.is_admin \ - and media['uploader'] != request.user._id \ + and media.uploader != request.user._id \ and request.method != 'POST': messages.add_message( request, messages.WARNING, diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 6beb6b18..64d4b541 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -64,7 +64,7 @@ def submit_start(request): entry['description_html'] = cleaned_markdown_conversion( entry['description']) - entry['uploader'] = request.user['_id'] + entry.uploader = request.user._id # Process the user's folksonomy "tags" entry['tags'] = convert_to_tag_list_of_dicts( diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 89fd104d..d7d510d4 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -115,7 +115,7 @@ - + @@ -57,7 +57,7 @@ {% for media_entry in failed_entries %} - + diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index e1b8cc9b..65ff09a4 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -33,9 +33,9 @@ - {% if entry['title'] %} + {% if entry.title %}
- {{ entry['title'] }} + {{ entry.title }} {% endif %} {% endfor %} -- cgit v1.2.3 From 5da0bf901be7551e9708dd248319ff57d7b29a57 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 4 Dec 2011 19:57:42 +0100 Subject: Dot-Notation for MediaEntry.slug --- mediagoblin/db/models.py | 12 ++++++------ mediagoblin/edit/views.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 7af76b9f..aeee69dd 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -249,13 +249,13 @@ class MediaEntry(Document): pass def generate_slug(self): - self['slug'] = url.slugify(self.title) + self.slug = url.slugify(self.title) duplicate = mg_globals.database.media_entries.find_one( - {'slug': self['slug']}) + {'slug': self.slug}) if duplicate: - self['slug'] = "%s-%s" % (self._id, self['slug']) + self.slug = "%s-%s" % (self._id, self.slug) def url_for_self(self, urlgen): """ @@ -269,7 +269,7 @@ class MediaEntry(Document): return urlgen( 'mediagoblin.user_pages.media_home', user=uploader.username, - media=self['slug']) + media=self.slug) else: return urlgen( 'mediagoblin.user_pages.media_home', @@ -287,7 +287,7 @@ class MediaEntry(Document): if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', user=self.get_uploader().username, - media=unicode(cursor[0]['slug'])) + media=unicode(cursor[0].slug)) def url_to_next(self, urlgen): """ @@ -301,7 +301,7 @@ class MediaEntry(Document): if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', user=self.get_uploader().username, - media=unicode(cursor[0]['slug'])) + media=unicode(cursor[0].slug)) def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index feda397d..51661a21 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -44,7 +44,7 @@ def edit_media(request, media): defaults = dict( title=media.title, - slug=media['slug'], + slug=media.slug, description=media['description'], tags=media_tags_as_string(media['tags'])) @@ -72,7 +72,7 @@ def edit_media(request, media): media['description_html'] = cleaned_markdown_conversion( media['description']) - media['slug'] = unicode(request.POST['slug']) + media.slug = unicode(request.POST['slug']) media.save() return exc.HTTPFound( -- cgit v1.2.3 From 1d9399660416fe5a04d322303986434815bc15f0 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 4 Dec 2011 20:06:42 +0100 Subject: Dot-Notation for MediaEntry.description(_html) --- mediagoblin/edit/views.py | 8 ++++---- mediagoblin/submit/views.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 51661a21..4cb98c15 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -45,7 +45,7 @@ def edit_media(request, media): defaults = dict( title=media.title, slug=media.slug, - description=media['description'], + description=media.description, tags=media_tags_as_string(media['tags'])) form = forms.EditForm( @@ -65,12 +65,12 @@ def edit_media(request, media): _(u'An entry with that slug already exists for this user.')) else: media.title = unicode(request.POST['title']) - media['description'] = unicode(request.POST.get('description')) + media.description = unicode(request.POST.get('description')) media['tags'] = convert_to_tag_list_of_dicts( request.POST.get('tags')) - media['description_html'] = cleaned_markdown_conversion( - media['description']) + media.description_html = cleaned_markdown_conversion( + media.description) media.slug = unicode(request.POST['slug']) media.save() diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1805e293..8da71341 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -60,9 +60,9 @@ def submit_start(request): unicode(request.POST['title']) or unicode(splitext(filename)[0])) - entry['description'] = unicode(request.POST.get('description')) - entry['description_html'] = cleaned_markdown_conversion( - entry['description']) + entry.description = unicode(request.POST.get('description')) + entry.description_html = cleaned_markdown_conversion( + entry.description) entry.uploader = request.user._id -- cgit v1.2.3 From f4ee839939e4215820df3132b62c51f721510f77 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 4 Dec 2011 20:16:01 +0100 Subject: Dot-Notation for MediaEntry.media_type --- mediagoblin/processing.py | 4 ++-- mediagoblin/submit/views.py | 2 +- mediagoblin/user_pages/views.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index 89c4ac89..7dd5cc7d 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -55,8 +55,8 @@ class ProcessMedia(Task): # Try to process, and handle expected errors. try: - #__import__(entry['media_type']) - manager = get_media_manager(entry['media_type']) + #__import__(entry.media_type) + manager = get_media_manager(entry.media_type) manager['processor'](entry) except BaseProcessingFail, exc: mark_entry_failed(entry._id, exc) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 8da71341..4e4c7c43 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -55,7 +55,7 @@ def submit_start(request): # create entry and save in database entry = request.db.MediaEntry() entry['_id'] = ObjectId() - entry['media_type'] = unicode(media_type) + entry.media_type = unicode(media_type) entry.title = ( unicode(request.POST['title']) or unicode(splitext(filename)[0])) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index dc549567..87b82c74 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -122,7 +122,7 @@ def media_home(request, media, page, **kwargs): comment_form = user_forms.MediaCommentForm(request.POST) - media_template_name = get_media_manager(media['media_type'])['display_template'] + media_template_name = get_media_manager(media.media_type)['display_template'] return render_to_response( request, -- cgit v1.2.3 From ddc1cae9ea4c80415557ec0408a56a3a1c60423b Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 4 Dec 2011 20:26:36 +0100 Subject: Dot-Notation for MediaEntry.media_data --- mediagoblin/db/models.py | 4 ++-- mediagoblin/media_types/video/processing.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index aeee69dd..569c3600 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -131,7 +131,7 @@ class MediaEntry(Document): For example, images might contain some EXIF data that's not appropriate to other formats. You might store it like: - mediaentry['media_data']['exif'] = { + mediaentry.media_data['exif'] = { 'manufacturer': 'CASIO', 'model': 'QV-4000', 'exposure_time': .659} @@ -139,7 +139,7 @@ class MediaEntry(Document): Alternately for video you might store: # play length in seconds - mediaentry['media_data']['play_length'] = 340 + mediaentry.media_data['play_length'] = 340 ... so what's appropriate here really depends on the media type. diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 6125e49c..93f16e86 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -75,7 +75,7 @@ def process_video(entry): entry['media_files']['webm_640'] = medium_filepath # Save the width and height of the transcoded video - entry['media_data']['video'] = { + entry.media_data['video'] = { u'width': transcoder.dst_data.videowidth, u'height': transcoder.dst_data.videoheight} -- cgit v1.2.3 From 4535f7597f112443d8997bbd6b8a445612c2440d Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 6 Dec 2011 23:05:47 +0100 Subject: Bug 681 - Comments from reviewing the new video merge in mediagoblin.media_types and submodules - Moved VideoThumbnailer.errors initialization to VideoThumbnailer.__init__ - Cleaned up the image.processing imports - Removed default ``None`` from get_media_manager(_media_type) in mediagoblin.views - Removed media_types import - Removed sys import, and passing of sys to root.html template --- mediagoblin/media_types/__init__.py | 21 ++++++++++++++++++--- mediagoblin/media_types/image/processing.py | 9 ++------- mediagoblin/media_types/video/transcoders.py | 4 ++-- mediagoblin/views.py | 6 +----- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 61786562..4fa56bc3 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -30,7 +30,7 @@ class InvalidFileType(Exception): def get_media_types(): """ - Generator that returns the available media types + Generator, yields the available media types """ for media_type in mg_globals.app_config['media_types']: yield media_type @@ -38,7 +38,7 @@ def get_media_types(): def get_media_managers(): ''' - Generator that returns all available media managers + Generator, yields all enabled media managers ''' for media_type in get_media_types(): __import__(media_type) @@ -46,20 +46,35 @@ def get_media_managers(): yield media_type, sys.modules[media_type].MEDIA_MANAGER -def get_media_manager(_media_type = None): +def get_media_manager(_media_type): + ''' + Get the MEDIA_MANAGER based on a media type string + + Example:: + get_media_type('mediagoblin.media_types.image') + ''' + if not _media_type: + return False + for media_type, manager in get_media_managers(): if media_type in _media_type: return manager def get_media_type_and_manager(filename): + ''' + Get the media type and manager based on a filename + ''' for media_type, manager in get_media_managers(): if filename.find('.') > 0: + # Get the file extension ext = os.path.splitext(filename)[1].lower() else: raise InvalidFileType( _('Could not find any file extension in "{filename}"').format( filename=filename)) + # Omit the dot from the extension and match it against + # the media manager if ext[1:] in manager['accepted_extensions']: return media_type, manager diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 5b8259fc..e493eb2b 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -17,15 +17,10 @@ import Image import os -from celery.task import Task -from celery import registry - -from mediagoblin.db.util import ObjectId from mediagoblin import mg_globals as mgg -from mediagoblin.processing import BaseProcessingFail, \ - mark_entry_failed, BadMediaFail, create_pub_filepath, THUMB_SIZE, \ - MEDIUM_SIZE +from mediagoblin.processing import BadMediaFail, \ + create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE ################################ # Media processing initial steps diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index d7ed14ca..7071b887 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -74,14 +74,14 @@ class VideoThumbnailer: buffer_probes = {} - errors = [] - def __init__(self, source_path, dest_path): ''' Set up playbin pipeline in order to get video properties. Initializes and runs the gobject.MainLoop() ''' + self.errors = [] + self.source_path = source_path self.dest_path = dest_path diff --git a/mediagoblin/views.py b/mediagoblin/views.py index cd6aba9b..1e1db6c3 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -14,14 +14,11 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import sys - from mediagoblin import mg_globals from mediagoblin.tools.pagination import Pagination from mediagoblin.tools.response import render_to_response from mediagoblin.db.util import DESCENDING from mediagoblin.decorators import uses_pagination -from mediagoblin import media_types @@ -36,8 +33,7 @@ def root_view(request, page): request, 'mediagoblin/root.html', {'media_entries': media_entries, 'allow_registration': mg_globals.app_config["allow_registration"], - 'pagination': pagination, - 'sys': sys}) + 'pagination': pagination}) def simple_template_render(request): -- cgit v1.2.3 From 3f45d9fbe8ed8cad2f3fc9a8e2a68a77ace0a958 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 7 Dec 2011 22:15:48 +0100 Subject: Move author text, "By X", to the sidebar --- mediagoblin/templates/mediagoblin/user_pages/media.html | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 7434664c..95197c15 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -55,12 +55,8 @@

{{ media.description_html }}

{% endautoescape %}

- {% trans date=media.created.strftime("%Y-%m-%d"), - user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader().username), - username=media.get_uploader().username -%} - By {{ username }} on {{ date }} + {% trans date=media.created.strftime("%Y-%m-%d") -%} + {{ date }} {%- endtrans %}

@@ -114,6 +110,13 @@ {% endif %}
+ {% trans user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader().username), + username=media.get_uploader().username -%} +

❖ Browsing media by {{ username }}

+ {%- endtrans %} + {% include "mediagoblin/utils/prev_next.html" %} {% if media['uploader'] == request.user._id or -- cgit v1.2.3 From 75a12d632dd281d4d74b93f9014000a3efdc3169 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 9 Dec 2011 22:37:20 +0100 Subject: Lots of changes to media page; rearranged things, added new styles, added jquery bits, gave the comment section a refresh --- mediagoblin/static/css/base.css | 29 ++++++-- .../templates/mediagoblin/user_pages/media.html | 79 +++++++++++++--------- mediagoblin/user_pages/forms.py | 2 +- 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 12d88ffa..bbc04342 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -117,7 +117,7 @@ a.mediagoblin_logo{ /* common website elements */ -.button_action, .button_action_highlight{ +.button_action, .button_action_highlight { color: #c3c3c3; background-color: #363636; border: 1px solid; @@ -128,16 +128,16 @@ a.mediagoblin_logo{ text-decoration: none; font-style: normal; font-weight: bold; - font-size: 1em; + font-size: 16px; + cursor: pointer; } -.button_action_highlight{ +.button_action_highlight { background-color: #86D4B1; border-color: #A2DEC3 #6CAA8E #5C9179; color: #283F35; } - .button_form, .cancel_link { height: 32px; min-width: 99px; @@ -171,15 +171,15 @@ a.mediagoblin_logo{ background-image: linear-gradient(top, #D2D2D2, #aaa); } -.pagination{ +.pagination { text-align: center; } -.pagination_arrow{ +.pagination_arrow { margin: 5px; } -.empty_space{ +.empty_space { background-image: url("../images/empty_back.png"); font-style: italic; text-align: center; @@ -187,6 +187,21 @@ text-align: center; padding-top: 70px; } +.right_align { + float: right; +} + +textarea { + border: none; + background-color: #f1f1f1; + padding: 3px; +} + +textarea#comment_content { + width: 634px; + height: 90px; +} + /* forms */ .form_box { diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 95197c15..12039473 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -22,11 +22,25 @@ {% block title %}{{ media.title }} — {{ super() }}{% endblock %} +{% block mediagoblin_head %} + +{% endblock mediagoblin_head %} + {% block mediagoblin_content %} {% if media %}
- {% block mediagoblin_media %} + {% block mediagoblin_media %} {% set display_media = request.app.public_store.file_url( media.get_display_media(media.media_files)) %} @@ -45,7 +59,7 @@ src="{{ display_media }}" alt="Image for {{ media.title }}" /> {% endif %} - {% endblock %} + {% endblock %}

@@ -59,9 +73,36 @@ {{ date }} {%- endtrans %}

-

- {% if request.user and comments.count() %} -

{% trans %}Post a comment{% endtrans %}

+ + {% if media['uploader'] == request.user._id or + request.user['is_admin'] %} +

+ {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', + user= media.get_uploader().username, + media= media._id) %} + {% trans %}Edit{% endtrans %} +

+

+ {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', + user= media.get_uploader().username, + media= media._id) %} + {% trans %}Delete{% endtrans %} +

+ {% endif %} + +

{% trans %}23 comments{% endtrans %}

+ {# 0 comments. Be the first to add one! #} + {% if request.user %} + +

{% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %}

+ {{ wtforms_util.render_divs(comment_form) }} +
+ + {{ csrf_token }} +
+ {% endif %} {% if comments %} {% for comment in comments %} @@ -90,18 +131,6 @@
{% endfor %} - {% if request.user %} -
- {{ wtforms_util.render_divs(comment_form) }} -
- - {{ csrf_token }} -
- - {% endif %} - {{ render_pagination(request, pagination, request.urlgen('mediagoblin.user_pages.media_home', user = media.get_uploader().username, @@ -119,22 +148,6 @@ {% include "mediagoblin/utils/prev_next.html" %} - {% if media['uploader'] == request.user._id or - request.user['is_admin'] %} -

- {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader().username, - media= media._id) %} - {% trans %}Edit{% endtrans %} -

-

- {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader().username, - media= media._id) %} - {% trans %}Delete{% endtrans %} -

- {% endif %} - {% if media.attachment_files|count %}

Attachments

    diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 301f1f0a..e04fd559 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -21,7 +21,7 @@ from mediagoblin.tools.translate import fake_ugettext_passthrough as _ class MediaCommentForm(wtforms.Form): comment_content = wtforms.TextAreaField( - _('Comment'), + _(''), [wtforms.validators.Required()]) -- cgit v1.2.3 From 9c6d8d77fba60a355b2b60d4c0a48de8bd58f2fa Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 9 Dec 2011 22:45:26 +0100 Subject: Only apply textarea style to comment box --- mediagoblin/static/css/base.css | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index bbc04342..89988c8b 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -191,15 +191,12 @@ text-align: center; float: right; } -textarea { - border: none; - background-color: #f1f1f1; - padding: 3px; -} - textarea#comment_content { width: 634px; height: 90px; + border: none; + background-color: #f1f1f1; + padding: 3px; } /* forms */ -- cgit v1.2.3 From 8f25d91b1ee8672afa2ebdfb9c938dd1e3439149 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 9 Dec 2011 22:48:20 +0100 Subject: Open Markdown link in new windows; I know _blank is sometimes frowned upon but it may be useful here --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 12039473..000b1b80 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -96,7 +96,7 @@
    -

    {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %}

    +

    {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %}

    {{ wtforms_util.render_divs(comment_form) }}
    -- cgit v1.2.3 From de73724066d0fb49b77b53332c80d3cbc5f59221 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 9 Dec 2011 23:47:11 +0100 Subject: Change wording in tags.html --- mediagoblin/templates/mediagoblin/utils/tags.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index c7dfc8eb..1f587411 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,12 +17,12 @@ #} {% block tags_content -%} -

    {% trans %}Tagged with{% endtrans %} +

    {% trans %}View more media tagged with{% endtrans %} {% for tag in media.tags %} {% if loop.last %} {# the 'and' should only appear if there is more than one tag #} {% if media.tags|length > 1 %} - {% trans %}and{% endtrans %} + {% trans %}or{% endtrans %} {% endif %} Previous page - {% trans %}Newer{% endtrans %} + {% trans %}← Newer{% endtrans %} {% endif %} {% if pagination.has_next %} {% set next_url = pagination.get_page_url_explicit( base_url, get_params, pagination.page + 1) %} - {% trans %}Older{% endtrans %} - Next page + {% trans %}Older →{% endtrans %} {% endif %}
    {% trans %}Go to page:{% endtrans %} -- cgit v1.2.3 From b27067371d6cb99cf21c7c0970b664e970d9a22d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 10 Dec 2011 21:03:18 +0100 Subject: Style changes for media_uploader (now media_specs); removed margins from button_action buttons --- mediagoblin/static/css/base.css | 16 ++++++++++------ mediagoblin/templates/mediagoblin/user_pages/media.html | 16 +++++----------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 89988c8b..c1239abb 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -96,6 +96,7 @@ input, textarea { a.mediagoblin_logo{ color: #fff; font-weight: bold; + margin-right: 8px; } .mediagoblin_footer { @@ -123,7 +124,6 @@ a.mediagoblin_logo{ border: 1px solid; border-color: #464646 #2B2B2B #252525; border-radius: 4px; - margin: 8px; padding: 3px 8px; text-decoration: none; font-style: normal; @@ -285,24 +285,28 @@ textarea#comment_content { /* media detail */ -h2.media_title{ +h2.media_title { margin-bottom: 0px; } -p.media_uploader{ +p.media_specs { font-size: 0.9em; + border-top: 1px solid #222; + border-bottom: 1px solid #222; + padding: 10px 0px; + color: #888; } /* icons */ -img.media_icon{ +img.media_icon { margin: 0 4px; vertical-align: sub; } /* navigation */ -.navigation_button{ +.navigation_button { width: 135px; display: block; float: left; @@ -317,7 +321,7 @@ img.media_icon{ margin: 0 0 20px } -.navigation_left{ +.navigation_left { margin-right: 6px; } diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 000b1b80..1a19443c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -68,28 +68,22 @@ {% autoescape False %}

    {{ media.description_html }}

    {% endautoescape %} -

    +

    {% trans date=media.created.strftime("%Y-%m-%d") -%} - {{ date }} + Added on {{ date }}. Licensed under an X license. {%- endtrans %} -

    - - {% if media['uploader'] == request.user._id or + {% if media['uploader'] == request.user._id or request.user['is_admin'] %} -

    {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.get_uploader().username, media= media._id) %} {% trans %}Edit{% endtrans %} -

    -

    {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', user= media.get_uploader().username, media= media._id) %} {% trans %}Delete{% endtrans %} -

    - {% endif %} - + {% endif %} +

    {% trans %}23 comments{% endtrans %}

    {# 0 comments. Be the first to add one! #} {% if request.user %} -- cgit v1.2.3 From ed1840ee64eca680581fd764369f81063dd72831 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 07:35:47 -0600 Subject: Mark "newer/older" buttons for translation --- mediagoblin/templates/mediagoblin/utils/prev_next.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 3363891b..b0c01963 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -25,23 +25,23 @@ {# There are no previous entries for the very first media entry #} {% if prev_entry_url %} - ← newer + ← {% trans %}newer{% endtrans %} {% else %} {# This is the first entry. display greyed-out 'previous' image #} {% endif %} {# Likewise, this could be the very last media entry #} {% if next_entry_url %} - older → + {% trans %}older{% endtrans %} → {% else %} {# This is the last entry. display greyed-out 'next' image #} {% endif %}
    -- cgit v1.2.3 From 23caf305f28d1e8baf5196703ac316cfe4e740dc Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 08:10:10 -0600 Subject: Allow administrators to disable keeping the original. That's the new default! --- mediagoblin/config_spec.ini | 5 +++++ mediagoblin/media_types/video/processing.py | 29 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 13ce925e..eb22bc1b 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -61,6 +61,11 @@ storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage base_dir = string(default="%(here)s/user_dev/media/queue") +# Should we keep the original file? +[media_type:mediagoblin.media_types.video] +keep_original = boolean(default=False) + + [beaker.cache] type = string(default="file") data_dir = string(default="%(here)s/user_dev/beaker/cache/data") diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 6125e49c..c0a3fb67 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -41,6 +41,8 @@ def process_video(entry): and attaches callbacks to that child process, hopefully, the entry-complete callback will be called when the video is done. """ + video_config = mgg.global_config['media_type:mediagoblin.media_types.video'] + workbench = mgg.workbench_manager.create_workbench() queued_filepath = entry['queued_media_file'] @@ -94,25 +96,24 @@ def process_video(entry): entry['media_files']['thumb'] = thumbnail_filepath + if video_config['keep_original']: + # Push original file to public storage + queued_file = file(queued_filename, 'rb') - # Push original file to public storage - queued_file = file(queued_filename, 'rb') - - with queued_file: - original_filepath = create_pub_filepath( - entry, - queued_filepath[-1]) + with queued_file: + original_filepath = create_pub_filepath( + entry, + queued_filepath[-1]) - with mgg.public_store.get_file(original_filepath, 'wb') as \ - original_file: - _log.debug('Saving original...') - original_file.write(queued_file.read()) - _log.debug('Saved original') + with mgg.public_store.get_file(original_filepath, 'wb') as \ + original_file: + _log.debug('Saving original...') + original_file.write(queued_file.read()) + _log.debug('Saved original') - entry['media_files']['original'] = original_filepath + entry['media_files']['original'] = original_filepath mgg.queue_store.delete_file(queued_filepath) - # Save the MediaEntry entry.save() -- cgit v1.2.3 From 438dd8cd8f79f32609cce15d70ef6a93f1531a3b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 08:13:46 -0600 Subject: Add a note on how to up the upload size limit --- docs/source/deploying.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index 70b1a6af..14b2c9cf 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -196,6 +196,9 @@ this ``nginx.conf`` file should be modeled on the following: :: # This is the section you should read ##################################### + # Change this to update the upload size limit for your users + client_max_body_size 8m; + server_name mediagoblin.example.org www.mediagoblin.example.org; access_log /var/log/nginx/mediagoblin.example.access.log; error_log /var/log/nginx/mediagoblin.example.error.log; -- cgit v1.2.3 From c36c3782737ef6d27137275ab98dbec49d7cd9ba Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 08:15:16 -0600 Subject: Removed extraneous whitespace from video.html --- mediagoblin/templates/mediagoblin/media_displays/video.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index 5b8ec789..5ef1a782 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -21,5 +21,5 @@ {%- endtrans -%}

    - {% endif %} + {% endif %} {% endblock %} -- cgit v1.2.3 From 528c8b8fabe7036b63c44d93adc9e7b068bbcd91 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 09:46:23 -0500 Subject: Tweak runtests to be more helpful If nose isn't installed, then runtests.sh says it can't find nosetests and exits, but doesn't tell you what you need to do to fix the situation. This fixes that. --- runtests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtests.sh b/runtests.sh index 1dfbf093..4265326c 100755 --- a/runtests.sh +++ b/runtests.sh @@ -23,7 +23,8 @@ elif which nosetests > /dev/null; then echo "Using nosetests from \$PATH"; export NOSETESTS="nosetests"; else - echo "No nosetests found, exiting! X_X"; + echo "nosetests not found. X_X"; + echo "Please install 'nose'. Exiting."; exit 1 fi -- cgit v1.2.3 From 5b9ef3d58f7b8f8669c5cfb7c4938e01d297ed10 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 09:53:41 -0500 Subject: Update README * tweaked some language * fixed some statements that aren't correct anymore --- README | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README b/README index 0aba179b..07f9a094 100644 --- a/README +++ b/README @@ -8,19 +8,18 @@ What is GNU MediaGoblin? * Initially, a place to store all your photos that’s as awesome as, if not more awesome than, existing network services (Flickr, SmugMug, Picasa, etc) -* Later, a place for all sorts of media, such as video, music, etc hosting. -* Federated with OStatus! * Customizable! * A place for people to collaborate and show off original and derived - creations. Free, as in freedom. We’re a GNU project in the making, - afterall. + creations. Free, as in freedom. We’re a GNU project after all. +* Later, a place for all sorts of media, such as video, music, etc hosting. +* Later, federated with OStatus! Is it ready for me to use? ========================== -Not yet! We're working on it and we hope to have a usable system by -September / October 2011. +Yes! But with caveats. The software is usable and there are instances +running, but it's still in its early stages. Can I help/hang out/participate/whisper sweet nothings in your ear? @@ -33,9 +32,9 @@ hang out, see `our Join page `_ Where is the documentation? =========================== -The beginnings of a user manual is located in the ``docs/`` directory -in HTML, Texinfo, and source (Restructured Text) forms. It's also -available online at http://docs.mediagoblin.org/ in HTML form. +The beginnings of a site administration manual is located in the ``docs/`` +directory in HTML, Texinfo, and source (Restructured Text) forms. It's +also available online at http://docs.mediagoblin.org/ in HTML form. Contributor/developer documentation as well as documentation on the project processes and infrastructure is located on -- cgit v1.2.3 From 78dc055e22b55253ed395d616a6ce5635ef91499 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 10:17:03 -0500 Subject: Add some documentation to lazyserver.sh I had no idea what it did, so I asked and tossed the answer at the top of the script. --- lazyserver.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lazyserver.sh b/lazyserver.sh index 63818a6a..4ca073b5 100755 --- a/lazyserver.sh +++ b/lazyserver.sh @@ -16,6 +16,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +# +# This runs Mediagoblin using Paste with Celery set to always eager mode. +# + if [ "$1" = "-h" ] then echo "$0 [-h] [-c paste.ini] [ARGS_to_paster ...]" -- cgit v1.2.3 From 076bf0cf28bae50dcd0f9e79e5c9e6501f1ad04a Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 10:20:05 -0500 Subject: Doc updates * fixed some language * fixed some consistency issues * fixed some 80-line-width issues * fixed some typos and markup problems --- docs/source/configuration.rst | 42 +++---- docs/source/deploying.rst | 195 +++++++++++++++++---------------- docs/source/foreword.rst | 8 +- docs/source/production-deployments.rst | 29 +++-- 4 files changed, 142 insertions(+), 132 deletions(-) diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index 093f492c..1e22ad2d 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -19,13 +19,13 @@ mediagoblin.ini tweak settings for MediaGoblin, you'll usually tweak them here. paste.ini - This is primarily a server configuration file, on the python side - (specifically, on the wsgi side, via `paste deploy + This is primarily a server configuration file, on the Python side + (specifically, on the WSGI side, via `paste deploy `_ / `paste script `_). It also sets up some middleware that you can mostly ignore, except to configure sessions... more on that later. If you are adding a different - python server other than fastcgi / plain http, you might configure + Python server other than fastcgi / plain HTTP, you might configure it here. You probably won't need to change this file very much. @@ -47,19 +47,23 @@ Let's assume you're doing the virtualenv setup described elsewhere in this manual, and you need to make local tweaks to the config files. How do you do that? Let's see. -To make changes to mediagoblin.ini: +To make changes to mediagoblin.ini :: - cp mediagoblin.ini mediagoblin_local.ini + cp mediagoblin.ini mediagoblin_local.ini -To make changes to paste.ini: - cp paste.ini paste_local.ini +To make changes to paste.ini :: + + cp paste.ini paste_local.ini From here you should be able to make direct adjustments to the files, and most of the commands described elsewhere in this manual will "notice" your local config files and use those instead of the non-local version. -(Note that all commands provide a way to pass in a specific config -file also, usually by a -cf flag.) +.. note:: + + Note that all commands provide a way to pass in a specific config + file also, usually by a ``-cf`` flag. + Common changes ============== @@ -69,9 +73,9 @@ Enabling email notifications You'll almost certainly want to enable sending emails. By default, MediaGoblin doesn't really do this... for the sake of developer -convenience, it runs in "email debug mode". Change this: +convenience, it runs in "email debug mode". Change this:: - email_debug_mode = false + email_debug_mode = false You can (and should) change the "from" email address by setting ``email_sender_address``. @@ -82,21 +86,21 @@ If you have more custom SMTP settings, you also have the following options at your disposal, which are all optional, and do exactly what they sound like. - - email_smtp_host - - email_smtp_port - - email_smtp_user - - email_smtp_pass +- email_smtp_host +- email_smtp_port +- email_smtp_user +- email_smtp_pass All other configuration changes ------------------------------- -To be perfectly honest, there are quite a few options and I'm not -going to be able to get to documanting them all in time for 0.1.0. +To be perfectly honest, there are quite a few options and we haven't had +time to document them all So here's a cop-out section saying that if you get into trouble, hop -onto IRC and we'll help you out: +onto IRC and we'll help you out:: - #mediagoblin on irc.freenode.net + #mediagoblin on irc.freenode.net Celery ====== diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index 14b2c9cf..4aded2e6 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -11,9 +11,11 @@ it simple with some assumptions and use a setup that combines mediagoblin + virtualenv + fastcgi + nginx on a .deb or .rpm based GNU/Linux distro. -Note: these tools are for administrators wanting to deploy a fresh -install. If instead you want to join in as a contributor, see our -`Hacking HOWTO `_ instead. +.. note:: + + These tools are for site administrators wanting to deploy a fresh + install. If instead you want to join in as a contributor, see our + `Hacking HOWTO `_ instead. Prepare System -------------- @@ -33,12 +35,15 @@ MediaGoblin has the following core dependencies: On a DEB-based system (e.g Debian, gNewSense, Trisquel, Ubuntu, and derivatives) issue the following command: :: - sudo apt-get install mongodb git-core python python-dev python-lxml python-imaging python-virtualenv + sudo apt-get install mongodb git-core python python-dev python-lxml \ + python-imaging python-virtualenv On a RPM-based system (e.g. Fedora, RedHat, and derivatives) issue the following command: :: - yum install mongodb-server python-paste-deploy python-paste-script git-core python python-devel python-lxml python-imaging python-virtualenv + yum install mongodb-server python-paste-deploy python-paste-script \ + git-core python python-devel python-lxml python-imaging \ + python-virtualenv Configure MongoDB ~~~~~~~~~~~~~~~~~ @@ -46,10 +51,11 @@ Configure MongoDB After installing MongoDB some preliminary database configuration may be necessary. -Ensure that MongoDB `journaling `_ -is enabled. Journaling is enabled by default in version 2.0 and later -64-bit MongoDB instances. Check your deployment, and consider enabling -journaling if you're running 32-bit systems or earlier version. +Ensure that MongoDB `journaling +`_ is enabled. Journaling +is enabled by default in version 2.0 and later 64-bit MongoDB instances. +Check your deployment, and consider enabling journaling if you're running +32-bit systems or earlier version. .. warning:: @@ -77,41 +83,42 @@ create "system account" or dedicated service user. Ensure that it is not possible to log in to your system with as this user. You should create a working directory for MediaGoblin. This document -assumes your local git repository will be located at ``/srv/mediagoblin.example.org/mediagoblin/`` -for this documentation. Substitute your prefer ed local deployment path -as needed. +assumes your local git repository will be located at +``/srv/mediagoblin.example.org/mediagoblin/`` for this documentation. +Substitute your prefer ed local deployment path as needed. This document assumes that all operations are performed as this user. To drop privileges to this user, run the following command: :: + su - [mediagoblin] - su - [mediagoblin]`` - -Where, "``[mediagoblin]`` is the username of the system user that will +Where, "``[mediagoblin]``" is the username of the system user that will run MediaGoblin. Install MediaGoblin and Virtualenv ---------------------------------- -As of |version|, MediaGoblin has a rapid development pace. As a result -the following instructions recommend installing from the ``master`` -branch of the git repository. Eventually production deployments will -want to transition to running from more consistent releases. +.. note:: + + As of |version|, MediaGoblin has a rapid development pace. As a result + the following instructions recommend installing from the ``master`` + branch of the git repository. Eventually production deployments will + want to transition to running from more consistent releases. Issue the following commands, to create and change the working -directory. Modify these commands to reflect your own environment: :: +directory. Modify these commands to reflect your own environment:: - mkdir -p /srv/mediagoblin.example.org/ - cd /srv/mediagoblin.example.org/ + mkdir -p /srv/mediagoblin.example.org/ + cd /srv/mediagoblin.example.org/ -Clone the MediaGoblin repository: :: +Clone the MediaGoblin repository:: - git clone git://gitorious.org/mediagoblin/mediagoblin.git + git clone git://gitorious.org/mediagoblin/mediagoblin.git -And setup the in-package virtualenv: :: +And setup the in-package virtualenv:: - cd mediagoblin - virtualenv . && ./bin/python setup.py develop + cd mediagoblin + virtualenv . && ./bin/python setup.py develop .. note:: @@ -127,16 +134,16 @@ more reliable and considerably easier to configure and illustrate. If you're familiar with Python packaging you may consider deploying with your preferred the method. -Assuming you are going to deploy with fastcgi, you should also install -flup: :: +Assuming you are going to deploy with FastCGI, you should also install +flup:: - ./bin/easy_install flup + ./bin/easy_install flup This concludes the initial configuration of the development environment. In the future, if at any point you want update your -codebase, you should also run: :: +codebase, you should also run:: - ./bin/python setup.py develop --upgrade && ./bin/gmg migrate. + ./bin/python setup.py develop --upgrade && ./bin/gmg migrate. Deploy MediaGoblin Services --------------------------- @@ -145,9 +152,9 @@ Test the Server ~~~~~~~~~~~~~~~ At this point MediaGoblin should be properly installed. You can -test the deployment with the following command: :: +test the deployment with the following command:: - ./lazyserver.sh --server-name=broadcast + ./lazyserver.sh --server-name=broadcast You should be able to connect to the machine on port 6543 in your browser to confirm that the service is operable. @@ -156,7 +163,7 @@ Connect the Webserver to MediaGoblin with FastCGI ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This section describes how to configure MediaGoblin to work via -fastcgi. Our configuration example will use nginx, however, you may +FastCGI. Our configuration example will use nginx, however, you may use any webserver of your choice as long as it supports the FastCGI protocol. If you do not already have a web server, consider nginx, as the configuration files may be more clear than the @@ -166,78 +173,78 @@ Create a configuration file at ``/srv/mediagoblin.example.org/nginx.conf`` and create a symbolic link into a directory that will be included in your ``nginx`` configuration (e.g. "``/etc/nginx/sites-enabled`` or ``/etc/nginx/conf.d``) with -one of the following commands (as the root user:) :: +one of the following commands (as the root user):: - ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/conf.d/ - ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/sites-enabled/ + ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/conf.d/ + ln -s /srv/mediagoblin.example.org/nginx.conf /etc/nginx/sites-enabled/ Modify these commands and locations depending on your preferences and the existing configuration of your nginx instance. The contents of -this ``nginx.conf`` file should be modeled on the following: :: - - server { - ################################################# - # Stock useful config options, but ignore them :) - ################################################# - include /etc/nginx/mime.types; - - autoindex off; - default_type application/octet-stream; - sendfile on; - - # Gzip - gzip on; - gzip_min_length 1024; - gzip_buffers 4 32k; - gzip_types text/plain text/html application/x-javascript text/javascript text/xml text/css; - - ##################################### - # Mounting MediaGoblin stuff - # This is the section you should read - ##################################### - - # Change this to update the upload size limit for your users - client_max_body_size 8m; - - server_name mediagoblin.example.org www.mediagoblin.example.org; - access_log /var/log/nginx/mediagoblin.example.access.log; - error_log /var/log/nginx/mediagoblin.example.error.log; - - # MediaGoblin's stock static files: CSS, JS, etc. - location /mgoblin_static/ { - alias /srv/mediagoblin.example.org/mediagoblin/mediagoblin/static/; - } - - # Instance specific media: - location /mgoblin_media/ { - alias /srv/mediagoblin.example.org/mediagoblin/user_dev/media/public/; - } - - # Mounting MediaGoblin itself via fastcgi. - location / { - fastcgi_pass 127.0.0.1:26543; - include /etc/nginx/fastcgi_params; - - # our understanding vs nginx's handling of script_name vs - # path_info don't match :) - fastcgi_param PATH_INFO $fastcgi_script_name; - fastcgi_param SCRIPT_NAME ""; - } +this ``nginx.conf`` file should be modeled on the following:: + + server { + ################################################# + # Stock useful config options, but ignore them :) + ################################################# + include /etc/nginx/mime.types; + + autoindex off; + default_type application/octet-stream; + sendfile on; + + # Gzip + gzip on; + gzip_min_length 1024; + gzip_buffers 4 32k; + gzip_types text/plain text/html application/x-javascript text/javascript text/xml text/css; + + ##################################### + # Mounting MediaGoblin stuff + # This is the section you should read + ##################################### + + # Change this to update the upload size limit for your users + client_max_body_size 8m; + + server_name mediagoblin.example.org www.mediagoblin.example.org; + access_log /var/log/nginx/mediagoblin.example.access.log; + error_log /var/log/nginx/mediagoblin.example.error.log; + + # MediaGoblin's stock static files: CSS, JS, etc. + location /mgoblin_static/ { + alias /srv/mediagoblin.example.org/mediagoblin/mediagoblin/static/; + } + + # Instance specific media: + location /mgoblin_media/ { + alias /srv/mediagoblin.example.org/mediagoblin/user_dev/media/public/; + } + + # Mounting MediaGoblin itself via FastCGI. + location / { + fastcgi_pass 127.0.0.1:26543; + include /etc/nginx/fastcgi_params; + + # our understanding vs nginx's handling of script_name vs + # path_info don't match :) + fastcgi_param PATH_INFO $fastcgi_script_name; + fastcgi_param SCRIPT_NAME ""; } + } Now, nginx instance is configured to serve the MediaGoblin application. Perform a quick test to ensure that this configuration works. Restart nginx so it picks up your changes, with a command that -resembles one of the following (as the root user:) :: +resembles one of the following (as the root user):: - sudo /etc/init.d/nginx restart - sudo /etc/rc.d/nginx restart + sudo /etc/init.d/nginx restart + sudo /etc/rc.d/nginx restart Now start MediaGoblin. Use the following command sequence as an -example: :: +example:: - cd /srv/mediagoblin.example.org/mediagoblin/ - ./lazyserver.sh --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 + cd /srv/mediagoblin.example.org/mediagoblin/ + ./lazyserver.sh --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 Visit the site you've set up in your browser by visiting . You should see MediaGoblin! diff --git a/docs/source/foreword.rst b/docs/source/foreword.rst index 835a7e7a..aa27647f 100644 --- a/docs/source/foreword.rst +++ b/docs/source/foreword.rst @@ -5,14 +5,14 @@ Foreword About the MediaGoblin Manual ============================ -This is the user manual for MediaGoblin. It covers how to set up and -configure MediaGoblin and the kind of information that someone running -MediaGoblin would need to know. +This is the site administrator manual for MediaGoblin. It covers how +to set up and configure MediaGoblin and the kind of information that +someone running MediaGoblin would need to know. We have other documentation at: * http://mediagoblin.org/join/ for general "join us" information -* http://wiki.mediagoblin.org/ for our contributor-focused wiki +* http://wiki.mediagoblin.org/ for our contributor/developer-focused wiki Improving the MediaGobiin Manual diff --git a/docs/source/production-deployments.rst b/docs/source/production-deployments.rst index 7bf26169..ef0bcad6 100644 --- a/docs/source/production-deployments.rst +++ b/docs/source/production-deployments.rst @@ -4,8 +4,7 @@ Considerations for Production Deployments This document contains a number of suggestions for deploying MediaGoblin in actual production environments. Consider -":doc:`deploying`" for a basic overview of how to deploy Media -Goblin. +":doc:`deploying`" for a basic overview of how to deploy MediaGoblin. Deploy with Paste ----------------- @@ -17,11 +16,11 @@ process. Use the following command as the basis for such a script: :: - CELERY_ALWAYS_EAGER=true \ - /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ - /srv/mediagoblin.example.org/mediagoblin/paste.ini \ - --pid-file=/var/run/mediagoblin.pid \ - --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ + CELERY_ALWAYS_EAGER=true \ + /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ + /srv/mediagoblin.example.org/mediagoblin/paste.ini \ + --pid-file=/var/run/mediagoblin.pid \ + --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 The above configuration places MediaGoblin in "always eager" mode with Celery, this means that submissions of content will be processed @@ -31,11 +30,11 @@ the user will be able to immediately return to the MediaGoblin site while processing is ongoing. In these cases, use the following command as the basis for your script: :: - CELERY_ALWAYS_EAGER=false \ - /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ - /srv/mediagoblin.example.org/mediagoblin/paste.ini \ - --pid-file=/var/run/mediagoblin.pid \ - --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 \ + CELERY_ALWAYS_EAGER=false \ + /srv/mediagoblin.example.org/mediagoblin/bin/paster serve \ + /srv/mediagoblin.example.org/mediagoblin/paste.ini \ + --pid-file=/var/run/mediagoblin.pid \ + --server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543 Separate Celery --------------- @@ -57,9 +56,9 @@ such as "ASCII art" or icon sharing, you will need to run ``celeryd`` as a separate process. Build an :ref:`init script ` around the following -command. +command:: - CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd + CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd Modify your existing MediaGoblin and application init scripts, if necessary, to prevent them from starting their own ``celeryd`` @@ -77,6 +76,6 @@ distribution/operating system. In the future, MediaGoblin will provide example scripts as examples. .. TODO insert init script here -.. TODO are additional concernts ? +.. TODO are additional concerns ? .. Other Concerns .. -------------- -- cgit v1.2.3 From 9bc2fc6c6a327a79ff5ad9d8f11f5b8f968154a6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 09:44:48 -0600 Subject: Added the "Media types" chapter --- docs/source/index.rst | 1 + docs/source/media-types.rst | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 docs/source/media-types.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 6ffe0974..f9c9285d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -16,6 +16,7 @@ Table of Contents: deploying production-deployments configuration + media-types help theming codebase diff --git a/docs/source/media-types.rst b/docs/source/media-types.rst new file mode 100644 index 00000000..809efe07 --- /dev/null +++ b/docs/source/media-types.rst @@ -0,0 +1,34 @@ +.. _media-types-chapter: + +==================== +Enabling Media Types +==================== + +In the future, there will be all sorts of media types you can enable, +but in the meanwhile there's only one additional media type: video. + +First, you should probably read ":doc:`configuration`" to make sure +you know how to modify the mediagoblin config file. + +Video +===== + +To enable video, first install gstreamer and the python-gstreamer +bindings (as well as whatever gstremaer extensions you want, +good/bad/ugly). On Debianoid systems: + + sudo apt-get install python-gst0.10 + +Next, modify (and possibly copy over from mediagoblin.ini) your +mediagoblin_local.ini. Uncomment this line in the [mediagoblin] +section: + + media_types = mediagoblin.media_types.image, mediagoblin.media_types.video + +Now you should be able to submit videos, and mediagoblin should +transcode them. + +Note that you almost certainly want to separate Celery from the normal +paste process or your users will probably find that their connections +time out as the video transcodes. To set that up, check out the +":doc:`production-deployments`" section of this manual. -- cgit v1.2.3 From 57875c83c253e6e6aa08c3dbc92a3eb58664c88b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 12 Dec 2011 09:45:45 -0600 Subject: Updated translations --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11805 -> 11802 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 10 +-- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 11754 -> 11749 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 6 +- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 12093 -> 12120 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 37 ++++++----- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 11596 -> 11350 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 58 ++++++++--------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 15455 -> 15457 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 4 +- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo | Bin 11789 -> 11993 bytes mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 75 ++++++++++++---------- 12 files changed, 100 insertions(+), 90 deletions(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index f7562eaa..a01abf9c 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 7d7e0ee9..e2765357 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -17,8 +17,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:26+0000\n" -"Last-Translator: elrond \n" +"PO-Revision-Date: 2011-12-06 21:16+0000\n" +"Last-Translator: gandaro \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -185,7 +185,7 @@ msgstr "Yeeeaaah! Geschafft!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Ungültiger Dateityp." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -284,7 +284,7 @@ msgstr "Bestätigen" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Passwort wiederherstellen" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" @@ -409,7 +409,7 @@ msgstr "%(username)ss Medien" #: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Von %(username)s am %(date)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 8f37922f..3e0a84bf 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index e5c6356e..c3c29b89 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 19:15+0000\n" +"PO-Revision-Date: 2011-12-06 20:04+0000\n" "Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -252,7 +252,7 @@ msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" -"Por aldoni viajn proprajn dosierojn, fari liston de plej plaĉantaj por vi, " +"Por aldoni viajn proprajn dosierojn, fari al vi liston de la plej plaĉaj, " "ks, vi povas ensaluti je via MediaGoblina konto." #: mediagoblin/templates/mediagoblin/root.html:31 @@ -272,7 +272,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" -msgstr "Plej nove aldonitaj dosieroj" +msgstr "Laste aldonitaj dosieroj" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 msgid "Enter your new password" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index bed6aab8..0f7f4026 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 460c074c..406e1923 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -16,7 +16,7 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:49+0000\n" +"PO-Revision-Date: 2011-12-05 23:20+0000\n" "Last-Translator: manolinux \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -83,12 +83,12 @@ msgstr "" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" msgstr "" -"Debes iniciar sesión para que podamos saber a quién le enviamos el correo " +"¡Debes iniciar sesión para que podamos saber a quién le enviamos el correo " "electrónico!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "Ya haz verificado tu dirección de email!" +msgstr "¡Ya has verificado tu dirección de correo!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -113,7 +113,7 @@ msgstr "Etiquetas" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "Separar etiquetas por comas." +msgstr "Separa las etiquetas con comas." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -164,7 +164,7 @@ msgstr "Contraseña incorrecta" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "Perfil editado!" +msgstr "¡Perfil editado!" #: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" @@ -184,7 +184,7 @@ msgstr "Debes proporcionar un archivo." #: mediagoblin/submit/views.py:127 msgid "Woohoo! Submitted!" -msgstr "¡Woohoo! ¡Enviado!" +msgstr "¡Yujú! ¡Enviado!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." @@ -192,7 +192,7 @@ msgstr "Tipo de archivo inválido." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "Ups!" +msgstr "¡Ups!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" @@ -220,7 +220,7 @@ msgstr "Enviar contenido" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "Verifica tu email!" +msgstr "¡Verifica tu email!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" @@ -246,7 +246,7 @@ msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "Hola, bienvenido a este sitio de MediaGoblin!" +msgstr "Hola, ¡bienvenido a este sitio de MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" @@ -267,7 +267,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "Aún no tienes una? Es fácil!" +msgstr "¿Aún no tienes una? ¡Es fácil!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -325,10 +325,13 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" -"Hola %(username)s , para cambiar su contraseña de GNU MediaGoblin, abra la " -"siguiente URL en su navegador: %(verification_url)s Si usted piensa que " -"esto es un error, simplemente ignore este mensaje y siga siendo un duende " -"feliz!" +"Hola %(username)s,\n" +"\n" +"Para cambiar tu contraseña de GNU MediaGoblin, abre la siguiente URL en un navegador:\n" +"\n" +"%(verification_url)s \n" +"\n" +"Si piensas que esto es un error, simplemente ignora este mensaje y sigue siendo un trasgo feliz." #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" @@ -373,7 +376,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format msgid "Editing %(media_title)s" -msgstr "Edición %(media_title)s " +msgstr "Editando %(media_title)s " #: mediagoblin/templates/mediagoblin/edit/edit.html:36 #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49 @@ -442,7 +445,7 @@ msgstr "Borrar" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "Realmente deseas eliminar %(title)s ?" +msgstr "¿Realmente deseas eliminar %(title)s?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" @@ -488,7 +491,7 @@ msgstr "Es necesario un correo electrónico de verificación" #: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." -msgstr "Casi terminas! Solo falta activar la cuenta." +msgstr "¡Casi hemos terminado! Solo falta activar la cuenta." #: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 95d6d0ae..87e62764 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index daa65e0f..f1c044d2 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-12-04 23:32+0000\n" +"Last-Translator: osc \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -59,7 +59,7 @@ msgstr "Desculpe, um usuário com este nome já existe." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Desculpe, um usuário com esse email já esta cadastrado" #: mediagoblin/auth/views.py:179 msgid "" @@ -75,11 +75,11 @@ msgstr "A chave de verificação ou nome usuário estão incorretos." #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr " " #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Você já verifico seu email!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -103,7 +103,7 @@ msgstr "Etiquetas" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Separar tags por virgulas." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -129,11 +129,11 @@ msgstr "Website" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Senha antiga" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Nova Senha" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -149,15 +149,15 @@ msgstr "Você está editando um perfil de usuário. Tenha cuidado." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Senha errada" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Perfil editado!" #: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr " " #: mediagoblin/submit/forms.py:25 msgid "File" @@ -177,7 +177,7 @@ msgstr "Eba! Enviado!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Tipo de arquivo inválido." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -209,11 +209,11 @@ msgstr "Enviar mídia" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Verifique seu email!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "Sair" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -235,7 +235,7 @@ msgstr "Explorar" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Olá, bemvindo ao site de MediaGoblin." #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" @@ -247,11 +247,11 @@ msgstr "" msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." -msgstr "" +msgstr " " #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr " " #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -276,11 +276,11 @@ msgstr "Enviar" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Recuperar senha" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Mandar instruções" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -383,7 +383,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Original" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -406,7 +406,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Postar um comentário" #: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" @@ -414,15 +414,15 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Postar comentário!" #: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Editar" #: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" +msgstr "Apagar" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -556,7 +556,7 @@ msgstr "Mais velho" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Ir a página:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" @@ -564,7 +564,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "e" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -576,15 +576,15 @@ msgstr "Eu tenho certeza de que quero pagar isso" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Opa, seu comentáio estava vazio." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Seu comentário foi postado!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Você deletou a mídia." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 0e34144d..7e62de83 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index c615cde2..098ea38c 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 17:53+0000\n" +"PO-Revision-Date: 2011-12-04 19:58+0000\n" "Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -251,7 +251,7 @@ msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" -"Для добавления собственных файлов, комментирования, ведения списка любиых " +"Для добавления собственных файлов, комментирования, ведения списка любимых " "файлов и т. п. вы можете представиться с помощью вашей MediaGoblin’овой " "учётной записи." diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo index 4e71eaa7..5ab7befa 100644 Binary files a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index a44f7866..34cf1679 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-12-10 23:09+0000\n" +"Last-Translator: martin \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -57,7 +57,7 @@ msgstr "Prepáč, rovnaké prihlasovacie meno už niekto používa." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Prepáč, používateľ s rovnakou e-mailovou adresou už existuje." #: mediagoblin/auth/views.py:179 msgid "" @@ -73,11 +73,11 @@ msgstr "Nesprávny overovací kľúč alebo používateľské ID" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "Aby sme ti mohli zaslať e-mail, je potrebné byť prihláseným!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Tvoja e-mailová adresa už bola raz overená!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -101,7 +101,7 @@ msgstr "Štítky" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Oddeľ štítky pomocou čiarky." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -126,11 +126,11 @@ msgstr "Webstránka" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Staré heslo" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Nové heslo" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -146,15 +146,15 @@ msgstr "Upravuješ používateľský profil. Pristupuj opatrne." #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Nesprávne heslo" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Profil upravený!" #: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "Nebolo možné nájsť žiadnu príponu v súbore \"{filename}\"" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -174,7 +174,7 @@ msgstr "Juchú! Úspešne vložené!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Nesprávny typ súboru." #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" @@ -206,11 +206,11 @@ msgstr "Vložiť výtvor" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Over si e-mail!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "odhlásenie" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -232,23 +232,27 @@ msgstr "Preskúmať" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Ahoj, vitaj na tejto MediaGoblin stránke!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"Táto stránka používa MediaGoblin, " +"výnimočne skvelý kus softvéru na hostovanie médií." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Pre pridanie vlastných výtvorov, vloženie komentárov, uloženie svojich " +"obľúbených položiek a viac, sa musíš prihlásiť so svojim MediaGoblin účtom." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Ešte žiaden nemáš? Je to jednoduché!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -257,6 +261,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"<a class=\"header_submit_highlight\" href=\"%(register_url)s\">Vytvoriť bezplatný účet</a>\n" +" alebo\n" +" <a class=\"header_submit\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Sprevádzkovať MediaGoblin na vlastnom serveri</a>" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" @@ -273,11 +280,11 @@ msgstr "Vložiť" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Obnoviť heslo" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Zaslať inštrukcie" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." @@ -377,11 +384,11 @@ msgstr "Úprava profilu, ktorý vlastní %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Výtvory označené s: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Originál" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -390,7 +397,7 @@ msgstr "Vlož svoj výtvor" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Výtvory používateľa %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format @@ -400,27 +407,27 @@ msgstr "Výtvory, ktoré vlastní %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Od %(username)s v čase %(date)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Zaslať komentár" #: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "o" #: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Zaslať komentár!" #: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Upraviť" #: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" +msgstr "Odstrániť" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -552,15 +559,15 @@ msgstr "Staršie" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Ísť na stránku:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Označené s" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "a" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -572,19 +579,19 @@ msgstr "Jednoznačne to chcem odstrániť" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Ajaj, tvoj komentár bol prázdny." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Tvoj komentár bol zaslaný!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Výtvor bol odstránený tebou." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" +msgstr "Výtvor nebol odstránený, nakoľko chýbala tvoja konfirmácia." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." -- cgit v1.2.3 From e91a4dcb738f28fe75d0387175e97dc16ea977fb Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 10:48:24 -0500 Subject: Tweak rest formatting --- docs/source/media-types.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/media-types.rst b/docs/source/media-types.rst index 809efe07..76478143 100644 --- a/docs/source/media-types.rst +++ b/docs/source/media-types.rst @@ -15,13 +15,13 @@ Video To enable video, first install gstreamer and the python-gstreamer bindings (as well as whatever gstremaer extensions you want, -good/bad/ugly). On Debianoid systems: +good/bad/ugly). On Debianoid systems:: sudo apt-get install python-gst0.10 -Next, modify (and possibly copy over from mediagoblin.ini) your -mediagoblin_local.ini. Uncomment this line in the [mediagoblin] -section: +Next, modify (and possibly copy over from ``mediagoblin.ini``) your +``mediagoblin_local.ini``. Uncomment this line in the ``[mediagoblin]`` +section:: media_types = mediagoblin.media_types.image, mediagoblin.media_types.video -- cgit v1.2.3 From a46f645e7fc724547979ced22c8f9b7aa4ae0d51 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 11:12:59 -0500 Subject: Fix doc footer This has the correct copyright statement. --- docs/source/_templates/mg_theme/layout.html | 39 --- .../_templates/mg_theme/static/default.css_t | 299 --------------------- docs/source/_templates/mg_theme/theme.conf | 31 --- docs/source/conf.py | 7 +- docs/source/themes/mg/layout.html | 29 ++ docs/source/themes/mg/theme.conf | 5 + 6 files changed, 38 insertions(+), 372 deletions(-) delete mode 100644 docs/source/_templates/mg_theme/layout.html delete mode 100644 docs/source/_templates/mg_theme/static/default.css_t delete mode 100644 docs/source/_templates/mg_theme/theme.conf create mode 100644 docs/source/themes/mg/layout.html create mode 100644 docs/source/themes/mg/theme.conf diff --git a/docs/source/_templates/mg_theme/layout.html b/docs/source/_templates/mg_theme/layout.html deleted file mode 100644 index eccda14b..00000000 --- a/docs/source/_templates/mg_theme/layout.html +++ /dev/null @@ -1,39 +0,0 @@ -{# - default/layout.html - ~~~~~~~~~~~~~~~~~~~ - - Sphinx layout template for the default theme. - - :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{% extends "basic/layout.html" %} - -{% if theme_collapsiblesidebar|tobool %} -{% set script_files = script_files + ['_static/sidebar.js'] %} -{% endif %} - -{%- block footer %} - - - -{%- endblock %} diff --git a/docs/source/_templates/mg_theme/static/default.css_t b/docs/source/_templates/mg_theme/static/default.css_t deleted file mode 100644 index f200a0fe..00000000 --- a/docs/source/_templates/mg_theme/static/default.css_t +++ /dev/null @@ -1,299 +0,0 @@ -/* - * default.css_t - * ~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- default theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: {{ theme_bodyfont }}; - font-size: 100%; - background-color: {{ theme_footerbgcolor }}; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - background-color: {{ theme_sidebarbgcolor }}; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -div.body { - background-color: {{ theme_bgcolor }}; - color: {{ theme_textcolor }}; - padding: 0 20px 30px 20px; -} - -{%- if theme_rightsidebar|tobool %} -div.bodywrapper { - margin: 0 230px 0 0; -} -{%- endif %} - -div.footer { - color: {{ theme_footertextcolor }}; - width: 100%; - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: {{ theme_footertextcolor }}; - text-decoration: underline; -} - -div.related { - background-color: {{ theme_relbarbgcolor }}; - line-height: 30px; - color: {{ theme_relbartextcolor }}; -} - -div.related a { - color: {{ theme_relbarlinkcolor }}; -} - -div.sphinxsidebar { - {%- if theme_stickysidebar|tobool %} - top: 30px; - bottom: 0; - margin: 0; - position: fixed; - overflow: auto; - height: auto; - {%- endif %} - {%- if theme_rightsidebar|tobool %} - float: right; - {%- if theme_stickysidebar|tobool %} - right: 0; - {%- endif %} - {%- endif %} -} - -{%- if theme_stickysidebar|tobool %} -/* this is nice, but it it leads to hidden headings when jumping - to an anchor */ -/* -div.related { - position: fixed; -} - -div.documentwrapper { - margin-top: 30px; -} -*/ -{%- endif %} - -div.sphinxsidebar h3 { - font-family: {{ theme_headfont }}; - color: {{ theme_sidebartextcolor }}; - font-size: 1.4em; - font-weight: normal; - margin: 0; - padding: 0; -} - -div.sphinxsidebar h3 a { - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar h4 { - font-family: {{ theme_headfont }}; - color: {{ theme_sidebartextcolor }}; - font-size: 1.3em; - font-weight: normal; - margin: 5px 0 0 0; - padding: 0; -} - -div.sphinxsidebar p { - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar p.topless { - margin: 5px 10px 10px 10px; -} - -div.sphinxsidebar ul { - margin: 10px; - padding: 0; - color: {{ theme_sidebartextcolor }}; -} - -div.sphinxsidebar a { - color: {{ theme_sidebarlinkcolor }}; -} - -div.sphinxsidebar input { - border: 1px solid {{ theme_sidebarlinkcolor }}; - font-family: sans-serif; - font-size: 1em; -} - - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - color: {{ theme_linkcolor }}; - text-decoration: none; -} - -a:visited { - color: {{ theme_visitedlinkcolor }}; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -{% if theme_externalrefs|tobool %} -a.external { - text-decoration: none; - border-bottom: 1px dashed {{ theme_linkcolor }}; -} - -a.external:hover { - text-decoration: none; - border-bottom: none; -} -{% endif %} - -/* -- body styles ----------------------------------------------------------- */ - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: {{ theme_headfont }}; - background-color: {{ theme_headbgcolor }}; - font-weight: normal; - color: {{ theme_headtextcolor }}; - border-bottom: 1px solid #ccc; - margin: 20px -20px 10px -20px; - padding: 3px 0 3px 10px; -} - -div.body h1 { margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 160%; } -div.body h3 { font-size: 140%; } -div.body h4 { font-size: 120%; } -div.body h5 { font-size: 110%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: {{ theme_headlinkcolor }}; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: {{ theme_headlinkcolor }}; - color: white; -} - -div.body p, div.body dd, div.body li { - text-align: justify; - line-height: 130%; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.admonition p { - margin-bottom: 5px; -} - -div.admonition pre { - margin-bottom: 5px; -} - -div.admonition ul, div.admonition ol { - margin-bottom: 5px; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 5px; - background-color: {{ theme_codebgcolor }}; - color: {{ theme_codetextcolor }}; - line-height: 120%; - border: 1px solid #ac9; - border-left: none; - border-right: none; -} - -tt { - background-color: #ecf0f3; - padding: 0 1px 0 1px; - font-size: 0.95em; -} - -th { - background-color: #ede; -} - -.warning tt { - background: #efc2c2; -} - -.note tt { - background: #d6d6d6; -} - -.viewcode-back { - font-family: {{ theme_bodyfont }}; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} diff --git a/docs/source/_templates/mg_theme/theme.conf b/docs/source/_templates/mg_theme/theme.conf deleted file mode 100644 index 49442e3b..00000000 --- a/docs/source/_templates/mg_theme/theme.conf +++ /dev/null @@ -1,31 +0,0 @@ -[theme] -inherit = basic -stylesheet = default.css -pygments_style = sphinx - -[options] -rightsidebar = false -stickysidebar = false -collapsiblesidebar = false -externalrefs = false - -footerbgcolor = #b11818 -footertextcolor = #ffffff -sidebarbgcolor = #6a0000 -sidebartextcolor = #ffffff -sidebarlinkcolor = #98dbcc -relbarbgcolor = #b11818 -relbartextcolor = #ffffff -relbarlinkcolor = #ffffff -bgcolor = #ffffff -textcolor = #000000 -headbgcolor = #fdeded -headtextcolor = #20435c -headlinkcolor = #c60f0f -linkcolor = #355f7c -visitedlinkcolor = #355f7c -codebgcolor = #eeffcc -codetextcolor = #333333 - -bodyfont = sans-serif -headfont = 'Trebuchet MS', sans-serif diff --git a/docs/source/conf.py b/docs/source/conf.py index eee9900f..f4d194e6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -28,7 +28,7 @@ sys.path.insert(0, os.path.abspath('.')) extensions = ["mgext.youcanhelp"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ['source/_templates'] # The suffix of source filenames. source_suffix = '.rst' @@ -91,7 +91,8 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +# html_theme = 'default' +html_theme = 'mg' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -99,7 +100,7 @@ html_theme = 'default' #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +html_theme_path = ['themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". diff --git a/docs/source/themes/mg/layout.html b/docs/source/themes/mg/layout.html new file mode 100644 index 00000000..891ed64c --- /dev/null +++ b/docs/source/themes/mg/layout.html @@ -0,0 +1,29 @@ +{# + default/layout.html + ~~~~~~~~~~~~~~~~~~~ + + Sphinx layout template for the default theme. + + :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +#} +{% extends "basic/layout.html" %} + +{% if theme_collapsiblesidebar|tobool %} +{% set script_files = script_files + ['_static/sidebar.js'] %} +{% endif %} + +{%- block footer %} + +{%- endblock %} diff --git a/docs/source/themes/mg/theme.conf b/docs/source/themes/mg/theme.conf new file mode 100644 index 00000000..f4fbd8cc --- /dev/null +++ b/docs/source/themes/mg/theme.conf @@ -0,0 +1,5 @@ +[theme] +inherit = default +stylesheet = default.css +pygments_style = sphinx + -- cgit v1.2.3 From 449f58e446ff50f9c84a99a123bd0225a4907f52 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 11:41:29 -0500 Subject: Update version numbers --- docs/source/conf.py | 4 ++-- mediagoblin/_version.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f4d194e6..829679b1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, Free Software Foundation, Inc and contributors' # built documents. # # The short X.Y version. -version = '0.1.0' +version = '0.2.0' # The full version, including alpha/beta/rc tags. -release = '0.1.0' +release = '0.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index d6c6e20d..7a41cf7c 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -14,4 +14,4 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -__version__ = "0.1.0" +__version__ = "0.2.0" -- cgit v1.2.3 From 6ae878e730e006ab674f12c581af8447a0994a9f Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 12 Dec 2011 11:52:24 -0500 Subject: Changer version to -dev --- docs/source/conf.py | 4 ++-- mediagoblin/_version.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 829679b1..dce254a1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, Free Software Foundation, Inc and contributors' # built documents. # # The short X.Y version. -version = '0.2.0' +version = '0.3.0' # The full version, including alpha/beta/rc tags. -release = '0.2.0' +release = '0.3.0-dev' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index 7a41cf7c..5e3f4e5a 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -14,4 +14,4 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -__version__ = "0.2.0" +__version__ = "0.3.0-dev" -- cgit v1.2.3 From bb298cde80ce60290607012cc742ebb7b53af716 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 14 Dec 2011 16:18:26 +0100 Subject: Change wording for change_fp; improved the button text --- mediagoblin/templates/mediagoblin/auth/change_fp.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 5677949c..03a6583b 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -26,11 +26,11 @@ {{ csrf_token }}
    -

    {% trans %}Enter your new password{% endtrans %}

    +

    {% trans %}Set your new password{% endtrans %}

    {{ wtforms_util.render_divs(cp_form) }}
    - +
    -- cgit v1.2.3 From cd4b519a78961e2ec33e696e9ee730d916c1e073 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 14 Dec 2011 16:36:29 +0100 Subject: Remove "X license" placeholder from media page --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 5760a68c..2c8c5033 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -67,7 +67,7 @@ {% endautoescape %}

    {% trans date=media.created.strftime("%Y-%m-%d") -%} - Added on {{ date }}. Licensed under an X license. + Added on {{ date }}. {%- endtrans %} {% if media['uploader'] == request.user._id or request.user['is_admin'] %} -- cgit v1.2.3 From 31f5c4567fbe8ec04cf649f00d50611aca67036d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 14 Dec 2011 16:42:40 +0100 Subject: Change "Submit" to "Add" for ticket #466 --- mediagoblin/templates/mediagoblin/base.html | 2 +- mediagoblin/templates/mediagoblin/submit/start.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b8061f24..41efbc0d 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -52,7 +52,7 @@ {% if request.user and request.user.status == 'active' %} - {% trans %}Submit media{% endtrans %} + {% trans %}Add media{% endtrans %} {% endif %} {% block mediagoblin_header_title %}{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 1a0dd4b7..47914550 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -23,11 +23,11 @@

    -

    {% trans %}Submit yer media{% endtrans %}

    +

    {% trans %}Add your media{% endtrans %}

    {{ wtforms_util.render_divs(submit_form) }}
    {{ csrf_token }} - +
    -- cgit v1.2.3 From 9c1c6c2a61ad23d5b68eb3794e81c5bee7c7cd46 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 15 Dec 2011 00:46:10 +0100 Subject: Added *very preliminary* support for webfinger --- mediagoblin/routing.py | 4 ++ .../templates/mediagoblin/webfinger/host-meta.xml | 27 +++++++++++++ .../templates/mediagoblin/webfinger/xrd.xml | 26 ++++++++++++ mediagoblin/webfinger/__init__.py | 15 +++++++ mediagoblin/webfinger/routing.py | 25 ++++++++++++ mediagoblin/webfinger/views.py | 46 ++++++++++++++++++++++ 6 files changed, 143 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/webfinger/host-meta.xml create mode 100644 mediagoblin/templates/mediagoblin/webfinger/xrd.xml create mode 100644 mediagoblin/webfinger/__init__.py create mode 100644 mediagoblin/webfinger/routing.py create mode 100644 mediagoblin/webfinger/views.py diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index ae56f8cb..bd727db5 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -21,6 +21,8 @@ from mediagoblin.submit.routing import submit_routes from mediagoblin.user_pages.routing import user_routes from mediagoblin.edit.routing import edit_routes from mediagoblin.listings.routing import tag_routes +from mediagoblin.webfinger.routing import webfinger_well_known_routes, \ + webfinger_routes def get_mapper(): @@ -36,5 +38,7 @@ def get_mapper(): mapping.extend(user_routes, '/u') mapping.extend(edit_routes, '/edit') mapping.extend(tag_routes, '/tag') + mapping.extend(webfinger_well_known_routes, '/.well-known') + mapping.extend(webfinger_routes, '/api/webfinger') return mapping diff --git a/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml new file mode 100644 index 00000000..dff2c9aa --- /dev/null +++ b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml @@ -0,0 +1,27 @@ +{# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +-#} + + + + {{ request.host }} + + + {{ llrd_title }} + + diff --git a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml new file mode 100644 index 00000000..2ef9b814 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml @@ -0,0 +1,26 @@ +{# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +-#} + + + + {{ uri }} + http://{{ request.host }}/u/{{ username }} + + + diff --git a/mediagoblin/webfinger/__init__.py b/mediagoblin/webfinger/__init__.py new file mode 100644 index 00000000..ba347c69 --- /dev/null +++ b/mediagoblin/webfinger/__init__.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/webfinger/routing.py b/mediagoblin/webfinger/routing.py new file mode 100644 index 00000000..effb2bf2 --- /dev/null +++ b/mediagoblin/webfinger/routing.py @@ -0,0 +1,25 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from routes.route import Route + +webfinger_well_known_routes = [ + Route('mediagoblin.webfinger.host_meta', '/host-meta', + controller='mediagoblin.webfinger.views:host_meta')] + +webfinger_routes = [ + Route('mediagoblin.webfinger.xrd', '/xrd', + controller='mediagoblin.webfinger.views:xrd')] diff --git a/mediagoblin/webfinger/views.py b/mediagoblin/webfinger/views.py new file mode 100644 index 00000000..f6294da9 --- /dev/null +++ b/mediagoblin/webfinger/views.py @@ -0,0 +1,46 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import re +import mediagoblin.mg_globals as mg_globals + +from mediagoblin.tools.response import render_to_response + +LRDD_TEMPLATE = '{protocol}://{host}/api/webfinger/xrd?uri={{uri}}' + +def host_meta(request): + ''' + Webfinger host-meta + ''' + return render_to_response( + request, + 'mediagoblin/webfinger/host-meta.xml', + {'request': request, + 'lrdd_template': LRDD_TEMPLATE.format( + protocol='http', + host=request.host)}) + +def xrd(request): + ''' + Find user data based on a webfinger URI + ''' + return render_to_response( + request, + 'mediagoblin/webfinger/xrd.xml', + {'request': request, + 'username': re.search( + r'^acct:([^@]*)', + request.GET.get('uri')).group(1)}) -- cgit v1.2.3 From 830a78cdfbb8fc1ee8af770a299f59f26e918aa0 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 15 Dec 2011 00:58:14 +0100 Subject: Changed some thngs to be compatible with webfinger.org, still *very preliminary* --- mediagoblin/templates/mediagoblin/webfinger/xrd.xml | 3 +++ mediagoblin/webfinger/views.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml index 2ef9b814..796de89f 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml @@ -20,6 +20,9 @@ {{ uri }} http://{{ request.host }}/u/{{ username }} + + diff --git a/mediagoblin/webfinger/views.py b/mediagoblin/webfinger/views.py index f6294da9..7cbd0913 100644 --- a/mediagoblin/webfinger/views.py +++ b/mediagoblin/webfinger/views.py @@ -42,5 +42,5 @@ def xrd(request): 'mediagoblin/webfinger/xrd.xml', {'request': request, 'username': re.search( - r'^acct:([^@]*)', - request.GET.get('uri')).group(1)}) + r'^(acct:)?([^@]*)', + request.GET.get('uri')).group(2)}) -- cgit v1.2.3 From 8d45c4463bf7bf9dfebe919bb12d588d45d7e30c Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 15 Dec 2011 09:27:56 -0500 Subject: Fix -dev version and add version number docs Version numbers should adhere to PEP-386. --- mediagoblin/_version.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index 5e3f4e5a..5e69f21a 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -14,4 +14,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -__version__ = "0.3.0-dev" +# valid version formats: +# * x.y - final release +# * x.ya1 - alpha 1 +# * x.yb1 - beta 1 +# * x.yrc1 - release candidate 1 +# * x.y.dev - dev + +# see http://www.python.org/dev/peps/pep-0386/ + +__version__ = "0.3.0.dev" -- cgit v1.2.3 From 9df07e87a8452e47eb594763bb700daf6fb69dbe Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 15 Dec 2011 19:35:53 +0100 Subject: webfinger fully compliant with webfinger.org! Still *preliminary* solution. --- mediagoblin/templates/mediagoblin/webfinger/xrd.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml index 796de89f..9a793637 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml @@ -17,7 +17,7 @@ - {{ uri }} + {{ request.GET.get('uri') }} http://{{ request.host }}/u/{{ username }} Date: Thu, 15 Dec 2011 21:15:21 +0100 Subject: Move sql models into db/sql/ So we can play with the sql models, let's put them in a proper place. --- mediagoblin/db/sql.py | 95 ------------------------------------------ mediagoblin/db/sql/__init__.py | 15 +++++++ mediagoblin/db/sql/models.py | 95 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 95 deletions(-) delete mode 100644 mediagoblin/db/sql.py create mode 100644 mediagoblin/db/sql/__init__.py create mode 100644 mediagoblin/db/sql/models.py diff --git a/mediagoblin/db/sql.py b/mediagoblin/db/sql.py deleted file mode 100644 index 31ebfbf4..00000000 --- a/mediagoblin/db/sql.py +++ /dev/null @@ -1,95 +0,0 @@ -import datetime - -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import ( - Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, - UniqueConstraint) - - -Base = declarative_base() - - -class User(Base): - __tablename__ = "users" - - id = Column(Integer, primary_key=True) - username = Column(Unicode, nullable=False, unique=True) - email = Column(Unicode, nullable=False) - created = Column(DateTime, nullable=False, default=datetime.datetime.now) - pw_hash = Column(Unicode, nullable=False) - email_verified = Column(Boolean) - status = Column(Unicode, default="needs_email_verification", nullable=False) - verification_key = Column(Unicode) - is_admin = Column(Boolean, default=False, nullable=False) - url = Column(Unicode) - bio = Column(UnicodeText) # ?? - bio_html = Column(UnicodeText) # ?? - fp_verification_key = Column(Unicode) - fp_verification_expire = Column(DateTime) - - ## TODO - # plugin data would be in a separate model - - -class MediaEntry(Base): - __tablename__ = "media_entries" - - id = Column(Integer, primary_key=True) - uploader = Column(Integer, ForeignKey('users.id'), nullable=False) - slug = Column(Unicode, nullable=False) - created = Column(DateTime, nullable=False, default=datetime.datetime.now) - description = Column(UnicodeText) # ?? - description_html = Column(UnicodeText) # ?? - media_type = Column(Unicode, nullable=False) - - fail_error = Column(Unicode) - fail_metadata = Column(UnicodeText) - - queued_media_file = Column(Unicode) - - queued_task_id = Column(Unicode) - - __table_args__ = ( - UniqueConstraint('uploader', 'slug'), - {}) - - ## TODO - # media_files - # media_data - # attachment_files - # fail_error - - -class Tag(Base): - __tablename__ = "tags" - - id = Column(Integer, primary_key=True) - slug = Column(Unicode, nullable=False, unique=True) - - -class MediaTag(Base): - __tablename__ = "media_tags" - - id = Column(Integer, primary_key=True) - tag = Column(Integer, ForeignKey('tags.id'), nullable=False) - name = Column(Unicode) - media_entry = Column( - Integer, ForeignKey('media_entries.id'), - nullable=False) - # created = Column(DateTime, nullable=False, default=datetime.datetime.now) - - __table_args__ = ( - UniqueConstraint('tag', 'media_entry'), - {}) - - -class MediaComment(Base): - __tablename__ = "media_comments" - - id = Column(Integer, primary_key=True) - media_entry = Column( - Integer, ForeignKey('media_entries.id'), nullable=False) - author = Column(Integer, ForeignKey('users.id'), nullable=False) - created = Column(DateTime, nullable=False, default=datetime.datetime.now) - content = Column(UnicodeText, nullable=False) - content_html = Column(UnicodeText) diff --git a/mediagoblin/db/sql/__init__.py b/mediagoblin/db/sql/__init__.py new file mode 100644 index 00000000..ba347c69 --- /dev/null +++ b/mediagoblin/db/sql/__init__.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py new file mode 100644 index 00000000..31ebfbf4 --- /dev/null +++ b/mediagoblin/db/sql/models.py @@ -0,0 +1,95 @@ +import datetime + +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import ( + Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint) + + +Base = declarative_base() + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True) + username = Column(Unicode, nullable=False, unique=True) + email = Column(Unicode, nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + pw_hash = Column(Unicode, nullable=False) + email_verified = Column(Boolean) + status = Column(Unicode, default="needs_email_verification", nullable=False) + verification_key = Column(Unicode) + is_admin = Column(Boolean, default=False, nullable=False) + url = Column(Unicode) + bio = Column(UnicodeText) # ?? + bio_html = Column(UnicodeText) # ?? + fp_verification_key = Column(Unicode) + fp_verification_expire = Column(DateTime) + + ## TODO + # plugin data would be in a separate model + + +class MediaEntry(Base): + __tablename__ = "media_entries" + + id = Column(Integer, primary_key=True) + uploader = Column(Integer, ForeignKey('users.id'), nullable=False) + slug = Column(Unicode, nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + description = Column(UnicodeText) # ?? + description_html = Column(UnicodeText) # ?? + media_type = Column(Unicode, nullable=False) + + fail_error = Column(Unicode) + fail_metadata = Column(UnicodeText) + + queued_media_file = Column(Unicode) + + queued_task_id = Column(Unicode) + + __table_args__ = ( + UniqueConstraint('uploader', 'slug'), + {}) + + ## TODO + # media_files + # media_data + # attachment_files + # fail_error + + +class Tag(Base): + __tablename__ = "tags" + + id = Column(Integer, primary_key=True) + slug = Column(Unicode, nullable=False, unique=True) + + +class MediaTag(Base): + __tablename__ = "media_tags" + + id = Column(Integer, primary_key=True) + tag = Column(Integer, ForeignKey('tags.id'), nullable=False) + name = Column(Unicode) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), + nullable=False) + # created = Column(DateTime, nullable=False, default=datetime.datetime.now) + + __table_args__ = ( + UniqueConstraint('tag', 'media_entry'), + {}) + + +class MediaComment(Base): + __tablename__ = "media_comments" + + id = Column(Integer, primary_key=True) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), nullable=False) + author = Column(Integer, ForeignKey('users.id'), nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + content = Column(UnicodeText, nullable=False) + content_html = Column(UnicodeText) -- cgit v1.2.3 From e365f980ac21a403a50f61ae687d7dc04760f8bb Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 15 Dec 2011 22:11:49 +0100 Subject: SQL: Some toys and little fix Run bin/python mediagoblin/db/sql/models.py and watch the create tables on a memory sqlite db. Also unicode strings need unicode defauls. Warning by sqlalchemy. --- mediagoblin/db/sql/models.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 31ebfbf4..a38be1cc 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -18,7 +18,7 @@ class User(Base): created = Column(DateTime, nullable=False, default=datetime.datetime.now) pw_hash = Column(Unicode, nullable=False) email_verified = Column(Boolean) - status = Column(Unicode, default="needs_email_verification", nullable=False) + status = Column(Unicode, default=u"needs_email_verification", nullable=False) verification_key = Column(Unicode) is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) @@ -93,3 +93,14 @@ class MediaComment(Base): created = Column(DateTime, nullable=False, default=datetime.datetime.now) content = Column(UnicodeText, nullable=False) content_html = Column(UnicodeText) + + +def show_table_init(): + from sqlalchemy import create_engine + engine = create_engine('sqlite:///:memory:', echo=True) + + Base.metadata.create_all(engine) + + +if __name__ == '__main__': + show_table_init() -- cgit v1.2.3 From 8eb216388f0999115d68c33e2fe2460bc9986112 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 15 Dec 2011 23:49:52 +0100 Subject: Fixed import_export - Mongokit instead of pymongo - db.MediaEntry instead of db.media_entry (pymongo style) --- mediagoblin/gmg_commands/import_export.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 1308f09e..eda41f4c 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -64,7 +64,7 @@ def _import_media(db, args): queue_cache = BasicFileStorage( args._cache_path['queue']) - for entry in db.media_entries.find(): + for entry in db.MediaEntry.find(): for name, path in entry['media_files'].items(): _log.info('Importing: {0} - {1}'.format( entry.title, @@ -107,7 +107,7 @@ def env_import(args): global_config, app_config = setup_global_and_app_config(args.conf_file) connection, db = setup_connection_and_db_from_config( - app_config, use_pymongo=True) + app_config) tf = tarfile.open( args.tar_file, @@ -206,7 +206,7 @@ def _export_media(db, args): queue_cache = BasicFileStorage( args._cache_path['queue']) - for entry in db.media_entries.find(): + for entry in db.MediaEntry.find(): for name, path in entry['media_files'].items(): _log.info(u'Exporting {0} - {1}'.format( entry.title, @@ -215,7 +215,7 @@ def _export_media(db, args): mc_file = media_cache.get_file(path, mode='wb') mc_file.write( mg_globals.public_store.get_file(path, mode='rb').read()) - except e: + except Exception as e: _log.error('Failed: {0}'.format(e)) _log.info('...Media exported') @@ -246,7 +246,7 @@ def env_export(args): setup_storage() connection, db = setup_connection_and_db_from_config( - app_config, use_pymongo=True) + app_config) _export_database(db, args) -- cgit v1.2.3 From 7c2c56a5ff0cb229cd3a64451368bf1e72646bc5 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 17 Dec 2011 17:34:55 +0100 Subject: Little sql model update - Add title to the MediaEntry - Rename fp_verification_expire to fp_token_expire to follow the mongo model. --- mediagoblin/db/sql/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index a38be1cc..7723a753 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -25,7 +25,7 @@ class User(Base): bio = Column(UnicodeText) # ?? bio_html = Column(UnicodeText) # ?? fp_verification_key = Column(Unicode) - fp_verification_expire = Column(DateTime) + fp_token_expire = Column(DateTime) ## TODO # plugin data would be in a separate model @@ -36,6 +36,7 @@ class MediaEntry(Base): id = Column(Integer, primary_key=True) uploader = Column(Integer, ForeignKey('users.id'), nullable=False) + title = Column(Unicode, nullable=False) slug = Column(Unicode, nullable=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) description = Column(UnicodeText) # ?? -- cgit v1.2.3 From dbcf5289dcc7bcd03a1a92a204fd7c4c8348d318 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 17 Dec 2011 21:37:02 +0100 Subject: Simple Mongo -> SQL migration tool This is just a start at a Migration tool from Mongo to SQL. It fills all currently available SQL models with data from MongoDB. A few fields in the SQL tables are left out, because some data format migrations are needed (notably: queue_file_name). This thing lives in mediagoblin/db/sql/convert.py because it has a lot of stuff hardcoded and is not, repeat not for end users! Hard coded: - output database: ./mediagoblin.db (sqlite) - Mediagoblin config: ./mediagoblin.ini --- mediagoblin/db/sql/convert.py | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 mediagoblin/db/sql/convert.py diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py new file mode 100644 index 00000000..2ffa9fd7 --- /dev/null +++ b/mediagoblin/db/sql/convert.py @@ -0,0 +1,143 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from mediagoblin.init import setup_global_and_app_config, setup_database +from mediagoblin.db.util import ObjectId + +from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment, + Tag, MediaTag) + +Session = sessionmaker() + + +obj_id_table = dict() + +def add_obj_ids(entry, new_entry): + global obj_id_table + print "%r -> %r" % (entry._id, new_entry.id) + obj_id_table[entry._id] = new_entry.id + + +def copy_attrs(entry, new_entry, attr_list): + for a in attr_list: + val = entry[a] + setattr(new_entry, a, val) + +def copy_reference_attr(entry, new_entry, ref_attr): + val = entry[ref_attr] + val = obj_id_table[val] + setattr(new_entry, ref_attr, val) + + +def convert_users(mk_db): + session = Session() + + for entry in mk_db.User.find(): + print entry.username + + new_entry = User() + copy_attrs(entry, new_entry, + ('username', 'email', 'created', 'pw_hash', 'email_verified', + 'status', 'verification_key', 'is_admin', 'url', + 'bio', 'bio_html', + 'fp_verification_key', 'fp_token_expire',)) + # new_entry.fp_verification_expire = entry.fp_token_expire + + session.add(new_entry) + session.flush() + add_obj_ids(entry, new_entry) + + session.commit() + session.close() + + +def convert_media_entries(mk_db): + session = Session() + + for entry in mk_db.MediaEntry.find(): + print repr(entry.title) + + new_entry = MediaEntry() + copy_attrs(entry, new_entry, + ('title', 'slug', 'created', + 'description', 'description_html', + 'media_type', + 'fail_error', + 'queued_task_id',)) + copy_reference_attr(entry, new_entry, "uploader") + + session.add(new_entry) + session.flush() + add_obj_ids(entry, new_entry) + + session.commit() + session.close() + + +def convert_media_tags(mk_db): + session = Session() + session.autoflush = False + + for media in mk_db.MediaEntry.find(): + print repr(media.title) + + for otag in media.tags: + print " ", repr((otag["slug"], otag["name"])) + + nslug = session.query(Tag).filter_by(slug=otag["slug"]).first() + print " ", repr(nslug) + if nslug is None: + nslug = Tag(slug=otag["slug"]) + session.add(nslug) + session.flush() + print " ", repr(nslug), nslug.id + + ntag = MediaTag() + ntag.tag = nslug.id + ntag.name = otag["name"] + ntag.media_entry = obj_id_table[media._id] + session.add(ntag) + + session.commit() + session.close() + + +def convert_media_comments(mk_db): + session = Session() + + for entry in mk_db.MediaComment.find(): + print repr(entry.content) + + new_entry = MediaComment() + copy_attrs(entry, new_entry, + ('created', + 'content', 'content_html',)) + copy_reference_attr(entry, new_entry, "media_entry") + copy_reference_attr(entry, new_entry, "author") + + session.add(new_entry) + session.flush() + add_obj_ids(entry, new_entry) + + session.commit() + session.close() + + +def main(): + engine = create_engine('sqlite:///mediagoblin.db', echo=True) + Session.configure(bind=engine) + + setup_global_and_app_config("mediagoblin.ini") + + mk_conn, mk_db = setup_database() + + Base.metadata.create_all(engine) + + convert_users(mk_db) + convert_media_entries(mk_db) + convert_media_tags(mk_db) + convert_media_comments(mk_db) + + +if __name__ == '__main__': + main() -- cgit v1.2.3 From 18517e888a90bf1c0434dd4da99ef7980d333ed0 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 00:31:39 +0100 Subject: Show actual comment number. Only shows plural for now (ticket #712) --- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 2c8c5033..b9e31667 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -81,7 +81,7 @@ {% trans %}Delete{% endtrans %} {% endif %}

    -

    {% trans %}23 comments{% endtrans %} +

    {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %}
    Date: Sun, 18 Dec 2011 01:04:41 +0100 Subject: First test lines for responsive design --- mediagoblin/static/css/base.css | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 2a78006d..805f0e29 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -389,3 +389,20 @@ table.media_panel th { margin-top: 10px; margin-left: 10px; } + +@media screen and (max-width: 480px) { + .navigation_button { + position: fixed; + bottom: 0px; + right: 0px; + width: 50%; + margin: 0; + } + .navigation_left { + left: 0px; + width: 50%; + } + .media_image { + width: 480px; + } +} -- cgit v1.2.3 From 436b13bb3e2253dc4361333d1260550d343ccfe2 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 01:31:06 +0100 Subject: Remove 960.gs stylesheets, add Eric Meyer's reset.css --- extlib/960.gs/960_16_col.css | 447 --------------------------- extlib/960.gs/MIT.txt | 20 -- extlib/960.gs/README.txt | 54 ---- extlib/960.gs/reset.css | 202 ------------ extlib/960.gs/text.css | 86 ------ mediagoblin/static/css/extlib/960_16_col.css | 1 - mediagoblin/static/css/extlib/reset.css | 1 - mediagoblin/static/css/extlib/text.css | 1 - mediagoblin/static/css/reset.css | 49 +++ mediagoblin/templates/mediagoblin/base.html | 6 +- 10 files changed, 50 insertions(+), 817 deletions(-) delete mode 100644 extlib/960.gs/960_16_col.css delete mode 100644 extlib/960.gs/MIT.txt delete mode 100755 extlib/960.gs/README.txt delete mode 100644 extlib/960.gs/reset.css delete mode 100644 extlib/960.gs/text.css delete mode 120000 mediagoblin/static/css/extlib/960_16_col.css delete mode 120000 mediagoblin/static/css/extlib/reset.css delete mode 120000 mediagoblin/static/css/extlib/text.css create mode 100644 mediagoblin/static/css/reset.css diff --git a/extlib/960.gs/960_16_col.css b/extlib/960.gs/960_16_col.css deleted file mode 100644 index faa6d8b2..00000000 --- a/extlib/960.gs/960_16_col.css +++ /dev/null @@ -1,447 +0,0 @@ -/* - 960 Grid System ~ Core CSS. - Learn more ~ http://960.gs/ - - Licensed under GPL and MIT. -*/ - -/* - Forces backgrounds to span full width, - even if there is horizontal scrolling. - Increase this if your layout is wider. - - Note: IE6 works fine without this fix. -*/ - -body { - min-width: 960px; -} - -/* Container -----------------------------------------------------------------------------------------------------*/ - -.container_16 { - margin-left: auto; - margin-right: auto; - width: 960px; -} - -/* Grid >> Global -----------------------------------------------------------------------------------------------------*/ - -.grid_1, -.grid_2, -.grid_3, -.grid_4, -.grid_5, -.grid_6, -.grid_7, -.grid_8, -.grid_9, -.grid_10, -.grid_11, -.grid_12, -.grid_13, -.grid_14, -.grid_15, -.grid_16 { - display: inline; - float: left; - position: relative; - margin-left: 10px; - margin-right: 10px; -} - -.push_1, .pull_1, -.push_2, .pull_2, -.push_3, .pull_3, -.push_4, .pull_4, -.push_5, .pull_5, -.push_6, .pull_6, -.push_7, .pull_7, -.push_8, .pull_8, -.push_9, .pull_9, -.push_10, .pull_10, -.push_11, .pull_11, -.push_12, .pull_12, -.push_13, .pull_13, -.push_14, .pull_14, -.push_15, .pull_15, -.push_16, .pull_16 { - position: relative; -} - -/* Grid >> Children (Alpha ~ First, Omega ~ Last) -----------------------------------------------------------------------------------------------------*/ - -.alpha { - margin-left: 0; -} - -.omega { - margin-right: 0; -} - -/* Grid >> 16 Columns -----------------------------------------------------------------------------------------------------*/ - -.container_16 .grid_1 { - width: 40px; -} - -.container_16 .grid_2 { - width: 100px; -} - -.container_16 .grid_3 { - width: 160px; -} - -.container_16 .grid_4 { - width: 220px; -} - -.container_16 .grid_5 { - width: 280px; -} - -.container_16 .grid_6 { - width: 340px; -} - -.container_16 .grid_7 { - width: 400px; -} - -.container_16 .grid_8 { - width: 460px; -} - -.container_16 .grid_9 { - width: 520px; -} - -.container_16 .grid_10 { - width: 580px; -} - -.container_16 .grid_11 { - width: 640px; -} - -.container_16 .grid_12 { - width: 700px; -} - -.container_16 .grid_13 { - width: 760px; -} - -.container_16 .grid_14 { - width: 820px; -} - -.container_16 .grid_15 { - width: 880px; -} - -.container_16 .grid_16 { - width: 940px; -} - -/* Prefix Extra Space >> 16 Columns -----------------------------------------------------------------------------------------------------*/ - -.container_16 .prefix_1 { - padding-left: 60px; -} - -.container_16 .prefix_2 { - padding-left: 120px; -} - -.container_16 .prefix_3 { - padding-left: 180px; -} - -.container_16 .prefix_4 { - padding-left: 240px; -} - -.container_16 .prefix_5 { - padding-left: 300px; -} - -.container_16 .prefix_6 { - padding-left: 360px; -} - -.container_16 .prefix_7 { - padding-left: 420px; -} - -.container_16 .prefix_8 { - padding-left: 480px; -} - -.container_16 .prefix_9 { - padding-left: 540px; -} - -.container_16 .prefix_10 { - padding-left: 600px; -} - -.container_16 .prefix_11 { - padding-left: 660px; -} - -.container_16 .prefix_12 { - padding-left: 720px; -} - -.container_16 .prefix_13 { - padding-left: 780px; -} - -.container_16 .prefix_14 { - padding-left: 840px; -} - -.container_16 .prefix_15 { - padding-left: 900px; -} - -/* Suffix Extra Space >> 16 Columns -----------------------------------------------------------------------------------------------------*/ - -.container_16 .suffix_1 { - padding-right: 60px; -} - -.container_16 .suffix_2 { - padding-right: 120px; -} - -.container_16 .suffix_3 { - padding-right: 180px; -} - -.container_16 .suffix_4 { - padding-right: 240px; -} - -.container_16 .suffix_5 { - padding-right: 300px; -} - -.container_16 .suffix_6 { - padding-right: 360px; -} - -.container_16 .suffix_7 { - padding-right: 420px; -} - -.container_16 .suffix_8 { - padding-right: 480px; -} - -.container_16 .suffix_9 { - padding-right: 540px; -} - -.container_16 .suffix_10 { - padding-right: 600px; -} - -.container_16 .suffix_11 { - padding-right: 660px; -} - -.container_16 .suffix_12 { - padding-right: 720px; -} - -.container_16 .suffix_13 { - padding-right: 780px; -} - -.container_16 .suffix_14 { - padding-right: 840px; -} - -.container_16 .suffix_15 { - padding-right: 900px; -} - -/* Push Space >> 16 Columns -----------------------------------------------------------------------------------------------------*/ - -.container_16 .push_1 { - left: 60px; -} - -.container_16 .push_2 { - left: 120px; -} - -.container_16 .push_3 { - left: 180px; -} - -.container_16 .push_4 { - left: 240px; -} - -.container_16 .push_5 { - left: 300px; -} - -.container_16 .push_6 { - left: 360px; -} - -.container_16 .push_7 { - left: 420px; -} - -.container_16 .push_8 { - left: 480px; -} - -.container_16 .push_9 { - left: 540px; -} - -.container_16 .push_10 { - left: 600px; -} - -.container_16 .push_11 { - left: 660px; -} - -.container_16 .push_12 { - left: 720px; -} - -.container_16 .push_13 { - left: 780px; -} - -.container_16 .push_14 { - left: 840px; -} - -.container_16 .push_15 { - left: 900px; -} - -/* Pull Space >> 16 Columns -----------------------------------------------------------------------------------------------------*/ - -.container_16 .pull_1 { - left: -60px; -} - -.container_16 .pull_2 { - left: -120px; -} - -.container_16 .pull_3 { - left: -180px; -} - -.container_16 .pull_4 { - left: -240px; -} - -.container_16 .pull_5 { - left: -300px; -} - -.container_16 .pull_6 { - left: -360px; -} - -.container_16 .pull_7 { - left: -420px; -} - -.container_16 .pull_8 { - left: -480px; -} - -.container_16 .pull_9 { - left: -540px; -} - -.container_16 .pull_10 { - left: -600px; -} - -.container_16 .pull_11 { - left: -660px; -} - -.container_16 .pull_12 { - left: -720px; -} - -.container_16 .pull_13 { - left: -780px; -} - -.container_16 .pull_14 { - left: -840px; -} - -.container_16 .pull_15 { - left: -900px; -} - -/* `Clear Floated Elements -----------------------------------------------------------------------------------------------------*/ - -/* http://sonspring.com/journal/clearing-floats */ - -.clear { - clear: both; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; -} - -/* http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified */ - -.clearfix:before, -.clearfix:after, -.container_16:before, -.container_16:after { - content: '.'; - display: block; - overflow: hidden; - visibility: hidden; - font-size: 0; - line-height: 0; - width: 0; - height: 0; -} - -.clearfix:after, -.container_16:after { - clear: both; -} - -/* - The following zoom:1 rule is specifically for IE6 + IE7. - Move to separate stylesheet if invalid CSS is a problem. -*/ - -.clearfix, -.container_16 { - zoom: 1; -} \ No newline at end of file diff --git a/extlib/960.gs/MIT.txt b/extlib/960.gs/MIT.txt deleted file mode 100644 index 5a2aeb47..00000000 --- a/extlib/960.gs/MIT.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extlib/960.gs/README.txt b/extlib/960.gs/README.txt deleted file mode 100755 index da0ea86f..00000000 --- a/extlib/960.gs/README.txt +++ /dev/null @@ -1,54 +0,0 @@ -=============== -960 GRID SYSTEM -=============== - -Created by Nathan Smith. See the official site for more info: http://960.gs/ - -============================================================================ - -To install the Adobe Fireworks extension, simply double-click the *.mxp file -included in the /fireworks_extension directory. If you are running Windows 7 -you will need admin permissions in order to install this extension properly. - -============================================================================ - -Thank you for downloading the 960 Grid System. I hope it helps to streamline -web development workflow. Enclosed in the bundle are printable sketch sheets -and template files for Adobe Fireworks and Photoshop, OmniGraffle and Visio. - -Also included is a lightweight CSS file, which contains the grid dimensions. -To use this file, simply include the 960.css in the of the HTML page. -You may also use the reset.css and text.css files, or opt to leave them out. -Here is an example of the XHTML code necessary to incorporate the CSS files: - - - - - - - -It is worth noting that these styles do not automatically make up a finished -site design. They are simply a starting point, ideally for rapid prototyping -or as a basis for creating your own designs. You should not feel constrained -by the way I have built the initial code. If you disagree with how something -has been done, feel free to revise it for the needs of your particular site. - -The files in the 960 Grid System are free of charge, licensed under MIT/GPL. - -============================================================================ - -Note that if you are building a site in a language which reads from right to -left, use the CSS files that end in "_rtl.css" instead. Denote the language: - - - -Be sure to replace "..." with the appropriate two-letter abbreviation of the -language you are using. Example: lang="he" for Hebrew, lang="ar" for Arabic. - -============================================================================ - -GPL license: -http://www.gnu.org/licenses/gpl.html - -MIT license: -http://www.opensource.org/licenses/mit-license.php \ No newline at end of file diff --git a/extlib/960.gs/reset.css b/extlib/960.gs/reset.css deleted file mode 100644 index 87b7f368..00000000 --- a/extlib/960.gs/reset.css +++ /dev/null @@ -1,202 +0,0 @@ -/* `XHTML, HTML4, HTML5 Reset -----------------------------------------------------------------------------------------------------*/ - -a, -abbr, -acronym, -address, -applet, -article, -aside, -audio, -b, -big, -blockquote, -body, -canvas, -caption, -center, -cite, -code, -dd, -del, -details, -dfn, -dialog, -div, -dl, -dt, -em, -embed, -fieldset, -figcaption, -figure, -font, -footer, -form, -h1, -h2, -h3, -h4, -h5, -h6, -header, -hgroup, -hr, -html, -i, -iframe, -img, -ins, -kbd, -label, -legend, -li, -mark, -menu, -meter, -nav, -object, -ol, -output, -p, -pre, -progress, -q, -rp, -rt, -ruby, -s, -samp, -section, -small, -span, -strike, -strong, -sub, -summary, -sup, -table, -tbody, -td, -tfoot, -th, -thead, -time, -tr, -tt, -u, -ul, -var, -video, -xmp { - border: 0; - margin: 0; - padding: 0; - font-size: 100%; -} - -html, -body { - height: 100%; -} - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { -/* - Override the default (display: inline) for - browsers that do not recognize HTML5 tags. - - IE8 (and lower) requires a shiv: - http://ejohn.org/blog/html5-shiv -*/ - display: block; -} - -b, -strong { -/* - Makes browsers agree. - IE + Opera = font-weight: bold. - Gecko + WebKit = font-weight: bolder. -*/ - font-weight: bold; -} - -img { - color: transparent; - font-size: 0; - vertical-align: middle; -/* - For IE. - http://css-tricks.com/ie-fix-bicubic-scaling-for-images -*/ - -ms-interpolation-mode: bicubic; -} - -li { -/* - For IE6 + IE7. -*/ - display: list-item; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -th, -td, -caption { - font-weight: normal; - vertical-align: top; - text-align: left; -} - -q { - quotes: none; -} - -q:before, -q:after { - content: ''; - content: none; -} - -sub, -sup, -small { - font-size: 75%; -} - -sub, -sup { - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -svg { -/* - For IE9. -*/ - overflow: hidden; -} \ No newline at end of file diff --git a/extlib/960.gs/text.css b/extlib/960.gs/text.css deleted file mode 100644 index 1a6b302f..00000000 --- a/extlib/960.gs/text.css +++ /dev/null @@ -1,86 +0,0 @@ -/* - 960 Grid System ~ Text CSS. - Learn more ~ http://960.gs/ - - Licensed under GPL and MIT. -*/ - -/* `Basic HTML -----------------------------------------------------------------------------------------------------*/ - -body { - font: 13px/1.5 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif; -} - -pre, -code { - font-family: 'DejaVu Sans Mono', Monaco, Consolas, monospace; -} - -hr { - border: 0 #ccc solid; - border-top-width: 1px; - clear: both; - height: 0; -} - -/* `Headings -----------------------------------------------------------------------------------------------------*/ - -h1 { - font-size: 25px; -} - -h2 { - font-size: 23px; -} - -h3 { - font-size: 21px; -} - -h4 { - font-size: 19px; -} - -h5 { - font-size: 17px; -} - -h6 { - font-size: 15px; -} - -/* `Spacing -----------------------------------------------------------------------------------------------------*/ - -ol { - list-style: decimal; -} - -ul { - list-style: disc; -} - -li { - margin-left: 30px; -} - -p, -dl, -hr, -h1, -h2, -h3, -h4, -h5, -h6, -ol, -ul, -pre, -table, -address, -fieldset, -figure { - margin-bottom: 20px; -} \ No newline at end of file diff --git a/mediagoblin/static/css/extlib/960_16_col.css b/mediagoblin/static/css/extlib/960_16_col.css deleted file mode 120000 index d4e43898..00000000 --- a/mediagoblin/static/css/extlib/960_16_col.css +++ /dev/null @@ -1 +0,0 @@ -../../../../extlib/960.gs/960_16_col.css \ No newline at end of file diff --git a/mediagoblin/static/css/extlib/reset.css b/mediagoblin/static/css/extlib/reset.css deleted file mode 120000 index 65d06d34..00000000 --- a/mediagoblin/static/css/extlib/reset.css +++ /dev/null @@ -1 +0,0 @@ -../../../../extlib/960.gs/reset.css \ No newline at end of file diff --git a/mediagoblin/static/css/extlib/text.css b/mediagoblin/static/css/extlib/text.css deleted file mode 120000 index 2d864de4..00000000 --- a/mediagoblin/static/css/extlib/text.css +++ /dev/null @@ -1 +0,0 @@ -../../../../extlib/960.gs/text.css \ No newline at end of file diff --git a/mediagoblin/static/css/reset.css b/mediagoblin/static/css/reset.css new file mode 100644 index 00000000..6ce25ce7 --- /dev/null +++ b/mediagoblin/static/css/reset.css @@ -0,0 +1,49 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 41efbc0d..6972fe2f 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -21,11 +21,7 @@ {% block title %}{{ app_config['html_title'] }}{% endblock %} - - + href="{{ request.staticdirect('/css/reset.css') }}"/> Date: Sun, 18 Dec 2011 01:32:13 +0100 Subject: Media query for everything(?) below 960px wide --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 805f0e29..effcec69 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -390,7 +390,7 @@ table.media_panel th { margin-left: 10px; } -@media screen and (max-width: 480px) { +@media handheld and (max-width: 480px), screen and (max-device-width: 480px), screen and (max-width: 960px) { .navigation_button { position: fixed; bottom: 0px; -- cgit v1.2.3 From 1bb8eb89c7566cb473c2a7c317420bceaf8e9111 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 01:37:57 +0100 Subject: Remove first 960.gs classes --- mediagoblin/static/css/base.css | 27 ++++++++++++++++++++------- mediagoblin/templates/mediagoblin/base.html | 12 +++--------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index effcec69..d3136788 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -84,23 +84,43 @@ input, textarea { .mediagoblin_body { position: relative; min-height: 100%; + margin-left: auto; + margin-right: auto; + width: 960px; } .mediagoblin_header { + width: 940px; height: 36px; + margin-left: 10px; + margin-right: 10px; padding-top: 14px; margin-bottom: 20px; border-bottom: 1px solid #333; } +.mediagoblin_header_right { + float: right; +} + a.mediagoblin_logo{ color: #fff; font-weight: bold; margin-right: 8px; } +.mediagoblin_content { + width: 940px; + margin-left: 10px; + margin-right: 10px; + padding-bottom: 74px; +} + .mediagoblin_footer { + width: 940px; height: 30px; + margin-left: 10px; + margin-right: 10px; border-top: 1px solid #333; bottom: 0px; padding-top: 8px; @@ -108,13 +128,6 @@ a.mediagoblin_logo{ font-size: 0.875em; } -.mediagoblin_content { - padding-bottom: 74px; -} - -.mediagoblin_header_right { - float: right; -} /* common website elements */ diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 6972fe2f..870a4861 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -37,8 +37,7 @@ {% block mediagoblin_body %}
    {% block mediagoblin_header %} -
    -
    {% endblock %} {% endblock mediagoblin_body %}
    -- cgit v1.2.3 From 4fe9c9b99fc14f827d87ef803a9a67508591220f Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 01:41:01 +0100 Subject: Move reset.css to extlib and symlink it --- extlib/reset/reset.css | 49 +++++++++++++++++++++++++++++++++ mediagoblin/static/css/extlib/reset.css | 1 + mediagoblin/static/css/reset.css | 49 --------------------------------- 3 files changed, 50 insertions(+), 49 deletions(-) create mode 100644 extlib/reset/reset.css create mode 120000 mediagoblin/static/css/extlib/reset.css delete mode 100644 mediagoblin/static/css/reset.css diff --git a/extlib/reset/reset.css b/extlib/reset/reset.css new file mode 100644 index 00000000..6ce25ce7 --- /dev/null +++ b/extlib/reset/reset.css @@ -0,0 +1,49 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + diff --git a/mediagoblin/static/css/extlib/reset.css b/mediagoblin/static/css/extlib/reset.css new file mode 120000 index 00000000..6084e137 --- /dev/null +++ b/mediagoblin/static/css/extlib/reset.css @@ -0,0 +1 @@ +../../../../extlib/reset/reset.css \ No newline at end of file diff --git a/mediagoblin/static/css/reset.css b/mediagoblin/static/css/reset.css deleted file mode 100644 index 6ce25ce7..00000000 --- a/mediagoblin/static/css/reset.css +++ /dev/null @@ -1,49 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} - -- cgit v1.2.3 From 42a7c010321a01d1abb01d1137cc46cd97d66843 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 01:54:58 +0100 Subject: Add styles to make media.html not fall apart entirely --- mediagoblin/static/css/base.css | 14 ++++++++++++++ mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d3136788..2a05e988 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -126,8 +126,22 @@ a.mediagoblin_logo{ padding-top: 8px; text-align: center; font-size: 0.875em; + clear: both; } +.media_pane { + width: 640px; + margin-left: 0px; + margin-right: 10px; + float: left; +} + +.media_sidebar { + width: 280px; + margin-left: 10px; + margin-right: 0px; + float: left; +} /* common website elements */ diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index b9e31667..0c3f373e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -37,7 +37,7 @@ {% endblock mediagoblin_head %} {% block mediagoblin_content %} -
    +
    {% block mediagoblin_media %} {% set display_media = request.app.public_store.file_url( @@ -141,7 +141,7 @@ media = media._id)) }} {% endif %}
    -
    +
    {% trans user_url=request.urlgen( 'mediagoblin.user_pages.user_home', user=media.get_uploader().username), -- cgit v1.2.3 From 00c1d00771e0db68f7775968c0e33f000c5f36af Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 18 Dec 2011 02:07:49 +0100 Subject: Change widths to percentages for small devices --- mediagoblin/static/css/base.css | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 2a05e988..187d1c7a 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -418,6 +418,9 @@ table.media_panel th { } @media handheld and (max-width: 480px), screen and (max-device-width: 480px), screen and (max-width: 960px) { + html { + padding:10px; + } .navigation_button { position: fixed; bottom: 0px; @@ -427,9 +430,19 @@ table.media_panel th { } .navigation_left { left: 0px; - width: 50%; } .media_image { - width: 480px; + width: 100%; + } + .mediagoblin_body { + width: 100%; + } + .mediagoblin_header, .mediagoblin_content, .mediagoblin_footer, .media_pane { + width: 100%; + margin-left: 0; + margin-right: 0; + } + .mediagoblin_footer { + margin-bottom: 100px; } } -- cgit v1.2.3 From 7b194a79f0ad789309b9c34340f19c5a962b0915 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 18 Dec 2011 17:02:27 +0100 Subject: SQL: mongokit like interface In trying to ease the migration to SQL, created an interface to sqlalchemy that looks a lot like the interface that is currently in use. *WARNING* Work in progress --- mediagoblin/db/sql/base.py | 16 ++++++++++++++++ mediagoblin/db/sql/convert.py | 7 ++++++- mediagoblin/db/sql/models.py | 4 +++- mediagoblin/db/sql/open.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 mediagoblin/db/sql/base.py create mode 100644 mediagoblin/db/sql/open.py diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py new file mode 100644 index 00000000..b8d5cc96 --- /dev/null +++ b/mediagoblin/db/sql/base.py @@ -0,0 +1,16 @@ +from sqlalchemy.orm import scoped_session, sessionmaker + + +Session = scoped_session(sessionmaker()) + + +class GMGTableBase(object): + query = Session.query_property() + + @classmethod + def find(cls, query_dict={}): + return cls.query.filter_by(**query_dict) + + @classmethod + def find_one(cls, query_dict={}): + return cls.query.filter_by(**query_dict).first() diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 2ffa9fd7..6de758ed 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -7,7 +7,8 @@ from mediagoblin.db.util import ObjectId from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment, Tag, MediaTag) -Session = sessionmaker() +# Session = sessionmaker() +from mediagoblin.db.sql.base import Session obj_id_table = dict() @@ -134,9 +135,13 @@ def main(): Base.metadata.create_all(engine) convert_users(mk_db) + Session.remove() convert_media_entries(mk_db) + Session.remove() convert_media_tags(mk_db) + Session.remove() convert_media_comments(mk_db) + Session.remove() if __name__ == '__main__': diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 7723a753..b87ff3aa 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -5,8 +5,10 @@ from sqlalchemy import ( Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint) +from mediagoblin.db.sql.base import GMGTableBase -Base = declarative_base() + +Base = declarative_base(cls=GMGTableBase) class User(Base): diff --git a/mediagoblin/db/sql/open.py b/mediagoblin/db/sql/open.py new file mode 100644 index 00000000..57feaf50 --- /dev/null +++ b/mediagoblin/db/sql/open.py @@ -0,0 +1,29 @@ +from sqlalchemy import create_engine + +from mediagoblin.db.sql.base import Session +from mediagoblin.db.sql.models import Base + + +class DatabaseMaster(object): + def __init__(self, engine): + self.engine = engine + + for k,v in Base._decl_class_registry.iteritems(): + setattr(self, k, v) + + def commit(self): + Session.commit() + + def save(self, obj): + Session.add(obj) + Session.flush() + + def reset_after_request(self): + Session.remove() + + +def setup_connection_and_db_from_config(app_config): + engine = create_engine(app_config['sql_engine'], echo=True) + Session.configure(bind=engine) + + return "dummy conn", DatabaseMaster(engine) -- cgit v1.2.3 From 046f9f8481a8950ce18dfc8b4f14e4d14cf59c7a Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 19:06:04 +0100 Subject: Move db/open.py to db/mongo/open.py Starting to move the mongo specific stuff into db/mongo. And create thin "from db.mongo.Y import z" wrappers in db/Y.py. Why? 1) Will make it lots easier to switch to sql for testing/developing. 2) The mongo stuff needs to stay around after moving to sql, because the converter needs it. --- mediagoblin/db/mongo/__init__.py | 15 +++++++++++ mediagoblin/db/mongo/open.py | 55 ++++++++++++++++++++++++++++++++++++++++ mediagoblin/db/open.py | 40 +---------------------------- 3 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 mediagoblin/db/mongo/__init__.py create mode 100644 mediagoblin/db/mongo/open.py diff --git a/mediagoblin/db/mongo/__init__.py b/mediagoblin/db/mongo/__init__.py new file mode 100644 index 00000000..ba347c69 --- /dev/null +++ b/mediagoblin/db/mongo/__init__.py @@ -0,0 +1,15 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . diff --git a/mediagoblin/db/mongo/open.py b/mediagoblin/db/mongo/open.py new file mode 100644 index 00000000..e677ba12 --- /dev/null +++ b/mediagoblin/db/mongo/open.py @@ -0,0 +1,55 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import pymongo +import mongokit +from paste.deploy.converters import asint +from mediagoblin.db import models + + +def connect_database_from_config(app_config, use_pymongo=False): + """ + Connect to the main database, take config from app_config + + Optionally use pymongo instead of mongokit for the connection. + """ + port = app_config.get('db_port') + if port: + port = asint(port) + + if use_pymongo: + connection = pymongo.Connection( + app_config.get('db_host'), port) + else: + connection = mongokit.Connection( + app_config.get('db_host'), port) + return connection + + +def setup_connection_and_db_from_config(app_config, use_pymongo=False): + """ + Setup connection and database from config. + + Optionally use pymongo instead of mongokit. + """ + connection = connect_database_from_config(app_config, use_pymongo) + database_path = app_config['db_name'] + db = connection[database_path] + + if not use_pymongo: + models.register_models(connection) + + return (connection, db) diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py index e677ba12..a92a6ada 100644 --- a/mediagoblin/db/open.py +++ b/mediagoblin/db/open.py @@ -14,42 +14,4 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import pymongo -import mongokit -from paste.deploy.converters import asint -from mediagoblin.db import models - - -def connect_database_from_config(app_config, use_pymongo=False): - """ - Connect to the main database, take config from app_config - - Optionally use pymongo instead of mongokit for the connection. - """ - port = app_config.get('db_port') - if port: - port = asint(port) - - if use_pymongo: - connection = pymongo.Connection( - app_config.get('db_host'), port) - else: - connection = mongokit.Connection( - app_config.get('db_host'), port) - return connection - - -def setup_connection_and_db_from_config(app_config, use_pymongo=False): - """ - Setup connection and database from config. - - Optionally use pymongo instead of mongokit. - """ - connection = connect_database_from_config(app_config, use_pymongo) - database_path = app_config['db_name'] - db = connection[database_path] - - if not use_pymongo: - models.register_models(connection) - - return (connection, db) +from mediagoblin.db.mongo.open import setup_connection_and_db_from_config -- cgit v1.2.3 From 4970960f8c8e0a49d44f15853a2929c3e615a015 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 19:20:09 +0100 Subject: Move db/indexes.py to db/mongo/indexes.py And change references (one!). --- mediagoblin/db/indexes.py | 146 ---------------------------------------- mediagoblin/db/mongo/indexes.py | 146 ++++++++++++++++++++++++++++++++++++++++ mediagoblin/db/util.py | 2 +- 3 files changed, 147 insertions(+), 147 deletions(-) delete mode 100644 mediagoblin/db/indexes.py create mode 100644 mediagoblin/db/mongo/indexes.py diff --git a/mediagoblin/db/indexes.py b/mediagoblin/db/indexes.py deleted file mode 100644 index 1dd73f2b..00000000 --- a/mediagoblin/db/indexes.py +++ /dev/null @@ -1,146 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -""" -Indexes for the local database. - -To add new indexes ------------------- - -Indexes are recorded in the following format: - -ACTIVE_INDEXES = { - 'collection_name': { - 'identifier': { # key identifier used for possibly deprecating later - 'index': [index_foo_goes_here]}} - -... and anything else being parameters to the create_index function -(including unique=True, etc) - -Current indexes must be registered in ACTIVE_INDEXES... deprecated -indexes should be marked in DEPRECATED_INDEXES. - -Remember, ordering of compound indexes MATTERS. Read below for more. - -REQUIRED READING: - - http://kylebanker.com/blog/2010/09/21/the-joy-of-mongodb-indexes/ - - - http://www.mongodb.org/display/DOCS/Indexes - - http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ - - -To remove deprecated indexes ----------------------------- - -Removing deprecated indexes is the same, just move the index into the -deprecated indexes mapping. - -DEPRECATED_INDEXES = { - 'collection_name': { - 'deprecated_index_identifier1': { - 'index': [index_foo_goes_here]}} - -... etc. - -If an index has been deprecated that identifier should NEVER BE USED -AGAIN. Eg, if you previously had 'awesomepants_unique', you shouldn't -use 'awesomepants_unique' again, you should create a totally new name -or at worst use 'awesomepants_unique2'. -""" - -from pymongo import ASCENDING, DESCENDING - - -################ -# Active indexes -################ -ACTIVE_INDEXES = {} - -# MediaEntry indexes -# ------------------ - -MEDIAENTRY_INDEXES = { - 'uploader_slug_unique': { - # Matching an object to an uploader + slug. - # MediaEntries are unique on these two combined, eg: - # /u/${myuser}/m/${myslugname}/ - 'index': [('uploader', ASCENDING), - ('slug', ASCENDING)], - 'unique': True}, - - 'created': { - # A global index for all media entries created, in descending - # order. This is used for the site's frontpage. - 'index': [('created', DESCENDING)]}, - - 'uploader_created': { - # Indexing on uploaders and when media entries are created. - # Used for showing a user gallery, etc. - 'index': [('uploader', ASCENDING), - ('created', DESCENDING)]}, - - 'state_uploader_tags_created': { - # Indexing on processed?, media uploader, associated tags, and - # timestamp Used for showing media items matching a tag - # search, most recent first. - 'index': [('state', ASCENDING), - ('uploader', ASCENDING), - ('tags.slug', DESCENDING), - ('created', DESCENDING)]}, - - 'state_tags_created': { - # Indexing on processed?, media tags, and timestamp (across all users) - # This is used for a front page tag search. - 'index': [('state', ASCENDING), - ('tags.slug', DESCENDING), - ('created', DESCENDING)]}} - - -ACTIVE_INDEXES['media_entries'] = MEDIAENTRY_INDEXES - - -# User indexes -# ------------ - -USER_INDEXES = { - 'username_unique': { - # Index usernames, and make sure they're unique. - # ... I guess we might need to adjust this once we're federated :) - 'index': 'username', - 'unique': True}, - 'created': { - # All most recently created users - 'index': 'created'}} - - -ACTIVE_INDEXES['users'] = USER_INDEXES - - -# MediaComment indexes - -MEDIA_COMMENT_INDEXES = { - 'mediaentry_created': { - 'index': [('media_entry', ASCENDING), - ('created', DESCENDING)]}} - -ACTIVE_INDEXES['media_comments'] = MEDIA_COMMENT_INDEXES - - -#################### -# Deprecated indexes -#################### - -DEPRECATED_INDEXES = {} diff --git a/mediagoblin/db/mongo/indexes.py b/mediagoblin/db/mongo/indexes.py new file mode 100644 index 00000000..1dd73f2b --- /dev/null +++ b/mediagoblin/db/mongo/indexes.py @@ -0,0 +1,146 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +""" +Indexes for the local database. + +To add new indexes +------------------ + +Indexes are recorded in the following format: + +ACTIVE_INDEXES = { + 'collection_name': { + 'identifier': { # key identifier used for possibly deprecating later + 'index': [index_foo_goes_here]}} + +... and anything else being parameters to the create_index function +(including unique=True, etc) + +Current indexes must be registered in ACTIVE_INDEXES... deprecated +indexes should be marked in DEPRECATED_INDEXES. + +Remember, ordering of compound indexes MATTERS. Read below for more. + +REQUIRED READING: + - http://kylebanker.com/blog/2010/09/21/the-joy-of-mongodb-indexes/ + + - http://www.mongodb.org/display/DOCS/Indexes + - http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ + + +To remove deprecated indexes +---------------------------- + +Removing deprecated indexes is the same, just move the index into the +deprecated indexes mapping. + +DEPRECATED_INDEXES = { + 'collection_name': { + 'deprecated_index_identifier1': { + 'index': [index_foo_goes_here]}} + +... etc. + +If an index has been deprecated that identifier should NEVER BE USED +AGAIN. Eg, if you previously had 'awesomepants_unique', you shouldn't +use 'awesomepants_unique' again, you should create a totally new name +or at worst use 'awesomepants_unique2'. +""" + +from pymongo import ASCENDING, DESCENDING + + +################ +# Active indexes +################ +ACTIVE_INDEXES = {} + +# MediaEntry indexes +# ------------------ + +MEDIAENTRY_INDEXES = { + 'uploader_slug_unique': { + # Matching an object to an uploader + slug. + # MediaEntries are unique on these two combined, eg: + # /u/${myuser}/m/${myslugname}/ + 'index': [('uploader', ASCENDING), + ('slug', ASCENDING)], + 'unique': True}, + + 'created': { + # A global index for all media entries created, in descending + # order. This is used for the site's frontpage. + 'index': [('created', DESCENDING)]}, + + 'uploader_created': { + # Indexing on uploaders and when media entries are created. + # Used for showing a user gallery, etc. + 'index': [('uploader', ASCENDING), + ('created', DESCENDING)]}, + + 'state_uploader_tags_created': { + # Indexing on processed?, media uploader, associated tags, and + # timestamp Used for showing media items matching a tag + # search, most recent first. + 'index': [('state', ASCENDING), + ('uploader', ASCENDING), + ('tags.slug', DESCENDING), + ('created', DESCENDING)]}, + + 'state_tags_created': { + # Indexing on processed?, media tags, and timestamp (across all users) + # This is used for a front page tag search. + 'index': [('state', ASCENDING), + ('tags.slug', DESCENDING), + ('created', DESCENDING)]}} + + +ACTIVE_INDEXES['media_entries'] = MEDIAENTRY_INDEXES + + +# User indexes +# ------------ + +USER_INDEXES = { + 'username_unique': { + # Index usernames, and make sure they're unique. + # ... I guess we might need to adjust this once we're federated :) + 'index': 'username', + 'unique': True}, + 'created': { + # All most recently created users + 'index': 'created'}} + + +ACTIVE_INDEXES['users'] = USER_INDEXES + + +# MediaComment indexes + +MEDIA_COMMENT_INDEXES = { + 'mediaentry_created': { + 'index': [('media_entry', ASCENDING), + ('created', DESCENDING)]}} + +ACTIVE_INDEXES['media_comments'] = MEDIA_COMMENT_INDEXES + + +#################### +# Deprecated indexes +#################### + +DEPRECATED_INDEXES = {} diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 52e97f6d..e2065693 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -34,7 +34,7 @@ from pymongo import ASCENDING, DESCENDING from pymongo.errors import InvalidId from mongokit import ObjectId -from mediagoblin.db.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES +from mediagoblin.db.mongo.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES ################ -- cgit v1.2.3 From 59bd06aabb0b9a6277d2ad5d1d38c3c8a8da5298 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 19:35:47 +0100 Subject: Move db/util.py -> db/mongo/util.py - Change some reference - Provide a wrapper db/util.py --- mediagoblin/db/migrations.py | 2 +- mediagoblin/db/models.py | 2 +- mediagoblin/db/mongo/util.py | 292 +++++++++++++++++++++++++++++++++++ mediagoblin/db/util.py | 278 +-------------------------------- mediagoblin/tests/test_migrations.py | 2 +- 5 files changed, 297 insertions(+), 279 deletions(-) create mode 100644 mediagoblin/db/mongo/util.py diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index cfc01287..cf4e94ae 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.util import RegisterMigration +from mediagoblin.db.mongo.util import RegisterMigration from mediagoblin.tools.text import cleaned_markdown_conversion diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 569c3600..51c6e98e 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -22,7 +22,7 @@ from mongokit import Document from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals from mediagoblin.db import migrations -from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId +from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination from mediagoblin.tools import url, common diff --git a/mediagoblin/db/mongo/util.py b/mediagoblin/db/mongo/util.py new file mode 100644 index 00000000..e2065693 --- /dev/null +++ b/mediagoblin/db/mongo/util.py @@ -0,0 +1,292 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +""" +Utilities for database operations. + +Some note on migration and indexing tools: + +We store information about what the state of the database is in the +'mediagoblin' document of the 'app_metadata' collection. Keys in that +document relevant to here: + + - 'migration_number': The integer representing the current state of + the migrations +""" + +import copy + +# Imports that other modules might use +from pymongo import ASCENDING, DESCENDING +from pymongo.errors import InvalidId +from mongokit import ObjectId + +from mediagoblin.db.mongo.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES + + +################ +# Indexing tools +################ + + +def add_new_indexes(database, active_indexes=ACTIVE_INDEXES): + """ + Add any new indexes to the database. + + Args: + - database: pymongo or mongokit database instance. + - active_indexes: indexes to possibly add in the pattern of: + {'collection_name': { + 'identifier': { + 'index': [index_foo_goes_here], + 'unique': True}} + where 'index' is the index to add and all other options are + arguments for collection.create_index. + + Returns: + A list of indexes added in form ('collection', 'index_name') + """ + indexes_added = [] + + for collection_name, indexes in active_indexes.iteritems(): + collection = database[collection_name] + collection_indexes = collection.index_information().keys() + + for index_name, index_data in indexes.iteritems(): + if not index_name in collection_indexes: + # Get a copy actually so we don't modify the actual + # structure + index_data = copy.copy(index_data) + index = index_data.pop('index') + collection.create_index( + index, name=index_name, **index_data) + + indexes_added.append((collection_name, index_name)) + + return indexes_added + + +def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES): + """ + Remove any deprecated indexes from the database. + + Args: + - database: pymongo or mongokit database instance. + - deprecated_indexes: the indexes to deprecate in the pattern of: + {'collection_name': { + 'identifier': { + 'index': [index_foo_goes_here], + 'unique': True}} + + (... although we really only need the 'identifier' here, as the + rest of the information isn't used in this case. But it's kept + around so we can remember what it was) + + Returns: + A list of indexes removed in form ('collection', 'index_name') + """ + indexes_removed = [] + + for collection_name, indexes in deprecated_indexes.iteritems(): + collection = database[collection_name] + collection_indexes = collection.index_information().keys() + + for index_name, index_data in indexes.iteritems(): + if index_name in collection_indexes: + collection.drop_index(index_name) + + indexes_removed.append((collection_name, index_name)) + + return indexes_removed + + +################# +# Migration tools +################# + +# The default migration registry... +# +# Don't set this yourself! RegisterMigration will automatically fill +# this with stuff via decorating methods in migrations.py + +class MissingCurrentMigration(Exception): + pass + + +MIGRATIONS = {} + + +class RegisterMigration(object): + """ + Tool for registering migrations + + Call like: + + @RegisterMigration(33) + def update_dwarves(database): + [...] + + This will register your migration with the default migration + registry. Alternately, to specify a very specific + migration_registry, you can pass in that as the second argument. + + Note, the number of your migration should NEVER be 0 or less than + 0. 0 is the default "no migrations" state! + """ + def __init__(self, migration_number, migration_registry=MIGRATIONS): + assert migration_number > 0, "Migration number must be > 0!" + assert migration_number not in migration_registry, \ + "Duplicate migration numbers detected! That's not allowed!" + + self.migration_number = migration_number + self.migration_registry = migration_registry + + def __call__(self, migration): + self.migration_registry[self.migration_number] = migration + return migration + + +class MigrationManager(object): + """ + Migration handling tool. + + Takes information about a database, lets you update the database + to the latest migrations, etc. + """ + def __init__(self, database, migration_registry=MIGRATIONS): + """ + Args: + - database: database we're going to migrate + - migration_registry: where we should find all migrations to + run + """ + self.database = database + self.migration_registry = migration_registry + self._sorted_migrations = None + + def _ensure_current_migration_record(self): + """ + If there isn't a database[u'app_metadata'] mediagoblin entry + with the 'current_migration', throw an error. + """ + if self.database_current_migration() is None: + raise MissingCurrentMigration( + "Tried to call function which requires " + "'current_migration' set in database") + + @property + def sorted_migrations(self): + """ + Sort migrations if necessary and store in self._sorted_migrations + """ + if not self._sorted_migrations: + self._sorted_migrations = sorted( + self.migration_registry.items(), + # sort on the key... the migration number + key=lambda migration_tuple: migration_tuple[0]) + + return self._sorted_migrations + + def latest_migration(self): + """ + Return a migration number for the latest migration, or 0 if + there are no migrations. + """ + if self.sorted_migrations: + return self.sorted_migrations[-1][0] + else: + # If no migrations have been set, we start at 0. + return 0 + + def set_current_migration(self, migration_number): + """ + Set the migration in the database to migration_number + """ + # Add the mediagoblin migration if necessary + self.database[u'app_metadata'].update( + {u'_id': u'mediagoblin'}, + {u'$set': {u'current_migration': migration_number}}, + upsert=True) + + def install_migration_version_if_missing(self): + """ + Sets the migration to the latest version if no migration + version at all is set. + """ + mgoblin_metadata = self.database[u'app_metadata'].find_one( + {u'_id': u'mediagoblin'}) + if not mgoblin_metadata: + latest_migration = self.latest_migration() + self.set_current_migration(latest_migration) + + def database_current_migration(self): + """ + Return the current migration in the database. + """ + mgoblin_metadata = self.database[u'app_metadata'].find_one( + {u'_id': u'mediagoblin'}) + if not mgoblin_metadata: + return None + else: + return mgoblin_metadata[u'current_migration'] + + def database_at_latest_migration(self): + """ + See if the database is at the latest migration. + Returns a boolean. + """ + current_migration = self.database_current_migration() + return current_migration == self.latest_migration() + + def migrations_to_run(self): + """ + Get a list of migrations to run still, if any. + + Note that calling this will set your migration version to the + latest version if it isn't installed to anything yet! + """ + self._ensure_current_migration_record() + + db_current_migration = self.database_current_migration() + + return [ + (migration_number, migration_func) + for migration_number, migration_func in self.sorted_migrations + if migration_number > db_current_migration] + + def migrate_new(self, pre_callback=None, post_callback=None): + """ + Run all migrations. + + Includes two optional args: + - pre_callback: if called, this is a callback on something to + run pre-migration. Takes (migration_number, migration_func) + as arguments + - pre_callback: if called, this is a callback on something to + run post-migration. Takes (migration_number, migration_func) + as arguments + """ + # If we aren't set to any version number, presume we're at the + # latest (which means we'll do nothing here...) + self.install_migration_version_if_missing() + + for migration_number, migration_func in self.migrations_to_run(): + if pre_callback: + pre_callback(migration_number, migration_func) + migration_func(self.database) + self.set_current_migration(migration_number) + if post_callback: + post_callback(migration_number, migration_func) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index e2065693..3fd96a1d 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -14,279 +14,5 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -""" -Utilities for database operations. - -Some note on migration and indexing tools: - -We store information about what the state of the database is in the -'mediagoblin' document of the 'app_metadata' collection. Keys in that -document relevant to here: - - - 'migration_number': The integer representing the current state of - the migrations -""" - -import copy - -# Imports that other modules might use -from pymongo import ASCENDING, DESCENDING -from pymongo.errors import InvalidId -from mongokit import ObjectId - -from mediagoblin.db.mongo.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES - - -################ -# Indexing tools -################ - - -def add_new_indexes(database, active_indexes=ACTIVE_INDEXES): - """ - Add any new indexes to the database. - - Args: - - database: pymongo or mongokit database instance. - - active_indexes: indexes to possibly add in the pattern of: - {'collection_name': { - 'identifier': { - 'index': [index_foo_goes_here], - 'unique': True}} - where 'index' is the index to add and all other options are - arguments for collection.create_index. - - Returns: - A list of indexes added in form ('collection', 'index_name') - """ - indexes_added = [] - - for collection_name, indexes in active_indexes.iteritems(): - collection = database[collection_name] - collection_indexes = collection.index_information().keys() - - for index_name, index_data in indexes.iteritems(): - if not index_name in collection_indexes: - # Get a copy actually so we don't modify the actual - # structure - index_data = copy.copy(index_data) - index = index_data.pop('index') - collection.create_index( - index, name=index_name, **index_data) - - indexes_added.append((collection_name, index_name)) - - return indexes_added - - -def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES): - """ - Remove any deprecated indexes from the database. - - Args: - - database: pymongo or mongokit database instance. - - deprecated_indexes: the indexes to deprecate in the pattern of: - {'collection_name': { - 'identifier': { - 'index': [index_foo_goes_here], - 'unique': True}} - - (... although we really only need the 'identifier' here, as the - rest of the information isn't used in this case. But it's kept - around so we can remember what it was) - - Returns: - A list of indexes removed in form ('collection', 'index_name') - """ - indexes_removed = [] - - for collection_name, indexes in deprecated_indexes.iteritems(): - collection = database[collection_name] - collection_indexes = collection.index_information().keys() - - for index_name, index_data in indexes.iteritems(): - if index_name in collection_indexes: - collection.drop_index(index_name) - - indexes_removed.append((collection_name, index_name)) - - return indexes_removed - - -################# -# Migration tools -################# - -# The default migration registry... -# -# Don't set this yourself! RegisterMigration will automatically fill -# this with stuff via decorating methods in migrations.py - -class MissingCurrentMigration(Exception): - pass - - -MIGRATIONS = {} - - -class RegisterMigration(object): - """ - Tool for registering migrations - - Call like: - - @RegisterMigration(33) - def update_dwarves(database): - [...] - - This will register your migration with the default migration - registry. Alternately, to specify a very specific - migration_registry, you can pass in that as the second argument. - - Note, the number of your migration should NEVER be 0 or less than - 0. 0 is the default "no migrations" state! - """ - def __init__(self, migration_number, migration_registry=MIGRATIONS): - assert migration_number > 0, "Migration number must be > 0!" - assert migration_number not in migration_registry, \ - "Duplicate migration numbers detected! That's not allowed!" - - self.migration_number = migration_number - self.migration_registry = migration_registry - - def __call__(self, migration): - self.migration_registry[self.migration_number] = migration - return migration - - -class MigrationManager(object): - """ - Migration handling tool. - - Takes information about a database, lets you update the database - to the latest migrations, etc. - """ - def __init__(self, database, migration_registry=MIGRATIONS): - """ - Args: - - database: database we're going to migrate - - migration_registry: where we should find all migrations to - run - """ - self.database = database - self.migration_registry = migration_registry - self._sorted_migrations = None - - def _ensure_current_migration_record(self): - """ - If there isn't a database[u'app_metadata'] mediagoblin entry - with the 'current_migration', throw an error. - """ - if self.database_current_migration() is None: - raise MissingCurrentMigration( - "Tried to call function which requires " - "'current_migration' set in database") - - @property - def sorted_migrations(self): - """ - Sort migrations if necessary and store in self._sorted_migrations - """ - if not self._sorted_migrations: - self._sorted_migrations = sorted( - self.migration_registry.items(), - # sort on the key... the migration number - key=lambda migration_tuple: migration_tuple[0]) - - return self._sorted_migrations - - def latest_migration(self): - """ - Return a migration number for the latest migration, or 0 if - there are no migrations. - """ - if self.sorted_migrations: - return self.sorted_migrations[-1][0] - else: - # If no migrations have been set, we start at 0. - return 0 - - def set_current_migration(self, migration_number): - """ - Set the migration in the database to migration_number - """ - # Add the mediagoblin migration if necessary - self.database[u'app_metadata'].update( - {u'_id': u'mediagoblin'}, - {u'$set': {u'current_migration': migration_number}}, - upsert=True) - - def install_migration_version_if_missing(self): - """ - Sets the migration to the latest version if no migration - version at all is set. - """ - mgoblin_metadata = self.database[u'app_metadata'].find_one( - {u'_id': u'mediagoblin'}) - if not mgoblin_metadata: - latest_migration = self.latest_migration() - self.set_current_migration(latest_migration) - - def database_current_migration(self): - """ - Return the current migration in the database. - """ - mgoblin_metadata = self.database[u'app_metadata'].find_one( - {u'_id': u'mediagoblin'}) - if not mgoblin_metadata: - return None - else: - return mgoblin_metadata[u'current_migration'] - - def database_at_latest_migration(self): - """ - See if the database is at the latest migration. - Returns a boolean. - """ - current_migration = self.database_current_migration() - return current_migration == self.latest_migration() - - def migrations_to_run(self): - """ - Get a list of migrations to run still, if any. - - Note that calling this will set your migration version to the - latest version if it isn't installed to anything yet! - """ - self._ensure_current_migration_record() - - db_current_migration = self.database_current_migration() - - return [ - (migration_number, migration_func) - for migration_number, migration_func in self.sorted_migrations - if migration_number > db_current_migration] - - def migrate_new(self, pre_callback=None, post_callback=None): - """ - Run all migrations. - - Includes two optional args: - - pre_callback: if called, this is a callback on something to - run pre-migration. Takes (migration_number, migration_func) - as arguments - - pre_callback: if called, this is a callback on something to - run post-migration. Takes (migration_number, migration_func) - as arguments - """ - # If we aren't set to any version number, presume we're at the - # latest (which means we'll do nothing here...) - self.install_migration_version_if_missing() - - for migration_number, migration_func in self.migrations_to_run(): - if pre_callback: - pre_callback(migration_number, migration_func) - migration_func(self.database) - self.set_current_migration(migration_number) - if post_callback: - post_callback(migration_number, migration_func) +from mediagoblin.db.mongo.util import (MigrationManager, ObjectId, InvalidId, + DESCENDING) diff --git a/mediagoblin/tests/test_migrations.py b/mediagoblin/tests/test_migrations.py index e7cef0a1..3e2e37ee 100644 --- a/mediagoblin/tests/test_migrations.py +++ b/mediagoblin/tests/test_migrations.py @@ -20,7 +20,7 @@ from pymongo import Connection from mediagoblin.tests.tools import ( install_fixtures_simple, assert_db_meets_expected) -from mediagoblin.db.util import ( +from mediagoblin.db.mongo.util import ( RegisterMigration, MigrationManager, ObjectId, MissingCurrentMigration) from mediagoblin.db.migrations import add_table_field -- cgit v1.2.3 From faf74067dae0f6f9d200a30369e9b7a4501b66ab Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 20:33:33 +0100 Subject: Move db/migrations.py -> db/mongo/migrations.py And change references. --- mediagoblin/db/migrations.py | 110 ----------------------------------- mediagoblin/db/models.py | 2 +- mediagoblin/db/mongo/migrations.py | 110 +++++++++++++++++++++++++++++++++++ mediagoblin/init/__init__.py | 2 +- mediagoblin/tests/test_migrations.py | 2 +- 5 files changed, 113 insertions(+), 113 deletions(-) delete mode 100644 mediagoblin/db/migrations.py create mode 100644 mediagoblin/db/mongo/migrations.py diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py deleted file mode 100644 index cf4e94ae..00000000 --- a/mediagoblin/db/migrations.py +++ /dev/null @@ -1,110 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from mediagoblin.db.mongo.util import RegisterMigration -from mediagoblin.tools.text import cleaned_markdown_conversion - - -def add_table_field(db, table_name, field_name, default_value): - """ - Add a new field to the table/collection named table_name. - The field will have the name field_name and the value default_value - """ - db[table_name].update( - {field_name: {'$exists': False}}, - {'$set': {field_name: default_value}}, - multi=True) - - -# Please see mediagoblin/tests/test_migrations.py for some examples of -# basic migrations. - - -@RegisterMigration(1) -def user_add_bio_html(database): - """ - Users now have richtext bios via Markdown, reflect appropriately. - """ - collection = database['users'] - - target = collection.find( - {'bio_html': {'$exists': False}}) - - for document in target: - document['bio_html'] = cleaned_markdown_conversion( - document['bio']) - collection.save(document) - - -@RegisterMigration(2) -def mediaentry_mediafiles_main_to_original(database): - """ - Rename "main" media file to "original". - """ - collection = database['media_entries'] - target = collection.find( - {'media_files.main': {'$exists': True}}) - - for document in target: - original = document['media_files'].pop('main') - document['media_files']['original'] = original - - collection.save(document) - - -@RegisterMigration(3) -def mediaentry_remove_thumbnail_file(database): - """ - Use media_files['thumb'] instead of media_entries['thumbnail_file'] - """ - database['media_entries'].update( - {'thumbnail_file': {'$exists': True}}, - {'$unset': {'thumbnail_file': 1}}, - multi=True) - - -@RegisterMigration(4) -def mediaentry_add_queued_task_id(database): - """ - Add the 'queued_task_id' field for entries that don't have it. - """ - add_table_field(database, 'media_entries', 'queued_task_id', None) - - -@RegisterMigration(5) -def mediaentry_add_fail_error_and_metadata(database): - """ - Add 'fail_error' and 'fail_metadata' fields to media entries - """ - add_table_field(database, 'media_entries', 'fail_error', None) - add_table_field(database, 'media_entries', 'fail_metadata', {}) - - -@RegisterMigration(6) -def user_add_forgot_password_token_and_expires(database): - """ - Add token and expiration fields to help recover forgotten passwords - """ - add_table_field(database, 'users', 'fp_verification_key', None) - add_table_field(database, 'users', 'fp_token_expire', None) - - -@RegisterMigration(7) -def media_type_image_to_multimedia_type_image(database): - database['media_entries'].update( - {'media_type': 'image'}, - {'$set': {'media_type': 'mediagoblin.media_types.image'}}, - multi=True) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 51c6e98e..e2ac1b5a 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -21,7 +21,7 @@ from mongokit import Document from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals -from mediagoblin.db import migrations +from mediagoblin.db.mongo import migrations from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination from mediagoblin.tools import url, common diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py new file mode 100644 index 00000000..cf4e94ae --- /dev/null +++ b/mediagoblin/db/mongo/migrations.py @@ -0,0 +1,110 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.db.mongo.util import RegisterMigration +from mediagoblin.tools.text import cleaned_markdown_conversion + + +def add_table_field(db, table_name, field_name, default_value): + """ + Add a new field to the table/collection named table_name. + The field will have the name field_name and the value default_value + """ + db[table_name].update( + {field_name: {'$exists': False}}, + {'$set': {field_name: default_value}}, + multi=True) + + +# Please see mediagoblin/tests/test_migrations.py for some examples of +# basic migrations. + + +@RegisterMigration(1) +def user_add_bio_html(database): + """ + Users now have richtext bios via Markdown, reflect appropriately. + """ + collection = database['users'] + + target = collection.find( + {'bio_html': {'$exists': False}}) + + for document in target: + document['bio_html'] = cleaned_markdown_conversion( + document['bio']) + collection.save(document) + + +@RegisterMigration(2) +def mediaentry_mediafiles_main_to_original(database): + """ + Rename "main" media file to "original". + """ + collection = database['media_entries'] + target = collection.find( + {'media_files.main': {'$exists': True}}) + + for document in target: + original = document['media_files'].pop('main') + document['media_files']['original'] = original + + collection.save(document) + + +@RegisterMigration(3) +def mediaentry_remove_thumbnail_file(database): + """ + Use media_files['thumb'] instead of media_entries['thumbnail_file'] + """ + database['media_entries'].update( + {'thumbnail_file': {'$exists': True}}, + {'$unset': {'thumbnail_file': 1}}, + multi=True) + + +@RegisterMigration(4) +def mediaentry_add_queued_task_id(database): + """ + Add the 'queued_task_id' field for entries that don't have it. + """ + add_table_field(database, 'media_entries', 'queued_task_id', None) + + +@RegisterMigration(5) +def mediaentry_add_fail_error_and_metadata(database): + """ + Add 'fail_error' and 'fail_metadata' fields to media entries + """ + add_table_field(database, 'media_entries', 'fail_error', None) + add_table_field(database, 'media_entries', 'fail_metadata', {}) + + +@RegisterMigration(6) +def user_add_forgot_password_token_and_expires(database): + """ + Add token and expiration fields to help recover forgotten passwords + """ + add_table_field(database, 'users', 'fp_verification_key', None) + add_table_field(database, 'users', 'fp_token_expire', None) + + +@RegisterMigration(7) +def media_type_image_to_multimedia_type_image(database): + database['media_entries'].update( + {'media_type': 'image'}, + {'$set': {'media_type': 'mediagoblin.media_types.image'}}, + multi=True) diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index 08a0618d..5f7f83d4 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -57,7 +57,7 @@ def setup_database(): app_config = mg_globals.app_config # This MUST be imported so as to set up the appropriate migrations! - from mediagoblin.db import migrations + from mediagoblin.db.mongo import migrations # Set up the database connection, db = setup_connection_and_db_from_config(app_config) diff --git a/mediagoblin/tests/test_migrations.py b/mediagoblin/tests/test_migrations.py index 3e2e37ee..8e573f5a 100644 --- a/mediagoblin/tests/test_migrations.py +++ b/mediagoblin/tests/test_migrations.py @@ -23,7 +23,7 @@ from mediagoblin.tests.tools import ( from mediagoblin.db.mongo.util import ( RegisterMigration, MigrationManager, ObjectId, MissingCurrentMigration) -from mediagoblin.db.migrations import add_table_field +from mediagoblin.db.mongo.migrations import add_table_field # This one will get filled with local migrations TEST_MIGRATION_REGISTRY = {} -- cgit v1.2.3 From 4ae4012dad3f5638ea7b510d40f0b4d0b641fe2a Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 20:41:21 +0100 Subject: Move db/models.py -> db/mongo/models.py To my surprise, there was only ONE reference to models.py. From open.py. --- mediagoblin/db/models.py | 363 ----------------------------------------- mediagoblin/db/mongo/models.py | 363 +++++++++++++++++++++++++++++++++++++++++ mediagoblin/db/mongo/open.py | 2 +- 3 files changed, 364 insertions(+), 364 deletions(-) delete mode 100644 mediagoblin/db/models.py create mode 100644 mediagoblin/db/mongo/models.py diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py deleted file mode 100644 index e2ac1b5a..00000000 --- a/mediagoblin/db/models.py +++ /dev/null @@ -1,363 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import datetime -import uuid - -from mongokit import Document - -from mediagoblin.auth import lib as auth_lib -from mediagoblin import mg_globals -from mediagoblin.db.mongo import migrations -from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId -from mediagoblin.tools.pagination import Pagination -from mediagoblin.tools import url, common - -################### -# Custom validators -################### - -######## -# Models -######## - - -class User(Document): - """ - A user of MediaGoblin. - - Structure: - - username: The username of this user, should be unique to this instance. - - email: Email address of this user - - created: When the user was created - - plugin_data: a mapping of extra plugin information for this User. - Nothing uses this yet as we don't have plugins, but someday we - might... :) - - pw_hash: Hashed version of user's password. - - email_verified: Whether or not the user has verified their email or not. - Most parts of the site are disabled for users who haven't yet. - - status: whether or not the user is active, etc. Currently only has two - values, 'needs_email_verification' or 'active'. (In the future, maybe - we'll change this to a boolean with a key of 'active' and have a - separate field for a reason the user's been disabled if that's - appropriate... email_verified is already separate, after all.) - - verification_key: If the user is awaiting email verification, the user - will have to provide this key (which will be encoded in the presented - URL) in order to confirm their email as active. - - is_admin: Whether or not this user is an administrator or not. - - url: this user's personal webpage/website, if appropriate. - - bio: biography of this user (plaintext, in markdown) - - bio_html: biography of the user converted to proper HTML. - """ - __collection__ = 'users' - use_dot_notation = True - - structure = { - 'username': unicode, - 'email': unicode, - 'created': datetime.datetime, - 'plugin_data': dict, # plugins can dump stuff here. - 'pw_hash': unicode, - 'email_verified': bool, - 'status': unicode, - 'verification_key': unicode, - 'is_admin': bool, - 'url': unicode, - 'bio': unicode, # May contain markdown - 'bio_html': unicode, # May contain plaintext, or HTML - 'fp_verification_key': unicode, # forgotten password verification key - 'fp_token_expire': datetime.datetime, - } - - required_fields = ['username', 'created', 'pw_hash', 'email'] - - default_values = { - 'created': datetime.datetime.utcnow, - 'email_verified': False, - 'status': u'needs_email_verification', - 'verification_key': lambda: unicode(uuid.uuid4()), - 'is_admin': False} - - def check_login(self, password): - """ - See if a user can login with this password - """ - return auth_lib.bcrypt_check_password( - password, self.pw_hash) - - -class MediaEntry(Document): - """ - Record of a piece of media. - - Structure: - - uploader: A reference to a User who uploaded this. - - - title: Title of this work - - - slug: A normalized "slug" which can be used as part of a URL to retrieve - this work, such as 'my-works-name-in-slug-form' may be viewable by - 'http://mg.example.org/u/username/m/my-works-name-in-slug-form/' - Note that since URLs are constructed this way, slugs must be unique - per-uploader. (An index is provided to enforce that but code should be - written on the python side to ensure this as well.) - - - created: Date and time of when this piece of work was uploaded. - - - description: Uploader-set description of this work. This can be marked - up with MarkDown for slight fanciness (links, boldness, italics, - paragraphs...) - - - description_html: Rendered version of the description, run through - Markdown and cleaned with our cleaning tool. - - - media_type: What type of media is this? Currently we only support - 'image' ;) - - - media_data: Extra information that's media-format-dependent. - For example, images might contain some EXIF data that's not appropriate - to other formats. You might store it like: - - mediaentry.media_data['exif'] = { - 'manufacturer': 'CASIO', - 'model': 'QV-4000', - 'exposure_time': .659} - - Alternately for video you might store: - - # play length in seconds - mediaentry.media_data['play_length'] = 340 - - ... so what's appropriate here really depends on the media type. - - - plugin_data: a mapping of extra plugin information for this User. - Nothing uses this yet as we don't have plugins, but someday we - might... :) - - - tags: A list of tags. Each tag is stored as a dictionary that has a key - for the actual name and the normalized name-as-slug, so ultimately this - looks like: - [{'name': 'Gully Gardens', - 'slug': 'gully-gardens'}, - {'name': 'Castle Adventure Time?!", - 'slug': 'castle-adventure-time'}] - - - state: What's the state of this file? Active, inactive, disabled, etc... - But really for now there are only two states: - "unprocessed": uploaded but needs to go through processing for display - "processed": processed and able to be displayed - - - queued_media_file: storage interface style filepath describing a file - queued for processing. This is stored in the mg_globals.queue_store - storage system. - - - queued_task_id: celery task id. Use this to fetch the task state. - - - media_files: Files relevant to this that have actually been processed - and are available for various types of display. Stored like: - {'thumb': ['dir1', 'dir2', 'pic.png'} - - - attachment_files: A list of "attachment" files, ones that aren't - critical to this piece of media but may be usefully relevant to people - viewing the work. (currently unused.) - - - fail_error: path to the exception raised - - fail_metadata: - """ - __collection__ = 'media_entries' - use_dot_notation = True - - structure = { - 'uploader': ObjectId, - 'title': unicode, - 'slug': unicode, - 'created': datetime.datetime, - 'description': unicode, # May contain markdown/up - 'description_html': unicode, # May contain plaintext, or HTML - 'media_type': unicode, - 'media_data': dict, # extra data relevant to this media_type - 'plugin_data': dict, # plugins can dump stuff here. - 'tags': [dict], - 'state': unicode, - - # For now let's assume there can only be one main file queued - # at a time - 'queued_media_file': [unicode], - 'queued_task_id': unicode, - - # A dictionary of logical names to filepaths - 'media_files': dict, - - # The following should be lists of lists, in appropriate file - # record form - 'attachment_files': list, - - # If things go badly in processing things, we'll store that - # data here - 'fail_error': unicode, - 'fail_metadata': dict} - - required_fields = [ - 'uploader', 'created', 'media_type', 'slug'] - - default_values = { - 'created': datetime.datetime.utcnow, - 'state': u'unprocessed'} - - def get_comments(self, ascending=False): - if ascending: - order = ASCENDING - else: - order = DESCENDING - - return self.db.MediaComment.find({ - 'media_entry': self._id}).sort('created', order) - - def get_display_media(self, media_map, - fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): - """ - Find the best media for display. - - Args: - - media_map: a dict like - {u'image_size': [u'dir1', u'dir2', u'image.jpg']} - - fetch_order: the order we should try fetching images in - - Returns: - (media_size, media_path) - """ - media_sizes = media_map.keys() - - for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: - if media_size in media_sizes: - return media_map[media_size] - - def main_mediafile(self): - pass - - def generate_slug(self): - self.slug = url.slugify(self.title) - - duplicate = mg_globals.database.media_entries.find_one( - {'slug': self.slug}) - - if duplicate: - self.slug = "%s-%s" % (self._id, self.slug) - - def url_for_self(self, urlgen): - """ - Generate an appropriate url for ourselves - - Use a slug if we have one, else use our '_id'. - """ - uploader = self.get_uploader() - - if self.get('slug'): - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=self.slug) - else: - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=unicode(self._id)) - - def url_to_prev(self, urlgen): - """ - Provide a url to the previous entry from this user, if there is one - """ - cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id}, - 'uploader': self.uploader, - 'state': 'processed'}).sort( - '_id', ASCENDING).limit(1) - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader().username, - media=unicode(cursor[0].slug)) - - def url_to_next(self, urlgen): - """ - Provide a url to the next entry from this user, if there is one - """ - cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id}, - 'uploader': self.uploader, - 'state': 'processed'}).sort( - '_id', DESCENDING).limit(1) - - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader().username, - media=unicode(cursor[0].slug)) - - def get_uploader(self): - return self.db.User.find_one({'_id': self.uploader}) - - def get_fail_exception(self): - """ - Get the exception that's appropriate for this error - """ - if self['fail_error']: - return common.import_component(self['fail_error']) - - -class MediaComment(Document): - """ - A comment on a MediaEntry. - - Structure: - - media_entry: The media entry this comment is attached to - - author: user who posted this comment - - created: when the comment was created - - content: plaintext (but markdown'able) version of the comment's content. - - content_html: the actual html-rendered version of the comment displayed. - Run through Markdown and the HTML cleaner. - """ - - __collection__ = 'media_comments' - use_dot_notation = True - - structure = { - 'media_entry': ObjectId, - 'author': ObjectId, - 'created': datetime.datetime, - 'content': unicode, - 'content_html': unicode} - - required_fields = [ - 'media_entry', 'author', 'created', 'content'] - - default_values = { - 'created': datetime.datetime.utcnow} - - def media_entry(self): - return self.db.MediaEntry.find_one({'_id': self['media_entry']}) - - def author(self): - return self.db.User.find_one({'_id': self['author']}) - - -REGISTER_MODELS = [ - MediaEntry, - User, - MediaComment] - - -def register_models(connection): - """ - Register all models in REGISTER_MODELS with this connection. - """ - connection.register(REGISTER_MODELS) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py new file mode 100644 index 00000000..e2ac1b5a --- /dev/null +++ b/mediagoblin/db/mongo/models.py @@ -0,0 +1,363 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import datetime +import uuid + +from mongokit import Document + +from mediagoblin.auth import lib as auth_lib +from mediagoblin import mg_globals +from mediagoblin.db.mongo import migrations +from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId +from mediagoblin.tools.pagination import Pagination +from mediagoblin.tools import url, common + +################### +# Custom validators +################### + +######## +# Models +######## + + +class User(Document): + """ + A user of MediaGoblin. + + Structure: + - username: The username of this user, should be unique to this instance. + - email: Email address of this user + - created: When the user was created + - plugin_data: a mapping of extra plugin information for this User. + Nothing uses this yet as we don't have plugins, but someday we + might... :) + - pw_hash: Hashed version of user's password. + - email_verified: Whether or not the user has verified their email or not. + Most parts of the site are disabled for users who haven't yet. + - status: whether or not the user is active, etc. Currently only has two + values, 'needs_email_verification' or 'active'. (In the future, maybe + we'll change this to a boolean with a key of 'active' and have a + separate field for a reason the user's been disabled if that's + appropriate... email_verified is already separate, after all.) + - verification_key: If the user is awaiting email verification, the user + will have to provide this key (which will be encoded in the presented + URL) in order to confirm their email as active. + - is_admin: Whether or not this user is an administrator or not. + - url: this user's personal webpage/website, if appropriate. + - bio: biography of this user (plaintext, in markdown) + - bio_html: biography of the user converted to proper HTML. + """ + __collection__ = 'users' + use_dot_notation = True + + structure = { + 'username': unicode, + 'email': unicode, + 'created': datetime.datetime, + 'plugin_data': dict, # plugins can dump stuff here. + 'pw_hash': unicode, + 'email_verified': bool, + 'status': unicode, + 'verification_key': unicode, + 'is_admin': bool, + 'url': unicode, + 'bio': unicode, # May contain markdown + 'bio_html': unicode, # May contain plaintext, or HTML + 'fp_verification_key': unicode, # forgotten password verification key + 'fp_token_expire': datetime.datetime, + } + + required_fields = ['username', 'created', 'pw_hash', 'email'] + + default_values = { + 'created': datetime.datetime.utcnow, + 'email_verified': False, + 'status': u'needs_email_verification', + 'verification_key': lambda: unicode(uuid.uuid4()), + 'is_admin': False} + + def check_login(self, password): + """ + See if a user can login with this password + """ + return auth_lib.bcrypt_check_password( + password, self.pw_hash) + + +class MediaEntry(Document): + """ + Record of a piece of media. + + Structure: + - uploader: A reference to a User who uploaded this. + + - title: Title of this work + + - slug: A normalized "slug" which can be used as part of a URL to retrieve + this work, such as 'my-works-name-in-slug-form' may be viewable by + 'http://mg.example.org/u/username/m/my-works-name-in-slug-form/' + Note that since URLs are constructed this way, slugs must be unique + per-uploader. (An index is provided to enforce that but code should be + written on the python side to ensure this as well.) + + - created: Date and time of when this piece of work was uploaded. + + - description: Uploader-set description of this work. This can be marked + up with MarkDown for slight fanciness (links, boldness, italics, + paragraphs...) + + - description_html: Rendered version of the description, run through + Markdown and cleaned with our cleaning tool. + + - media_type: What type of media is this? Currently we only support + 'image' ;) + + - media_data: Extra information that's media-format-dependent. + For example, images might contain some EXIF data that's not appropriate + to other formats. You might store it like: + + mediaentry.media_data['exif'] = { + 'manufacturer': 'CASIO', + 'model': 'QV-4000', + 'exposure_time': .659} + + Alternately for video you might store: + + # play length in seconds + mediaentry.media_data['play_length'] = 340 + + ... so what's appropriate here really depends on the media type. + + - plugin_data: a mapping of extra plugin information for this User. + Nothing uses this yet as we don't have plugins, but someday we + might... :) + + - tags: A list of tags. Each tag is stored as a dictionary that has a key + for the actual name and the normalized name-as-slug, so ultimately this + looks like: + [{'name': 'Gully Gardens', + 'slug': 'gully-gardens'}, + {'name': 'Castle Adventure Time?!", + 'slug': 'castle-adventure-time'}] + + - state: What's the state of this file? Active, inactive, disabled, etc... + But really for now there are only two states: + "unprocessed": uploaded but needs to go through processing for display + "processed": processed and able to be displayed + + - queued_media_file: storage interface style filepath describing a file + queued for processing. This is stored in the mg_globals.queue_store + storage system. + + - queued_task_id: celery task id. Use this to fetch the task state. + + - media_files: Files relevant to this that have actually been processed + and are available for various types of display. Stored like: + {'thumb': ['dir1', 'dir2', 'pic.png'} + + - attachment_files: A list of "attachment" files, ones that aren't + critical to this piece of media but may be usefully relevant to people + viewing the work. (currently unused.) + + - fail_error: path to the exception raised + - fail_metadata: + """ + __collection__ = 'media_entries' + use_dot_notation = True + + structure = { + 'uploader': ObjectId, + 'title': unicode, + 'slug': unicode, + 'created': datetime.datetime, + 'description': unicode, # May contain markdown/up + 'description_html': unicode, # May contain plaintext, or HTML + 'media_type': unicode, + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. + 'tags': [dict], + 'state': unicode, + + # For now let's assume there can only be one main file queued + # at a time + 'queued_media_file': [unicode], + 'queued_task_id': unicode, + + # A dictionary of logical names to filepaths + 'media_files': dict, + + # The following should be lists of lists, in appropriate file + # record form + 'attachment_files': list, + + # If things go badly in processing things, we'll store that + # data here + 'fail_error': unicode, + 'fail_metadata': dict} + + required_fields = [ + 'uploader', 'created', 'media_type', 'slug'] + + default_values = { + 'created': datetime.datetime.utcnow, + 'state': u'unprocessed'} + + def get_comments(self, ascending=False): + if ascending: + order = ASCENDING + else: + order = DESCENDING + + return self.db.MediaComment.find({ + 'media_entry': self._id}).sort('created', order) + + def get_display_media(self, media_map, + fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): + """ + Find the best media for display. + + Args: + - media_map: a dict like + {u'image_size': [u'dir1', u'dir2', u'image.jpg']} + - fetch_order: the order we should try fetching images in + + Returns: + (media_size, media_path) + """ + media_sizes = media_map.keys() + + for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: + if media_size in media_sizes: + return media_map[media_size] + + def main_mediafile(self): + pass + + def generate_slug(self): + self.slug = url.slugify(self.title) + + duplicate = mg_globals.database.media_entries.find_one( + {'slug': self.slug}) + + if duplicate: + self.slug = "%s-%s" % (self._id, self.slug) + + def url_for_self(self, urlgen): + """ + Generate an appropriate url for ourselves + + Use a slug if we have one, else use our '_id'. + """ + uploader = self.get_uploader() + + if self.get('slug'): + return urlgen( + 'mediagoblin.user_pages.media_home', + user=uploader.username, + media=self.slug) + else: + return urlgen( + 'mediagoblin.user_pages.media_home', + user=uploader.username, + media=unicode(self._id)) + + def url_to_prev(self, urlgen): + """ + Provide a url to the previous entry from this user, if there is one + """ + cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id}, + 'uploader': self.uploader, + 'state': 'processed'}).sort( + '_id', ASCENDING).limit(1) + if cursor.count(): + return urlgen('mediagoblin.user_pages.media_home', + user=self.get_uploader().username, + media=unicode(cursor[0].slug)) + + def url_to_next(self, urlgen): + """ + Provide a url to the next entry from this user, if there is one + """ + cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id}, + 'uploader': self.uploader, + 'state': 'processed'}).sort( + '_id', DESCENDING).limit(1) + + if cursor.count(): + return urlgen('mediagoblin.user_pages.media_home', + user=self.get_uploader().username, + media=unicode(cursor[0].slug)) + + def get_uploader(self): + return self.db.User.find_one({'_id': self.uploader}) + + def get_fail_exception(self): + """ + Get the exception that's appropriate for this error + """ + if self['fail_error']: + return common.import_component(self['fail_error']) + + +class MediaComment(Document): + """ + A comment on a MediaEntry. + + Structure: + - media_entry: The media entry this comment is attached to + - author: user who posted this comment + - created: when the comment was created + - content: plaintext (but markdown'able) version of the comment's content. + - content_html: the actual html-rendered version of the comment displayed. + Run through Markdown and the HTML cleaner. + """ + + __collection__ = 'media_comments' + use_dot_notation = True + + structure = { + 'media_entry': ObjectId, + 'author': ObjectId, + 'created': datetime.datetime, + 'content': unicode, + 'content_html': unicode} + + required_fields = [ + 'media_entry', 'author', 'created', 'content'] + + default_values = { + 'created': datetime.datetime.utcnow} + + def media_entry(self): + return self.db.MediaEntry.find_one({'_id': self['media_entry']}) + + def author(self): + return self.db.User.find_one({'_id': self['author']}) + + +REGISTER_MODELS = [ + MediaEntry, + User, + MediaComment] + + +def register_models(connection): + """ + Register all models in REGISTER_MODELS with this connection. + """ + connection.register(REGISTER_MODELS) diff --git a/mediagoblin/db/mongo/open.py b/mediagoblin/db/mongo/open.py index e677ba12..63889292 100644 --- a/mediagoblin/db/mongo/open.py +++ b/mediagoblin/db/mongo/open.py @@ -17,7 +17,7 @@ import pymongo import mongokit from paste.deploy.converters import asint -from mediagoblin.db import models +from mediagoblin.db.mongo import models def connect_database_from_config(app_config, use_pymongo=False): -- cgit v1.2.3 From c8cb0ee88f8eb667af77c5741cfb04f95afe66b0 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 20 Dec 2011 22:06:36 +0100 Subject: Polishing the webfinger implementation - Changed quotes in the templates from " to ' - Changed all link generation to use request.urlgen - Moved xrd links data generation from template to view - Added parsing of the account URI using urlparse --- .../templates/mediagoblin/webfinger/host-meta.xml | 12 +- .../templates/mediagoblin/webfinger/xrd.xml | 20 +- mediagoblin/tools/feed.py | 527 +++++++++++++++++++++ mediagoblin/webfinger/views.py | 94 +++- 4 files changed, 623 insertions(+), 30 deletions(-) create mode 100644 mediagoblin/tools/feed.py diff --git a/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml index dff2c9aa..95a1a176 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml @@ -14,14 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -#} - - + + {{ request.host }} - - {{ llrd_title }} + + {{ lrdd_title }} diff --git a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml index 9a793637..1fe34577 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml @@ -14,16 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -#} - - + + - {{ request.GET.get('uri') }} - http://{{ request.host }}/u/{{ username }} - - - - + {{ subject }} + {{ alias }} + {% for link in links %} + + {%- endfor %} diff --git a/mediagoblin/tools/feed.py b/mediagoblin/tools/feed.py new file mode 100644 index 00000000..7c14a42a --- /dev/null +++ b/mediagoblin/tools/feed.py @@ -0,0 +1,527 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from lxml import etree +from lxml.builder import ElementMaker +from werkzeug.wrappers import BaseResponse + +import datetime + +""" + Feed engine written for GNU MediaGoblin, + based on werkzeug atom feeds tool (werkzeug.contrib.atom) + + The feed library contains two types of classes: + - Entities that contains the feed data. + - Generators that are injected to the above classes and are able to + generate feeds in a specific format. An atom feed genearator is + provided, but others could be written as well. + + The Werkzeurg library interface have been mimetized, so the replacement can + be done with only switching the import call. + + Example:: + + def atom_feed(request): + feed = AtomFeed("My Blog", feed_url=request.url, + url=request.host_url, + subtitle="My example blog for a feed test.") + for post in Post.query.limit(10).all(): + feed.add(post.title, post.body, content_type='html', + author=post.author, url=post.url, id=post.uid, + updated=post.last_update, published=post.pub_date) + return feed.get_response() +""" + + +## +# Class FeedGenerator +# +class FeedGenerator(object): + def __init__(self): + pass + + def format_iso8601(self, obj): + """Format a datetime object for iso8601""" + return obj.strftime('%Y-%m-%dT%H:%M:%SZ') + + +## +# Class AtomGenerator +# +class AtomGenerator(FeedGenerator): + """ Generator that generate feeds in Atom format """ + NAMESPACE = "http://www.w3.org/2005/Atom" + + def __init__(self): + pass + + def generate(self, data): + """Return an XML tree representation.""" + if isinstance(data, AtomFeed): + return self.generate_feed(data) + elif isinstance(data, FeedEntry): + return self.generate_feedEntry(data) + + def generate_text_block(self, name, content, content_type=None): + """Helper method for the builder that creates an XML text block.""" + root = etree.Element(name) + + if content_type: + root.set('type', content_type) + + if content_type == 'xhtml': + div_ele = etree.Element('div') + div_ele.set('xmlns', XHTML_NAMESPACE) + div_ele.text = content + root.append(div_ele) + else: + root.text = content + + return root + + def generate_feed(self, data): + """Return an XML tree representation of the feed.""" + NSMAP = {None: self.NAMESPACE} + root = etree.Element("feed", nsmap=NSMAP) + + E = ElementMaker() + + # atom demands either an author element in every entry or a global one + if not data.author: + if False in map(lambda e: bool(e.author), data.entries): + data.author = ({'name': 'Unknown author'},) + + if not data.updated: + dates = sorted([entry.updated for entry in data.entries]) + data.updated = dates and dates[-1] or datetime.utcnow() + + title_ele = self.generate_text_block( + 'title', + data.title, + data.title_type) + root.append(title_ele) + + root.append(E.id(data.id)) + root.append(E.updated(self.format_iso8601(data.updated))) + + if data.url: + link_ele = etree.Element("link") + link_ele.set("href", data.url) + root.append(link_ele) + + if data.feed_url: + link_ele = etree.Element("link") + link_ele.set("href", data.feed_url) + link_ele.set("rel", "self") + root.append(link_ele) + + for link in data.links: + link_ele = etree.Element("link") + for name, value in link.items(): + link_ele.set(name, value) + root.append(link_ele) + + for author in data.author: + author_element = etree.Element("author") + author_element.append(E.name(author['name'])) + if 'uri' in author: + author_element.append(E.name(author['uri'])) + if 'email' in author: + author_element.append(E.name(author['email'])) + + root.append(author_element) + + if data.subtitle: + root.append(self.generate_text_block('subtitle', data.subtitle, + data.subtitle_type)) + if data.icon: + root.append(E.icon(data.icon)) + + if data.logo: + root.append(E.logo(data.logo)) + + if data.rights: + root.append(self.generate_text_block('rights', data.rights, + data.rights_type)) + + generator_name, generator_url, generator_version = data.generator + if generator_name or generator_url or generator_version: + generator_ele = etree.Element("generator") + if generator_url: + generator_ele.set("uri", generator_url, True) + if generator_version: + generator_ele.set("version", generator_version) + + generator_ele.text = generator_name + + root.append(generator_ele) + + for entry in data.entries: + root.append(entry.generate()) + + return root + + def generate_feedEntry(self, data): + """Return an XML tree representation of the feed entry.""" + E = ElementMaker() + root = etree.Element("entry") + + if data.xml_base: + root.base = data.xml_base + + title_ele = self.generate_text_block( + 'title', + data.title, + data.title_type) + root.append(title_ele) + + root.append(E.id(data.id)) + root.append(E.updated(self.format_iso8601(data.updated))) + + if data.published: + root.append(E.published(self.format_iso8601(data.published))) + + if data.url: + link_ele = etree.Element("link") + link_ele.set("href", data.url) + root.append(link_ele) + + for author in data.author: + author_element = etree.Element("author") + author_element.append(E.name(author['name'])) + if 'uri' in author: + author_element.append(E.name(author['uri'])) + if 'email' in author: + author_element.append(E.name(author['email'])) + + root.append(author_element) + + for link in data.links: + link_ele = etree.Element("link") + for name, value in link.items(): + link_ele.set(name, value) + root.append(link_ele) + + print data.thumbnail + + if data.thumbnail: + namespace = "http://search.yahoo.com/mrss/" + nsmap = {"media": namespace} + thumbnail_ele = etree.Element( + "{http://search.yahoo.com/mrss/}thumbnail", nsmap=nsmap) + thumbnail_ele.set("url", data.thumbnail) + + root.append(thumbnail_ele) + + if data.summary: + summary_ele = self.generate_text_block('summary', data.summary, + data.summary_type) + root.append(summary_ele) + + if data.content: + content = data.content + + if data.thumbnail: + thumbnail_html = etree.Element("img") + thumbnail_html.set("src", data.thumbnail) + content = etree.tostring(thumbnail_html) + content + + content_ele = self.generate_text_block('content', content, + data.content_type) + root.append(content_ele) + + for name, value in data.custom.items(): + element = etree.Element(name) + element.text = value + root.append(element) + + return root + + +## +# Class AtomFeed +# +class AtomFeed(object): + """ + A helper class that contains feeds. By default, it uses the AtomGenerator + but others could be injected. It has the AtomFeed name to keep the name + it had on werkzeug library + + Following Werkzeurg implementation, the constructor takes a lot of + parameters. As an addition, the class will also store custom parameters for + fields not explicitly supported by the library. + + :param feed_generator: The generator that will be used to generate the feed + defaults to AtomGenerator + :param title: the title of the feed. Required. + :param title_type: the type attribute for the title element. One of + ``'html'``, ``'text'`` or ``'xhtml'``. + :param url: the url for the feed (not the url *of* the feed) + :param id: a globally unique id for the feed. Must be an URI. If + not present the `feed_url` is used, but one of both is + required. + :param updated: the time the feed was modified the last time. Must + be a :class:`datetime.datetime` object. If not + present the latest entry's `updated` is used. + :param feed_url: the URL to the feed. Should be the URL that was + requested. + :param author: the author of the feed. Must be either a string (the + name) or a dict with name (required) and uri or + email (both optional). Can be a list of (may be + mixed, too) strings and dicts, too, if there are + multiple authors. Required if not every entry has an + author element. + :param icon: an icon for the feed. + :param logo: a logo for the feed. + :param rights: copyright information for the feed. + :param rights_type: the type attribute for the rights element. One of + ``'html'``, ``'text'`` or ``'xhtml'``. Default is + ``'text'``. + :param subtitle: a short description of the feed. + :param subtitle_type: the type attribute for the subtitle element. + One of ``'text'``, ``'html'``, ``'text'`` + or ``'xhtml'``. Default is ``'text'``. + :param links: additional links. Must be a list of dictionaries with + href (required) and rel, type, hreflang, title, length + (all optional) + :param generator: the software that generated this feed. This must be + a tuple in the form ``(name, url, version)``. If + you don't want to specify one of them, set the item + to `None`. + :param entries: a list with the entries for the feed. Entries can also + be added later with :meth:`add`. + + For more information on the elements see + http://www.atomenabled.org/developers/syndication/ + + Everywhere where a list is demanded, any iterable can be used. + """ + + default_generator = ('GNU Mediagoblin', None, None) + default_feed_generator = AtomGenerator() + + def __init__(self, title=None, entries=None, feed_generator=None, + **kwargs): + self.feed_generator = feed_generator + self.title = title + self.title_type = kwargs.get('title_type', 'text') + self.url = kwargs.get('url') + self.feed_url = kwargs.get('feed_url', self.url) + self.id = kwargs.get('id', self.feed_url) + self.updated = kwargs.get('updated') + self.author = kwargs.get('author', ()) + self.icon = kwargs.get('icon') + self.logo = kwargs.get('logo') + self.rights = kwargs.get('rights') + self.rights_type = kwargs.get('rights_type') + self.subtitle = kwargs.get('subtitle') + self.subtitle_type = kwargs.get('subtitle_type', 'text') + self.generator = kwargs.get('generator') + if self.generator is None: + self.generator = self.default_generator + self.links = kwargs.get('links', []) + self.entries = entries and list(entries) or [] + + if not hasattr(self.author, '__iter__') \ + or isinstance(self.author, (basestring, dict)): + self.author = [self.author] + for i, author in enumerate(self.author): + if not isinstance(author, dict): + self.author[i] = {'name': author} + + if not self.feed_generator: + self.feed_generator = self.default_feed_generator + if not self.title: + raise ValueError('title is required') + if not self.id: + raise ValueError('id is required') + for author in self.author: + if 'name' not in author: + raise TypeError('author must contain at least a name') + + # Look for arguments that we haven't matched with object members. + # They will be added to the custom dictionary. + # This way we can have custom fields not specified in this class. + self.custom = {} + properties = dir(self) + + for name, value in kwargs.items(): + if (properties.count(name) == 0): + self.custom[name] = value + + def add(self, *args, **kwargs): + """Add a new entry to the feed. This function can either be called + with a :class:`FeedEntry` or some keyword and positional arguments + that are forwarded to the :class:`FeedEntry` constructor. + """ + if len(args) == 1 and not kwargs and isinstance(args[0], FeedEntry): + args[0].generator = self.generator + self.entries.append(args[0]) + else: + kwargs['feed_url'] = self.feed_url + self.entries.append(FeedEntry(feed_generator=self.feed_generator, + *args, **kwargs)) + + def __repr__(self): + return '<%s %r (%d entries)>' % ( + self.__class__.__name__, + self.title, + len(self.entries) + ) + + def generate(self): + """Return an XML tree representation of the feed.""" + return self.feed_generator.generate(self) + + def to_string(self): + """Convert the feed into a string.""" + return etree.tostring(self.generate(), encoding='UTF-8') + + def get_response(self): + """Return a response object for the feed.""" + return BaseResponse(self.to_string(), mimetype='application/atom+xml') + + def __call__(self, environ, start_response): + """Use the class as WSGI response object.""" + return self.get_response()(environ, start_response) + + def __unicode__(self): + return self.to_string() + + def __str__(self): + return self.to_string().encode('utf-8') + + +## +# Class FeedEntry +# +class FeedEntry(object): + """Represents a single entry in a feed. + + Following Werkzeurg implementation, the constructor takes a lot of + parameters. As an addition, the class will also store custom parameters for + fields not explicitly supported by the library. + + :param feed_generator: The generator that will be used to generate the feed. + defaults to AtomGenerator + :param title: the title of the entry. Required. + :param title_type: the type attribute for the title element. One of + ``'html'``, ``'text'`` or ``'xhtml'``. + :param content: the content of the entry. + :param content_type: the type attribute for the content element. One + of ``'html'``, ``'text'`` or ``'xhtml'``. + :param summary: a summary of the entry's content. + :param summary_type: the type attribute for the summary element. One + of ``'html'``, ``'text'`` or ``'xhtml'``. + :param url: the url for the entry. + :param id: a globally unique id for the entry. Must be an URI. If + not present the URL is used, but one of both is required. + :param updated: the time the entry was modified the last time. Must + be a :class:`datetime.datetime` object. Required. + :param author: the author of the feed. Must be either a string (the + name) or a dict with name (required) and uri or + email (both optional). Can be a list of (may be + mixed, too) strings and dicts, too, if there are + multiple authors. Required if not every entry has an + author element. + :param published: the time the entry was initially published. Must + be a :class:`datetime.datetime` object. + :param rights: copyright information for the entry. + :param rights_type: the type attribute for the rights element. One of + ``'html'``, ``'text'`` or ``'xhtml'``. Default is + ``'text'``. + :param links: additional links. Must be a list of dictionaries with + href (required) and rel, type, hreflang, title, length + (all optional) + :param xml_base: The xml base (url) for this feed item. If not provided + it will default to the item url. + + For more information on the elements see + http://www.atomenabled.org/developers/syndication/ + + Everywhere where a list is demanded, any iterable can be used. + """ + + default_feed_generator = AtomGenerator() + + def __init__(self, title=None, content=None, feed_url=None, + feed_generator=None, **kwargs): + self.feed_generator = feed_generator + self.title = title + self.title_type = kwargs.get('title_type', 'text') + self.content = content + self.content_type = kwargs.get('content_type', 'html') + self.url = kwargs.get('url') + self.id = kwargs.get('id', self.url) + self.updated = kwargs.get('updated') + self.summary = kwargs.get('summary') + self.summary_type = kwargs.get('summary_type', 'html') + self.author = kwargs.get('author') + self.published = kwargs.get('published') + self.rights = kwargs.get('rights') + self.links = kwargs.get('links', []) + self.xml_base = kwargs.get('xml_base', feed_url) + self.thumbnail = kwargs.get('thumbnail') + + + if not hasattr(self.author, '__iter__') \ + or isinstance(self.author, (basestring, dict)): + self.author = [self.author] + for i, author in enumerate(self.author): + if not isinstance(author, dict): + self.author[i] = {'name': author} + + if not self.feed_generator: + self.feed_generator = self.default_feed_generator + if not self.title: + raise ValueError('title is required') + if not self.id: + raise ValueError('id is required') + if not self.updated: + raise ValueError('updated is required') + + # Look for arguments that we haven't matched with object members. + # They will be added to the custom dictionary. + # This way we can have custom fields not specified in this class. + self.custom = {} + properties = dir(self) + + for name, value in kwargs.items(): + if ( properties.count(name) == 0 ): + self.custom[name] = value + + + def __repr__(self): + return '<%s %r>' % ( + self.__class__.__name__, + self.title + ) + + def generate(self): + """Returns lxml element tree representation of the feed entry""" + return self.feed_generator.generate(self) + + def to_string(self): + """Convert the feed item into a unicode object.""" + return etree.tostring(self.generate(), encoding='utf-8') + + def __unicode__(self): + return self.to_string() + + def __str__(self): + return self.to_string().encode('utf-8') + + diff --git a/mediagoblin/webfinger/views.py b/mediagoblin/webfinger/views.py index 7cbd0913..e9aa600c 100644 --- a/mediagoblin/webfinger/views.py +++ b/mediagoblin/webfinger/views.py @@ -15,32 +15,100 @@ # along with this program. If not, see . import re -import mediagoblin.mg_globals as mg_globals -from mediagoblin.tools.response import render_to_response +from urlparse import urlparse -LRDD_TEMPLATE = '{protocol}://{host}/api/webfinger/xrd?uri={{uri}}' +from mediagoblin.tools.response import render_to_response, render_404 def host_meta(request): ''' Webfinger host-meta ''' + + placeholder = 'MG_LRDD_PLACEHOLDER' + + lrdd_title = 'GNU MediaGoblin - User lookup' + + lrdd_template = request.urlgen( + 'mediagoblin.webfinger.xrd', + uri=placeholder, + qualified=True) + return render_to_response( request, 'mediagoblin/webfinger/host-meta.xml', {'request': request, - 'lrdd_template': LRDD_TEMPLATE.format( - protocol='http', - host=request.host)}) + 'lrdd_template': lrdd_template, + 'lrdd_title': lrdd_title, + 'placeholder': placeholder}) + +MATCH_SCHEME_PATTERN = re.compile(r'^acct:') def xrd(request): ''' Find user data based on a webfinger URI ''' - return render_to_response( - request, - 'mediagoblin/webfinger/xrd.xml', - {'request': request, - 'username': re.search( - r'^(acct:)?([^@]*)', - request.GET.get('uri')).group(2)}) + param_uri = request.GET.get('uri') + + if not param_uri: + return render_404(request) + + ''' + :py:module:`urlparse` does not recognize usernames in URIs of the + form ``acct:user@example.org`` or ``user@example.org``. + ''' + if not MATCH_SCHEME_PATTERN.search(param_uri): + # Assume the URI is in the form ``user@example.org`` + uri = 'acct://' + param_uri + else: + # Assumes the URI looks like ``acct:user@example.org + uri = MATCH_SCHEME_PATTERN.sub( + 'acct://', param_uri) + + parsed = urlparse(uri) + + xrd_subject = param_uri + + # TODO: Verify that the user exists + # Q: Does webfinger support error handling in this case? + # Returning 404 seems intuitive, need to check. + if parsed.username: + # The user object + # TODO: Fetch from database instead of using the MockUser + user = MockUser() + user.username = parsed.username + + xrd_links = [ + {'attrs': { + 'rel': 'http://microformats.org/profile/hcard', + 'href': request.urlgen( + 'mediagoblin.user_pages.user_home', + user=user.username, + qualified=True)}}, + {'attrs': { + 'rel': 'http://schemas.google.com/g/2010#updates-from', + 'href': request.urlgen( + 'mediagoblin.user_pages.atom_feed', + user=user.username, + qualified=True)}}] + + xrd_alias = request.urlgen( + 'mediagoblin.user_pages.user_home', + user=user.username, + qualified=True) + + return render_to_response( + request, + 'mediagoblin/webfinger/xrd.xml', + {'request': request, + 'subject': xrd_subject, + 'alias': xrd_alias, + 'links': xrd_links }) + else: + return render_404(request) + +class MockUser(object): + ''' + TEMPORARY user object + ''' + username = None -- cgit v1.2.3 From 448a58534f585aac95db9d04f43d73634e96eb4b Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 20 Dec 2011 22:13:43 +0100 Subject: Removed mediagoblin.tools.feed which was accidentally included --- mediagoblin/tools/feed.py | 527 ---------------------------------------------- 1 file changed, 527 deletions(-) delete mode 100644 mediagoblin/tools/feed.py diff --git a/mediagoblin/tools/feed.py b/mediagoblin/tools/feed.py deleted file mode 100644 index 7c14a42a..00000000 --- a/mediagoblin/tools/feed.py +++ /dev/null @@ -1,527 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -from lxml import etree -from lxml.builder import ElementMaker -from werkzeug.wrappers import BaseResponse - -import datetime - -""" - Feed engine written for GNU MediaGoblin, - based on werkzeug atom feeds tool (werkzeug.contrib.atom) - - The feed library contains two types of classes: - - Entities that contains the feed data. - - Generators that are injected to the above classes and are able to - generate feeds in a specific format. An atom feed genearator is - provided, but others could be written as well. - - The Werkzeurg library interface have been mimetized, so the replacement can - be done with only switching the import call. - - Example:: - - def atom_feed(request): - feed = AtomFeed("My Blog", feed_url=request.url, - url=request.host_url, - subtitle="My example blog for a feed test.") - for post in Post.query.limit(10).all(): - feed.add(post.title, post.body, content_type='html', - author=post.author, url=post.url, id=post.uid, - updated=post.last_update, published=post.pub_date) - return feed.get_response() -""" - - -## -# Class FeedGenerator -# -class FeedGenerator(object): - def __init__(self): - pass - - def format_iso8601(self, obj): - """Format a datetime object for iso8601""" - return obj.strftime('%Y-%m-%dT%H:%M:%SZ') - - -## -# Class AtomGenerator -# -class AtomGenerator(FeedGenerator): - """ Generator that generate feeds in Atom format """ - NAMESPACE = "http://www.w3.org/2005/Atom" - - def __init__(self): - pass - - def generate(self, data): - """Return an XML tree representation.""" - if isinstance(data, AtomFeed): - return self.generate_feed(data) - elif isinstance(data, FeedEntry): - return self.generate_feedEntry(data) - - def generate_text_block(self, name, content, content_type=None): - """Helper method for the builder that creates an XML text block.""" - root = etree.Element(name) - - if content_type: - root.set('type', content_type) - - if content_type == 'xhtml': - div_ele = etree.Element('div') - div_ele.set('xmlns', XHTML_NAMESPACE) - div_ele.text = content - root.append(div_ele) - else: - root.text = content - - return root - - def generate_feed(self, data): - """Return an XML tree representation of the feed.""" - NSMAP = {None: self.NAMESPACE} - root = etree.Element("feed", nsmap=NSMAP) - - E = ElementMaker() - - # atom demands either an author element in every entry or a global one - if not data.author: - if False in map(lambda e: bool(e.author), data.entries): - data.author = ({'name': 'Unknown author'},) - - if not data.updated: - dates = sorted([entry.updated for entry in data.entries]) - data.updated = dates and dates[-1] or datetime.utcnow() - - title_ele = self.generate_text_block( - 'title', - data.title, - data.title_type) - root.append(title_ele) - - root.append(E.id(data.id)) - root.append(E.updated(self.format_iso8601(data.updated))) - - if data.url: - link_ele = etree.Element("link") - link_ele.set("href", data.url) - root.append(link_ele) - - if data.feed_url: - link_ele = etree.Element("link") - link_ele.set("href", data.feed_url) - link_ele.set("rel", "self") - root.append(link_ele) - - for link in data.links: - link_ele = etree.Element("link") - for name, value in link.items(): - link_ele.set(name, value) - root.append(link_ele) - - for author in data.author: - author_element = etree.Element("author") - author_element.append(E.name(author['name'])) - if 'uri' in author: - author_element.append(E.name(author['uri'])) - if 'email' in author: - author_element.append(E.name(author['email'])) - - root.append(author_element) - - if data.subtitle: - root.append(self.generate_text_block('subtitle', data.subtitle, - data.subtitle_type)) - if data.icon: - root.append(E.icon(data.icon)) - - if data.logo: - root.append(E.logo(data.logo)) - - if data.rights: - root.append(self.generate_text_block('rights', data.rights, - data.rights_type)) - - generator_name, generator_url, generator_version = data.generator - if generator_name or generator_url or generator_version: - generator_ele = etree.Element("generator") - if generator_url: - generator_ele.set("uri", generator_url, True) - if generator_version: - generator_ele.set("version", generator_version) - - generator_ele.text = generator_name - - root.append(generator_ele) - - for entry in data.entries: - root.append(entry.generate()) - - return root - - def generate_feedEntry(self, data): - """Return an XML tree representation of the feed entry.""" - E = ElementMaker() - root = etree.Element("entry") - - if data.xml_base: - root.base = data.xml_base - - title_ele = self.generate_text_block( - 'title', - data.title, - data.title_type) - root.append(title_ele) - - root.append(E.id(data.id)) - root.append(E.updated(self.format_iso8601(data.updated))) - - if data.published: - root.append(E.published(self.format_iso8601(data.published))) - - if data.url: - link_ele = etree.Element("link") - link_ele.set("href", data.url) - root.append(link_ele) - - for author in data.author: - author_element = etree.Element("author") - author_element.append(E.name(author['name'])) - if 'uri' in author: - author_element.append(E.name(author['uri'])) - if 'email' in author: - author_element.append(E.name(author['email'])) - - root.append(author_element) - - for link in data.links: - link_ele = etree.Element("link") - for name, value in link.items(): - link_ele.set(name, value) - root.append(link_ele) - - print data.thumbnail - - if data.thumbnail: - namespace = "http://search.yahoo.com/mrss/" - nsmap = {"media": namespace} - thumbnail_ele = etree.Element( - "{http://search.yahoo.com/mrss/}thumbnail", nsmap=nsmap) - thumbnail_ele.set("url", data.thumbnail) - - root.append(thumbnail_ele) - - if data.summary: - summary_ele = self.generate_text_block('summary', data.summary, - data.summary_type) - root.append(summary_ele) - - if data.content: - content = data.content - - if data.thumbnail: - thumbnail_html = etree.Element("img") - thumbnail_html.set("src", data.thumbnail) - content = etree.tostring(thumbnail_html) + content - - content_ele = self.generate_text_block('content', content, - data.content_type) - root.append(content_ele) - - for name, value in data.custom.items(): - element = etree.Element(name) - element.text = value - root.append(element) - - return root - - -## -# Class AtomFeed -# -class AtomFeed(object): - """ - A helper class that contains feeds. By default, it uses the AtomGenerator - but others could be injected. It has the AtomFeed name to keep the name - it had on werkzeug library - - Following Werkzeurg implementation, the constructor takes a lot of - parameters. As an addition, the class will also store custom parameters for - fields not explicitly supported by the library. - - :param feed_generator: The generator that will be used to generate the feed - defaults to AtomGenerator - :param title: the title of the feed. Required. - :param title_type: the type attribute for the title element. One of - ``'html'``, ``'text'`` or ``'xhtml'``. - :param url: the url for the feed (not the url *of* the feed) - :param id: a globally unique id for the feed. Must be an URI. If - not present the `feed_url` is used, but one of both is - required. - :param updated: the time the feed was modified the last time. Must - be a :class:`datetime.datetime` object. If not - present the latest entry's `updated` is used. - :param feed_url: the URL to the feed. Should be the URL that was - requested. - :param author: the author of the feed. Must be either a string (the - name) or a dict with name (required) and uri or - email (both optional). Can be a list of (may be - mixed, too) strings and dicts, too, if there are - multiple authors. Required if not every entry has an - author element. - :param icon: an icon for the feed. - :param logo: a logo for the feed. - :param rights: copyright information for the feed. - :param rights_type: the type attribute for the rights element. One of - ``'html'``, ``'text'`` or ``'xhtml'``. Default is - ``'text'``. - :param subtitle: a short description of the feed. - :param subtitle_type: the type attribute for the subtitle element. - One of ``'text'``, ``'html'``, ``'text'`` - or ``'xhtml'``. Default is ``'text'``. - :param links: additional links. Must be a list of dictionaries with - href (required) and rel, type, hreflang, title, length - (all optional) - :param generator: the software that generated this feed. This must be - a tuple in the form ``(name, url, version)``. If - you don't want to specify one of them, set the item - to `None`. - :param entries: a list with the entries for the feed. Entries can also - be added later with :meth:`add`. - - For more information on the elements see - http://www.atomenabled.org/developers/syndication/ - - Everywhere where a list is demanded, any iterable can be used. - """ - - default_generator = ('GNU Mediagoblin', None, None) - default_feed_generator = AtomGenerator() - - def __init__(self, title=None, entries=None, feed_generator=None, - **kwargs): - self.feed_generator = feed_generator - self.title = title - self.title_type = kwargs.get('title_type', 'text') - self.url = kwargs.get('url') - self.feed_url = kwargs.get('feed_url', self.url) - self.id = kwargs.get('id', self.feed_url) - self.updated = kwargs.get('updated') - self.author = kwargs.get('author', ()) - self.icon = kwargs.get('icon') - self.logo = kwargs.get('logo') - self.rights = kwargs.get('rights') - self.rights_type = kwargs.get('rights_type') - self.subtitle = kwargs.get('subtitle') - self.subtitle_type = kwargs.get('subtitle_type', 'text') - self.generator = kwargs.get('generator') - if self.generator is None: - self.generator = self.default_generator - self.links = kwargs.get('links', []) - self.entries = entries and list(entries) or [] - - if not hasattr(self.author, '__iter__') \ - or isinstance(self.author, (basestring, dict)): - self.author = [self.author] - for i, author in enumerate(self.author): - if not isinstance(author, dict): - self.author[i] = {'name': author} - - if not self.feed_generator: - self.feed_generator = self.default_feed_generator - if not self.title: - raise ValueError('title is required') - if not self.id: - raise ValueError('id is required') - for author in self.author: - if 'name' not in author: - raise TypeError('author must contain at least a name') - - # Look for arguments that we haven't matched with object members. - # They will be added to the custom dictionary. - # This way we can have custom fields not specified in this class. - self.custom = {} - properties = dir(self) - - for name, value in kwargs.items(): - if (properties.count(name) == 0): - self.custom[name] = value - - def add(self, *args, **kwargs): - """Add a new entry to the feed. This function can either be called - with a :class:`FeedEntry` or some keyword and positional arguments - that are forwarded to the :class:`FeedEntry` constructor. - """ - if len(args) == 1 and not kwargs and isinstance(args[0], FeedEntry): - args[0].generator = self.generator - self.entries.append(args[0]) - else: - kwargs['feed_url'] = self.feed_url - self.entries.append(FeedEntry(feed_generator=self.feed_generator, - *args, **kwargs)) - - def __repr__(self): - return '<%s %r (%d entries)>' % ( - self.__class__.__name__, - self.title, - len(self.entries) - ) - - def generate(self): - """Return an XML tree representation of the feed.""" - return self.feed_generator.generate(self) - - def to_string(self): - """Convert the feed into a string.""" - return etree.tostring(self.generate(), encoding='UTF-8') - - def get_response(self): - """Return a response object for the feed.""" - return BaseResponse(self.to_string(), mimetype='application/atom+xml') - - def __call__(self, environ, start_response): - """Use the class as WSGI response object.""" - return self.get_response()(environ, start_response) - - def __unicode__(self): - return self.to_string() - - def __str__(self): - return self.to_string().encode('utf-8') - - -## -# Class FeedEntry -# -class FeedEntry(object): - """Represents a single entry in a feed. - - Following Werkzeurg implementation, the constructor takes a lot of - parameters. As an addition, the class will also store custom parameters for - fields not explicitly supported by the library. - - :param feed_generator: The generator that will be used to generate the feed. - defaults to AtomGenerator - :param title: the title of the entry. Required. - :param title_type: the type attribute for the title element. One of - ``'html'``, ``'text'`` or ``'xhtml'``. - :param content: the content of the entry. - :param content_type: the type attribute for the content element. One - of ``'html'``, ``'text'`` or ``'xhtml'``. - :param summary: a summary of the entry's content. - :param summary_type: the type attribute for the summary element. One - of ``'html'``, ``'text'`` or ``'xhtml'``. - :param url: the url for the entry. - :param id: a globally unique id for the entry. Must be an URI. If - not present the URL is used, but one of both is required. - :param updated: the time the entry was modified the last time. Must - be a :class:`datetime.datetime` object. Required. - :param author: the author of the feed. Must be either a string (the - name) or a dict with name (required) and uri or - email (both optional). Can be a list of (may be - mixed, too) strings and dicts, too, if there are - multiple authors. Required if not every entry has an - author element. - :param published: the time the entry was initially published. Must - be a :class:`datetime.datetime` object. - :param rights: copyright information for the entry. - :param rights_type: the type attribute for the rights element. One of - ``'html'``, ``'text'`` or ``'xhtml'``. Default is - ``'text'``. - :param links: additional links. Must be a list of dictionaries with - href (required) and rel, type, hreflang, title, length - (all optional) - :param xml_base: The xml base (url) for this feed item. If not provided - it will default to the item url. - - For more information on the elements see - http://www.atomenabled.org/developers/syndication/ - - Everywhere where a list is demanded, any iterable can be used. - """ - - default_feed_generator = AtomGenerator() - - def __init__(self, title=None, content=None, feed_url=None, - feed_generator=None, **kwargs): - self.feed_generator = feed_generator - self.title = title - self.title_type = kwargs.get('title_type', 'text') - self.content = content - self.content_type = kwargs.get('content_type', 'html') - self.url = kwargs.get('url') - self.id = kwargs.get('id', self.url) - self.updated = kwargs.get('updated') - self.summary = kwargs.get('summary') - self.summary_type = kwargs.get('summary_type', 'html') - self.author = kwargs.get('author') - self.published = kwargs.get('published') - self.rights = kwargs.get('rights') - self.links = kwargs.get('links', []) - self.xml_base = kwargs.get('xml_base', feed_url) - self.thumbnail = kwargs.get('thumbnail') - - - if not hasattr(self.author, '__iter__') \ - or isinstance(self.author, (basestring, dict)): - self.author = [self.author] - for i, author in enumerate(self.author): - if not isinstance(author, dict): - self.author[i] = {'name': author} - - if not self.feed_generator: - self.feed_generator = self.default_feed_generator - if not self.title: - raise ValueError('title is required') - if not self.id: - raise ValueError('id is required') - if not self.updated: - raise ValueError('updated is required') - - # Look for arguments that we haven't matched with object members. - # They will be added to the custom dictionary. - # This way we can have custom fields not specified in this class. - self.custom = {} - properties = dir(self) - - for name, value in kwargs.items(): - if ( properties.count(name) == 0 ): - self.custom[name] = value - - - def __repr__(self): - return '<%s %r>' % ( - self.__class__.__name__, - self.title - ) - - def generate(self): - """Returns lxml element tree representation of the feed entry""" - return self.feed_generator.generate(self) - - def to_string(self): - """Convert the feed item into a unicode object.""" - return etree.tostring(self.generate(), encoding='utf-8') - - def __unicode__(self): - return self.to_string() - - def __str__(self): - return self.to_string().encode('utf-8') - - -- cgit v1.2.3 From 85c916919b1e1fe31472feac74f8c216a5df608f Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 20 Dec 2011 22:55:13 +0100 Subject: Added references to docstring in mediagoblin.webfinger and mediagoblin.webfinger.views [references mediagoblin.webfinger] --- mediagoblin/webfinger/__init__.py | 10 ++++++++++ mediagoblin/webfinger/views.py | 3 +++ 2 files changed, 13 insertions(+) diff --git a/mediagoblin/webfinger/__init__.py b/mediagoblin/webfinger/__init__.py index ba347c69..ec7ec884 100644 --- a/mediagoblin/webfinger/__init__.py +++ b/mediagoblin/webfinger/__init__.py @@ -13,3 +13,13 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +''' +mediagoblin.webfinger_ provides an LRDD discovery service and +a web host meta information file + +Links: +- `LRDD Discovery Draft + `_. +- `RFC 6415 - Web Host Metadata + `_. +''' diff --git a/mediagoblin/webfinger/views.py b/mediagoblin/webfinger/views.py index e9aa600c..22086396 100644 --- a/mediagoblin/webfinger/views.py +++ b/mediagoblin/webfinger/views.py @@ -13,6 +13,9 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +''' +For references, see docstring in mediagoblin/webfinger/__init__.py +''' import re -- cgit v1.2.3 From 871fc591dd2492d2bdca0a530fdffac14f3feece Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 21 Dec 2011 00:06:38 +0100 Subject: Workaround for Routes/urlgen bug. This is relevant for fcgi: Some servers (cherokee for example) put "HTTP":"off" in the environ. And the following code in urlgen breaks on this: if environ.get('HTTPS') or environ.get('wsgi.url_scheme') == 'https' \ or environ.get('HTTP_X_FORWARDED_PROTO') == 'https': hostinfo['protocol'] = 'https' workaround is to remove HTTPS:off from the environ. --- mediagoblin/app.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 04eb2acc..49dc8d97 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -122,6 +122,10 @@ class MediaGoblinApp(object): # The other option would be: # request.full_path = environ["SCRIPT_URL"] + # Fix up environ for urlgen + if environ.get('HTTPS', '').lower() == 'off': + environ.pop('HTTPS') + ## Attach utilities to the request object request.matchdict = route_match request.urlgen = routes.URLGenerator(self.routing, environ) -- cgit v1.2.3 From d23d4b23dad2e14e330664f58994dcbbbaa32720 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 21 Dec 2011 00:34:02 +0100 Subject: Note reported bug in workaround So that the workaround can eventually be removed, note the URL for the relevant bug in a comment. --- mediagoblin/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 49dc8d97..96b2c8ab 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -123,6 +123,7 @@ class MediaGoblinApp(object): # request.full_path = environ["SCRIPT_URL"] # Fix up environ for urlgen + # See bug: https://bitbucket.org/bbangert/routes/issue/55/cache_hostinfo-breaks-on-https-off if environ.get('HTTPS', '').lower() == 'off': environ.pop('HTTPS') -- cgit v1.2.3 From 6c191eb3de3bbaf3880ef270461422954554683a Mon Sep 17 00:00:00 2001 From: Karen Rustad Date: Sun, 18 Dec 2011 22:50:36 -0800 Subject: Added a 'you don't have HTML5 so this video will not work' warning using just the inherent properties of the
    -- cgit v1.2.3 From fb7dd855de987d4e3dded1e55cad09a9fe6120cc Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 18 Dec 2011 22:52:49 +0100 Subject: Turn MediaComment's author() into get_author property 1) MediaComment's author method conflicts with the author field. So rename it to get_author. 2) Turn it from a normal function into a python property. That means you call it by ".get_author" not by ".get_author()". This is exactly what sqlalchemy gives us free of charge. --- mediagoblin/db/mongo/models.py | 3 ++- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index e2ac1b5a..0e31fc1c 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -346,7 +346,8 @@ class MediaComment(Document): def media_entry(self): return self.db.MediaEntry.find_one({'_id': self['media_entry']}) - def author(self): + @property + def get_author(self): return self.db.User.find_one({'_id': self['author']}) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index b9e31667..c171dd5a 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -109,7 +109,7 @@ {% endif %} {% if comments %} {% for comment in comments %} - {% set comment_author = comment.author() %} + {% set comment_author = comment.get_author %} {% if pagination.active_id == comment._id %}
    -- cgit v1.2.3 From 2608982885477e2f41579240d24a26864f718123 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 19:08:20 +0100 Subject: Add search level one() method And create a _fix_query_dict which converts '_id' to 'id'. --- mediagoblin/db/sql/base.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index b8d5cc96..38b04334 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -4,13 +4,26 @@ from sqlalchemy.orm import scoped_session, sessionmaker Session = scoped_session(sessionmaker()) +def _fix_query_dict(query_dict): + if '_id' in query_dict: + query_dict['id'] = query_dict.pop('_id') + + class GMGTableBase(object): query = Session.query_property() @classmethod def find(cls, query_dict={}): + _fix_query_dict(query_dict) return cls.query.filter_by(**query_dict) @classmethod def find_one(cls, query_dict={}): + _fix_query_dict(query_dict) return cls.query.filter_by(**query_dict).first() + + @classmethod + def one(cls, query_dict): + retval = cls.find_one(query_dict) + assert retval is not None + return retval -- cgit v1.2.3 From 4305580e8538e5523e9f621c3ffbed14a2ddc350 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 18:19:40 +0100 Subject: Improve .one() by using sqlalchemy's .one() --- mediagoblin/db/sql/base.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 38b04334..5e420bdc 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -24,6 +24,4 @@ class GMGTableBase(object): @classmethod def one(cls, query_dict): - retval = cls.find_one(query_dict) - assert retval is not None - return retval + return cls.find(query_dict).one() -- cgit v1.2.3 From 4deda94a380dc4217247b49df6e8a5bce0082ddc Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 19 Dec 2011 22:29:40 +0100 Subject: Replace media.get_uploader()._id by media.uploader media.get_uploader()._id loads a complete user object without actually needing it, because media.uploader already has the id! --- mediagoblin/decorators.py | 6 +++--- mediagoblin/user_pages/views.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 229664d7..4cf14a70 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -57,10 +57,10 @@ def user_may_delete_media(controller): Require user ownership of the MediaEntry to delete. """ def wrapper(request, *args, **kwargs): - uploader = request.db.MediaEntry.find_one( - {'_id': ObjectId(request.matchdict['media'])}).get_uploader() + uploader_id = request.db.MediaEntry.find_one( + {'_id': ObjectId(request.matchdict['media'])}).uploader if not (request.user.is_admin or - request.user._id == uploader._id): + request.user._id == uploader_id): return exc.HTTPForbidden() return controller(request, *args, **kwargs) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 87b82c74..449e3b1c 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -192,7 +192,7 @@ def media_confirm_delete(request, media): location=media.url_for_self(request.urlgen)) if ((request.user.is_admin and - request.user._id != media.get_uploader()._id)): + request.user._id != media.uploader)): messages.add_message( request, messages.WARNING, _("You are about to delete another user's media. " -- cgit v1.2.3 From 0c0ab3227430b3d55ce9d19b37a01cd2a3c90259 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 19:58:37 +0100 Subject: Translate one string "There doesn't seem to be any media here yet..." is now translated also here (it's already in the list from another place). --- mediagoblin/templates/mediagoblin/utils/object_gallery.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 65ff09a4..b8155f03 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -68,7 +68,11 @@ {% endif %} {% else %}

    - There doesn't seem to be any media here yet... + + {%- trans -%} + There doesn't seem to be any media here yet... + {%- endtrans -%} +

    {% endif %} {% endmacro %} -- cgit v1.2.3 From 479e8a833ba502c976574af77181f60a2a660aec Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 20:11:09 +0100 Subject: Move verification key generation to view Instead of creating the email verication key on the db model as a default for the field, create it in the registration view. Now all verification key generation is only in auth/views.py! --- mediagoblin/auth/views.py | 1 + mediagoblin/db/mongo/models.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 919aa3cd..66178371 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -84,6 +84,7 @@ def register(request): user.email = email user.pw_hash = auth_lib.bcrypt_gen_password_hash( request.POST['password']) + user.verification_key = unicode(uuid.uuid4()) user.save(validate=True) # log the user in diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 0e31fc1c..b068fb06 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -15,7 +15,6 @@ # along with this program. If not, see . import datetime -import uuid from mongokit import Document @@ -88,7 +87,6 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, 'status': u'needs_email_verification', - 'verification_key': lambda: unicode(uuid.uuid4()), 'is_admin': False} def check_login(self, password): -- cgit v1.2.3 From 0eb649ff7ac3f1eb71eb1d2cb66019a860b2c5c7 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 20 Dec 2011 18:47:33 +0100 Subject: Use media.url_for_self instead of calling urlgen directly Replace urlgen('ID', user=media.get_uploader().username, media=media.*) by media.url_for_self(urlgen) in a few places. It's just a lot nicer! --- mediagoblin/db/mongo/models.py | 12 ++++-------- mediagoblin/templates/mediagoblin/user_pages/media.html | 6 ++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index b068fb06..8cd0da1b 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -282,10 +282,8 @@ class MediaEntry(Document): 'uploader': self.uploader, 'state': 'processed'}).sort( '_id', ASCENDING).limit(1) - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader().username, - media=unicode(cursor[0].slug)) + for media in cursor: + return media.url_for_self(urlgen) def url_to_next(self, urlgen): """ @@ -296,10 +294,8 @@ class MediaEntry(Document): 'state': 'processed'}).sort( '_id', DESCENDING).limit(1) - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.get_uploader().username, - media=unicode(cursor[0].slug)) + for media in cursor: + return media.url_for_self(urlgen) def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index c171dd5a..77461983 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -135,10 +135,8 @@
    {% endfor %} - {{ render_pagination(request, pagination, - request.urlgen('mediagoblin.user_pages.media_home', - user = media.get_uploader().username, - media = media._id)) }} + {{ render_pagination(request, pagination, + media.url_for_self(request.urlgen)) }} {% endif %}
    -- cgit v1.2.3 From 05751758469a03835975dd2998aa727fa29c9a16 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 00:08:28 +0100 Subject: Turn media.get_uploader into a property sqlalchemy gives autoloading (hopefully caching) link to other objects as properties. So turn get_uploader on the current mongo based stuff into a property to ease transition. --- mediagoblin/db/mongo/models.py | 3 ++- mediagoblin/listings/views.py | 2 +- mediagoblin/templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 14 +++++++------- .../mediagoblin/user_pages/media_confirm_delete.html | 2 +- mediagoblin/user_pages/views.py | 2 +- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 8cd0da1b..5de59c12 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -261,7 +261,7 @@ class MediaEntry(Document): Use a slug if we have one, else use our '_id'. """ - uploader = self.get_uploader() + uploader = self.get_uploader if self.get('slug'): return urlgen( @@ -297,6 +297,7 @@ class MediaEntry(Document): for media in cursor: return media.url_for_self(urlgen) + @property def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index 6b83ffcf..3ecf06f4 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -86,7 +86,7 @@ def tag_atom_feed(request): feed.add(entry.get('title'), entry.get('description_html'), content_type='html', - author=entry.get_uploader().username, + author=entry.get_uploader.username, updated=entry.get('created'), url=entry.url_for_self(request.urlgen)) diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html index 6a5ab896..124d0313 100644 --- a/mediagoblin/templates/mediagoblin/edit/attachments.html +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -20,7 +20,7 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %}
    diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index aa46af3d..2dfaddc8 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -22,7 +22,7 @@ {% block mediagoblin_content %}
    diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 77461983..13fa1baa 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -72,11 +72,11 @@ {% if media['uploader'] == request.user._id or request.user['is_admin'] %} {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader().username, + user= media.get_uploader.username, media= media._id) %} {% trans %}Edit{% endtrans %} {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader().username, + user= media.get_uploader.username, media= media._id) %} {% trans %}Delete{% endtrans %} {% endif %} @@ -95,7 +95,7 @@ {# 0 comments. Be the first to add one! #} {% if request.user %}

    {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %} @@ -128,7 +128,7 @@ {% trans %}at{% endtrans %} {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} @@ -142,8 +142,8 @@

    {% trans user_url=request.urlgen( 'mediagoblin.user_pages.user_home', - user=media.get_uploader().username), - username=media.get_uploader().username -%} + user=media.get_uploader.username), + username=media.get_uploader.username -%}

    ❖ Browsing media by {{ username }}

    {%- endtrans %} {% include "mediagoblin/utils/prev_next.html" %} @@ -164,7 +164,7 @@ or request.user.is_admin) %}

    Add attachment

    {% endif %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 7c7218ae..6c483769 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -22,7 +22,7 @@ {% block mediagoblin_content %}
    diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 449e3b1c..f721f012 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -173,7 +173,7 @@ def media_confirm_delete(request, media): if request.method == 'POST' and form.validate(): if form.confirm.data is True: - username = media.get_uploader().username + username = media.get_uploader.username # Delete all files on the public storage delete_media_files(media) -- cgit v1.2.3 From 19ed039ba6d65cecfd6e8ad6e47b5cb008350b04 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 20:03:11 +0100 Subject: Implement _id proxy on sql objects (on User for now) So that the old code can access the primary key still as "._id". Quite simple Python Descriptor thing. Very generic. --- mediagoblin/db/sql/models.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index b87ff3aa..68b078a5 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -11,6 +11,18 @@ from mediagoblin.db.sql.base import GMGTableBase Base = declarative_base(cls=GMGTableBase) +class SimpleFieldAlias(object): + """An alias for any field""" + def __init__(self, fieldname): + self.fieldname = fieldname + + def __get__(self, instance, cls): + return getattr(instance, self.fieldname) + + def __set__(self, instance, val): + setattr(instance, self.fieldname, val) + + class User(Base): __tablename__ = "users" @@ -32,6 +44,8 @@ class User(Base): ## TODO # plugin data would be in a separate model + _id = SimpleFieldAlias("id") + class MediaEntry(Base): __tablename__ = "media_entries" -- cgit v1.2.3 From c6263400cfd334a820122bd1b22eaa4d4d6765cd Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 18:12:38 +0100 Subject: SQL Model: Forgot MediaEntry.state field While creating the new SQL model, the "state" field of MediaEntry was left out. Currently using a plain unicode string for it. Maybe should use sqlalchemy.types.Enum? --- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/models.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 6de758ed..c6bed1e9 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -62,7 +62,7 @@ def convert_media_entries(mk_db): copy_attrs(entry, new_entry, ('title', 'slug', 'created', 'description', 'description_html', - 'media_type', + 'media_type', 'state', 'fail_error', 'queued_task_id',)) copy_reference_attr(entry, new_entry, "uploader") diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 68b078a5..268f5715 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -58,6 +58,7 @@ class MediaEntry(Base): description = Column(UnicodeText) # ?? description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) + state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? fail_error = Column(Unicode) fail_metadata = Column(UnicodeText) -- cgit v1.2.3 From 88e90f41eb86b8aa1fcfef1e0585f314afb5180d Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 16:00:05 +0100 Subject: SQL Model: Add relationship properties MediaEntry now has a get_uploader (property) loading the appropiate User object for the MediaEntry (and caches it). MediaComment has the same for author as get_author. --- mediagoblin/db/sql/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 268f5715..31a6ed3b 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -4,6 +4,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import ( Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint) +from sqlalchemy.orm import relationship from mediagoblin.db.sql.base import GMGTableBase @@ -71,6 +72,8 @@ class MediaEntry(Base): UniqueConstraint('uploader', 'slug'), {}) + get_uploader = relationship(User) + ## TODO # media_files # media_data @@ -112,6 +115,8 @@ class MediaComment(Base): content = Column(UnicodeText, nullable=False) content_html = Column(UnicodeText) + get_author = relationship(User) + def show_table_init(): from sqlalchemy import create_engine -- cgit v1.2.3 From 0724930a6880ea9a088785480cfa7803d43a6370 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 28 Dec 2011 23:27:46 +0100 Subject: Show --log-file option in lazyserver help. --- lazyserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lazyserver.sh b/lazyserver.sh index 4ca073b5..843993e6 100755 --- a/lazyserver.sh +++ b/lazyserver.sh @@ -26,7 +26,7 @@ then echo "" echo " For example:" echo " $0 -c fcgi.ini port_number=23371" - echo " or: $0 --server-name=fcgi" + echo " or: $0 --server-name=fcgi --log-file=paste.log" echo "" echo " The configfile defaults to paste_local.ini," echo " if that is readable, otherwise paste.ini." -- cgit v1.2.3 From 690672580e333bb6a2dc67466390847a79566045 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 28 Dec 2011 23:46:36 +0100 Subject: Fix "bin/gmg migrate" after mongo move When moving most stuff from db to db/mongo, "gmg migrate" was left out. Fix it now! --- mediagoblin/gmg_commands/migrate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/gmg_commands/migrate.py b/mediagoblin/gmg_commands/migrate.py index bd3bcb20..0a8ee7dc 100644 --- a/mediagoblin/gmg_commands/migrate.py +++ b/mediagoblin/gmg_commands/migrate.py @@ -16,12 +16,12 @@ import sys -from mediagoblin.db import util as db_util +from mediagoblin.db.mongo import util as db_util from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.init import setup_global_and_app_config # This MUST be imported so as to set up the appropriate migrations! -from mediagoblin.db import migrations +from mediagoblin.db.mongo import migrations def migrate_parser_setup(subparser): -- cgit v1.2.3 From 03c22862322f42a68351e70956e24e512028f0b2 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 16:01:25 +0100 Subject: Support .get(fieldname) on sql db objects Some parts of the code like to call .get("somefield") on the db objects. It's easy to support this on sqlalchemy based objects, so lets do it. --- mediagoblin/db/sql/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 5e420bdc..1249bace 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -25,3 +25,6 @@ class GMGTableBase(object): @classmethod def one(cls, query_dict): return cls.find(query_dict).one() + + def get(self, key): + return getattr(self, key) -- cgit v1.2.3 From 9f264942d88c563f9d310c3fea4a554731c1bbbc Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 19:09:23 +0100 Subject: Add a .save method on the sql db objects This is a shortcut to adding the object to a session (if needed) and giving a commit on the session. In reality, calling code should probably utilize the session on its own and call commit in an appropiate place. --- mediagoblin/db/sql/base.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 1249bace..40140327 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -1,4 +1,4 @@ -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import scoped_session, sessionmaker, object_session Session = scoped_session(sessionmaker()) @@ -28,3 +28,11 @@ class GMGTableBase(object): def get(self, key): return getattr(self, key) + + def save(self, validate = True): + assert validate + sess = object_session(self) + if sess is None: + sess = Session() + sess.add(self) + sess.commit() -- cgit v1.2.3 From dab1d70280652049078add60c6c44f675fbe267c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 29 Dec 2011 22:40:45 +0100 Subject: Finished #485 and worked out bugs: password fields always update, added margins, fixed Chrome width bug, wrapped checkbox in label element --- mediagoblin/static/css/base.css | 5 +++++ mediagoblin/templates/mediagoblin/auth/register.html | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 625269a2..ecdd0474 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -251,6 +251,11 @@ textarea#comment_content { text-align: right; } +#password_boolean { + margin-top: 4px; + width: 20px; +} + /* comments */ .comment_author { diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index bded1d7e..73eae0d8 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -22,7 +22,7 @@ {% block mediagoblin_head %} {% endblock mediagoblin_head %} -- cgit v1.2.3 From 4e9d467fc0b3dfc55db15e84d5d988cefa400fa1 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 29 Dec 2011 22:54:31 +0100 Subject: Isolate JavaScript; add new show_password.js to forgot-password-page as well --- mediagoblin/auth/forms.py | 8 +------- .../templates/mediagoblin/auth/change_fp.html | 5 +++++ .../templates/mediagoblin/auth/register.html | 23 ++-------------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 4cd3e9d8..5a707c7b 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -62,13 +62,7 @@ class ChangePassForm(wtforms.Form): password = wtforms.PasswordField( 'Password', [wtforms.validators.Required(), - wtforms.validators.Length(min=6, max=30), - wtforms.validators.EqualTo( - 'confirm_password', - 'Passwords must match.')]) - confirm_password = wtforms.PasswordField( - 'Confirm password', - [wtforms.validators.Required()]) + wtforms.validators.Length(min=6, max=30)]) userid = wtforms.HiddenField( '', [wtforms.validators.Required()]) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 03a6583b..e8e64023 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -19,6 +19,11 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} +{% block mediagoblin_head %} + +{% endblock mediagoblin_head %} + {% block mediagoblin_content %} - $(document).ready(function(){ - $("#password").after(''); - $('#password_clear').hide(); - $('#password_boolean').click(function(){ - if($('#password_boolean').prop("checked")) { - $('#password_clear').val($('#password').val()); - $('#password').hide(); - $('#password_clear').show(); - } else { - $('#password').val($('#password_clear').val()); - $('#password_clear').hide(); - $('#password').show(); - }; - }); - $('#password,#password_clear').keyup(function(){ - $('#password').val($(this).val()); - $('#password_clear').val($(this).val()); - }); - }); - + {% endblock mediagoblin_head %} {% block mediagoblin_content %} -- cgit v1.2.3 From 550d48d04059d94894573d93aed98f4faa63e3fb Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 29 Dec 2011 22:56:42 +0100 Subject: Forgot to include the newly created JS file --- mediagoblin/static/js/show_password.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 mediagoblin/static/js/show_password.js diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js new file mode 100644 index 00000000..519b29c1 --- /dev/null +++ b/mediagoblin/static/js/show_password.js @@ -0,0 +1,19 @@ +$(document).ready(function(){ + $("#password").after(''); + $('#password_clear').hide(); + $('#password_boolean').click(function(){ + if($('#password_boolean').prop("checked")) { + $('#password_clear').val($('#password').val()); + $('#password').hide(); + $('#password_clear').show(); + } else { + $('#password').val($('#password_clear').val()); + $('#password_clear').hide(); + $('#password').show(); + }; + }); + $('#password,#password_clear').keyup(function(){ + $('#password').val($(this).val()); + $('#password_clear').val($(this).val()); + }); +}); -- cgit v1.2.3 From 3ea6a305ce2addc8c2d6322f0d9bdca957bd972c Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 30 Dec 2011 14:23:12 +0100 Subject: Lots of little fixes and removal of all 960.gs classes: * Removed

    margin-top * Vertically align logo so Add-media button does not fall off * Remove last 960.gs traces (grid_X/container_X) and add custom classes/sizes to css * Add clear class * Update form_box and add form_box_xl for bigger forms * Switch all pages that use forms to new classes * Remove padding from notification messages so they take full width * Other tiny fixes I forgot about --- mediagoblin/static/css/base.css | 60 +++++++++++++++++----- mediagoblin/templates/mediagoblin/404.html | 19 +++---- .../templates/mediagoblin/auth/change_fp.html | 6 +-- .../mediagoblin/auth/forgot_password.html | 2 +- mediagoblin/templates/mediagoblin/auth/login.html | 2 +- .../templates/mediagoblin/auth/register.html | 2 +- .../templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- .../templates/mediagoblin/edit/edit_profile.html | 2 +- .../templates/mediagoblin/listings/tag.html | 13 ++--- mediagoblin/templates/mediagoblin/root.html | 28 +++++----- .../templates/mediagoblin/submit/start.html | 2 +- .../templates/mediagoblin/user_pages/gallery.html | 16 +++--- .../user_pages/media_confirm_delete.html | 2 +- .../templates/mediagoblin/user_pages/user.html | 16 +++--- .../templates/mediagoblin/utils/prev_next.html | 46 ++++++++--------- 16 files changed, 115 insertions(+), 105 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 187d1c7a..e8924edf 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -44,24 +44,28 @@ form { /* text styles */ -h1{ +h1 { margin-bottom: 15px; margin-top: 15px; color: #fff; font-size: 1.875em; } -h2{ +h2 { font-size: 1.375em; margin-top: 20px; color: #fff; } -h3{ +h3 { border-bottom: 1px solid #333; font-size: 1.125em; } +p { + margin-top: 0px; +} + a { color: #86D4B1; } @@ -103,12 +107,16 @@ input, textarea { float: right; } -a.mediagoblin_logo{ +a.mediagoblin_logo { color: #fff; font-weight: bold; margin-right: 8px; } +.mediagoblin_logo img { + vertical-align: middle; +} + .mediagoblin_content { width: 940px; margin-left: 10px; @@ -143,6 +151,18 @@ a.mediagoblin_logo{ float: left; } +.profile_sidebar { + width: 340px; + margin-right: 10px; + float: left; +} + +.profile_showcase { + width: 580px; + margin-left: 10px; + float: left; +} + /* common website elements */ .button_action, .button_action_highlight { @@ -219,28 +239,33 @@ text-align: center; float: right; } -textarea#comment_content { - width: 634px; - height: 90px; - border: none; - background-color: #f1f1f1; - padding: 3px; +.clear { + clear: both; + display: block; + overflow: hidden; + visibility: hidden; + width: 0; + height: 0; } /* forms */ -.form_box { +.form_box,.form_box_xl { background-color: #222; background-image: url("../images/background_lines.png"); background-repeat: repeat-x; - padding-bottom: 30px; - padding-top: 30px; + width: 340px; + padding: 30px 60px; margin-left: auto; margin-right: auto; display: block; float: none; } +.form_box_xl { + width: 460px; +} + .edit_box { background-image: url("../images/background_edit.png"); } @@ -294,6 +319,14 @@ textarea#comment_content { margin-bottom: 0px; } +textarea#comment_content { + width: 634px; + height: 90px; + border: none; + background-color: #f1f1f1; + padding: 3px; +} + /* media galleries */ .media_thumbnail { @@ -358,6 +391,7 @@ img.media_icon { ul.mediagoblin_messages { list-style: none inside; color: #f7f7f7; + padding: 0; } .mediagoblin_messages li { diff --git a/mediagoblin/templates/mediagoblin/404.html b/mediagoblin/templates/mediagoblin/404.html index 7db68941..392c14f5 100644 --- a/mediagoblin/templates/mediagoblin/404.html +++ b/mediagoblin/templates/mediagoblin/404.html @@ -18,17 +18,12 @@ {% extends "mediagoblin/base.html" %} {% block mediagoblin_content %} + {% trans %}Image of 404 goblin stressing out{% endtrans %}

    {% trans %}Oops!{% endtrans %}

    - -
    -

    {% trans %}There doesn't seem to be a page at this address. Sorry!{% endtrans %}

    -

    - {%- trans %}If you're sure the address is correct, maybe the page you're looking for has been moved or deleted.{% endtrans -%} -

    -
    - -
    - {% trans %}Image of 404 goblin stressing out{% endtrans %} -
    +

    {% trans %}There doesn't seem to be a page at this address. Sorry!{% endtrans %}

    +

    + {%- trans %}If you're sure the address is correct, maybe the page you're looking for has been moved or deleted.{% endtrans -%} +

    +
    {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html index 03a6583b..9c8c79bf 100644 --- a/mediagoblin/templates/mediagoblin/auth/change_fp.html +++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html @@ -20,19 +20,15 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_content %} - {{ csrf_token }} - -
    +

    {% trans %}Set your new password{% endtrans %}

    - {{ wtforms_util.render_divs(cp_form) }}
    -
    {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html index 41940742..672e9d9a 100644 --- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html +++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html @@ -23,7 +23,7 @@
    {{ csrf_token }} -
    +

    {% trans %}Recover password{% endtrans %}

    {{ wtforms_util.render_divs(fp_form) }}
    diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index c3807e5f..993790eb 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -23,7 +23,7 @@ {{ csrf_token }} -
    +

    {% trans %}Log in{% endtrans %}

    {% if login_failed %}
    diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index bded1d7e..2520ca9b 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -43,7 +43,7 @@ -
    +

    {% trans %}Create an account!{% endtrans %}

    {{ wtforms_util.render_divs(register_form) }} {{ csrf_token }} diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html index 6a5ab896..ff357a8c 100644 --- a/mediagoblin/templates/mediagoblin/edit/attachments.html +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -23,7 +23,7 @@ user= media.get_uploader().username, media= media._id) }}" method="POST" enctype="multipart/form-data"> -
    +

    Editing attachments for {{ media.title }}

    -
    +

    {% trans media_title=media.title %}Editing {{ media_title }}{% endtrans %}

    -
    +

    {%- trans username=user.username -%} Editing {{ username }}'s profile diff --git a/mediagoblin/templates/mediagoblin/listings/tag.html b/mediagoblin/templates/mediagoblin/listings/tag.html index f797f72f..a7cbe241 100644 --- a/mediagoblin/templates/mediagoblin/listings/tag.html +++ b/mediagoblin/templates/mediagoblin/listings/tag.html @@ -35,14 +35,9 @@ {% trans %}Media tagged with: {{ tag_name }}{% endtrans %}

    - + {{ object_gallery(request, media_entries, pagination) }} -
    - {% set feed_url = request.urlgen( - 'mediagoblin.listings.tag_atom_feed', - tag=tag_slug) %} - {% include "mediagoblin/utils/feed_link.html" %} -
    + {% set feed_url = request.urlgen('mediagoblin.listings.tag_atom_feed', + tag=tag_slug) %} + {% include "mediagoblin/utils/feed_link.html" %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 0f769f2f..300570ad 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -23,22 +23,18 @@ {% if request.user %}

    {% trans %}Explore{% endtrans %}

    {% else %} -
    -

    {% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}

    -

    {% trans %}This site is running MediaGoblin, an extraordinarily great piece of media hosting software.{% endtrans %}

    -

    {% trans %}To add your own media, place comments, save your favourites and more, you can log in with your MediaGoblin account.{% endtrans %}

    - {% if allow_registration %} -

    {% trans %}Don't have one yet? It's easy!{% endtrans %}

    - {% trans register_url=request.urlgen('mediagoblin.auth.register') -%} - Create an account at this site - or - Set up MediaGoblin on your own server - {%- endtrans %} - {% endif %} -
    -
    - -
    + +

    {% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}

    +

    {% trans %}This site is running MediaGoblin, an extraordinarily great piece of media hosting software.{% endtrans %}

    +

    {% trans %}To add your own media, place comments, save your favourites and more, you can log in with your MediaGoblin account.{% endtrans %}

    + {% if allow_registration %} +

    {% trans %}Don't have one yet? It's easy!{% endtrans %}

    + {% trans register_url=request.urlgen('mediagoblin.auth.register') -%} + Create an account at this site + or + Set up MediaGoblin on your own server + {%- endtrans %} + {% endif %}
    {% endif %}

    {% trans %}Most recent media{% endtrans %}

    diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 47914550..afae2f1f 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -22,7 +22,7 @@ {% block mediagoblin_content %} -
    +

    {% trans %}Add your media{% endtrans %}

    {{ wtforms_util.render_divs(submit_form) }}
    diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html index b066dd71..b0bfacf8 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html +++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html @@ -42,14 +42,10 @@ {%- endtrans %}

    - - -
    - {% set feed_url = request.urlgen( - 'mediagoblin.user_pages.atom_feed', - user=user.username) %} - {% include "mediagoblin/utils/feed_link.html" %} -
    + {{ object_gallery(request, media_entries, pagination) }} + + {% set feed_url = request.urlgen('mediagoblin.user_pages.atom_feed', + user=user.username) %} + {% include "mediagoblin/utils/feed_link.html" %} + {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 7c7218ae..8e0f2904 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -25,7 +25,7 @@ user=media.get_uploader().username, media=media._id) }}" method="POST" enctype="multipart/form-data"> -
    +

    {%- trans title=media.title -%} Really delete {{ title }}? diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index b952e88c..8a1d3a76 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -46,7 +46,7 @@ {% elif user.status == "needs_email_verification" %} {% if user == request.user %} {# this should only be visible when you are this user #} -
    +

    {% trans %}Email verification needed{% endtrans %}

    @@ -66,7 +66,7 @@

    {% else %} {# if the user is not you, but still needs to verify their email #} -
    +

    {% trans %}Email verification needed{% endtrans %}

    @@ -91,7 +91,7 @@ {% if not user.url and not user.bio %} {% if request.user._id == user._id %} -

    +

    {% trans %}Here's a spot to tell others about yourself.{% endtrans %}

    @@ -102,7 +102,7 @@
    {% else %} -
    +

    {% trans -%} This user hasn't filled in their profile (yet). @@ -111,7 +111,7 @@

    {% endif %} {% else %} -
    +
    {% include "mediagoblin/utils/profile.html" %} {% if request.user._id == user._id or request.user.is_admin %} +
    {{ object_gallery(request, media_entries, pagination, pagination_base_url=user_gallery_url, col_number=3) }} {% include "mediagoblin/utils/object_gallery.html" %} @@ -141,7 +141,7 @@
    {% else %} {% if request.user._id == user._id %} -
    + {% else %} -
    +

    {% trans -%} There doesn't seem to be any media here yet... diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index b0c01963..66766555 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -21,28 +21,26 @@ {% set next_entry_url = media.url_to_next(request.urlgen) %} {% if prev_entry_url or next_entry_url %} -

    - {# There are no previous entries for the very first media entry #} - {% if prev_entry_url %} - - ← {% trans %}newer{% endtrans %} - - {% else %} - {# This is the first entry. display greyed-out 'previous' image #} - - {% endif %} - {# Likewise, this could be the very last media entry #} - {% if next_entry_url %} - - {% trans %}older{% endtrans %} → - - {% else %} - {# This is the last entry. display greyed-out 'next' image #} - - {% endif %} -
    + {# There are no previous entries for the very first media entry #} + {% if prev_entry_url %} + + ← {% trans %}newer{% endtrans %} + + {% else %} + {# This is the first entry. display greyed-out 'previous' image #} + + {% endif %} + {# Likewise, this could be the very last media entry #} + {% if next_entry_url %} + + {% trans %}older{% endtrans %} → + + {% else %} + {# This is the last entry. display greyed-out 'next' image #} + + {% endif %} {% endif %} -- cgit v1.2.3 From 426808cc8fe4961e938bc8f6df10ea755980e6c1 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 30 Dec 2011 18:01:28 +0100 Subject: Random changes that break stuff and eat piglets --- mediagoblin/static/css/base.css | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index e8924edf..8ed94e36 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -29,7 +29,6 @@ body { background-color: #111; background-image: url("../images/background.png"); color: #C3C3C3; - font-family: sans-serif; padding: none; margin: 0px; height: 100%; @@ -94,7 +93,7 @@ input, textarea { } .mediagoblin_header { - width: 940px; + width: 100%; height: 36px; margin-left: 10px; margin-right: 10px; @@ -118,14 +117,14 @@ a.mediagoblin_logo { } .mediagoblin_content { - width: 940px; + width: 100%; margin-left: 10px; margin-right: 10px; padding-bottom: 74px; } .mediagoblin_footer { - width: 940px; + width: 100%; height: 30px; margin-left: 10px; margin-right: 10px; @@ -451,10 +450,22 @@ table.media_panel th { margin-left: 10px; } -@media handheld and (max-width: 480px), screen and (max-device-width: 480px), screen and (max-width: 960px) { - html { - padding:10px; +@media screen and (max-width: 960px) { + .mediagoblin_body { + width: 100%; } + .mediagoblin_footer { + position: fixed; + left: 0px; + top: 100px; + width: 50px; + height: 20px; + background-color: #f00; + } +} + + + /* old code .navigation_button { position: fixed; bottom: 0px; @@ -465,18 +476,4 @@ table.media_panel th { .navigation_left { left: 0px; } - .media_image { - width: 100%; - } - .mediagoblin_body { - width: 100%; - } - .mediagoblin_header, .mediagoblin_content, .mediagoblin_footer, .media_pane { - width: 100%; - margin-left: 0; - margin-right: 0; - } - .mediagoblin_footer { - margin-bottom: 100px; - } -} + */ -- cgit v1.2.3 From 7c7ba01ee3450ded81f3ec9630cde0818865ed03 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 30 Dec 2011 19:11:47 +0100 Subject: Fixed broken confirm_password test --- mediagoblin/tests/test_auth.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index d3b8caf1..9b0dea66 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -89,7 +89,6 @@ def test_register_views(test_app): form = context['register_form'] assert form.username.errors == [u'This field is required.'] assert form.password.errors == [u'This field is required.'] - assert form.confirm_password.errors == [u'This field is required.'] assert form.email.errors == [u'This field is required.'] # Try to register with fields that are known to be invalid @@ -101,7 +100,6 @@ def test_register_views(test_app): '/auth/register/', { 'username': 'l', 'password': 'o', - 'confirm_password': 'o', 'email': 'l'}) context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] form = context['register_form'] @@ -125,18 +123,6 @@ def test_register_views(test_app): assert form.email.errors == [ u'Invalid email address.'] - ## mismatching passwords - template.clear_test_template_context() - test_app.post( - '/auth/register/', { - 'password': 'herpderp', - 'confirm_password': 'derpherp'}) - context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html'] - form = context['register_form'] - - assert form.password.errors == [ - u'Passwords must match.'] - ## At this point there should be no users in the database ;) assert not mg_globals.database.User.find().count() @@ -147,7 +133,6 @@ def test_register_views(test_app): '/auth/register/', { 'username': 'happygirl', 'password': 'iamsohappy', - 'confirm_password': 'iamsohappy', 'email': 'happygrrl@example.org'}) response.follow() @@ -227,7 +212,6 @@ def test_register_views(test_app): '/auth/register/', { 'username': 'happygirl', 'password': 'iamsohappy2', - 'confirm_password': 'iamsohappy2', 'email': 'happygrrl2@example.org'}) context = template.TEMPLATE_TEST_CONTEXT[ @@ -304,7 +288,6 @@ def test_register_views(test_app): '/auth/forgot_password/verify/', { 'userid': parsed_get_params['userid'], 'password': 'iamveryveryhappy', - 'confirm_password': 'iamveryveryhappy', 'token': parsed_get_params['token']}) response.follow() assert template.TEMPLATE_TEST_CONTEXT.has_key( -- cgit v1.2.3 From 6f559060785270d32a6ca99d2cdb89b5fedfaf9e Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 30 Dec 2011 19:45:00 +0100 Subject: Fix #715: On media submit page, "Separate" is misspelled --- mediagoblin/edit/forms.py | 2 +- mediagoblin/submit/forms.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index dd339e08..f9cc92bf 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -28,7 +28,7 @@ class EditForm(wtforms.Form): _('Tags'), [tag_length_validator], description=_( - "Seperate tags by commas.")) + "Separate tags by commas.")) slug = wtforms.TextField( _('Slug'), [wtforms.validators.Required(message=_("The slug can't be empty"))], diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index ad420771..e21b00ee 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -32,4 +32,4 @@ class SubmitStartForm(wtforms.Form): _('Tags'), [tag_length_validator], description=_( - "Seperate tags by commas.")) + "Separate tags by commas.")) -- cgit v1.2.3 From 694e965f45b8da0af96e3ae99c85b4f1f4819ee6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 30 Dec 2011 20:17:59 +0100 Subject: Fix #712: Comment counter always uses plural --- .../templates/mediagoblin/user_pages/media.html | 86 ++++++++++++---------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 13fa1baa..4c255112 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -81,18 +81,25 @@ {% trans %}Delete{% endtrans %} {% endif %}

    -

    {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %} - -

    - {# 0 comments. Be the first to add one! #} + {% if comments %} +

    + {% if comments.count()==1 %} + {% trans comment_count=comments.count() -%}{{ comment_count }} comment{%- endtrans %} + {% elif comments.count()>1 %} + {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %} + {% else %} + {% trans %}No comments yet.{% endtrans %} + {% endif %} + +

    {% if request.user %} - - {% else %} -
    - {% endif %} -
    - {% autoescape False %} - {{ comment.content_html }} - {% endautoescape %} - - - {{ comment_author.username }} - - {% trans %}at{% endtrans %} - - {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} - -
    -
    - {% endfor %} + {% for comment in comments %} + {% set comment_author = comment.get_author %} + {% if pagination.active_id == comment._id %} +
    + + {% else %} +
    + {% endif %} +
    + {% autoescape False %} + {{ comment.content_html }} + {% endautoescape %} + + + {{ comment_author.username }} + + {% trans %}at{% endtrans %} + + {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }} + +
    +
    + {% endfor %} {{ render_pagination(request, pagination, media.url_for_self(request.urlgen)) }} {% endif %} -- cgit v1.2.3 From 992e4f80324e5e2d0079fd70cce9d4ad962f7047 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 30 Dec 2011 21:29:15 +0100 Subject: Change forgotten password process: different redirect, added/changed messages --- mediagoblin/auth/views.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 66178371..f707ecbe 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -232,16 +232,12 @@ def forgot_password(request): """ Forgot password view - Sends an email whit an url to renew forgoten password + Sends an email with an url to renew forgotten password """ fp_form = auth_forms.ForgotPassForm(request.POST) if request.method == 'POST' and fp_form.validate(): - # Here, so it doesn't depend on the actual mail being sent - # and thus doesn't reveal, wether mail was sent. - email_debug_message(request) - # '$or' not available till mongodb 1.5.3 user = request.db.User.find_one( {'username': request.POST['username']}) @@ -257,6 +253,14 @@ def forgot_password(request): user.save() send_fp_verification_email(user, request) + + messages.add_message( + request, + messages.INFO, + _("An email has been sent with instructions on how to " + "change your password.")) + email_debug_message(request) + else: # special case... we can't send the email because the # username is inactive / hasn't verified their email @@ -270,9 +274,13 @@ def forgot_password(request): return redirect( request, 'mediagoblin.user_pages.user_home', user=user.username) - - # do not reveal whether or not there is a matching user - return redirect(request, 'mediagoblin.auth.fp_email_sent') + return redirect(request, 'mediagoblin.auth.login') + else: + messages.add_message( + request, + messages.WARNING, + _("Couldn't find someone with that username or email.")) + return redirect(request, 'mediagoblin.auth.forgot_password') return render_to_response( request, -- cgit v1.2.3 From a246ccca69e863904718537f45a17d226b33a123 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 30 Nov 2011 21:21:39 +0100 Subject: ASCII media type support & fix a bug in file submission error handling * Added ASCII media processing * Added ASCII media display * Added ASCII media type Rebased from Joar Wandborg's ascii art branch (squashed to remove the commits borrowing code of dubious license) Fixed a bug in file submission error handling: - Moved file-extension condition out of loop (what did it do there?) - Updated file submission tests - Changed error handling in file submission, should now report more than absolutely necessary. --- extlib/inconsolata/INFO.txt | 4 + extlib/inconsolata/Inconsolata.otf | Bin 0 -> 58464 bytes extlib/inconsolata/Inconsolata.pfa | 1088 ++++ extlib/inconsolata/Inconsolata.sfd | 5730 ++++++++++++++++++++ extlib/inconsolata/OFL_1.1.txt | 97 + extlib/inconsolata/textest.pdf | Bin 0 -> 22783 bytes mediagoblin/media_types/__init__.py | 20 +- mediagoblin/media_types/ascii/__init__.py | 27 + mediagoblin/media_types/ascii/asciitoimage.py | 172 + .../media_types/ascii/fonts/Inconsolata.otf | 1 + mediagoblin/media_types/ascii/processing.py | 93 + mediagoblin/static/css/base.css | 12 + mediagoblin/static/fonts/Inconsolata.otf | 1 + mediagoblin/submit/views.py | 8 +- .../mediagoblin/media_displays/ascii.html | 40 + .../mediagoblin/media_displays/image.html | 18 + .../mediagoblin/media_displays/video.html | 18 + mediagoblin/tests/test_submission.py | 5 +- 18 files changed, 7323 insertions(+), 11 deletions(-) create mode 100644 extlib/inconsolata/INFO.txt create mode 100644 extlib/inconsolata/Inconsolata.otf create mode 100644 extlib/inconsolata/Inconsolata.pfa create mode 100644 extlib/inconsolata/Inconsolata.sfd create mode 100644 extlib/inconsolata/OFL_1.1.txt create mode 100644 extlib/inconsolata/textest.pdf create mode 100644 mediagoblin/media_types/ascii/__init__.py create mode 100644 mediagoblin/media_types/ascii/asciitoimage.py create mode 120000 mediagoblin/media_types/ascii/fonts/Inconsolata.otf create mode 100644 mediagoblin/media_types/ascii/processing.py create mode 120000 mediagoblin/static/fonts/Inconsolata.otf create mode 100644 mediagoblin/templates/mediagoblin/media_displays/ascii.html diff --git a/extlib/inconsolata/INFO.txt b/extlib/inconsolata/INFO.txt new file mode 100644 index 00000000..61d3a0f1 --- /dev/null +++ b/extlib/inconsolata/INFO.txt @@ -0,0 +1,4 @@ +Inconsolata +----------- + +This font is found at http://www.levien.com/type/myfonts/inconsolata.html diff --git a/extlib/inconsolata/Inconsolata.otf b/extlib/inconsolata/Inconsolata.otf new file mode 100644 index 00000000..34888982 Binary files /dev/null and b/extlib/inconsolata/Inconsolata.otf differ diff --git a/extlib/inconsolata/Inconsolata.pfa b/extlib/inconsolata/Inconsolata.pfa new file mode 100644 index 00000000..83a17d7a --- /dev/null +++ b/extlib/inconsolata/Inconsolata.pfa @@ -0,0 +1,1088 @@ +%!PS-AdobeFont-1.0: Inconsolata 001.010 +%%Title: Inconsolata +%Version: 001.010 +%%CreationDate: Sat Feb 7 12:03:37 2009 +%%Creator: Raph Levien +%Copyright: Created by Raph Levien using his own tools and FontForge. +%Copyright: Copyright 2006 Raph Levien. Released under the SIL Open +%Copyright: Font License, http://scripts.sil.org/OFL. +% 2005-8-26: Created. +% Generated by FontForge 20090121 (http://fontforge.sf.net/) +%%EndComments + +10 dict begin +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def +/FontName /Inconsolata def +/FontBBox {-1 -177 510 835 }readonly def +/PaintType 0 def +/FontInfo 11 dict dup begin + /version (001.010) readonly def + /Notice (Created by Raph Levien using his own tools and FontForge. Copyright 2006 Raph Levien. Released under the SIL Open Font License, http://scripts.sil.org/OFL.) readonly def + /FullName (Inconsolata) readonly def + /FamilyName (Inconsolata) readonly def + /Weight (Medium) readonly def + /FSType 8 def + /ItalicAngle 0 def + /isFixedPitch true def + /UnderlinePosition -100 def + /UnderlineThickness 50 def + /ascent 820 def +end readonly def +/Encoding 256 array + 0 1 255 { 1 index exch /.notdef put} for +dup 1/NameMe.1 put +dup 2/NameMe.2 put +dup 3/NameMe.3 put +dup 4/NameMe.4 put +dup 5/NameMe.5 put +dup 6/NameMe.6 put +dup 7/NameMe.7 put +dup 8/NameMe.8 put +dup 9/NameMe.9 put +dup 10/NameMe.10 put +dup 11/NameMe.11 put +dup 12/NameMe.12 put +dup 13/NameMe.13 put +dup 14/NameMe.14 put +dup 15/NameMe.15 put +dup 16/NameMe.16 put +dup 17/NameMe.17 put +dup 18/NameMe.18 put +dup 19/NameMe.19 put +dup 20/NameMe.20 put +dup 21/NameMe.21 put +dup 22/NameMe.22 put +dup 23/NameMe.23 put +dup 24/NameMe.24 put +dup 25/NameMe.25 put +dup 26/NameMe.26 put +dup 27/NameMe.27 put +dup 28/NameMe.28 put +dup 29/NameMe.29 put +dup 30/NameMe.30 put +dup 31/NameMe.31 put +dup 32/space put +dup 33/exclam put +dup 34/quotedbl put +dup 35/numbersign put +dup 36/dollar put +dup 37/percent put +dup 38/ampersand put +dup 39/quotesingle put +dup 40/parenleft put +dup 41/parenright put +dup 42/asterisk put +dup 43/plus put +dup 44/comma put +dup 45/hyphen put +dup 46/period put +dup 47/slash put +dup 48/zero put +dup 49/one put +dup 50/two put +dup 51/three put +dup 52/four put +dup 53/five put +dup 54/six put +dup 55/seven put +dup 56/eight put +dup 57/nine put +dup 58/colon put +dup 59/semicolon put +dup 60/less put +dup 61/equal put +dup 62/greater put +dup 63/question put +dup 64/at put +dup 65/A put +dup 66/B put +dup 67/C put +dup 68/D put +dup 69/E put +dup 70/F put +dup 71/G put +dup 72/H put +dup 73/I put +dup 74/J put +dup 75/K put +dup 76/L put +dup 77/M put +dup 78/N put +dup 79/O put +dup 80/P put +dup 81/Q put +dup 82/R put +dup 83/S put +dup 84/T put +dup 85/U put +dup 86/V put +dup 87/W put +dup 88/X put +dup 89/Y put +dup 90/Z put +dup 91/bracketleft put +dup 92/backslash put +dup 93/bracketright put +dup 94/asciicircum put +dup 95/underscore put +dup 96/grave put +dup 97/a put +dup 98/b put +dup 99/c put +dup 100/d put +dup 101/e put +dup 102/f put +dup 103/g put +dup 104/h put +dup 105/i put +dup 106/j put +dup 107/k put +dup 108/l put +dup 109/m put +dup 110/n put +dup 111/o put +dup 112/p put +dup 113/q put +dup 114/r put +dup 115/s put +dup 116/t put +dup 117/u put +dup 118/v put +dup 119/w put +dup 120/x put +dup 121/y put +dup 122/z put +dup 123/braceleft put +dup 124/bar put +dup 125/braceright put +dup 126/asciitilde put +dup 127/NameMe.127 put +dup 128/NameMe.128 put +dup 129/NameMe.129 put +dup 130/NameMe.130 put +dup 131/NameMe.131 put +dup 132/NameMe.132 put +dup 133/NameMe.133 put +dup 134/NameMe.134 put +dup 135/NameMe.135 put +dup 136/NameMe.136 put +dup 137/NameMe.137 put +dup 138/NameMe.138 put +dup 139/NameMe.139 put +dup 140/NameMe.140 put +dup 141/NameMe.141 put +dup 142/NameMe.142 put +dup 143/NameMe.143 put +dup 144/NameMe.144 put +dup 145/NameMe.145 put +dup 146/NameMe.146 put +dup 147/NameMe.147 put +dup 148/NameMe.148 put +dup 149/NameMe.149 put +dup 150/NameMe.150 put +dup 151/NameMe.151 put +dup 152/NameMe.152 put +dup 153/NameMe.153 put +dup 154/NameMe.154 put +dup 155/NameMe.155 put +dup 156/NameMe.156 put +dup 157/NameMe.157 put +dup 158/NameMe.158 put +dup 159/NameMe.159 put +dup 160/nonbreakingspace put +dup 161/exclamdown put +dup 162/cent put +dup 163/sterling put +dup 164/euro put +dup 165/yen put +dup 166/Scaron put +dup 167/section put +dup 168/scaron put +dup 169/copyright put +dup 170/ordfeminine put +dup 171/guillemotleft put +dup 172/logicalnot put +dup 173/softhyphen put +dup 174/registered put +dup 175/macron put +dup 176/degree put +dup 177/plusminus put +dup 178/uni00B2 put +dup 179/uni00B3 put +dup 180/Zcaron put +dup 181/micro put +dup 182/paragraph put +dup 183/periodcentered put +dup 184/zcaron put +dup 185/uni00B9 put +dup 186/ordmasculine put +dup 187/guillemotright put +dup 188/OE put +dup 189/oe put +dup 190/Ydieresis put +dup 191/questiondown put +dup 192/Agrave put +dup 193/Aacute put +dup 194/Acircumflex put +dup 195/Atilde put +dup 196/Adieresis put +dup 197/Aring put +dup 198/AE put +dup 199/Ccedilla put +dup 200/Egrave put +dup 201/Eacute put +dup 202/Ecircumflex put +dup 203/Edieresis put +dup 204/Igrave put +dup 205/Iacute put +dup 206/Icircumflex put +dup 207/Idieresis put +dup 208/Eth put +dup 209/Ntilde put +dup 210/Ograve put +dup 211/Oacute put +dup 212/Ocircumflex put +dup 213/Otilde put +dup 214/Odieresis put +dup 215/multiply put +dup 216/Oslash put +dup 217/Ugrave put +dup 218/Uacute put +dup 219/Ucircumflex put +dup 220/Udieresis put +dup 221/Yacute put +dup 222/Thorn put +dup 223/germandbls put +dup 224/agrave put +dup 225/aacute put +dup 226/acircumflex put +dup 227/atilde put +dup 228/adieresis put +dup 229/aring put +dup 230/ae put +dup 231/ccedilla put +dup 232/egrave put +dup 233/eacute put +dup 234/ecircumflex put +dup 235/edieresis put +dup 236/igrave put +dup 237/iacute put +dup 238/icircumflex put +dup 239/idieresis put +dup 240/eth put +dup 241/ntilde put +dup 242/ograve put +dup 243/oacute put +dup 244/ocircumflex put +dup 245/otilde put +dup 246/odieresis put +dup 247/divide put +dup 248/oslash put +dup 249/ugrave put +dup 250/uacute put +dup 251/ucircumflex put +dup 252/udieresis put +dup 253/yacute put +dup 254/thorn put +dup 255/ydieresis put +readonly def +currentdict end +currentfile eexec +743F8413F3636CA85A9FFEFB50B4BB27302A5D8F831C8E7403C0106A132FF59D98092C95 +DC41D4C9241F1BD142718DBFC7990762D5702DF0A9EB7021A4E2963A13092EE8CE8D5420 +1693D02365290EAA96629C387B0C4D1D8F02EB5E206499E04031887F3D8326E1D52DE489 +DAF6385A0DF2C94A15E48C4F20A9A6E49ED44889E52CB5C42B509B29A2E21E2F65EDB849 +6A92804F43E45E2A5F7C701DC5251F457E338E2C67AFBFFFC9F1DC889EE31B6AC70DFF59 +766BC955C317A79D28364884CB3B1485A8CF42F0EB33E3A89026B9BB3082A4357FD4D28D +ED92CF5006DCB258B0583019C44096C4F55E26B71018B6D73D9C82F9CD1FD4D3AF3B373B +86AE36D5F73674AC34BFF15373CCF3744BDD34566C2D355AAA3C7A2BF5F440B13550AB25 +F9774E5E426548CD877393C89D2C66A0223C3B799F1BFADC79A2F135FB491B6A0DBBF42D +E22E06C135617487E09820B8E435C13BB493D18EAB3F09530A17B104E9A21ECC2F6A3099 +8BB197801D507A4D287734EAC59F28F3F1543BB64C64D43516EAF67DC96E4FEF71EC4D98 +C8BCCAE296BF517D3A6927DD85765F85B59CB2FEEA4978825D5BA7832CC9C44F8D7195AE +D2D27773E6A93C1CB545AAB95CE469EBE7DBE770CBB3A4B913542C93B2716BB48C4F5F5E +ABDDBE740AE279051CA883F22E80E4AED31D5D5001A055F97A1FCA1DAA1E4319E97F484D +301D9CD958A63214722032F006332D39C950DDBB0FB2FCDB82E0626291B4DB630BAD5EB4 +429F0484513B463E8EB1E2BE15F7DA7C9F1365025585465A6593B4246C6FF4447CF57700 +BE5577BF3F417FD88630D661D61693F9E92083EFE6EBE8054C4368233C3CF0FCCE71B15D +D33AC388B678D0CC1BC8E5820AC2EEAF141C25BF2A423583ABD12395A6029A283F77B210 +B1C394F8BC8B835B0DD4A668E36FF47E3569DD995A18123945E06C82B043D76C87E57CEF +19BCC653762D133144AFAD088F345F7E9AE84942696C1985529EAB4CE22965A4B256DEBC +9B4A39B65DB7378B9917D76A15E978DD881078BE13967CB730D7A171F9DFCA9294ACA80E +CE24E834CD0FDE0620FE9ECC22B5D72221D6A625B26C69925D22656DEFCCD6534045E522 +B942ADEAA201528C758566E6D9F8FCE0ED25854FD16417A7461A5092E5602ED96CE20787 +975FE5569193B044B83549541DE2226557952E53E90409A11C9BCA440D77A9179EFA65FA +43FF7C10FF7B17D61A758C7F3E658542A0E44D8D84A638CDAC6595CCFDDEB2EF67FBBDF0 +B5B3BABBF5FD497FC88B32AE0EB2C7A62624A74146712946A106E7DAB8F455A8CFD88736 +F917A3EAC075D30BBE94F3D54301637ACA3DF58C7A652420BE7D221C53C8DD6C03C4F22F +28E291C8D8C5C3D6CFE745A7F438EF594812E849D6E54666DAB28F6D0D6EF5E77C456AB8 +BB71F5AA6D677EEF06A784F99E1531C00C02312F42EEAE3A67C87BBE018E1E09895FED1F +3F3712315F712F718BF4E7B672905E8B51522A7684DDDC6C4AED805A04BDFB6930D77A49 +67CD4CF63010A7AE4D88EA75138A9F27B15F50FD125C5182DB692F5B45FFDA25A63C1481 +40837722F0AE5823DAB6757D38A6EADCCDD7A0F2BC6825616CBA755697E699B40A3CA817 +17261FE9E09BE98650FEEB8D1525C2A9E33C174005F9C600832C4E8F426E7479B507F7DA +884C72AF75C1818F6A1D35C1FDBC7B3FAF26A1F0F31B92E58CE39D892245BFB4212E9A77 +5836C9CF189550EFB8B23F147B4CC78B48040A2C2E1D83A35D0691B761DB111D4CCCDCEA +09F13E8831AA4E330E0128105868F6F194771F9317127815D25653AD3F6981596D5C665A +9613A6370D667980AE148B4F2C8B208AC2A3FBD0264FA03610C2764985C46924B6EF3A05 +1A2CD3F33BCC0C1D6D6D96008FCB58D84D88125D5B1A87083397D4302A1B2773F2CC59A9 +A7313CB431EA3A66C05E50EA8D94CF488C792E01C7F773FC42D394B9BB4CF7BFB76E73AD +8B3CA41B172CEBB4BA391BB113CE4DBD6E4956628B4B20BAB6521EBFA45066FC65A2C7F3 +2F3DCBC22D01949EC33D19278FF72B3AEDC014BBF1041466A7C86EB1299881015A826235 +B13D7B3FA708A93686ED59D187050F8FBDB81DD98FC72EA4BCC5A40CEEB88192BB6AB175 +8B6A5A6BF4544F4831CC2AD93B09D1BE11156F97313F927DB21ACCF0DE0C925813365CE1 +1B5DBC508028ADCE89BE4B25DBD6D9906D6BD8AC2B3B1631BAE58619C5319CD83EDFCA29 +BADCE8580BFBFDE29EBE31879EF741795C0B962DCA3AE3F5C6A1AA2CE6D21EE239BB1B9E +C7BBCE8C17CA0C8769773897E69615DB661CA26CD5444805CEA78414BE8A66A1685535C3 +E56A8EB579498386E9017B5233853CB9D031F863B7DFDDCCF39D55FCB073B2E3153DF76D +C738D92FA3BB53B8C5067C347888A3CA135D04A214C30996D8721BFA425BCD69D069F314 +F4E761FC7F18EA5031715F01E89C6DEB95FDA6BB7A1C4CB2123CE36D13EEE81647141D27 +CAE4F80850746CA32876F6DFB1C191EF5B6AAE0A9C74EAAE17EF095996DAAAE24619161B +F3B659ECFD3C4DD95C2229238BFC9E5A495080827D6A747C3B3FD3EF1247D2979C816A5C +CEC294EE4A51A5089850F152D7BF2DC4682129846F159698CEED06499EE842AA45658986 +0E32068679836E0B726CFA1F0FB7E95ACCD3BBD70FD14F14161FE3168789593A659C768D +D0F49748C1EB3D813F7C33ACF19D9627D82A6F457002B731AFFD24A3B9EE378295C37BB4 +11F39323247E845A80DD99625FE0BCAB3545F586BF74993BD3784D307CEC418481748420 +BBF213417639866D6112944C198BCF8E4D20B521B79FC5D935AA1184C2AADC4E7A89180F +6A3380CB10F5542E5AB05881749C0512DBBE9101FFD2B4E79892BAC9428982CE386B64F3 +3B8A7C2FB184F1CC35B0EA584EF80A07D5A280AB944492F84D22FDFE47B9C893EB3F1515 +458859572F0DE48C7E5A10B6E3F946159B630D813CAC9312DA1683D923C4D9099FDD7A15 +B8667037556DF0536E44D3EEBFDD7CE67BCD0B1C09151A5AE07F3021023070C4159799F1 +88FDF758F48FF19E9D6CF06054E22F723BA336A81B127443743AA3D98EF3A209EC712894 +84EC103DE6523F763F944E31718BA6D56FC6DD03A29B49C2FF1894F736AA1AB9BCFAD31C +60407CC4476DF0F69B96F7685141C8B63A5587875198ECE5BDD4924685773715E943A92A +5A22415B8E85911EB72DF7410F6F1BADE8E8FD9348CB4D483C6D1200F35014D82DA9ABE3 +B476C00E7D3C762395A65D29148102224E6593AD80A566D10C8C14D577BFAF6D425FD2DD +FCFB898E1F25199C2F2202ACE9E8425A7476510A4DBEEEE0B925B9D7D53E39E18E7B4F71 +809D01631B121F11C0785ED6D8F63319CFD11D4F810D04CB0D1C1997F50814451FF5E50A +28F7D421CFEA781B89BDB53A9752A2F94A55A3EF211683E4CB4193EC3487909A46511643 +96B8C9F47C038ACB3A2940336596E008F9180171E06B8DDAB417E9FDFE042B952AC201F1 +CA2796E98374A16248C3939CB6FA9ADA4A6E1438E34394E8BB27275EC021F368BEFD7614 +9924EFAA8652A9B2CC4F493AB91452CABAABFCC7CD99D8BCA7F43852D40EB7897130F9A9 +548D091295511913275DB758BEEBEC3C4FEDBFBE13B92BC84412DE875938AEFF92F8B7F5 +5906A4A398768107C74AB503E55335AACFD3D107A3EE49D58CC291D4F507598311FB0FBB +12F343A50237D83D8D281B1CCFFBFA2865EC4BF19998D3B60B5FCF20D1C2B699867EB100 +7A1C3FA5BB0F307C0F1A248225E4426C1E13352A1A1BA2511EF9A977A166106DED6682B8 +41A84D03A090FBE879045EE849E55D47530F269AC5F2212CD29F02F652C29DCED3B79101 +51937689C3BAB8D15DFFBF02676188AB1360792FC364143A6C0FA49494024EDEB72F0E90 +58E6D37CCF2A423120DB91DC7078887ED2561991B9B6C48EC10AB1084918C660A31EEF79 +4F5E1643E30046E876CBF84658483BC815343866EB1652FA6EEF41F98034FAF691169136 +76B9BFF152F9ED8C825BB9692A7E4CEB06AC4266CCADF5182E7A1586BDEC3B411064D6A5 +7B4A78162600FE4461CB0A6FCE4125B19ACB5F4BE5B1C70A565693CEC9BAE9EC277C5CF1 +3EC22CEE695858694DF4BB1D5FCEBE9E496D6A2B780D5FA9AE9E672FE35AF6558340DB82 +4213CE5AF7786FD5BEE2873B6508575C2BE154C4B2E7ED11D317A5058D23B335E3D0C5B2 +10BAAAF8270E01BEB660DA7D441B7A70921000E7564CCAE5FC90DD7E843BFBA1E1752021 +4C99A1411BE9CA4F64B48661B452D1674994DBB3B91F8CD458C787BCF29101F3D3D5236E +37912A31A058EF76E3C74BB472A2C008305D1E8B35E7F40E0257AAE3BC7F24C48C18E5EF +0FDC4DBBFCF48803BD7BBB797E128E39285BCDB6D0874B3764AF273D050264AF5810FCD4 +44A5EB6CFF8D48A1C7648E9D28966CD59EF607293054B22F111FF473C3D41336237DBCB8 +0062D35521EC38382AE3A54782962A18284A3AD75ADF2CBF18C5BD25B34D6594924F652E +55D52507DC2CB831505223A5D86BF5C5AD1B7495C1BC9EBB7A7DF85C88DEB148018D9A79 +BE9954FEA2A3BD0D900FEF063EF37F552E3D5750E02C185F5EE94D7A93833A5EAC075BDC +1C7ECE2D2482EEE2BC8E64D94A186008E6B4E53759ABF9AA74AFC8318BB810FEF89F6145 +BC72F812C6DE3091F3A351E1CF34BC3D1097AB5B7E05CEED21E41E2CE6E519938E4C7BFE +D27C8E7B14B7042FDF155892E806B581977A0B6FF68334D903673DDE588EFC59B4F695F3 +4269A0B280435E546A34CC83D67D92915D842AFF0887903D9DFCC2EB1E64352BF165C1C2 +0767307C99F16D31E343B1A9F58F8CEA1C4F4B1505A75768838D7D7B7EC6CAEB5D464D21 +41A7BC21FD5DA3EFE42C9E6E74DD3BD11A844A395D83FF422E41DF1519C73466385C7779 +C1668D1269004CAD19E2FBCD012A741DB8F8E4B92E32D6121E7EF9808619C1A85E8552D1 +97D6E1C41F7E45708B4EBC90D54887B5A0774A19710EC804544AB557012D7D59BAE248FA +A13614C9F3024F888A211D4F756E32473DA876138C1E7EEDFA604EC3CD33EF1F056F90F6 +4F836C1893A17C2CA4CD7558C9F63745CD659F3A5B5E23B260F0F17756092B5EE980E039 +3405F6289EBD24CB343FC7E68038981670D7407725397D88BB1406E8DD70C31429F74CE8 +A8F86BE6A1662353BD763548AD4A4E5A1318A54EC9A3AB56BFD991AC1E9A43E5BEE0A331 +DE6080DA712C6F2FACD94191EA36BCA53257F8856A7A108469A684012053B3D07813DEBD +B7120CCF3087158F7229A05562A4D414BB9E5AF84EB08E560032862BC7FC1D4D5E00E6E5 +052A9E88327B6C7F018CDB5229EC282EC87E5A9E841D1903D72277E4C82D82F098BB7B7B +D39EED6BB7EC87B5B70AE7219B43E3F6212570E7A2AC7D0738A7FA0303A0269B0BF62D2B +D527026D57E5752527C8AB8D0C63BF1D914574A405C3E2C3944353796D86AA5E2F6B2A04 +C6AD1171377F3E1D26609B050952E0DABD4CE338AFC0BB4775D3779BFBF7F3365594C610 +176E3B0A62F5AFFA655D3ACFB8FF1BD7AF48A56E4AEC7D1B4FAFC8294E84BB9B3C4316FE +B1C99131D63E7681F8F8D4ECDE8B7904CE3307FEA96D569994F63F7C1EB02F93AB1B2BAB +2D95489642AD5FDF9D4ECEFF5619E70AE4A677881EEA0F84DEF708A7F73C5C99E43723ED +3AD445D2A3FE327FA2FFFF37CAC7960E4585C3086735CC1167E73B9628EF17FF7AFEE09D +D98F7016E8963B3CD7BDA0F756A6036D00A6FB11EB2DAF93FAF7A39BC2EC273650ED3E2D +6C0DC9DC875C4BB852A0E0C1C8E546263309373E96DF8221B8309F3D35ECB61906D2A7E4 +0B6A2C92F04BD39E74EEF161D8A2F5EE7F4788E4C65BA7582C63858FD7E9E34250849CE0 +C8EAC1036C2055BDC50BD9D2BD0F228F0F6DD950F5850523C376364E394BBC979FFDE391 +5603CFE721359639069B00E0B09A3831677C1CC0AD41B0741FAFE3153807AECB7CB39A87 +56C53F818B2C0E03F8AE2E7766B1BD43595955E719169FDECBE1E93FFA0719275A971A93 +05FA40D2F715B0DE5AFA9299077A6DD1C46E6E7B98EFD6FE106CC2C5591AF6371054B80D +4B17CF8F7E7A925E2289C9F063D7D6EBE5E2450D3FAAC78F2AED7479A9DCB9E42B0BB39E +1E50801169216DDC66316C628C72A1046C0E414D16465DCAA2BCD7C499DA8511F6BCDC6D +69F68EF6D98497C51749046384A3433906AFAED3058AF24D1827F498733562C6A4813188 +B008C48FCB1BE78F89CD1809D22A984DE092AD78EEA4143A731D1F48322767A1503AAB4C +70E9B42A240B0770CAC79FD58579F57B23FFF37623883B7F33B060D8DAD0C21975CDEEF5 +2F5F2E395DE45E97E22A558F181478A86DAB0CE022C1FA5C513279FBA66536A4D1D13ABC +E569CCD74DF5245190912983CA329C943B421B4CA583A6047AD453FA2E8E9583F6C9081D +1DF2FF6469092B0FBE6EB38F789035EB82933CBF3D16D30C1DBA9F404D0C1C0892A36ED3 +A92D3BBEF436F3F1556536727F16D3F54C00A1A1693F285708ECA695D3B30ED177E353A6 +820E02F738027FDDA3BEEA8DF4B61D51ECB2201AFAFFD71C5D0BC21EFD4B381A8B14D8D5 +599D784FECFE6C0B83A126238ED4DCA2B797F360685049A7407B92C16FAED859CC68FBD0 +6F8A715BE5369E6F702539CDF50244E3414CA90A74D2E63FFF1253AA87F2B8D96874F0D4 +0292C41D3BA060434C45E6E88D8DF9E025196E310D3BA2045AF6570E3F87EB248A942BBA +75528BC7FCA8B0C0B73874496BE86EBFCA8A1F28F18C1B29E924BCD56E8A1ECC202025A0 +4C81CD070F2DF6302F69B890EF4E7F1723D91434D9E2C7DB91E375E5F352F81DEAB15DBF +5B702CF085535F4EA8B62BFD3C10455CB744A0FF840EB52BEE87C94DD8081BB23C3F1132 +D15BE52C4ED0BACA4794C96A2014381B3FEFE22E5B4B37BFF2C99C04C6FC4FBC71B465DC +0AF985148120E96CBB1D34B8F63E3120ED7826D799EDA434B9DF86E00BABC41C9095C69D +341249CDEE62D2F119C8C74029181AA202045AEEFA9EB41050653D356404BFB650DB8DF0 +F5680D8F5EC8A44F423540BBB43771220867F173D8D0CAD7406F8E64287A8DB8FDC947D3 +AEC9B0C5BF050735BF2CC285099C9799DBB9D3FA6FD87AA957683F9569D3261E14DD796B +463F973B16F8895A738177E7CFB94EED7207BE01253F879351B2776C28F361860BD5182D +A21F7B995B7A6B4BB09089DC6618343E0EDD922ED395A3D615CEBC9AE71992438429EE83 +ECB9E64ED7573F2F0C32F41010AAD6EF7F7902B397423433C297AAE40F16CDE76DA7BD43 +7A738C99709A13CE7EEF117B0D01ADD0E240135B754F7E16B7C7CD4E82F0BC951CB069E3 +AB189926C7C07F49C7EA7C3B5FACD93863A8D3E9917B417B2D2A5256ABAA9123B66179D8 +91B4EA97ADA8F1DB43EF175FD3487CDEC72BE6A2B89E43F340630535765411FA15D2B3C6 +350FDB2E3BFD6F660D539CB8120ED86B59AA539BE0AFCF84D03B8BC4BA0F0CA8FDC45893 +F061190878BD44003EB80D54E84CD41FB4244D5749FD17D9C7FB045357E651390A1CB833 +A43390912C1EAC62F86D50F1843D212EA2B72689D2681F46E327B28DFBF8D7D8FA2731F2 +D620C306703A4428DC3E8C22566D84A8F38C61C3F1A64F63FC65D0431BD7CF9C47A66569 +B4FA594DEA0944707062BCBC9E91BF4541A374E167E10E9EF02F5BC483A23FF0C6FEF410 +4618393C9BC5BDC5C2F4B69E81A93E6BC40D70D409B10E85D2CF9CE8E8FA6C8E125AFBEA +452B79C547F82334D49B0EE386446E2351B6C8FD8031EA0E134B2CD41DDD622F0FEAF670 +1486D8288A5BCC146B35F7E75B6970338C6C613F9FC5E24C37E6E7C4C8C959417D30B406 +3CFC5B53E0B1833D10D72AA19D4F9852378E0BDDA8825C726F241E5A973286180C106FB5 +1D285AEAF479F7DBCA63AFD05CE41CB88E0E6D74F60210D66E73EA0E5AAEEA61672C088C +0F86588F749D689E51A205B54A4B3C841B0298C77A3D82AD88BB02886B229371948D1A2D +8D4D9B6E2331C4666FC7257E2ECFC1225093FFAF7A060876A2CB7D828BA0848EA0B52D9F +96F9E7C786B928962DD71E761211432D66CBD6265DAC3FD3D3AB6A87DB72A6C266245B65 +6321255C4EAF77284AE1F46A76D1470C79FC4376DBB53DD7C0B660D629EEE6CA728ECDA9 +E4A7F91D10EADF2A143EA09689139F88BBF9E41DA8F09899669CFAFE4782DCF736BE2429 +8DEEFEE14143BFC8A22DF8A9092013AC3413AD2A6A59ECB2B9047FB27B4B3457B87F670F +6F9A8A4F25C3B3294FB84012C70B90FB25662D6D5C8E9C1F9521FA9A9D9422BF378A6BFE +C25B973C89F1BD470F6B8988AFFC9A87EA0F02693C054DF043A562572744E38B0D0B8FFB +E9270EA45CCFAD6C7FF0374FE0EC402F788007F6025D5D33FCC84573A912F0E63526878D +D09C2855792DC97AB90F6A000FDBDE52DC493363DF430F2B55DD9BC6B6BEB9735686D645 +3DE803AD239321053F764B9C12D8A3D19823B052A8CBBACCBE2A958154E57BAE9257430B +A807220BC18C0141CE899B07BF776A8A50E84923E3163145ED3BBB84C7325FE6210E9776 +44DF731EF1A83F58CC60292D0A7EF1C2DDC93F7C56FBFA24BF220B1908C5600918154444 +F14363DA2D46933FDF42CB5B284777DB7AE316711CDE5FB27FD5A6D8ADBB8BC711395E1C +50BC77674568C7C18A5F9DB1DC31501B263C0CEAE79A1EA01A389E61BCB744C18E6C9345 +C8339E3542A53EC210278175A9FB5476FB32562BAA6A01EE5A06A5D03C9773B8BCDCF7FD +A89420F3B9A04D9A7ACA7A79F6F1DDEF968DF0A568B0062B8D0B14382FCB924170B7752B +56E6AF3B37B5C0D7DF4A7D9FFFF71CA476DB2414372686B1F0223F7BC7D26EE75A4068A5 +8BF93E6E81D04EA847CAC1CA42550AF0956A3E6CBF7CBF28A87395502A8A4FBB49BAA7D6 +22A1A8AF3BBB9CCDFFD99232069ECEAAB36A476F1D0D57AB4F925A7E8F227FA9CB8458E7 +7050221CE4F99776D8862B82E023753CD502B02FD1FE3A041873CBEAD85629B6A1B81AA5 +DCB2A82D368F2BC05672CE027F44BF28ECC41A28C636240F494A8E963319FAE4EFB0059B +B97B5CCAB45B87FA6DE1D67E7717C8295A580AD9860C3A539A62EA5049645174BBA5D93D +6ADA0EC957186C469B13133F7C253424A41D9CFF5D48FF5C1E6D0BFFA39668C2D5254F27 +937F6C113ECB59FAA417C79DC0A0602A03244E81D6AFC40C112504D82AEE2F880FB1418F +B3A13D31BD659820CF24504E230589651BF49F02210D877EFD77F166D02A731612386A4C +0D7E0DF87D77D26DF0FBC832B5F9221EE8003886EB4DD87FDC063278D50C3FC638046C77 +99BA361F5419F74ACD06D18B9330343EAD919AF3BE0EAF2F97FB8C681F1241C661E13DB7 +BC5A42410396360388C76A57917459DF9E3AD893E16E47C6D19DEF058BB6B8F15C9074BB +0D3FED9568CA6016FC6C343F78D3DE779225741E24712206FB7DF5B9E60E6B1A49ADFA80 +4E9C6F59A9372AA2381443D81D3834CCD26DD9A498C511511F0A3C2ED105D31BCC102BA2 +2BCD1E033BE7D90C5078DA0587D44AD84E8C62CE26D5676D92994C01255A999AAA42331A +BC8CAD6BEDA04739C4C6BC6FCB3E584576DC94C44C776783EE4F72DEF2A0F76D9A31CFE8 +66D5DB6220ABA6A643466DAB3F62DDA5D6EDAC1160D0C586F5C0562E73DC27CD1F97CD76 +81EDA5E2D16C486785E7D64B8338EBF758684313E1746B927D3D751DC8BC4F2F53E82AA2 +AABE4BA7A4432E22311F471D45E5F9C1AF00D8537E2B56D14376FEE8244989943ED01F3F +33800310E62BF9DA08DF47C2560EDEF3291D321547D11D478A6FEE8280D6A58DCD0E4704 +565F44CF46537A32AA37EF20F55528894368932B3E0D5CCADD1815237C02D7BF5D38C2C0 +95F0198AB0E775C2A3650CDA6280791093B0F0FDBCC12EB0ED6258FF5A38226FCE85955B +1B5864A9E7414D4A530356CB0A4A59274894E80B03F500332F18F7E53D1B712C17CF2D22 +DC5561320E28F9F9D2CE5A54E51EA54A73D953FF56B3A281F3F4F393E078852A9F08D2F8 +176746C413BC5BBC8C40118E522E7F82758E03A92194FBF92790666F067930381852D53E +655D32AB79475193F6F460F080405F7A7C1D4131207C8B5E9612A0F3906A45C8BBEFC352 +9F536EE2A388C728A73BAE869BC1376DB0F9F0B2B2E8003EE628FB639188499D07420B88 +460C137877AF93A3943A07634A236BEBE206B5CE3BBFABD0F42ABB4F4E2CED4F64D6FB2F +0B1A92A79A5E160846BE6A37D52B75FC3DB80F4213681D9DBB12E093DCD15973530620BE +2B5166E10B3440073246E1CDC87A43925AD4192A758232E8C025D38A31A976FCD40E54FA +47F8E95415C18B5A8F3AE5C9D08EC07C97D72850FB9448D046F731E75A8BE351FE452B7A +582EAA1CDF5360D96E065AF534B7683CE811DA3FA17E4165101CA68FAE7992D39CE9E260 +5ABF320AD456A3859C113076429F1FACD7D7299F4C97FFCBA3E5AB8611167380D46F3620 +2E0203BE1756FD086BA019DB1C3AEE521027A24905D7FEB24DBA39640FD79028C37B0175 +F0105CB9E9D62FB1473ACBDE309461473FDBC7DE6213DFD2AE88B5DCE787CC00C515927B +B8705A3B42B7B702C33BEF950CF965BF5A761FD8706E7C780879916D436FF963DB2F8B17 +B5DE1B7586A88662C1D43A157AE3C82424F42861B7871EFBEB104F5DE9611BAF463A2B2F +C69C34F5BF921FFE2EBB8EC63D63A3E59DD87F9643C44346D8A75D46BF92429404481C15 +32F4F2096C49DC7E8705E48C371E01C17279591A35874BB8B05577E1E758794B661EC58C +5ABE361DEBD59EA914A5E922374B5729CF338575A44120BCAAF373ABB05425B583C3123A +7129335B7BEA84B063261C606A1136CFB4771795968511038513BDC4BA6B2622E3CDABF3 +0ABC3EC8777F26A243528F1BEDB447FFCE543691DC700FD61F88B78F35F54ED90E0EE490 +50BBA809C6A1624CE093B7C07268F8D9B9618728BF9E73788E53DBF1085D0F4261736C05 +3306F412079BB44BF2AD382126D9F5F1A89C2938448B8B2EA584490574AAC3826DD6D0E2 +4D18BADE49B35E5A551495A7E0283C4A6335B46EB7635E1D93BB227A6956F5C99587E524 +D2ECEE3B038CE4C240477F6F052B66918951F1A7C86DAE384A7DF3E6F4C2DF39BB842386 +262F3093D94709E44B4F6C1508B3C8A34AFAA4DDF298EA4E9D452727BCADC3447D4DEF16 +F9158B579098E80FE8528A7EBB4639BEF180933089AE85856C4F1B4B3D9FE3F9993772B8 +87D3A415368ECDE584053E933C6A66512552F161FD7D1F3C089E55180F0FBD42AF74D108 +9A6ECC2A8A0A566861A07EF2D570F1F6A4A0D333FAD864F0C722A10C7E709844F75AA6BE +FEAD7C7C21F947E8764598862CC5A098D8D7A90232B3D4C4A3479CEA0C5AF82B9B22596C +2D4755269FE5187A2BDE3106867CEF50BD128E3489F77930B4B0A81CDD4A2432028AA58E +9580470632FA24C48BEFAF51D726AAB97988058BE56B699D031C957B843DC0197D368E2E +268991D6E0D4064EA111CB25B7843979331DDF2708059ACA15BBD1753326CFF7126C4EBD +5E339C62B17304964057FD31E81E3EB7B66B56CF8C4EFA1026FF09190CBFAB39C62E9F97 +3032C5E2475C6F55B72F2BE77BDB4EE0E635A424B85FF0B4EC0EE96F1C54504094786343 +77E35C4FB1FE64426842E3B9350DC31A3051107525BD8A15BCD93BCB24EF5B0DE378771A +E8803DBA93CBEABDA312EADB3E33D19F307B76D31FE0E60D1BFF457DB8DBBDFB91B040BD +845CDF6EE02A4D81CFBBF5985FD060B763E3C4141F0A9BAE9EB8DF14E40D7C93A46190A8 +9C295AE87281CA6CA9749400BC3F6FFE287CEBB0F6F82C4DB5FA010D833D81816DA700DF +63FC04B324AFD0AD229ED76DB877710E83618F9C621A26870D2A31AA418F4C8FB2E7E7C4 +1B57CFCE2DC46460876BA91246E82477702CF24EFC20FE32C096BF31E38F8AACE860DE81 +D888B1C5B0F195CD6C147A2E422474D1335E2584A67EB6E1FE6133951290C3879F885BFB +ACCD497F349BF7DC76F7A0567225E79A635A85523FB9B5C058A248B60ADE40C1D5DC9537 +9D5111642CE8868CBDFF94BC41714ACBF551D4634955DC86272A31DAA51A460B5B66F379 +DFEC84C2DE47EE94053F3DD318693A3DD0485D08FFD5DF88D2102F18B0787AF6F5A4E312 +69E316FD499B6F36A06355F7D329C27886B24437A67144A7CDAD71299A95AB6B75992DE5 +802935A847B4FBDD755264209E967A434647E026410755664E58290755D47FB7DAF6CA62 +28351DECF90BDCAA9E97A4B683B1BDEC6EDA812D5D27AD68D87F76A05F66D7E8327C855D +FC353D133402B597330650E52BE7E9DF382A2E7664EA34C8DFACA713E06964813ECFD915 +C8FC76E98338772F97C78A250DE27DF108F8EA6A6E01C5279CDCB99DC0E9DEA49E2A6C48 +3C9A3F315DE9866D7AA8A3B84C5C30E43752D497D8AFD4788D2AF10BBAC57EF224A54704 +2E455EA1B15526700697522CB192DD142B6C04A1E5ECC8CBDA2B0531E2742974D427A874 +E93A089B946D41EB841BA2DA3EA57080AE895B4D88953C7DC0CBB55100E7B56475FD7F81 +951238AA52B7376B8B7CB4A08F93CFBC31414CD644F6813FE411A2076A2087467B62C6B0 +47C11619DFAB0E6034DF21C52F6E0687A630D35C2F689EF4ACE325FA6AB3FE47AF250BFD +17A3A34A45E6B3EEF17B402536DBEC877B95730F9CB5370A68094511CBB793258302D883 +117542B2AA7FAC3C1992E1FAACD8D1ED6C26A218CC7ED2E438DEF09CF268CB706C371D79 +282C3B007B0A199DA60DA023C7DD797F8199C8BA4693DC77206D8B455DEDCF45A2C27B06 +CE8B98097E68E34DF45C447722111CAE1FE9A2132A949EC35B928CF31C373F8117B03284 +D48F200B22114E254C08282AAD37418951B825A5E2B3F428DFAC65D48560FDA6DC092155 +FA29A09467E049109C2E5D2BB7CE2EA8B449A1D01F64B996B34625F3D60C5C48DCB6C6AB +99A3431149D1BAA1380AA884F1F21BFC3C28AA9A8D72A3B8AF91541810C05FAEDD7F3DD6 +04574837DE6A378CF04E34C6B6460953B498594F7676B94EA4BE8C3CD8AF20E5B467B175 +D544FE69BE9942340FC0220A2FA134D4B97CC523C9AE4C86A7841590495DCC3DE6ED645B +58F50D11159EDEBCEEDA679D55FB8288D52AAD3F685227C514E43E284DFAC06BDF9C7D9F +ADAF527840DF255E92962C5C78B46E68C72893EABBD1FD4E1858842A9B2EF85663966869 +C734D1E577B3EB650A68D7270659984344CA91BE8F7CCB53A1E3CE26D043C9CF9A94981F +3AC6E593E61128B3093481A80E172528F5B887CD55B5807E3310F55EA87E90AF1F7C9AA4 +BC4CE22E0D3B27A670AB2759C349F596FAB2AA24BCA521F9C22B9C02FAF37FB9F852A3F4 +FD6B3AF1A1F3D1F4EA285BCFB0C0F7C5B8333BD2013EBB6613347824AFF2DB14F28B7712 +3189B3DB4668035E7C7ABCD09CB7A58C02D09EDA98306B567FCCEA4060DEC980901FE159 +C75D65E7EDA505FABC3646E5E48820DECC78552F854DACD0C1E8FCD34BE4513C1D0A5657 +C4429DFBAD3625390AE9CD8C40087E0D1FCC0D1BD0B0504DAFC30C16239ABEE7D9CF9799 +F5E506028BF66E9393BEB384CF20965B03A73B465852CAAC82772D828663AD729DF3F492 +14824703CE36BCBE2F492DC778C8D6467205171BCE00CF11C2ED4651DC9DF4F8C33D9BBE +971E3594BA10511827E453ABEA44AD355B3ACC323EFFA3995651F572988F182431C5593E +4504903AFA37AEFD95DBD5E147BC1E2A29C2C8542F2658C06D212AFDBCF47CB0A3D70665 +355F72AC1DD9CE376E5E717B653860975E2138CD053C496AF9A6551586447A31932F3C75 +9951BC52CBAB7BC6305B6C11C00D1880DD285E3A8F21B7421E1B3C6437BF40675560B499 +1E4291BC2BB91D61C6ACD1770B78FEDA917DFE69656AB91D19FA3F2F35278EC7DC3F75AD +CBF76BF301AC248CC66C2BC0739BFE8339EC1F81A8B81F5CC59F8B38CDE717700998B65A +AD729140C89CE76E44AAFB5720DB8D088FF7028C3BB12EBFF413324B247ACEDCE4706528 +02EED0F9621BD22A9FE207B493B5C2431C172CC1E5E465A2ADF672C917E428E3D9EB628B +01D5D637EE70620DA8639C52389EA2D619DE192620CFB21934B037930B3BDB495D641C5A +532B823AB00B436B69E64AC361331CBC85B9F54E95F8862F85A2FA947399FF1499A63E5B +62F022D3191810521E873AA747A7A7CA664485F539B923B95C2459114034F985E671B240 +263687FF2DECD8A97973A102C95992F3A5315DFA8CD2825A9C8512FDCF8EA5A649E57FA1 +6CB149998608CCAAB6AF6D311DD8444022C0A3D53585786D9AFE05AE23DDBF6461CAB60C +FBA85D7C2B5C983F6AABFD65A02CBD89869B880765B09194B888CFD57D34429581F505B2 +453A0DE55E0A727D9C02561CC3FA538463AE65D91A36D71FF34C1A65981DCA294989C8BE +053166A8627C01610DA5828AB836279AD2C688FA8A96961F4F03B4E0A620C8D60D931F1A +ED6DC195A458D42CC9E18A8290EC050E6C832442857558C6F3984FCC5FE57E3C641B0CB2 +7DC78113D3BF91DED8AB6D2592A90A323AD5FDF725BB3ED60B9BFDE427DEDBFCEC35A147 +1898A2BFD5ED3C39E764393CCD5A41FEAA287E88A828C228B37B3086B91473B913DE0B87 +F5E0A3E6379D1110830B46BD1B9CF1EC261076AD78D5C426D9578589228BD2D0624912BB +A60666E1767EF59F6E88A3E2BC1CD2FEC4E75F8162121E4F1E91E5818B78202D31B8BA09 +9E1B10D90BBA1BB994638CD6E1A53DDA70C41EA727958555F99508899982FAC290D739A6 +A27DCCF89B199F9BB895694CF97349651AACBA7F5C6961D888FDE51CD1D039E7A6B4E249 +D2503A5FC4DA4AC3A4D52E1908CA72733601F38CFC77BDD4627A99C7205644678AF0A119 +B4826C816E4EEE5763B111E7F6F64E94A2E21B4AA165726A3BD4BF7B2D029EA2A5F0D8B2 +121F13F70944F7C4E08BDC081E783931476005BEEF2AA44895125B603E1AD0D5630B9839 +1DE18F15A89B8CAC43E7773985BFACDF40A4AAF72B32B989A97A9CE012BDE6506048910A +950E81528F6836E33E4EA06DBEB483DEAD014F6FF4CCC17FBA14557B93F07738733CD69A +FF3FAD8D030AA5BF7C0DAE9B2293A85FE6685E4CD06D3A3A5FF69233DC41A9256DC96E56 +4DC8804ADCB562AF017EC5371CBE336AA48B8A47353657511C8C345E5FFB5B2D1DCC385D +7ACEDDE127E1C1396E34A63AA9EAB19E3A03542BA99C15CFF99AC5ED8E765AE6A17FA3C2 +6D33DFA0CD291856100A8EEE51D4752A3BDF71E670CB1ADCA1A946F6284370CDB73A57C3 +B92D7ECDE804DD72981CDE024BF09E1A6FEE156FFA5EED52EBFC63CCA6B99DFA55B7C0C9 +D2F6CA796869CED592CC18592A0E52F5BDC1FE6181E8FB38E7F7D8409CC1A52F990163C7 +D4EF1F3C52CFD0EDF376FC5D8D0ADD14E01BE5A6C63A30CA12F10DF0E863B661F94E5187 +66C1640C2E53B05E44FD7F6BBDC704BBCE316C416B8F5440B2007280858AEF3A2D5858DB +174B3A4C51D4973F227D50B433F444C2B015EC09E62FEBA96F71589269374CC4D860F0AA +DDA5838983CF417CD294FBE3B66B3722957C50811482BBEA6E67F64B112A1D41B9AB965A +163DA85EAF8808DA9B8CEA7873C37FFD40CDBD5BF558A687F42F4D85D179377585FB9399 +4C0F941F378C9ACDA1FE1C8000D434F8A6E25761AA589165D3FE816E1121EC41B08C8606 +9633A2FBB88A57C69D0C960AD5670E3D8A23A8E932C56BF10AF7D232B4F509DE979BA0BF +983A7AE7C63D0BDB98DC4DA7F83BA079689FCAB1D3F616FB4F6ACFA1EEDA10154113CFC7 +6F705B6BB560FD91F513B371D645595DA6ACCEDD983F2535401E8805ECFA30A50C0CBEB0 +C9A167E95ABF41E46F6135F16BF263992E53AC0AC674595752E44B646D347DD5006477BD +F689D53471714018FBAB73B6DB59E38E888F156969563AD9A60D1F1DBA5EE335891CEA6F +E09EC37A81B1C01AB0DF819909E7CEB02A652A570C3AE5A709C50B0A84B2372A6BDD0A0B +2D74A26929AE6FACC2085607F274983EA9BD6E4EE5B335F0BB8559031C6A1119FA896259 +1B9B692D9953CA48EDB4DD5620713A7D520DC49539654E83A41AD1E1981AF3FC348456A2 +FDB2615E84A0C04CBE72C5583A0EB2DA8E16BC093343218BFA7B3FAB2F392292642B8E7E +D6D7F60EAFF40C5FE2D5E3922119967C016EEACAA12E9C9BB9E95C543E4142D8FE5B3C59 +F12272D12A5AF94F64B2AB0AA81B5D4E6F021716728450F4FD3A4A124286901F2E569B7E +4B7BAF1FA08D9546C65DDB4D172F0A36F17CFC2E3317A8F602A65539707FCCE7D3EE5F8B +97D4A5EFC7BD49C272068A590A031FD988BEC2B4B243195902F059F15F513C1D0A565F3D +1CF75776E45F913C074E9F92D29C4C495FB210526FF826B16010EF716E721210390F8CA0 +BF5DB3CBEE6A2AA442287C7547FDA4162F35603BD98F76F2DA93566DB89DB7DFC181012D +69C6F57A39A6A11D7BA61F7C5E49974AEF69E08240719EED3BDB3DB39BD1AFAA39DC5B7C +72E19373CEE017D3AC8BE09150DB004D1933346059927C5C3F11A21B0A52C3A9C5E50294 +8A5A29E0C4EDAC562371353454EB5AB59ECCF71656B1B765467F55142E5B42DAEE517065 +04854760D63726F38543DDE1415904ED707A8C75DF3CBF6412CE799DE6FA7B74F92FBA55 +8F75F16B730AFB8BE0425FD7B40EC1ADCE67ED48E804396F104CDA42F7FA7C25E9C45016 +41AAA410BAFE1856E1925DA6B6FC2CCB5C6EF5C78A65B36D1EC2B7C6D65769F69F6DBB5F +556058598F6B7D92FB81A280D60796462F40FBE9623E7FB44C3E1E3232B30421253863C7 +B1518A8CDF2CAD468632D726AD70F61242EDDF20EC15D9E502E8668C26A583A9185C88DA +7678483F8AEA59F97373701E25F698B3C60B8524BD34C596DC7FFE284FD59D4F2765915C +8562A919E48AEF5882B04548426B3F91CE52AC4B0C6B8B055374793DB94D87F37E2EC09C +B5707CFEE332B79327D5832160FEEF1E7256D2D828B3B932CB9596AF1A74F72A5A58B462 +457EC9622EA70C8E7BCCA6010C62D375A1E4B819642937E46BED83AAC3447C9EDDD660A8 +128273CEDE717E93D46C8A445322AAFFE6ABAF50D6EB8647FA9E75893673BD3C3298693D +CCCF823FC5CE853B5B9B894F8CBC00B0CFF16D662785C8A72A83B6817966D27274058804 +361C58B673F78C9CDBB4716EEEC89B7A80BD85003AFC1CC4287ACE0F4CD12DFA940689D0 +357E71E2BD2219BB273AF131B7FC88B0F59E867D7968E77EA32736DF6AA0640D1F7EBE54 +7FA6B4863B3A6D3E61C3F86E9A621B64290EFA830DF1476F70145777B02C9A4EE785BCC5 +1293915FAF0728B0A3C76370080BEFF2C121943FED45A075B90D810209D97AF4A58BFDB9 +C2BEDDFA79AA0398800B0372CEF1C6EBA3639F980469D048FE41FF7F3E62C38BED78439A +172D4974184A55B9F7EE80E58A05DE801577AE94F41A5AA0A58B10A1218C6B211B13EAB0 +5E8E685B4AFF1D9BED162967D352CBD30CC256F5D656189C064CD04F636730EC75C6DC93 +5BD33B933AAB1AE67B9CFAC5CC422EEA6FD1D759D7A9076811D5C16D251DB24F3C84A66A +1B89B0BCCCAD2E602F7CFE6FD81F40B15FA59CE4FFCE9EAB3368555B584A0E7BD1230586 +9BC6935EFF37C0CDA1A2B048850EA555E500048D12DA09F1AF426AEE319B3C29CB084C81 +AF6CB695495F4C4BA7D82F0CCD5B1E37B5B54FA0B4F310946A95A24E4F0EAB558D5DBDF3 +3240960F738A090A7C48ECB77DA89A2F5BCC71E59DCE2CD1D9D60E4CF84162D838394794 +C1128C29861FF5B6D853C2973C5DBEB4B2EA6DC8BF9F39C128FE6C03071D666DCA2F2F59 +034E01F861F6ED0F2A47F929463866D9747755B19E87EAF688F63FF61398982B2B578A6D +1126D12FAD575C6748D9A869280A1DF1A6C065C30127CEF0D320CCF0B70AFE78FDF8F85D +73D92B58CF31CAFBFAE863C733CAF86F0C21CB12BE7AB4685B75192707ACB49072E4DF0C +CB5C8820B266096773164D42D8700F690F3875921B3BD06B5A7547F7F28C0D66E9C847B3 +A6ED4205AB7DC565AD386EF9E9F26300B7DA7815D89ACEF70F7747C4839E077EDAF1425F +516B28DFBDE2A50FA09456FF518BAA484FB2AB219F869159D1C90A367C2D0AD37A41CF2B +F251107318239B0D2AED86B90BC5A609A9E23EB23DA7A9B3B09F5B77160D3107D67279B8 +FB27C672DD2C451210D8ECA64F38A82FFBC5B32DE24BB88FDEF3E00343ACF94C0F70727D +EB162B037C07E42FB61EFA6CD8716B76266AD0736C2DEA741DEAD3C8970856750E626208 +47177E8BA6C165EC9332E89379B0F42895F378E7F40A891EDE85D7D3B269AB3FFB162F6F +5523A5AEEA6C63A09FB477C75F48E84D80944477B3CDE2FFDE7041970DD9F0F2D3C200A4 +28939960C25D39197820ABC862FD747B6351EA1FADF7DCD5469293034E8FB6ED32BB93CA +734B4C6C7309CE8CE974D9464ABCA6FB789915B8BB8F6F9C233ED5CC1B3130481C72DC63 +B766F3C3B4E6881540D3B9701101082E43DFAE894B1EEFDCD7B60E3A441E8F42E47FED67 +CF5478A0E57424B19B6F2B110D7B508EBF532D37E86E4046A0EF69D7E188719640C5DDF4 +F1C8AB2CB2D1A03583E0BBD530CB90097D881466A0FBDC68C8C82C2DF517B0832A695D94 +DC0073F03210A8E9DA4340E9076DC29FEB24F6AF46D11869CD7AF8B03D56A9A9D4DC8B10 +714E558C94D505A160425468277FFB7453A54FA3A048F2E755B836757F590F976E4F57B7 +B34D0C1E931E0F46F665CA10A584111B63FC0D1DBBC583451A390F33010AF97C1A5436F4 +633C63E5FEB3F57CCE852A3264E8D6FC40BFC47AF469563AC79BD0FAF36DB986AAE2291B +426E4FADF2BBB75D097D84E4219B50C69E4BD6B883C399C1A1764BDA9BFA7C8F507BD3DA +043DBAAF1B2A1CED051407DD9904978A3372A237C63201D6AC08F45760F2A9F9A05E17C6 +3BF3FBF88F5C22B84A7C31A93DF8094A22E0BEC8FA6B5B8392E2FEE1167C9BE75C71FC61 +D96B1A64962EA9AD2351E4BC0E9D1251E08B32E46EE414A02E4BDA4EFC756B50BACAC527 +05358FA4E0831DDCC2EA109E658818F4AE3BD1B529EC8290068949CDAF8432B32D761D5B +A189F6D754A6BE6AF0F9B7228B4A0CCECD9C1612FF5267AFF1D80CE0DE78D34AE50DE18E +45DAE4668CD8AD3CD83FBBCD1C9FDFD0DF6D1EB98319F2B0B8FB3160ACF30A50A76519EC +5C6E29AF1858EAE89DF07CEDC156242C097D510DAA16983DBEC439FAFC4B92F644880754 +2C0C9070401A365467D5B92FB0265E36C043DD057689520146CE13AD1202A05DB8EF6FFD +BD83EB5B66A7039819EB3A3569D7934BA17D6843F33B90E29B3B70E41B6E3952627B50A7 +9B22946085E1C3B49ECC799223301FF665267577EB42EDD3F96570BE473D8FADF6E20977 +B828BCCDCA9E99B656F843C421C29C3761AC94B209CF662A504BD6F476270081DF274BF9 +CFBE86EC832EE64AC7594107F77A6F5D32AFEE61FF06EC0916B60EA34CC474F77C8C9360 +C9AB3DF8D00E46865C787F991025EE0B8753CEA8CE04D3CE619FD3FC7989EE6DE3BE2DC8 +DC4AE51580948374F63C5B4DEF6A3218EBFACF11FE052E68086354D82F7CF192A869EB95 +F1C3B82F9C9BDDA35B7664E7CD414756D14BCB4C85F0277055D2C024F97CFCEE848F1218 +C0465D65EE3A2460168E96D8BC5FCA42D002CF8CCA740E88B4BDA4C77B630564D41F6F1B +8E2C293F18B6F11C43552FC1853FA0E56B4A9D4C8B64E36CCEBFB42AA4025DB07A232EA5 +940843188D522F2DC1E18009431A2466B9F5DF0BA85735257068DE21E97893098B8017CA +FF59BB33325E98C8075D2729BDB3EEBB248E070312A158DDBC5F8781335377BE1F9A4D46 +08EC02CFF83D7D2C0CBE5EE3DF3A8D011AA2204D89051CBFFE3FF73793C116C8D143C569 +C04FADA0F8AB036202C4ADA2547CF472700A6CB6F9398678A247707E56A071592D681E0E +1B7D3161AE15052258E9FA1E8FE0B898D71F8F01126DEBC69849A4A74631884F85DC8B10 +714E4D1E1956B81F1C6A1D2B686371FC3C1149A9BF24CC1517D0F91E6445E3175D623D7E +8EAD5AFC6FE9471C6819CEAE1B54E4291357E4B4B0A727FB86661F1EA4D3F4619887CA5C +CFBF0A7BE994EC0407C16A8AF8717F43E41A86DDC430CD2C994D6D8334B3787DF02F40A1 +E79CF18FEE729182E50F8ACFECEECC42975BC8E5F3CE308F3A9F69134264D5C1076F8B6E +6C4EA6DC3C20C6E49391F273E535A26A7FC9EE50AE0FE832C46C05BB0EB4BE92C2137584 +E7110638D5EC824EC36ED32F1C91060A536F655C67BA76BDCBF1CB66116D0792032F000C +85606DC9833581F4C1608D51B057317FC222680FEEAB0B39E8B35068A1AFAC8760880DAC +57D3B55D4B1A1896D50C6D763E7F9D84AA3FAB44492E73EB3E58651B2F165545D812CC0E +DE84339255EF752B634CCA91D3A1439FFF188ED53918FC5851DD87C737716DEF2EF6C51C +ECE2208476B3E08C40A2784CA7AF19353C70C7B5EAEB58203D1467C7B4B70BED56E1ADA5 +69970A0D10311791ACEFB789C507E55703B486B7E99270C89D463767F8454637321B9372 +A328AF3909C4546C3410DA87CDC2BF68FA036E08A0EC5166D23403440814FE86C0D2E416 +6CD26C987EEB9697AEAD9766123084F5EC5D85DE26BAABC45BBD878E585C07CF65C95FAE +0982B682A6B1CAD0CA3328603183E7F5DF27049D82D1AABCBE4BBEC41907FE324CDCF673 +92A65748DA5BED12559BB107ABD75A5A32B41AF45C1935C8855198E7E5CE55AC5E550424 +E55089A346F5F979506BB888AE30D1B7A2E6B1EFCAB878304F9A5C7D8646E1D556875092 +2F1F8659E6C6DB246BFB335BF9B0EE59951590891E58DE50973B2B9E75CA0722050457C1 +48A2B9C300D725495D5F05D770EBFA877CEAA1834C9F4F434F6175DD978B1DDEBA14E3C3 +5617411FB5F674A6268FB29DF3DE86B96CB9447D5277EA57925F7377FD6AB1DD03CA66E9 +6B596711F0071A87E01E623A47B3EA208D4C8E644BAA232941E5800CF2C0DC3C4B5C26D3 +4C38E37318ADF7F39CA908028FB22E858024A3905FC3FB12B298F5A44A11DF87FCD7EB15 +0C846266EA6CF4A2B6175E86CF6AFE500315B7C3AA86D1F604335F752C4047F296CBA798 +D3DBC9377C0D18529AD322C7AB69ECB3453DB53F695BE4CAA84F822F13BCFB78F03C6C27 +DB249DBEF37EAE3097C3EAAD54B9093139C8992DA550A5DD4CA7BA79CC58F10984F759A1 +8A3F9EF2B3CD8C4AA2D7DB6510EF0E86C9C1E876A7AC52551C42B4D33515637FD07C213F +3B91A63E333F0276F7F44E1DD1D1F759D9E1495164D70266EA56A08DE62D0EDB09230885 +2D0BAA1D4CE4A6B115030D7B0046E9EB044E15FEB765FD515346B13B196227AA5AC9C76F +272B6C2FB67DE3442032DD9812BE1181B4A35099239ABF44B2274BD7D057359C45DCEA84 +D8BC14C8D1D32BFD3ACBBFD120C24CDE608625C4BA3661E4038EDB5F45B7959C86643EA8 +FAC43E82B5600ACBDAC16A77E800507CD63399F452823BABB430E3E11B40B046E826296B +C04B5F5755EBE54A5294BD473FF5E4ABC08AB729814F662B446F83203F1620DD8FED7AD0 +C86FC2E50AD277DD72EEF9406878F1A416F16A834EB4202094FBB08877ABB6AD51695BF5 +A60C7C44C5AC2DA5CCEE1A5FCE5AAE9C07BB8746F17ABE4787BEF37862F760944C1E85A9 +2D796850780F6DD44A5172F3D0A2A677F4CFA0E40C06B09776961568DA8EFB910DEFD453 +F20F9748F2F0FC1D5A17541238225B1AC8E22621B24F9A7CD333AD60B287C176EE71C3F1 +6282B327BEF2D375ACC762D18DC468A656E7F4BD033CAE3B231EA1B8DE994D62110A37A5 +D9314CC49579ACB4CF85A7F7B9C41409FCF9CE7247502322D0D3344A193C61A211C9907F +242C2F0FF5EB017F1B77F2FD7B88C66246131BC5975966AC9E81A0396BEC796ECDA76CAE +5BFABB1A0FBCEC6ED3466ADF3205BCF247366EA693C774D215486DB5EE25A6BA41032343 +9CC5F8244D9F5863C52CE2F0C8D99AC7C26D201E2511C4F470402FF7F2B4C093580059CA +CF313F4E34481433F71206DB8579675BEF328E9011BFF3DE8D022338DDE02B66061F7088 +815988CB5C55224C08E67540610EA37D36D3841E78AA828F385EDFC3FDA57220D1988155 +80841533C9CF1DD3D0A1FCFDA06BB2F3A2B93978FEF0EDFD43CCFBA400301D8BAB8B9A57 +FCCD0CCDECF7FC72387D45722ABDF00E89AEADBE8A158729F64B74465C6AFCFBFA93149A +C42CBA17C01C029E88974C944EE96557BEC1B0B3C8C3CAD0B1F013D590BCD448774AD3AF +607F3AE1A0B9C8AB20CEFAE3B44F4DDA7AB0385906A3202D5BEF00E1EE3D7D746C16421B +AA4B9E2B27070C84439DDE56F8A1B71A0CC0AF02FF9DCD8AC122B1C3BC87A0BC820A93C6 +A35B334770DC4DEA570B0CFB4701A2B84DEA09F5A37A4923259DED0280F188E13C57E6D2 +46D604578B97B72D73F2F1A10BE0B56CC1EC28147876D45B4E25EBB8ED2467EB7A482EB4 +CAF28AFEE76C9DD02C34CB329AF07630EBE2B6473C415B0FEA259E79CECF2713303F582D +DF2B507D97FD832A25C4C0C8F531CA12C0E971DBA26F9C6903CD2662FC141EDF3B047103 +0B7B990435AE540AD4A9E8BF58B526A82E9DBB76DC2B12D7CAF24491B082D8383D925534 +C443CA3892D7213A768CB30DE5370A0B80B29A602002FA0DEFF2CEE7CA08F36C6588F4EC +7F0C6129CA4CA71FA746B016F2179E2404D812357A770C7FC90763091EBE3FF724A019D4 +AF46CB7DBB1467D38132EF68D342A0BD675C58FFDB637540C36525B6C0A2E083CB180FCA +C47985138372802E3C664951CAC4AD20C39A270F2E188EC9BABAF6EB85151F368C061A77 +E47E19246A5BF0E11C483865E3FF1B8FEBE7CD2D6E88A63856FAE1F9786A630EF2182327 +79A8AFB30B1795B3E2067FFD182768ACE773729479D8C88B6DCF70E0810B3888DC189F62 +8E0FB822842885123952A8476B6BB1E80FBFBAC64EEBC76063058A59F18BB79F01D157F0 +34C68463297C14F56582163520C5170DFFAB8E8C2289A0C7D98FEF9C6D3763D5BC2DEE13 +402B099AC4AFF19341D0B104F2EFF754D073B411BB4E5F8461D9E74E471638CE2F22460F +4B17AFDB86525079E03F9D53FA1FAC798BA4B1E8934A94EA36644E335AA43E226A39CFA3 +520D1B38EC3A7660BCAF9428CBD29564DFBA6E588ECF65C8977C753FBA30D3C97AD33536 +34B3E8036CB25F49D7D326F7A4C465EFE9DCB3265DFE95D01EC47830A62D9111130685D9 +DAA06DAE163BF469DCADB9CEBF10A632D01352D426D732AA93042CE3F6312E6DEB456EF0 +78656751EF0D7C1F39CEAE7C27D4E55C35901C45547AAB8ECF631EE91A75B926A8EB877B +B73253F7BF74EDABB131705E13BA733CA7CF88D3D6F59226D9C6EC5C9B0050BF104C0ED5 +333CB2B417DD1BE2BF416591F3B3D98C0E711111843D7537F3F8CDA6C9FDA7377794E11A +34209562AE12078766488C00C8EBFF7312055FFD94D35B56933E39A77095206911AFE9D5 +C2F2898784E19E06297701AEA9272380F34B66C70730EF6AD704340CB739F721A749BD33 +28CC458CD29F363F3C7D767AA4087DB56607A875CA33E729D6974437479A70E3D1524045 +3B9E06DDBD5593FA8F894AA18AA673199D2DD71AF92FE8B869552FFA10E9855D64E352AB +B37FD730FD30FFAF7B32FEE7869A78A035931977302369838F960F2C99B0EEA106E3A8E7 +BCEF05F2E34235BEBE41CF85B9DA4693985C7691B77BBC03DA6C3DA49512681DAA302AE2 +13863FCD1EE2C1AA2A9E02E073C10F25A9FD798892B60A79727D23EA39591B617E8B08D9 +77F2F7B60A371AC227D2EEE3B2094153B619A5AD541FCAB29F27015BBFAE6CCFB1CC2EAD +0D6C1A4E28A67FC438E476109AAEB67956634812A0BF3E9257163A82B0A57459F1150C1A +0F13AD982CB26FD01CCDF78C3C267B372D8E331129D4E83609FADD5DCBFA7D18D93D8367 +2F422874A6699DFC45E2A0B76A19935CD20A66CD278CA3A7AB9893685475E0F7E3D75C50 +22B8A9F17E1776B2960C31A972B19475BCFC90973CB642823E77E8455A363F66524BC0A9 +22A24A3D2DB5E71AF729A911BE97EDE5971612CED400BE5A2C961B2336F37B92512AB53E +153434325BCCA89A56A9DCC8694BE02496F4BD2DAFE14ED9F9ACCA3807FE1ACF6B0E4D67 +0D5AA3340A2217EE7BA81379852965832A4DBD1C24025FDD3FA69D7299C7619344F7DDB0 +484CA724CEEFB12BC12456A1E025D4506BCB9D6DBA5E9FCE5B7333DDA2E4C2567CF6CAF3 +B4247A8B4724AD346CABF550B0048C3FE0CCF9972CCBC27DF540E8BF4CB21938731CAA4D +95FC5E97DDA9572B4D80D4DAB8D1611045BD4D167AAC9CFCA24240CFCE5590CFF8292A6B +BA2338FE074609B6E79447E9719C6E742AC8C70FD49F86799CDF01B6991F7AD227789AF9 +EEB32C33DFB91A6F5D0406560F8317D7FD29077F0247E018B8E3E17F9E45D81379031D9C +1B0F488BDE49FC8A2EE6144858FA62385BBDC6B059E4DB9EBA87632108356196E0635846 +0A64BD1BD2C84B65D68CFF9C9F2FE26EDD945568DBFE2DA290A494C60B6518EB078BCA18 +4520D7A760473C1EEBB4D445DA7DB6B07CB64FB9DD54BE65CAB634DD2A84E9389EE0B802 +2B36DB3BE097C5B1BBC4730391B20177893535ACE5DD439EEC48BDEB1DC360841896BEA9 +48CFC8E52DBCD3395074C6A452E07CA86B48C403386B24BDCE0FA1AC0457E66555A37E6E +B7F1E0C4DE61A8DFB64512F17C59A8146D8A696D9C78287348AD410C30C390346EB85479 +4A1B95FCA1A460486C75270009E9259DEBB8EA4DEA89C92A88E699B33BE47441D8531681 +2006CBC6A79BA334E32B9E8462FC79214050BF435FC8F761FEAD9C5BB2B43D478F2D9DF9 +8E852CBAB9D2027BA02249CF0D51A8E9E67FDB7216E1FB9AA19CFABFEE4FA7E750D51418 +82FFFEB96CDA1D70E30C522A46536000F848914EE4DB09E87C87D9D6A4139E380A8BB504 +DFAB13992E51643100EBAC3C643B0EDF6ED2221AB1AFA7CA0AA8638D487D46ADB2D87428 +3F5FBB88784F373B9382BF51B014B7BD5B1AB56E07708AB0F86BC92B19496DE0FA422436 +D58E13970762EC3F077B5A5D13F5D846F25EBEB1E5BA587957888E0C799991BC474FB65A +0D8549E4C71979EF3EE15067F463605487328A1C0C43424ED2A8B2A708F882C1565370B1 +F34E3CDCFFD50B425A39D4D77E4462B211C18055E0C78468ED3EB67DD723E90565332C1A +E2715A7C2280CE585A2C90C7ABC6498030690C6404042035E3409AE39DA7423922C05DF5 +89082510AE3C530C41B28346DFD3EA56DE3902D7628839573BA4A407A258630836526D27 +2EA67666F6DFCA7371964BD4A134D8C1636683C1541CA1EA1E3E0F21056BFCFFA1174DB4 +65D249623BC98DF5143D8BA83615803D8AC0331ED613FE6EBC2AA378AD31156CA35D3A64 +CE42EE3AA148C9D8AF84CC71C0C3D2903939962E4B8AE3599D65A430FC53FF8C861E6DB6 +3D40A050AD7DA591CF7022DAF4C39DDE990CBF87E5FF207682722E133B2ABBDEF737F861 +B8894BD16849E211B45863B0A04A081DEC99C417A1A868F10FC1FE5CD1CBF59E130989A9 +9A616B1E371E8E1EBA3798D93BFA918679C4F111ED67DFBDD654CEB0F013D051B5C638A0 +6A3D87E2D67A5B5778C85D591795CD3AF53C402497274ADFB41E82778862C8FBA2491348 +FE69F11A49E1530714290D270410C4176BF193FCB0B7A6A540E2E8DF659B55C31241A834 +2181080534AD74DB0D901E4AED75DC4947E76C6FFABB530216F365A8E15213E6CD93D442 +213AF03E5C31D88C13CA104CAC3AC8C61D7E013125A5ECB8F614F4C3D3119CAC6B5887F6 +6E0A3FBCDA41C9C70FC9CAD83AFBC5963BA0BE0359B116CAB3E22AAD48415912AB97DF85 +F1725B8CB130CDAA459C4B1160046DCBA8AB1492489A1BF0A78D6EE8856C3BF6675200FF +01E4C1DF4DD6C5255EA056C4948ACCD662722BA288D24112584AA6FB8BB2556D3E387F84 +853E15C9BAF3A95D4538A77DCE6D87EFD432845C23BE92930E4C515524BF88FFAEA89627 +D063D9A0C33868D452E4C919E97A526833DAE1A520B4A73F799C0596B627F8D454F5D294 +3CCEB0F168701B3EE0372EC4F2053CAA10A03389D51FB0211E5A2BEC78960D9009C7F8A0 +1098E47636371CA07F63798C7D6D28F3D543B7F045C148151EE2875257505CC73F004DB0 +C80FA641966E382B93268367FE1A86E26A3A441987243402046C3A644F10604D63BBDB68 +102E44331F1289A2430C190F8D1C117915AA2EDA80DB1BF53034F5FE0381A8C86E91FD02 +C20FE7796311639A78A6354320109D59BD0644E07DC2D6E7828570FCEDD755634D808390 +DF3958672AE4430469FE4C749464393504B1DB4FF33A75FAB1A3900FB314E16B16E9EE54 +64FE7FCDB952C502C43EFB543538FBF7332CCCBDA721F15F0FFE3F8D07C3F21929FBDC94 +7585286FAAF20E85EEDA2F24FC7DD486448953BDA34005911B26C054F3F7DB8DFDB79FB0 +34467B2306B6B7C0DACC36605B902DEC41741AD0C8A8674A6EA9F084CAD9B8F5AB9C228D +26A30D2072F564A9F686824684D6CAA6CE487EB1F180CAA1E0A05A22F09B2A652AAE3CCE +14B0ABE95EA58FB109FA2D69F3E6888244F910104DF7849F2560C9641E290A2B58A90F62 +C6A712DA56D46787AA8B15E15E27BC88C3F597253A993E19D7150D4B5A4EF00B30912289 +2F912C9A985A2B467DF999F850068ED2BD6E601D8DC62DFC549EA79D707F964737043DD2 +71497FE7A62E6E17C4BBDC28D27E332A467C49B38D35FBBC078B755A1068BDCE06ED48B3 +CFE23FE250426E551F5081D8353BCA6F48C4D5E29C9134F728A77DC014CD81295E94ED5A +3E4C5DE2E668051112C6D512E91B14001ED0B897F95D5D5CE152C743A34488E4EA5603E0 +8B500C5E8CD0F289CE321AC01262C00CDFE79EF7E5907106CC94B38B54998D648158BBBA +896FF3ED5DB7D4A65567DE77202DADF99AE89B0A81E795AF26C989C0A268B7B3CFA38EC3 +E9F47CC72DE23783E0E98674871D632A80127EB72ACB44A32DDADD2826B7FD75DD34363A +9802925456A9C75D1A63593D7C7A2CA85404C9AC5F17DA23D3B2FFA177740C9ABC114453 +9096CCCB278AD177AC129A12B05D1DB56B1C8B05F0232D28D33264692E4CE2C5F738AC0D +DE16A2C22336CDC6836C63326BB6ADE37DFC0276440D4E77C8748915855D497E3E10B8DE +5D1A6911242BCD1B0BA1E521359B5141DA815459BB250A85F1BABB939428B972367E96F8 +BFAD9A9A5DB65640FC2ECD1B8E012F437D156629605301F68A83022C66D55114E0A9E894 +0EC3A7D6C12574DC2F13C70C92B900560D3D2EA6271437F57ACFACD10998DD584134832B +4DC51C207173824B4F907435F4579505CFCB0DE2710BBF9C562EA874BC4D1CD4443F367F +80226AD929CD3CA7D903B0932EC58A6B577306F7AFAF505AE6ECF6204B7C22236ECC73AC +87C5B84748ADC6DD20644B0F279AC21BCC70B0974B1E98B771203D6BA583EC68AE2428EE +DB849E2FE9AB201D412779871E456021BF7735F59FD757D3B82A2D571D951774A231E9CE +DB89DB0B00E57972FEC2BE1473464C965D9978BEBE027F4BA96B965C83C4642928F240C8 +C6E34605182C4D48239AD52DDEDB18715CC463E9DD9EAC3E423334E380B71D9E1EA2BC85 +6CA424B9289185505FB5230C10CC9AC1E7C527CB950F957168350E7A4690C52D4E994195 +36B5B2F662AED95029784FF3CAC75365449E8192103E85E5A5BBD9EA92BA1A33F5BF3C07 +F7E249904F35D98297A35761492FA533DFFC52AAB59C0603499710C9266FCE7AF71CCD17 +07EB519BF7561E6CC6CA964A091F944F1FEA70BADE12416C70CBCFDBFDECCFE17FC13DA3 +9B537FC4948C3EF99B33B5B77B575149A3B960717724D77B5A2EBC6FA7FBEAB74505EE9A +120B384013684C4FC246E5DF1C72904C5CC46CD98C078E348C470C2D9FE80B26616BD146 +6AFF56EEF2BAE0409935CC85F9C0677DE18C304CD3D9D0C42E777920CCD17D3279923439 +734CD43F1CE70017603E8BC790B6536016436CCFFB47578936709527C3755581B365EEBD +1E9DBBA2B305A64930C87E1F194378356E119B636D45F683604E22485328D19E2824DB1D +129D57253A7589AB6AF57F56E9983CA2DCAB946D06863A9F85A860D1FA777212A8D2B8DB +E7EDA1A901DB70F486BFF4695B3BA2EF0E443F87280BD82210335EA90A9018EEE52D9C3E +26C08A82076F174B01DDA052C7BCF761E59CE04BFD12375D04392C73CF4110DF029F41C6 +2FB0C8D5275857B84E5F0C6EC2DB27679077CF1912AA522887A9D0DA75DDD0CDD726AAB6 +FDF02C2546D0721ACE715FF5904EE52F3B0469C6ECC767C1522C114B662857F05FB14890 +3E927D39BAF05D3D85F9D1E0CA8989D5AFA42F9088289998BD422E56C1556C5506D93351 +8A313AB966CA8AE369474E3C3E61ED6FCC1FD4E190E8DCDA65F4D6CBE86CD66955CB2DFE +11BD578A277FC4CCD7C73B44029C4FCDBAE216863CB6735EDEAA35EB914EC8A6F57B0230 +AAFD580737C9DC91A39192FE58B98B0DADA0373E6F6EE30A66F664CA11F5E6D7BC221CDB +E1039D67D317900574BCB27C5D8F3F84C5FDD49FFE5D8C1FF2FF160981BAF653FC44D19C +33A2DD9B18497A3C1CC2A87AB080F39AA7B434360733F91D8815FE29A046F9C8EC1616AE +1FFFCCFB9DE60E8AD1E2F9856F74CCAD5FA26A1A15D3B81613B2BECACE1A07F2A683FBED +AB23D39A515FEB186715565F3732C663EABC8B0ABE2CEF70D9812DE0B8233DA1892D2F16 +E551650A097E6907331A6F06FDC0D159F08A8A1012FC9667DD421405B09BC488DBCD72B3 +2D15D54566B858C0CB14D7EB591EB58C4C61E4A89CCA95EA78BBF76BE3DE2FF49286F4A0 +41DCB403996B18FEF60A07220F6E0A3CD2EDD1492C93662398542BEC29453C3975C9E9B0 +FA0F5E3E5ACEDCE222D4D5A1A3DAAAD27DFBCC2EAD423D8D67A00C7F8B66682CEC168AF5 +52A639EC758C65DA1D296A4EA98BBEAA87358166BD3DEC7EF724B34A5BB440FA2CB36FDC +163292CDF1BE9E828354CB8F9B28D17DBDBEDF4DB850126C4072CF9ED3C4D3A3BF7FA9BE +5F6B6DBAD11DF57E6142122F9644C2915D4E915867F39A7BE786D1D2F1C9BF24ABA46D40 +E2DA32712FFBBB07529750B2FCFE14269DAAA3DCB17F88AF45048D16A54AEC645A87F7FE +06A843E9D65921C63E7E9FD162ADCB84E0A46259A29E04734A447158A6501EEA3D40889B +2DC9C945A3688F018C1BF849693A1ABBEDE397DF6E3DB71C1B4397E0A600E699B59F32AC +9DF8C9AE80670204EF7BDC61F1AE4534E990DAA975A26F26B6E44AD026E5C4AF6AA8087E +4F2A0BF2055B7B61C2C7F9140F301EC739252F755DC8572498FAB49F66D6C073C19593A4 +82155BEB06EE04D7950DFB2E67C6648C2AAAAC8727F83A5E195FE06244FDF8AC0334DCD9 +497AAA571DC490A3240F4CC4DC5F14BE0816E05356F75255072AA4EC6EF524E8A6206432 +3A268F4369290986496FB10FEA939AC4F6639286B6C46871AE21A24AFFF626774EA79961 +04E304E4AF97D4A154B151BEF4FEFC189B5C4A937B6AB0A16861C4FE37AE52A6FA70B1E5 +C3E72C69100EB33401E1C51BB985096BF3DE3229EE0ED44ED76C5338CEA2F39B405D4362 +AB8EF09A0648C835DACB5697B55FE97B699BC61F52229DDBE2673EDB704D7A48A323F63D +121D25F4013609DD069FDEA816D1FD749098D2D9E16DB63BCE13DEBCD52DFBE3F062964B +EDF5ECB154922C1E021DC13FA0ECE4629E6194BAD1DC165C96F7D764F6307AF084B2B293 +F353DC0900FE772A5A5F642C074B3D3BD52C5F1416F0B0D2365CA07A625AB7607F20C8B8 +AFB6B89AC456BB3C5196AC21E976438675FEB49AC93378048CBF69BDC0A028C5BAEF39E8 +C4B009B0CBEF2979033E55912FD8664E0116CD58213BED64359E5A68F01032FF733F8799 +258724D01A2E1B7953C19DAB829184601545011BD76FA53C55ADD11CF5568CFFF5A1CEAC +8FE43EBE767045975029E210D481D6F0AB6E403546F1C72D4C17466DED4A0C8A071AA7F3 +C828FFEFAC73D46A1A461466CB132D0283DBB07271C0AE4E3917DE5FBB22A3C0CA6CDDAE +A500192B7C7331EB1703A0020EECB68BFBDD927546068D107AEF60E2C9D7C77542D8806C +C1BE2B954F0A7755A9BA1496D8C62076A5B49CC7B8B07CB10D966A223A7197B69D4CABD0 +64AD6E9AC671ED3A7BA87A3D605BA045A8AF1C3DE284B527CFFA9FC5213B2D185FD73E69 +9658DD7B97F479BF66710B13290CA72E16E8BF0C3E16222730C83706FDBFC39DE6B3876B +C3AE08BB9CDC4A3F9904598F68F50375EFBB60E0E2BC63F20E4A133DC1A86DFA0875B3D4 +64DFAF465DD3DDD0323EBE52E5A7C6544CDBAC27B8001B0B7F0A219B99C547154302966F +301E4BA8EF6A29D7B4F71CC91CEB83F567C4ED07F16308DEEAC5C10B906AEA5B308ADCEE +93DD66850765EDEBE947EDD62749C9DD4C22D81D7310F6700F49D55AD6DA522A30D87088 +47B08459299C124E9C5446D5A01EFFFA7A1B9C4DA0184DF2F9C33E15092C9B94C6A1A152 +38BE2498B202534CADFFD96216B5BBF0A8C93F5FDEF9711A38AEFF2D2487944ADAEE7FD5 +1C4B1345D11030312AF66BE535150F3D944CA32B86B318713C4DBC8CC39C425E3D939C3A +BF93F86FD924DFD1067C1A692A557DA5E2E12F7E620FFA9497353D0CF34824B467FDAF82 +63E4B2CCA0B3FE909D5C62A24733575FAEC6892CD7883F09B2476C1796D3D19D89AD2B5B +6AD25BE6920947AC99CF196F77523D2E52D639107D5788AE985F9C59E56895317DC8E3C9 +44B05744201FFA75CEC2C0C1B88BC01AB444D0A63967C93CBB54DD6248D8A2ECDF906D65 +E03BD0C920DC424755EF7DBFCD9E75554D139FA38969E66CBF914AFBF161E24EFEB3D5D2 +3684BD113C1BFBC3DBDDA1DC334C79A4372D1B2943AA534393C0FA8BF6DAF9A89F6A941E +A5234C56DC788AA8FADC705FDD87B6E47BB5C6A175CCDEC1E4C48DD6C8425103157ACCB2 +70D3E54D16E609280F511A5F7358B9EF8DF16E69C970F465EE188067C619BC80EA9504F9 +4C55667F7AFA8614C87514EF2BAE3F9A556607F1BD4E686D161E3B8F2ED6D7C056E7ACEE +24D78CEACB7DC5A70AFD13D815612483409C6B3F4E736CDC0DB3AD2637905D49D3B18BC1 +531F98F22F268DCC658B4A6A263A984046D643EAA1BE3FA1A0AB42432D7214F2D67BF68E +C36481229EF94AA4D99117E5DF72DEA397FB16F71E00AE1EE676545E647B2E5BA86D6C41 +0F0A54B270FA6F1C0970586F3FEC2C9F5FB23C6EFB6A7A982BAA45F50135BD1D46B3CA7B +134C3CE39F195A447B23EB3532EE7C17A03CEAC710B45FA419D022EE4D59E3D03ABCABA2 +6D5854BF6FAB1494E0817D1A884DB4EE52A230BED371F18B2E8BCBD78AEF92D0EDA42497 +FD3278222FD696B07713A0383FE3C6A1485950B6402E43AFD1C293228E17CD9BF76788EB +EA31D28DA718A19DBF5908DE8B9AE27F1F74A5EE23859901E47BDD323385C3412A2FA672 +8D542AE01690894A02FC14084E48389F7DCFA93AE87BBA8B77C766394C46F8BC3103A69A +441D4BB7035003E242663D2E2DE99AA7CB51EB473C3F4DCFBA36F1FA0A6242736A73FBCF +2DCD98BFD0031485641FAE1501B92680A347059ADA5526903E7B2EB28582010A0816A93F +8A921674C87EE149D80820C859E8383D1E27B88665E1919D4CC63FB38A162581D08235E5 +99410FDB67D6113048EE02BA570DCA25FCDFD216D5E609BCEE6844506300BAA6B0249547 +C5B0EDEF6F01B97EC4996EA1E997211294B55779298AC81BDF612FED978BB6A82FCA144E +455B41746D2CB7A468324DB1D179BDE9352ED8729488623F1F4F6B83609A425F12374F2D +A058510E997DC7BCED1C4D00F1BEEE0D7CE92C99287B965112994FC2A0EAD8A6D48C8A3F +37D09BEBD6BA74F344B4630FEA04951CC3D320094CFE066A9D1563984074A678701A51FC +B379148165AC421D4FE67C2046F98DFC638366E55B958FF6753E24704BD9EDAB877CAEFB +6C6CCA8B1753940EA08A3284DB2F831F5562F4BA152D94DB9B755AD4C61E482AA018D160 +020A03BB441DBF1A0158E19B38E85B3883AF7C8F4ACBA54A90ECEF5360819159F7B23A49 +7A6D75B0CD2A23E5F94718B45550EFF77318CD7E81BC64B67876867114340AF64CBEE039 +709FDD10EDD1D841F43724DD464501E523D09BFB6A6674DAC7AC4D7D8A7D4CC8DC41CE74 +5EFEAE2EBB03189D6B908195CF644E621E1417FFB8DB507DDE8121EA5CFA4F86FD1D4E2C +032666342DE81F4B4A726D9C2E053BBBFA8E6EE04C30A9A38A6667AFA346458E8535E6CC +D7D81614AE3828AE428BBA8272C1A3D3118AC00DD852B112AE85217F21BCCF879824764E +5D70F17114F256D71D0E865CEDFCC39759962AA8FEDBA34AAC01DAD722BB4F0F26D69660 +A5886F0B58EEDE6FCED9DD72580EB3D345A3519FE4B20CC154FD4C9BDB92E9CF953B5108 +6097A5DA323B48124F004AB16035D5464B37C5C1F115DE6F9D67D42D179C70B42EF8AE2B +533745B020D0C27E662446BA2E2704FADAB63CD2EA88895F06D6A65ECC9FA7AA0D904734 +66E3EBFB475B7DE4DFC639B3C1F24F1C8E15A6CA4C0B890EF2F848925EA54372F662A899 +F72A0E658C8812C076C1280C0321493AF73217F48C189F3D5B05D590518CB5BBABB38BAE +7DD209BA73C47638BC2E125F686B01D0B69AAFD1579EC5EEFEED33365B0B389E48B5EFDF +8480E6F60ADC2B291FBFDED2087ACB94658B3AC91DD89B27E46DF498C586E74E9639FE94 +3AFF60352BF9B9CBD6D747EE9EFAD079F13F362DB2B3B6BEE70D0769C2FAD11E578C753F +AC2E13246D0C1EFD8DB91A72DCAFD2837288B2694B7F98D85189750A8ED83EFE24AE7DE3 +C1E6143CAEFDC3158A89432E6CD0D7CF76FD01A37FB632E75DE7E978A769A78FDCCF8DE7 +189C25EED67C42D17922B2E7E0ECD02A12148C847BBA0C7039F7641271048CF720B62657 +2C90A8E734EFF686CF8900A56CD1BAA4175FE1D956C8E384E8639B27C7DAB95EBB6D7621 +8E2F4FB19733E3D2B8453BA19542338BB677AD08AF33DF746BA3CE6145589106E8BD6402 +92DE977B8B647726A522ACFB9D608F3A2086BC0D571777CDD16B7C67D6DE8264400969B8 +4283A29AAAA9CB965CAD70F6AA8536F10CAFC0F011E6771A5D026203DB34BB67B643CD53 +3EFA2E2305C70B64C49BA305C99A861D4985510371FAABD574E293029616F056E690CE15 +996B9231BC5274AE3436797415A1CE9555B9CDDFA5B5B2CF1D52023D6B59F205050B413E +D2835B8879EA5C14241C8D4157C05B863F02E7F53067CABC864508C3E4573EA3DDAFD85A +6EEB9D9A4E4C20946F1CB9BDAB6FDC5BE017765A663673A7FA93212C4FC4A3A0A1D3DFD7 +536579D8A6AB08A3F62C4ED9902118938B3324EC14EE509465DBA5A7DB37BA6F461A9748 +82CB3F7F5AC826A622711A3DBBA6F9F6CCE8F9151E5B79AF081519224F9C7926249AD1AD +E98017B2C724C5C4D2E2B43DF4A581CD906FA42F734E0F006D4E2FA48FB27DF408F8BF48 +0975F73FBE94ADCADEBDBDF934E8B079732BE957C5F64CB95368B6BCB0914C4C6C4B1343 +CC697E1D56C5C8B6396652754A621ADBB8F76215A0291176C92420502063A45F05A73227 +9CEE6B197E37062422C4715B195B06626F753F3441C83409193A43596A40B14B7A627D2E +8E2DF6A3B6599BBF3E189C0975CBB8AAD384AD51A92B04DF688C7ED7F381A585793A661A +C57A6FD17944B8F8AB511D4783F1256F598C23BF09EE63531F7802EB86AA57BBACD6B35E +C0FEF97D7969F5B7FD1BAE7161D512815C7A99E6949B3DCB42604F2016EBD5A8ED4E65DF +39B0BCE9F1468F0CC6F8803F3016A4C409B3C06688848D6BC42C5458B22954FDC9AC300E +0CA3350A57E31D536BCD1B430B54939B1D9F6FA179470042555981891ECDDA2279273FC9 +09F7284A182219E9E488CF5BBAD809323DFB4F8BE7677771CD7915E46FE2D471A9BD0667 +7798BBFF9030135542A72ABF81B773F9B8CDA74427A947EDA4CBC79AB74B960E983C7AFB +DC6ADA57F5284B278048D791F6BDA50367DF7093D763BA62BA5ACC0820BD593EC2C0FAA5 +7C698F2052CC1389F4449529C0BBB5885647D6B14845D59A91FB46E556D14882DC39146A +FE98351D0D93486967B8FC121DCF5258CEA66C3A156CC055E60B2FCB147BCFCEC5E5D3B0 +1D5D4779B9C04F4F6C6C84EA66C9A3058FDD4F4D0D9BDC64E0667700A1FB54DC6949E547 +998A33320E0BF8739956DB6B6C1E79498CE81E3FC7666C8B63CB129172714628D1BCFFD9 +7302B93F7712FF9548E99043B89412D71903E6D339936295157B29C3CCC79FF43ABA8A7C +3D118BFB3C6BB430BD0CE932751792EAE59A1E1452F44006DB57B741BF8E8FEBA824624E +748C719D448B56D657DBDA89504C3C59B2A8F52D193472E004DE32E77DC04BEC1CBFD555 +141E7CF9968BAFC38CC322F734EC9D1A77BBCA1C7B0443F626FCEA4A1B000EA5250629F0 +30FE73ECD04A99D3FAB80CDB3B7E35B2D66EA563E8B552C0A3AD1A6080B91F4A72CE9437 +E23FC75D146BF9CD75908321C433E1D740CC7E4536F3C1B21786CD40EEFB1272421DA616 +40F2ABC43EFD01B9C8AD954B9223B0D58C5374AF7ECFCC8D92E729A78887BB4BF4B3AA5D +FF0F0275523EE1A8C507E79A7E778575FB9BD2C68D573CF1FE4DD89B70CE0399B534E06B +98D44CD700BDCA211B0A79CCA45FB7F6CB6DF389698B0279CFC9A686F84CD102B4CFF224 +B9712D26B8F6EB004413A729A03C13DB1793538113F314EA9A421957A71A623108717C09 +E231F3B418DA57E6B74F591B1AC8FF3135E87A2C0E17EBC0DBFEB9E060460528DAE4BD95 +D4199FF544176441856CF2162998BB9CAE3327BE0B0331B2DE7FCF6B8F1156B34754BD6F +E668A096BD8762482D814CB5B66C98112FA8EF724C1A271D47A6043E588BC5F963172F39 +EE634F4D433C885FCDD395204ABF027C55210CB8B733E36B465359DBDD074F6ED7D917F8 +C2D8DBC8E7EFA564CB194ECBB5C03E60254143E15AE940670CC156A6C40F8F1937FB8697 +3AB99C97CB43E2FF36FAA721F2EA3C675E53FA12CB838E0A40921CDAE8593E466B7BDEC4 +F7777CE4B9A7A8522414BEC29E7EFCF6A4FCD8CF872D5825A8743841C0AA881B2F4D293A +C2AB4CD36A780A58B20F4BF8557CA8DB5BE772B2790FDEEE20D30161FE5897DFDF2749B9 +018AAF5031017C9405EF04CA4F5FEB1C62F48A1536550F2D07625F84EAFC567FF88D0B9C +BAD85C30AF56163470ED619CF33C32B032A0DAEF5BD0F3FCF08005AFD8251A0E8FC15ACD +4D4D6CEA19F5BEE36E14FD91942E5284F635F6713043D4CEC1BF5E80703867B963DD0655 +179ED91BC2A94EDE291B2B34A1B53F7464D475CE3844F61B3AC34B258CA202B1BCDCCD76 +F81C170704E741156833A14E84120C10D4974D98F9A64967658236F3796A15F4715EE660 +F4356DAF786522D829D5F64AC39BA6FD4A5F9831A2B180DD76983D6B3510332A1350EF68 +DEE95CFF7E22D1DFA1B83790DEF05713733B2C98678810D1B863B2CF11AB0DBF62327741 +E4541051C333F43542367B4C0F581668AEDD2E5071436A4A50D07368F4AAC3F6FD25F903 +B11AC0D050CF88AE29928516A369C963116DC58E2984D7849E0F12F40E8807332DEE7642 +A44A4D1C9CF9E4CB01C819EDC63E7986AB3907C825886127E54D643F429E63EAA62C4655 +E12459DC40DA2216FA76ABC1F62206D6E26FD74240B67240F0A59325EAC5815493A5DC32 +2F936D086139C334BB102BABE70008D39BABAD2E8DFC7F6556E8916C8071F414A1468232 +7D430B20BFC0DCFF09A05DE9015F95CEAC2B33D3269977B04712AFAEAB6A0CF1DBF151A3 +C49FFD79DF318A96E7AB3BF9916F3B63DF6FFB63BF6B09637D02AA5DAA4DF410E37A52B4 +D24D93659CDD4F8D093E7DCB77A966B065991F5D858ABFD24E7CF353A29103BDCD78C5DA +C279A5EF2E66AF66B0BC5705E0F445FDEE26037F5712BA69958866259B47D7A0C6163932 +4A519757D0DC2BB945F4D54F2A948268F023AC8AC93DE6CA49A8B69FAD310DA292BF34D6 +72A4F5987A948AF5B3077F9E3AD60772A97ABF83A28A7E9BB2F1C49DC533AE9F157FB9BD +7F226B58103FDD5C38E599483DE93D923B8184453EFF9DC237BFC31417AD09117009FC8C +87391FB0BE7E011336228D81198B2E23C51EBDB26CC8D976978BC2C3BAD7418504BD30AF +AFA333E52B306B25E1CAC2D19482F4C08D57E68D8D6F152A6AF4A83FFB3DC6079CDC7D6C +62D1625CCF55B0D84D1A381EFE53F6FC0A2D3060DC19B20BB71DF70598304E430FAA9735 +6FB0CD51F28FF859E07F859CC2DE30D9B0C61443A68341573857D03E3B17DD1DA6BFFF7A +15DE805C05B6C8D0D38E105836BC590A233EE35C9035BB23384A48257D36A79A525CB7AC +AC3DAC11B4C78ACE64F5148F0DF009C79D7272AC879D9647C9ABC2EABCA007E955CE3C80 +4EA43D8F81303D9C4DB7039D84A7214D1CAB1DE644575612CC4D96B6A12EB9FBC47223E9 +1EE4A38BEB3E44B70FC03A1AEF6D55EBCBAE8181F9FED9BC352DF768F5C1204D16C73B18 +612C48FB955DA7E1ECF9A38B13182D8782F55405299BFC1555CBC1C8B2D3187824572BAE +2FD8B7D7A34FD5A2B31A108DB5908A94C6161F8109124E4210F38D53217A9362A384CB0D +9EAA16DF6A30580E8CCAE71152F2A0441703175C90DDB9D3D4AB8886199B14B38E846DEE +9397794CB3B0E709139EF09B4D1F39F406E46AB7780A496C04B1D058A7AA51D09F35F6EE +DCC2720D34EC9F7003E4FDD48D09FA67A5244F461EF4D8B66970A990E992285CFD068C25 +F3C5734C6FFEFE7C9D1CA87E9829007FED4083A1FFC8025F8D14C270D95581A2F46D9869 +FEB681A8C199E8BF2C4D13525709FD0F0215B818FCE1E5BE59EC4C2B455283EC6A7BC5B0 +5ECFF4F4A80672776C20B8C09124D3E0D0A5B2079F7F2392397D7E0CADFA288391347454 +487F1EB52262C53F30D1D02F5C2D2B3B810A76BFFC4286408F772ADABF1277E19031703B +676FBCE5DBEFB35E53D5B09CA9549E447EF6B5F917B080CCD466FE5AD1286A0982F6B04E +8CC59378BA5F999CC7C1E0899E69F7629BFEA7D2642930F05385A7767AF2CCA54831D0E5 +3A78C373A52D8A4987265DC54BCCE9DD3F950B18E4B4C6BAA653BDCCAAD9654A64040C5F +01B51F1C6E456259954739FA3E632CDCC78E1B7E5B364AFE33CAC76B56A8E68D260B8880 +7B15AB439AC1F9E379C6492257C0BDC14BFF623B2406EE4C0820E06D1498E862C69A60E2 +3333D7678120E8949F1552505F8D9234604CFCC2C0AE4361FE33C3C2792F33618099B296 +6EC69B58B589B11AB8F3678A797BBDB5D40754397873D41EF9DB3D26405D5D0AC64D4331 +31147C38F40512F63D63D21EE432D19C566A9FB62F7E1343990F5B6A1A45B0D90AA9276F +35C1C7E2DD322A7B2BBC758B7748703BF28CE1E4943C3C956831147297D4D23446BFA194 +92BCEE0AC533F7A1776365299F1E8B9727687E1A0EB7942D8F20C402372B56D951CA9268 +5FA6931EE0CCC3C4D6DF269B0AA6A9969A86339482F9B7B20FC245CF284B6C1787F8712D +1B7A5893E8E5B535F45321AB2882960A3A3D660E624BB68F5E453519F07B307408016AD2 +ED623A7931F3C25D16C55BC5FF05A37628B354B347FD0DAC5FC7088D20C777E86C51D541 +A8A73D729E43F798F473B36C1526A34179A34871626FBE64866A20247BCE6A0B8EC16CAF +7F04892C3265CC2D2ED7122E3583AB662F3FA612643382A8B071B052BA7BDDD0D17F3787 +B73678342F7AC5CB452C24A1ED57CB976E3B0E0AE0E1F7BAF615024BD874E65AB8576885 +00D2113078A44D8FAA468FAA53C39330E480023E4D901645F2FF3DC69735CE5109EC5648 +A58BDFD166B5410B1C52A19AF5EAE5B335621FC6C3A636E63E808502BCBD39C1B18B3D78 +D53DFC209664485C2FE7078A4C1ED53DD25CA9E4AF287385DFEAF67180F66A7D924A1C1D +A48309ADDBFD9EEDF2E0FDA513779C7D4E14BDF49DA3534A6F0CA66093CC884F778AA14A +EA804C43C94E6609CB1BE12A2EE09C33FC455C10BBE8F1A86E37469FC84D3D36FA92BD45 +70C7F34664353C1E999D3C684A7F57A920FB1F3CB2C6154674217E37758B75FC3BDE0644 +6EB5DE501F7B33232783F18A0743EF63C6153BE284BB9CCDEB5EF3F74127F5157D997376 +31A4CF3706756E9C273BBC8FC91890A13736BF03B0965BAB474463EB51A222F20D4C0DF2 +7101ABAB804A6F2D1A2EBD713DF7787319A520F06942F0234D8B8F75039E8C18147590B0 +9895FB4AE19F8AB3CAA93D77ABBA7FBEF6450A5C32A5D2325D26C79BCB3A5021D4DAD6B0 +D998F7B05E8EEBDCD762E972126AC5A831E3F2840D1E276AB173580CCEA003D28332FB26 +CB301880CDA511510480FFFEE849CF496079757E89902141277143A0D534B1C43C77FCF7 +E07398191EEFADDED6A222577BB9BC144B0B9E4B3894DA1B1A8CED51BADD8EF33C12E7C4 +83A4B1A32E8154EC7DC52E935EEFAB25432330A5959A5FE0898B3C3729A953D54F31CD43 +488EB4A0C2BA351E00EB0F41733E1231DE089B5183E6611B6075639E3B221641B7C4FF3E +B67EF531C9DD81FC4B1B98490C6B4050619CF6594E126D66BA0F2F187C229AAC7D69D8EA +937DE324990F72E47B9DA3C90C05D8D0A1F08C5EDEC145436D9FEAF82D27051F8BBD5D5E +249498A36AE396CB1D848B8250A8C005DE98907FF3B4BB16C62F4781A605EFE61B0757C9 +8FFE6F65450556C59F3D0E51ABF63DFBDD378BB94E12CD21BA4413FC05E717DFD54CC63D +AD68396CDC334446B603C826B5CCA1A06959F355E54CCAD7118E492471C60ED383E02ED1 +D95CA17911FC3271B6088A3C09205C1A8B04B3DAC2C8E92199FCAE0D3F0BA09AB1CEB719 +004A936FEB0E35166591FF051461B8E19671216EF16AB67113878C3C5D6A3D7D810E2C1A +988D519672C21E7D711389CDDB6DE03EEEC77A063E0FAB6893650DFC8D041B316711D922 +4B622FFF02FFA06545F5082BECDF430B69E2F839C9F1D3AB53E1FBE68F778F7EA0D4E68E +1ABFAF43139BF00FA4A306BF5D6ED688702A3ACD7B6A8E607402D45EFEEF86E28272A142 +6A7953C2DA42605487328A313D3264191C127014A613FE97806901D12A94A7CC6437FCAF +7DD14D33F2937C7AAEFCB2B07B45DE22D60C8ED4C0DAA5039803870A0CE4AF90AC3BB9B3 +248033B297B842044DAAF16C0479C8A3226A999EFD0FF6FDCF8BB331E27445F7B6B27EAF +3AFE02A75318BEEFD57CABDCA3BBF53C734E489AED62313E29CBF47634E650D26F95F243 +56AB5F5A7BDC0C4ABBD0373FAB6056451D9F6863871D49019012FCF90BF30DE0CFF003C3 +37E21A9BB502F37F24E599C882AC03BC5805850E189AAD1BBD869A5C713A44B13D853403 +D7BE84885E9E3B8283D972FE7E891F3FA1C3D785EFA99186F0C4F2D6A71BEC5A4537C4AA +0EE42126B49831684BCC2992316FB29E20EACB2AE0C0AA6AD22BEDE3394A19D1FBF0F899 +3C3AE559AC6E998BC28F148C9E4FFA70B343EA64C05A17587B4DB0D4E1450C3B55D35C0B +BC0F9ED68B669176C5E110276E295D632B712925DEF6F46B6FEFC7DDAE8904EB2D890AE7 +F7E514330EEDBCD45616B620C6514529B426B8C2DC4B0F302330662112B3F41F2A7D6B08 +30C7FAA87E0A41B5B37A166A0ED59572A98FC99E7B79DE270DCCC068A284031D8975BA09 +C5B8865D24586EFD7669E012974B4B7FAE26ECBE5293BF8059C9D41616E5CDEED6774E9A +9721BFD35178FB026A26DD2EC8B2A17B712129F18061B25BF34D75EBE8751EBD7F103464 +8FD62A60EE0BA9EF57C033DD35261DD3FF832F7759FCC67C5DE884D6A75087D1902CF681 +8241E6B1224B0515C5BA +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/extlib/inconsolata/Inconsolata.sfd b/extlib/inconsolata/Inconsolata.sfd new file mode 100644 index 00000000..3415c8b9 --- /dev/null +++ b/extlib/inconsolata/Inconsolata.sfd @@ -0,0 +1,5730 @@ +SplineFontDB: 3.0 +FontName: Inconsolata +FullName: Inconsolata +FamilyName: Inconsolata +Weight: Medium +Copyright: Created by Raph Levien using his own tools and FontForge. Copyright 2006 Raph Levien. Released under the SIL Open Font License, http://scripts.sil.org/OFL. +UComments: "2005-8-26: Created." +Version: 001.010 +ItalicAngle: 0 +UnderlinePosition: -100 +UnderlineWidth: 50 +Ascent: 820 +Descent: 180 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 77 1780377399 11264577] +FSType: 8 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 0 +CreationTime: 1161020814 +ModificationTime: 1234036730 +PfmFamily: 17 +TTFWeight: 500 +TTFWidth: 5 +LineGap: 200 +VLineGap: 0 +Panose: 2 11 6 9 3 0 3 0 0 0 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 0 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +DEI: 91125 +LangName: 1033 +Encoding: Custom +UnicodeInterp: none +NameList: Adobe Glyph List +DisplaySize: -36 +AntiAlias: 1 +FitToEm: 1 +WinInfo: 64 16 14 +Grid +168 917 m 25 + 406.5 917 l 25 +EndSplineSet +TeXData: 1 0 0 629145 314572 209715 554697 1048576 209715 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 +BeginChars: 359 294 + +StartChar: a +Encoding: 97 97 0 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +115 467 m 0 + 164.456 518.083 232.512 541.055 303.925 541.055 c 0 + 386.091 541.055 453.267 510.995 488.008 453.097 c 0 + 512.442 412.375 514 371.39 514 328 c 0 + 514 0 l 0 + 435 0 l 0 + 435 58 l 0 + 377.24 10.665 309.94 -13.0023 244.918 -13.0023 c 0 + 134.316 -13.0023 66.8187 59.1626 66.8187 136.825 c 0 + 66.8187 195.507 104.707 257.379 188.205 288.065 c 0 + 255.557 312.817 339.023 312 417 312 c 0 + 434 312 l 0 + 434 331 l 0 + 434 359.055 434.409 393.114 416.772 422.078 c 0 + 401.83 446.615 370.745 473.031 307.869 473.031 c 0 + 258.955 473.031 199.358 459.393 156 414 c 0 + 115 467 l 0 +437 248 m 0 + 418 248 l 0 + 362.991 248 292.114 251.465 244.035 239.987 c 0 + 177.665 224.143 150.668 180.909 150.668 142.456 c 0 + 150.668 95.137 191.681 50.8142 261.864 50.8142 c 0 + 331.199 50.8142 381.823 92.8437 401.058 113.287 c 0 + 436.77 151.242 437 185.578 437 213 c 0 + 437 248 l 0 +EndSplineSet +EndChar + +StartChar: c +Encoding: 99 99 1 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +SplineSet +539 442 m 4 + 480 373 l 4 + 470.825 379.924 477.126 390.809 472.703 399.753 c 4 + 469.634 405.96 426.164 469.074 335.78 469.074 c 4 + 238.504 469.074 160.969 393.768 160.969 273.126 c 4 + 160.969 149.42 239.6 62.9789 342.756 62.9789 c 4 + 395.811 62.9789 447.209 86.4429 483 127 c 4 + 531 71 l 4 + 480.516 16.5812 409.687 -13.0011 335.781 -13.0011 c 4 + 186.048 -13.0011 74.9996 104.892 74.9996 264.509 c 4 + 74.9996 423.38 185.476 540.028 341.051 540.028 c 4 + 426.18 540.028 497.315 503.103 539 442 c 4 +EndSplineSet +EndChar + +StartChar: m +Encoding: 109 109 2 +Width: 600 +Flags: HMW +TeX: 109 0 +LayerCount: 2 +Fore +SplineSet +54 0 m 0 + 54 529 l 0 + 131 529 l 0 + 130 477 l 0 + 154.337 514.017 194.92 542.056 238.342 542.056 c 0 + 285.783 542.056 323.7 508.722 332 465 c 0 + 352.564 511.823 399.84 542.002 450.616 542.002 c 0 + 480.394 542.002 513.14 530.575 533.429 499.943 c 0 + 556.856 464.574 555 419.808 555 376 c 0 + 555 -1 l 0 + 476 -1 l 0 + 476 375 l 0 + 476 399.068 478.585 429.361 468.835 451.652 c 0 + 460.274 471.228 443.933 481.204 426.805 481.204 c 0 + 394.659 481.204 374.014 448.262 365.249 433.479 c 0 + 345.703 400.513 343 377.821 343 350 c 0 + 343 0 l 0 + 265 0 l 0 + 265 368 l 0 + 265 389.832 266.608 415.372 259.774 437.513 c 0 + 250.804 466.572 229.599 478.297 210.74 478.297 c 0 + 189.54 478.297 165.885 464.471 146.732 428.907 c 0 + 131.729 401.049 130 377.928 130 353 c 0 + 130 0 l 0 + 54 0 l 0 +EndSplineSet +EndChar + +StartChar: s +Encoding: 115 115 3 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +511 459 m 0 + 462 386 l 0 + 459.954 386.487 455.921 388.387 455.967 395.318 c 0 + 455.994 399.389 456.754 402.17 453.49 406.383 c 0 + 433.342 432.386 382.005 479.074 306.539 479.074 c 0 + 246.687 479.074 195 449.386 195 406.786 c 0 + 195 389 204.202 363.327 247.446 342.429 c 0 + 296.926 318.517 382.175 306.563 441.996 272.983 c 0 + 504.635 237.822 519.699 189.926 519.699 153.285 c 0 + 519.699 73.3785 444.137 -12.0003 299.462 -12.0003 c 0 + 219.049 -12.0003 138.142 14.2177 76 72 c 0 + 124 155 l 0 + 129.709 152.331 129.203 145.694 129.13 144.104 c 0 + 128.917 139.47 128.401 136.208 132.349 131.72 c 0 + 149.099 112.681 207.222 58 297.964 58 c 0 + 373.592 58 434.068 92.1676 434.068 141.757 c 0 + 434.068 160.887 424.919 188.765 381.245 209.208 c 0 + 342.194 227.486 283.74 241.548 238.968 257.732 c 0 + 210.234 268.119 109.997 301.799 109.997 394.231 c 0 + 109.997 473.3 190.548 542.004 313.496 542.004 c 0 + 391.8 542.004 462.083 512.905 511 459 c 0 +EndSplineSet +EndChar + +StartChar: I +Encoding: 73 73 4 +Width: 600 +Flags: HMW +TeX: 73 0 +LayerCount: 2 +Fore +SplineSet +112 722 m 0 + 470 722 l 0 + 470 654 l 0 + 327 654 l 0 + 327 66 l 0 + 477 66 l 0 + 477 -1 l 0 + 104 -1 l 0 + 104 67 l 0 + 246 67 l 0 + 246 654 l 0 + 112 654 l 0 + 112 722 l 0 +EndSplineSet +EndChar + +StartChar: o +Encoding: 111 111 5 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +543.113 262.304 m 0 + 543.113 86.8043 430.326 -14 304.969 -14 c 0 + 171.548 -14 56.8677 99.5323 56.8677 260.578 c 0 + 56.8677 424.14 172.53 541.005 307.44 541.005 c 0 + 427.751 541.005 543.113 445.084 543.113 262.304 c 0 +301.758 470.103 m 0 + 220.795 470.103 144.985 397.575 144.985 267.806 c 0 + 144.985 137.225 221.249 57.9927 305.614 57.9927 c 0 + 382.884 57.9927 459.167 125.6 459.167 258.844 c 0 + 459.167 404.202 378.128 470.103 301.758 470.103 c 0 +EndSplineSet +EndChar + +StartChar: n +Encoding: 110 110 6 +Width: 600 +Flags: HMW +TeX: 110 0 +LayerCount: 2 +Fore +SplineSet +89 0 m 0 + 89 529 l 0 + 174 529 l 0 + 174 436 l 0 + 212.871 495.002 278.12 542.003 349.957 542.003 c 0 + 410.281 542.003 464.544 508.129 490.899 448.568 c 0 + 509.729 406.014 510 362.334 510 321 c 0 + 510 321 l 0 + 510 0 l 0 + 428 0 l 0 + 428 319 l 0 + 428 356.393 427.762 401.823 399.11 436.061 c 0 + 380.097 458.781 353.908 469.58 327.341 469.58 c 0 + 271.362 469.58 220.49 422.787 200.308 395.893 c 0 + 178.287 366.55 174 340.651 174 305 c 0 + 174 0 l 0 + 89 0 l 0 +EndSplineSet +EndChar + +StartChar: l +Encoding: 108 108 7 +Width: 600 +Flags: HMW +TeX: 108 0 +LayerCount: 2 +Fore +SplineSet +108 770 m 0 + 342 770 l 0 + 342 67 l 0 + 498 67 l 0 + 498 0 l 0 + 101 0 l 0 + 101 67 l 0 + 258 67 l 0 + 258 703 l 0 + 108 703 l 0 + 108 770 l 0 +EndSplineSet +EndChar + +StartChar: t +Encoding: 116 116 8 +Width: 600 +Flags: HMW +TeX: 116 0 +LayerCount: 2 +Fore +SplineSet +228 671 m 0 + 319 686 l 0 + 323.069 674.25 314.74 667.101 312.438 654.7 c 0 + 306.99 625.35 299 530 299 530 c 0 + 472 530 l 0 + 472 461 l 0 + 298 461 l 0 + 291.31 392.178 287.955 323.066 287.955 253.871 c 0 + 287.955 177.138 290.735 156.77 291.356 152.111 c 0 + 299.829 88.539 340.908 66.6734 380.424 66.6734 c 0 + 413.027 66.6734 454.079 81.5989 499 115 c 0 + 525 49 l 0 + 480.23 16.2302 418.815 -10.1214 355.783 -10.1214 c 0 + 301.714 -10.1214 260.342 10.8883 235.238 46.2593 c 0 + 204.429 89.6687 204 142.866 204 190.358 c 0 + 204 280.259 207.611 370.358 215 461 c 0 + 91 461 l 0 + 92 529 l 0 + 218 529 l 0 + 228 671 l 0 +EndSplineSet +EndChar + +StartChar: e +Encoding: 101 101 9 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +SplineSet +309.698 542.272 m 0 + 396.487 542.272 495.286 496.221 519.331 354.102 c 0 + 524.53 323.371 526.211 289.371 523 253 c 1 + 147.298 253 l 1 + 153.598 94.4857 256.131 55.4411 326.953 55.4411 c 0 + 379.589 55.4411 429.496 76.3575 464 115 c 1 + 510 70 l 1 + 464.675 15.507 396.045 -12.143 320.487 -12.143 c 0 + 176.7 -12.143 66.2985 82.2264 66.2985 258.611 c 0 + 66.2985 451.856 183.262 542.272 309.698 542.272 c 0 +150.008 317 m 1 + 441 317 l 1 + 450.942 402.839 389.68 478.169 303.883 478.169 c 0 + 247.072 478.169 166.495 441.85 150.008 317 c 1 +EndSplineSet +EndChar + +StartChar: space +Encoding: 32 32 10 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +EndChar + +StartChar: b +Encoding: 98 98 11 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +SplineSet +79 771 m 0 + 177 771 l 0 + 178.976 764.036 172.638 759.556 170.696 758.012 c 0 + 165.256 753.69 164 751.156 164 745 c 0 + 164 448 l 0 + 197.57 506.183 259.707 542.07 327.128 542.07 c 0 + 431.167 542.07 540.005 456.138 540.005 271.2 c 0 + 540.005 79.1558 427.245 -13.0764 318.695 -13.0764 c 0 + 255.173 -13.0764 196.766 18.3503 162 70 c 0 + 133 0 l 0 + 79 0 l 0 + 79 771 l 0 +298.069 470.353 m 0 + 245.668 470.353 197.567 440.714 177.844 392.983 c 0 + 165.809 363.856 163.969 329.782 163.969 281.904 c 0 + 163.969 236.092 163.584 204.899 167.224 177.364 c 0 + 180.563 76.4436 260.537 61.9726 296.744 61.9726 c 0 + 348.522 61.9726 453.238 91.5609 453.238 253.679 c 0 + 453.238 440.584 347.817 470.353 298.069 470.353 c 0 +EndSplineSet +EndChar + +StartChar: H +Encoding: 72 72 12 +Width: 600 +Flags: HMW +TeX: 72 0 +LayerCount: 2 +Fore +SplineSet +73 722 m 0 + 163 722 l 0 + 163.822 720.356 164.252 718.529 164.252 716.663 c 0 + 164.252 707.549 157 706.38 157 694 c 0 + 157 413 l 0 + 440 413 l 0 + 440 722 l 0 + 528 722 l 0 + 528.872 720.545 529.336 718.865 529.336 717.137 c 0 + 529.336 708.364 521 708.006 521 696 c 0 + 521 -1 l 0 + 439 -1 l 0 + 439 344 l 0 + 157 344 l 0 + 157 0 l 0 + 73 0 l 0 + 73 722 l 0 +EndSplineSet +EndChar + +StartChar: g +Encoding: 103 103 13 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +SplineSet +155.954 364.263 m 0 + 155.954 300.152 208.143 247.999 272.491 247.999 c 0 + 336.833 247.999 389.059 300.157 389.059 364.307 c 0 + 389.059 428.413 336.878 480.571 272.536 480.571 c 0 + 208.19 480.571 155.954 428.416 155.954 364.263 c 0 +277.609 546.548 m 0 + 325.887 546.548 370.362 528.527 403 496 c 1 + 443.962 530.332 496.755 547.196 550 543 c 1 + 560 475 l 1 + 549.913 476.74 539.695 477.615 529.459 477.615 c 0 + 496.841 477.615 464.884 468.735 437 452 c 1 + 454.566 425.561 464.002 394.366 464.002 362.278 c 0 + 464.002 264.564 378.096 180.942 273.257 180.942 c 0 + 250.3 180.942 227.525 185.021 206 193 c 1 + 200.797 188.707 168.184 161.819 168.184 133.805 c 0 + 168.184 117.119 179.985 104.638 200.262 99.0661 c 0 + 211.549 95.9645 236.341 92.4042 275.863 92.4042 c 0 + 335.853 92.4042 399.797 99.8481 455.06 77.4073 c 0 + 511.29 54.5739 537.372 8.31551 537.372 -37.512 c 0 + 537.372 -108.516 473.087 -199.384 293.795 -199.384 c 0 + 108.265 -199.384 54.4288 -131.698 54.4288 -73.9838 c 0 + 54.4288 -31.9211 83.7043 7.00723 140.521 43.2787 c 1 + 107.075 60.8546 98.0562 91.7838 98.0562 113.827 c 0 + 98.0562 147.839 119.806 183.618 158 216 c 1 + 109.489 247.565 79.7405 301.443 79.7405 359.36 c 0 + 79.7405 462.8 172.219 546.548 277.609 546.548 c 0 +196.923 28.2968 m 1 + 166.505 11.5929 130.974 -16.2077 130.974 -54.2593 c 0 + 130.974 -72.7564 140.35 -101.884 183.142 -118.899 c 0 + 223.159 -134.81 268.208 -136.199 292.38 -136.199 c 0 + 327.814 -136.199 372.581 -133.958 411.372 -113.024 c 0 + 447.725 -93.4056 460.904 -65.7032 460.904 -42.7611 c 0 + 460.904 -19.4526 446.825 11.4411 397.736 18.8405 c 0 + 367.367 23.4181 324.656 20.4798 285.59 21.9264 c 0 + 245.08 23.4265 216.987 25.7017 196.923 28.2968 c 1 +EndSplineSet +EndChar + +StartChar: h +Encoding: 104 104 14 +Width: 600 +Flags: HMW +TeX: 104 0 +LayerCount: 2 +Fore +SplineSet +91 0 m 4 + 91 770 l 4 + 187 770 l 4 + 187.379 768.886 187.572 767.712 187.572 766.526 c 4 + 187.572 760.484 182.866 756.916 180.206 754.11 c 4 + 176.27 749.956 176 746.931 176 743 c 4 + 176 436 l 4 + 214.871 495.002 280.12 542.003 351.957 542.003 c 4 + 412.281 542.003 466.544 508.129 492.899 448.568 c 4 + 511.729 406.014 512 362.334 512 321 c 4 + 512 321 l 4 + 512 0 l 4 + 430 0 l 4 + 430 319 l 4 + 430 356.393 429.762 401.823 401.11 436.061 c 4 + 382.097 458.781 355.908 469.58 329.341 469.58 c 4 + 273.362 469.58 222.49 422.787 202.308 395.893 c 4 + 180.287 366.55 176 340.651 176 305 c 4 + 176 0 l 4 + 91 0 l 4 +EndSplineSet +EndChar + +StartChar: u +Encoding: 117 117 15 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +83 529 m 0 + 167 529 l 0 + 167 234 l 0 + 167 198.5 166.87 157.109 185.678 119.763 c 0 + 206.758 77.9067 245.414 54.9999 286.847 54.9999 c 0 + 337.84 54.9999 384.893 89.1882 409.153 133.494 c 0 + 426.843 165.8 430 197.247 430 238 c 0 + 430 529 l 0 + 514 529 l 0 + 514 48 l 0 + 514 32.4901 514.914 15.8204 520 0 c 0 + 432 0 l 0 + 429.806 13.6499 429.662 27.494 430 41 c 0 + 431 81 l 0 + 396.509 22.5849 333.904 -13.0167 267.52 -13.0167 c 0 + 198.648 -13.0167 133.916 25.4335 102.995 94.9656 c 0 + 82.3165 141.466 81.8438 187.899 82 234 c 0 + 83 529 l 0 +EndSplineSet +EndChar + +StartChar: r +Encoding: 114 114 16 +Width: 600 +Flags: HMW +TeX: 114 0 +LayerCount: 2 +Fore +SplineSet +125 529 m 0 + 212 529 l 0 + 209 427 l 0 + 243.671 502.684 322.168 541.803 399.502 541.803 c 0 + 458.959 541.803 507.697 518.114 541 484 c 0 + 502 404 l 0 + 493.106 412.505 489.308 421.668 482.352 430.554 c 0 + 467.489 449.542 439.485 470.205 394.944 470.205 c 0 + 357.514 470.205 294.325 457.033 246.222 380.981 c 0 + 210.237 324.088 209 288.944 209 257 c 0 + 209 -1 l 0 + 125 -1 l 0 + 125 529 l 0 +EndSplineSet +EndChar + +StartChar: i +Encoding: 105 105 17 +Width: 600 +Flags: HMW +TeX: 105 0 +LayerCount: 2 +Fore +SplineSet +133 530 m 4 + 345 530 l 4 + 345 67 l 4 + 469 67 l 4 + 469 0 l 4 + 126 0 l 4 + 126 67 l 4 + 261 67 l 4 + 261 462 l 4 + 133 462 l 4 + 133 530 l 4 +305.003 760 m 4 + 338.171 760 365.019 733.28 365.019 700.493 c 4 + 365.019 667.727 338.182 640.992 304.99 640.992 c 4 + 271.818 640.992 244.981 667.716 244.981 700.486 c 4 + 244.981 733.264 271.822 760 305.003 760 c 4 +EndSplineSet +EndChar + +StartChar: f +Encoding: 102 102 18 +Width: 600 +Flags: HMW +TeX: 102 0 +LayerCount: 2 +Fore +SplineSet +408.022 777.453 m 0 + 474.61 777.453 532.121 750.586 570 705 c 1 + 532 628 l 1 + 528.434 627.638 523.23 629.721 522.592 637.659 c 0 + 522.194 642.608 523.122 645.776 519.403 651.402 c 0 + 497.139 685.077 454.727 711.981 403.749 711.981 c 0 + 359.969 711.981 319.106 692.476 297.273 653.356 c 0 + 277.495 617.916 278 577.346 278 539 c 2 + 278 498 l 1 + 451 498 l 1 + 451 432 l 1 + 278 432 l 1 + 278 0 l 1 + 198 0 l 1 + 198 432 l 1 + 83 432 l 1 + 83 498 l 1 + 198 498 l 1 + 198 550 l 2 + 198 596.99 199.926 641.1 227.059 685.226 c 0 + 264.056 745.394 333.642 777.453 408.022 777.453 c 0 +EndSplineSet +EndChar + +StartChar: v +Encoding: 118 118 19 +Width: 600 +Flags: HMW +TeX: 118 0 +LayerCount: 2 +Fore +SplineSet +56 530 m 0 + 156 530 l 0 + 158 520.53 152.295 514.363 152.295 507.316 c 0 + 152.295 504.529 153.032 502.45 154 500 c 0 + 307 113 l 0 + 392 310 l 0 + 421.967 379.454 449.99 452.863 464 530 c 0 + 539 530 l 0 + 521.386 449.313 491.663 372.127 460 298 c 0 + 331 -4 l 0 + 266 -4 l 0 + 56 530 l 0 +EndSplineSet +EndChar + +StartChar: d +Encoding: 100 100 20 +Width: 600 +Flags: HMW +TeX: 100 0 +LayerCount: 2 +Fore +SplineSet +440 452 m 0 + 440 771 l 0 + 529 771 l 0 + 529.429 763.115 525.033 757.358 522.644 753.665 c 0 + 518.515 747.282 517.991 744.04 518 738 c 0 + 519 49 l 0 + 519.023 32.976 519.825 16.2095 524 0 c 0 + 441 0 l 0 + 436.758 12.8474 436 26.4226 436 39 c 0 + 436 85 l 0 + 402.754 25.5822 340.198 -11.7426 272.502 -11.7426 c 0 + 170.172 -11.7426 61.9989 73.6686 61.9989 269.088 c 0 + 61.9989 471.408 183.85 543.089 284.756 543.089 c 0 + 357.905 543.089 414.551 506.411 440 452 c 0 +288.638 475.041 m 0 + 227.729 475.041 142.873 433.439 142.873 282.731 c 0 + 142.873 108.363 231.935 61.8091 291.87 61.8091 c 0 + 347.081 61.8091 401.871 98.7178 422.26 162.214 c 0 + 430.843 188.943 433.29 218.613 433.29 258.526 c 0 + 433.29 317.62 430.953 347.168 424.391 371.787 c 0 + 403.443 450.383 335.053 475.041 288.638 475.041 c 0 +EndSplineSet +EndChar + +StartChar: p +Encoding: 112 112 21 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +79 529 m 0 + 164 529 l 0 + 164 448 l 0 + 199.965 505.862 263.255 541 331.196 541 c 0 + 435.346 541 546.008 457.517 546.008 270.69 c 0 + 546.008 76.5707 432.1 -14.1497 323.885 -14.1497 c 0 + 259.582 -14.1497 200.339 17.6548 165 70 c 0 + 165 -193 l 0 + 80 -193 l 0 + 79 529 l 0 +300.599 469.911 m 0 + 247.269 469.911 198.023 440.745 177.865 393.197 c 0 + 166.21 365.704 163.875 333.505 163.875 288.853 c 0 + 163.875 212.177 163.543 168.56 179.045 132.849 c 0 + 199.943 84.7085 249.872 59.8372 300.077 59.8372 c 0 + 349.666 59.8372 459.207 86.5412 459.207 253.487 c 0 + 459.207 445.62 347.069 469.911 300.599 469.911 c 0 +EndSplineSet +EndChar + +StartChar: q +Encoding: 113 113 22 +Width: 600 +Flags: HMW +TeX: 113 0 +LayerCount: 2 +Fore +SplineSet +443 452 m 0 + 443 529 l 0 + 522 529 l 0 + 522 -193 l 0 + 439 -193 l 0 + 439 85 l 0 + 405.898 26.0553 344.027 -11.6567 276.61 -11.6567 c 0 + 159.718 -11.6567 58.9968 98.0805 58.9968 269.638 c 0 + 58.9968 449.541 172.706 543.066 288.684 543.066 c 0 + 406.139 543.066 443 451.618 443 452 c 0 +291.949 475.034 m 0 + 220.924 475.034 142.881 419.676 142.881 281.575 c 0 + 142.881 131.999 219.654 61.7898 295.168 61.7898 c 0 + 350.366 61.7898 404.936 99.0666 425.25 162.164 c 0 + 433.889 188.997 436.294 218.713 436.294 258.291 c 0 + 436.294 322.298 433.787 355.626 423.349 384.853 c 0 + 400.165 449.771 339.214 475.034 291.949 475.034 c 0 +EndSplineSet +EndChar + +StartChar: y +Encoding: 121 121 23 +Width: 600 +Flags: HMW +TeX: 121 0 +LayerCount: 2 +Fore +SplineSet +63 529 m 0 + 167 529 l 0 + 167.651 518.579 161.833 512.755 161.833 504.226 c 0 + 161.833 500.853 162.694 498.287 164 495 c 0 + 319 105 l 0 + 420 389 l 0 + 436.209 434.578 451.255 481.532 460 530 c 0 + 547 530 l 0 + 531.434 478.243 513.035 427.412 494 377 c 0 + 329 -60 l 0 + 317.685 -89.9672 306.505 -117.887 283.381 -143.905 c 0 + 248.107 -183.593 198.508 -201.18 150.696 -201.18 c 0 + 107.172 -201.18 66.5488 -186.251 36 -157 c 0 + 79 -82 l 0 + 85.8372 -87.3566 85.2476 -95.0835 88.2407 -100.819 c 0 + 91.1874 -106.465 111.21 -132.772 150.447 -132.772 c 0 + 175.241 -132.772 202.436 -121.95 224.474 -98.4823 c 0 + 241.247 -80.621 251.822 -58.0558 261 -37 c 0 + 278 2 l 0 + 63 529 l 0 +EndSplineSet +EndChar + +StartChar: period +Encoding: 46 46 24 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +355.002 53.4929 m 0 + 355.002 17.0088 324.552 -13.046 286.441 -13.046 c 0 + 248.415 -13.046 217.952 16.9803 217.952 53.509 c 0 + 217.952 89.9628 248.383 120.002 286.462 120.002 c 0 + 324.556 120.002 355.002 89.961 355.002 53.4929 c 0 +EndSplineSet +EndChar + +StartChar: comma +Encoding: 44 44 25 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +SplineSet +364.152 22.8349 m 0 + 364.152 -37.4943 321.706 -113.057 241 -195 c 0 + 201 -160 l 0 + 228.481 -134.726 247.951 -106.529 259.27 -87.9335 c 0 + 264.928 -78.6381 276.427 -58.8335 276.427 -39.6582 c 0 + 276.427 -15.8026 259.351 -5.13308 249.284 1.56253 c 0 + 239.047 8.37111 216.973 21.6939 216.973 52.8528 c 0 + 216.973 87.8494 245.536 118.93 283.672 118.93 c 0 + 324.887 118.93 364.152 82.133 364.152 22.8349 c 0 +EndSplineSet +EndChar + +StartChar: colon +Encoding: 58 58 26 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +Refer: 24 46 S 1 0 0 1 0 370 2 +Refer: 24 46 S 1 0 0 1 0 0 2 +EndChar + +StartChar: semicolon +Encoding: 59 59 27 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +Refer: 25 44 N 1 0 0 1 0 0 2 +Refer: 24 46 S 1 0 0 1 0 370 2 +EndChar + +StartChar: plus +Encoding: 43 43 28 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +267 606 m 5 + 340 606 l 5 + 340 408 l 5 + 538 408 l 5 + 538 337 l 5 + 340 337 l 5 + 340 120 l 5 + 267 120 l 5 + 267 337 l 5 + 62 337 l 5 + 62 408 l 5 + 267 408 l 5 + 267 606 l 5 +EndSplineSet +EndChar + +StartChar: minus +Encoding: 256 8722 29 +Width: 600 +Flags: HMW +TeX: 104 0 +LayerCount: 2 +Fore +SplineSet +62 398 m 29 + 538 398 l 29 + 538 327 l 29 + 62 327 l 29 + 62 398 l 29 +EndSplineSet +EndChar + +StartChar: equal +Encoding: 61 61 30 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 29 8722 N 1 0 0 1 0 110 2 +Refer: 29 8722 N 1 0 0 1 0 -130 2 +EndChar + +StartChar: underscore +Encoding: 95 95 31 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +50 -22 m 29 + 550 -22 l 29 + 550 -93 l 29 + 50 -93 l 29 + 50 -22 l 29 +EndSplineSet +EndChar + +StartChar: less +Encoding: 60 60 32 +Width: 600 +Flags: HMW +TeX: 108 0 +LayerCount: 2 +Fore +SplineSet +541 575 m 29 + 541 657 l 29 + 50 399 l 29 + 50 343 l 29 + 544 55 l 29 + 544 142 l 29 + 139 370 l 29 + 541 575 l 29 +EndSplineSet +EndChar + +StartChar: greater +Encoding: 62 62 33 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +Refer: 32 60 S -1 0 0 1 600 0 2 +EndChar + +StartChar: quotesingle +Encoding: 39 39 34 +Width: 600 +Flags: HMWO +TeX: 113 0 +LayerCount: 2 +Fore +SplineSet +379.671 700.649 m 0 + 379.671 670.206 369.816 633.244 341 554 c 0 + 313 477 l 0 + 249 493 l 0 + 274 571 l 0 + 280.25 590.5 285.304 612.364 285.304 635.105 c 0 + 285.304 660.263 278.044 683.429 278.044 708.518 c 0 + 278.044 754.3 305.162 772.143 327.505 772.143 c 0 + 350.267 772.143 379.671 753.082 379.671 700.649 c 0 +EndSplineSet +EndChar + +StartChar: grave +Encoding: 96 96 35 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +Refer: 34 39 S -0.766045 -0.642788 0.642788 -0.766045 104.985 1311.87 2 +EndChar + +StartChar: slash +Encoding: 47 47 36 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +84 -15 m 25 + 447 770 l 25 + 516 735 l 25 + 152 -49 l 25 + 84 -15 l 25 +EndSplineSet +EndChar + +StartChar: backslash +Encoding: 92 92 37 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +Refer: 36 47 N -1 0 0 1 600 0 2 +EndChar + +StartChar: micro +Encoding: 181 181 38 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +38 -193 m 0 + 38.9384 -58.9867 61 87.3183 61 234 c 0 + 61 529 l 0 + 137 529 l 0 + 137 215 l 0 + 137 180.23 138.185 147.14 154.248 114.565 c 0 + 174.86 72.7648 211.805 49.9847 248.66 49.9847 c 0 + 290.595 49.9847 331.561 78.8859 352.027 125.633 c 0 + 365.243 155.818 367 186.455 367 222 c 0 + 367 529 l 0 + 441 529 l 0 + 441 134 l 0 + 441 116.206 440.844 95.0245 450.744 77.6249 c 0 + 459.417 62.3819 473.241 54.8661 487.238 54.8661 c 0 + 526.513 54.8661 551 111 551 111 c 0 + 582 52 l 0 + 559.818 18.1186 523.188 -12.1017 480.237 -12.1017 c 0 + 431.193 -12.1017 391.479 28.1352 385 78 c 0 + 358.195 22.6019 302.55 -13.0043 242.87 -13.0043 c 0 + 186.505 -13.0043 135.089 18.999 111 70 c 0 + 111.199 -18.023 110.861 -105.668 110 -193 c 0 + 38 -193 l 0 +EndSplineSet +EndChar + +StartChar: braceleft +Encoding: 123 123 39 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +SplineSet +71 329 m 0 + 94 329 l 0 + 114.58 329 146.235 328.585 171.534 355.122 c 0 + 198.692 383.608 201.554 425.157 201.554 453.492 c 0 + 201.554 481.497 198.598 507.731 198.598 536.425 c 0 + 198.598 580.04 204.818 645.199 255.772 691.645 c 0 + 311.368 742.324 385.82 738 448 738 c 0 + 483 738 l 0 + 483 672 l 0 + 443 672 l 0 + 392.342 672 357.045 676.742 325.874 657.279 c 0 + 281.263 629.425 279.43 573.026 279.43 549.494 c 0 + 279.43 521.751 282.855 496.368 282.855 468.063 c 0 + 282.855 440.501 279.771 406.244 264.439 374.889 c 0 + 247.328 339.898 217.845 312.378 182 297 c 0 + 225.958 281.72 279.876 237.615 279.876 116.516 c 0 + 279.876 80.6922 276.205 50.3097 276.205 19.6336 c 0 + 276.205 -20.2481 282.098 -70.9759 323.519 -99.512 c 0 + 355.221 -121.352 391.356 -119 439 -119 c 0 + 482 -119 l 0 + 482 -184 l 0 + 440 -184 l 0 + 368.421 -184 309.076 -187.506 259.023 -149.094 c 0 + 197.979 -102.247 194.437 -23.0053 194.437 19.058 c 0 + 194.437 64.2177 198.784 98.7588 198.784 134.884 c 0 + 198.784 184.919 190.964 218.659 168.219 240.946 c 0 + 144.453 264.235 114.606 264 95 264 c 0 + 71 264 l 0 + 71 329 l 0 +EndSplineSet +EndChar + +StartChar: braceright +Encoding: 125 125 40 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +Refer: 39 123 S -1 0 0 1 600 0 2 +EndChar + +StartChar: asterisk +Encoding: 42 42 41 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +257 601 m 0 + 351 601 l 0 + 349.036 587.217 345.49 584.406 344 570 c 0 + 326 396 l 0 + 510 480 l 0 + 541 409 l 0 + 342 349 l 0 + 488 174 l 0 + 425 124 l 0 + 300 316 l 0 + 170 123 l 0 + 107 174 l 0 + 258 348 l 0 + 58 409 l 0 + 88 484 l 0 + 275 396 l 0 + 257 601 l 0 +EndSplineSet +EndChar + +StartChar: O +Encoding: 79 79 42 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +SplineSet +556.008 359.504 m 0 + 556.008 296.095 551.428 206.273 513.069 128.645 c 0 + 465.538 32.4568 382.426 -11.0151 304.485 -11.0151 c 0 + 193.976 -11.0151 43.9996 78.3988 43.9996 362.113 c 0 + 43.9996 645.884 196.081 730 303.761 730 c 0 + 382.353 730 464.443 686.67 511.792 593.902 c 0 + 551.172 516.748 556.008 427.05 556.008 359.504 c 0 +300.361 654.01 m 0 + 224.496 654.01 123.971 587.911 123.971 372.659 c 0 + 123.971 143.053 223.619 67.987 304.834 67.987 c 0 + 353.415 67.987 409.355 95.4454 442.765 165.717 c 0 + 472.355 227.951 475.085 301.614 475.085 348.897 c 0 + 475.085 410.01 471.386 479.154 446.984 539.849 c 0 + 413.335 623.543 351.591 654.01 300.361 654.01 c 0 +EndSplineSet +EndChar + +StartChar: zero +Encoding: 48 48 43 +Width: 600 +Flags: HMWO +TeX: 122 0 +LayerCount: 2 +Fore +SplineSet +301.249 727 m 0 + 412.345 727 531.007 595.219 531.007 348.788 c 0 + 531.007 100.694 407.312 -13.0219 302.525 -13.0219 c 0 + 188.358 -13.0219 67.9924 121.658 67.9924 355.222 c 0 + 67.9924 586.285 186.665 727 301.249 727 c 0 +414.067 561.958 m 1 + 383.092 625.695 339.657 656 300.157 656 c 0 + 228.597 656 143.795 554.031 143.795 369.311 c 0 + 143.795 318.267 149.725 272.506 159.907 232.842 c 1 + 414.067 561.958 l 1 +440.863 484.525 m 1 + 186.653 159.413 l 1 + 218.03 96.0835 262.445 60.8848 305.327 60.8848 c 0 + 369.033 60.8848 456.099 137.611 456.099 339.376 c 0 + 456.099 395.528 450.46 443.805 440.863 484.525 c 1 +EndSplineSet +EndChar + +StartChar: one +Encoding: 49 49 44 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +357 723 m 0 + 357 -1 l 0 + 276 -1 l 0 + 276 622 l 0 + 131 579 l 0 + 112 624 l 0 + 301 723 l 0 + 357 723 l 0 +EndSplineSet +EndChar + +StartChar: two +Encoding: 50 50 45 +Width: 600 +Flags: HMW +TeX: 116 0 +LayerCount: 2 +Fore +SplineSet +100 610 m 0 + 142.552 682.72 220.175 727.008 302.107 727.008 c 0 + 419.975 727.008 511.536 636.692 511.536 524.194 c 0 + 511.536 420.356 437.434 346.096 384.502 296.506 c 0 + 332.446 247.737 248.223 175.987 188 71 c 0 + 491 71 l 0 + 496.284 71 498.692 71.7409 503.392 75.7939 c 0 + 505.8 77.8706 511.479 83.4955 519 81 c 0 + 519 0 l 0 + 95 0 l 0 + 95 51 l 0 + 155.807 170.93 222.305 245.442 304.763 319.728 c 0 + 357.118 366.894 431.226 430.278 431.226 518.244 c 0 + 431.226 595.847 369.481 655.449 292.555 655.449 c 0 + 229.497 655.449 186.147 616.16 169.108 589.668 c 0 + 162.928 580.06 165.889 572.819 159 563 c 0 + 100 610 l 0 +EndSplineSet +EndChar + +StartChar: N +Encoding: 78 78 46 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +68 0 m 0 + 68 722 l 0 + 147 722 l 0 + 450 187 l 0 + 450 723 l 0 + 536 723 l 0 + 536.929 716.255 533.916 710.683 532.621 708.22 c 0 + 529.844 702.938 528 700.058 528 692 c 0 + 528 -1 l 0 + 464 -1 l 0 + 146 568 l 0 + 146 0 l 0 + 68 0 l 0 +EndSplineSet +EndChar + +StartChar: four +Encoding: 52 52 47 +Width: 600 +Flags: HMW +TeX: 102 0 +LayerCount: 2 +Fore +SplineSet +373 723 m 0 + 441 723 l 0 + 441 271 l 0 + 534 271 l 0 + 534 199 l 0 + 441 199 l 0 + 441 0 l 0 + 357 0 l 0 + 357 200 l 0 + 66 200 l 0 + 66 260 l 0 + 373 723 l 0 +358 594 m 0 + 146 271 l 0 + 358 271 l 0 + 358 594 l 0 +EndSplineSet +EndChar + +StartChar: eight +Encoding: 56 56 48 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +SplineSet +309.222 731.061 m 0 + 415.174 731.061 497.201 655.222 497.201 560.081 c 0 + 497.201 490.519 451.989 422.756 382 386 c 0 + 463.398 348.449 521.364 271.387 521.364 186.38 c 0 + 521.364 76.38 425.926 -12.0638 299.122 -12.0638 c 0 + 174.777 -12.0638 79.845 73.9895 79.845 181.557 c 0 + 79.845 264.873 138.311 343.716 224 384 c 0 + 158.829 417.286 113.953 482.052 113.953 553.066 c 0 + 113.953 650.336 198.716 731.061 309.222 731.061 c 0 +285 351 m 0 + 216.282 322.472 162.993 260.535 162.993 192.304 c 0 + 162.993 119.655 224.278 60.9956 302.825 60.9956 c 0 + 380.01 60.9956 439.255 117.609 439.255 187.223 c 0 + 439.255 257.778 377.894 321.691 285 351 c 0 +303.003 663.016 m 0 + 239.989 663.016 191.919 616.894 191.919 559.982 c 0 + 191.919 464.568 319 415 319 415 c 0 + 375.248 445.252 418 499.154 418 554.724 c 0 + 418 615.015 367.541 663.016 303.003 663.016 c 0 +EndSplineSet +EndChar + +StartChar: five +Encoding: 53 53 49 +Width: 600 +Flags: HMW +TeX: 102 0 +LayerCount: 2 +Fore +SplineSet +133 722 m 0 + 499 722 l 0 + 499 649 l 0 + 201 649 l 0 + 190 441 l 0 + 227.409 459.661 267.74 469.014 307.613 469.014 c 0 + 428.503 469.014 526.046 382.829 526.046 228.267 c 0 + 526.046 71.7703 422.799 -13.0166 297.988 -13.0166 c 0 + 212.187 -13.0166 131.88 27.3246 84 98 c 0 + 156 152 l 0 + 165.915 144.928 159.968 133.516 164.636 124.688 c 0 + 168.652 117.094 219.025 57.9865 296.99 57.9865 c 0 + 374.5 57.9865 443.032 118.764 443.032 229.807 c 0 + 443.032 344.87 371.274 402.108 295.262 402.108 c 0 + 245.957 402.108 194.845 377.882 160 334 c 0 + 108 355 l 0 + 133 722 l 0 +EndSplineSet +EndChar + +StartChar: S +Encoding: 83 83 50 +Width: 600 +Flags: HMW +TeX: 83 0 +LayerCount: 2 +Fore +SplineSet +514 636 m 0 + 463 567 l 0 + 460.467 567.77 457.129 570.059 456.897 576.479 c 0 + 456.744 580.739 457.326 583.155 454.259 587.627 c 0 + 426.295 628.402 374.583 659.139 307.322 659.139 c 0 + 224.667 659.139 176.928 608.659 176.928 553.304 c 0 + 176.928 523.788 190.278 480.959 250.701 445.621 c 0 + 316.767 406.982 418.491 386.478 481.296 327.335 c 0 + 526.491 284.776 537.39 234.352 537.39 196.567 c 0 + 537.39 105.698 472.479 -12.0688 296.743 -12.0688 c 0 + 207.646 -12.0688 126.78 19.1667 70 81 c 0 + 118 164 l 0 + 123.54 161.188 123.285 154.812 123.259 152.899 c 0 + 123.193 148.118 122.894 145.188 126.519 140.598 c 0 + 158.801 99.712 219.842 60.9499 299.1 60.9499 c 0 + 403.921 60.9499 456.763 129.108 456.763 191.929 c 0 + 456.763 224.218 443.541 261.931 396.186 291.612 c 0 + 341.618 325.813 237.401 350.797 170.523 400.177 c 0 + 110.323 444.627 93.8001 498.906 93.8001 541.004 c 0 + 93.8001 639.749 183.363 726.008 313.761 726.008 c 0 + 392.466 726.008 465.102 694.099 514 636 c 0 +EndSplineSet +EndChar + +StartChar: M +Encoding: 77 77 51 +Width: 600 +Flags: HMW +TeX: 77 0 +LayerCount: 2 +Fore +SplineSet +57 722 m 0 + 121 722 l 0 + 300 369 l 0 + 482 723 l 0 + 543 723 l 0 + 543 -1 l 0 + 466 -1 l 0 + 466 545 l 0 + 310 254 l 0 + 279 254 l 0 + 133 541 l 0 + 133 -1 l 0 + 57 -1 l 0 + 57 722 l 0 +EndSplineSet +EndChar + +StartChar: L +Encoding: 76 76 52 +Width: 600 +Flags: HMW +TeX: 76 0 +LayerCount: 2 +Fore +SplineSet +87 722 m 0 + 181 722 l 0 + 182.252 713.763 178.671 707.037 176.957 703.776 c 0 + 173.543 697.278 171 693.469 171 683 c 0 + 171 69 l 0 + 519 69 l 0 + 519 -1 l 0 + 87 -1 l 0 + 87 722 l 0 +EndSplineSet +EndChar + +StartChar: ampersand +Encoding: 38 38 53 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +275.219 729.113 m 0 + 362.09 729.113 430.049 664.093 430.049 574.842 c 0 + 430.049 499.041 380.587 423.321 305 382 c 0 + 435 201 l 0 + 462.526 232.964 478.373 266.737 487.03 294.093 c 0 + 487.898 296.839 488.581 299.921 488.581 303.138 c 0 + 488.581 307.706 486.98 312.21 486.98 316.938 c 0 + 486.98 322.596 489.256 326.511 492 329 c 0 + 567 277 l 0 + 540.906 230.061 511.512 184.947 479 142 c 0 + 560 37 l 0 + 492 -14 l 0 + 428 88 l 0 + 382.006 30.9903 310.65 -12.0313 232.619 -12.0313 c 0 + 128.337 -12.0313 51.7317 66.2734 51.7317 169.432 c 0 + 51.7317 258.731 108.958 348.313 198 397 c 0 + 155.129 448.798 115.988 513.456 115.988 577.085 c 0 + 115.988 663.563 187.113 729.113 275.219 729.113 c 0 +195.898 575.613 m 0 + 195.898 545.141 208.5 503.946 266 432 c 0 + 319.757 461.715 354.165 516.513 354.165 569.305 c 0 + 354.165 624.184 316.438 660.403 273.735 660.403 c 0 + 232.647 660.403 195.898 626.428 195.898 575.613 c 0 +238 343 m 0 + 176.427 303.101 139.365 237.448 139.365 177.45 c 0 + 139.365 110.152 186.019 62.8265 245.174 62.8265 c 0 + 322.406 62.8265 386 143 386 143 c 0 + 238 343 l 0 +EndSplineSet +EndChar + +StartChar: F +Encoding: 70 70 54 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +100 723 m 0 + 516 723 l 0 + 516 652 l 0 + 182 652 l 0 + 182 425 l 0 + 452 425 l 0 + 452 355 l 0 + 182 355 l 0 + 182 0 l 0 + 100 0 l 0 + 100 723 l 0 +EndSplineSet +EndChar + +StartChar: w +Encoding: 119 119 55 +Width: 600 +Flags: HMW +TeX: 119 0 +LayerCount: 2 +Fore +SplineSet +28 530 m 0 + 113 530 l 0 + 116.047 520.997 112.999 513.233 111.087 507.077 c 0 + 108.216 497.832 108.458 493.651 110 486 c 0 + 187 104 l 0 + 278 480 l 0 + 329 480 l 0 + 441 105 l 0 + 486.611 406.209 492.089 465.021 490 529 c 0 + 567 529 l 0 + 544.196 351.317 514.841 174.519 479 -1 c 0 + 401 -1 l 0 + 303 342 l 0 + 210 -1 l 0 + 135 -1 l 0 + 28 530 l 0 +EndSplineSet +EndChar + +StartChar: quoteright +Encoding: 257 8217 56 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 25 44 S 1 0 0 1 0 620 2 +EndChar + +StartChar: quoteleft +Encoding: 258 8216 57 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 56 8217 N -1 0 0 -1 565.146 1163.92 2 +EndChar + +StartChar: quotedbl +Encoding: 34 34 58 +Width: 600 +Flags: HMW +TeX: 113 0 +LayerCount: 2 +Fore +Refer: 34 39 S 1 0 0 1 90 0 2 +Refer: 34 39 S 1 0 0 1 -110 0 2 +EndChar + +StartChar: T +Encoding: 84 84 59 +Width: 600 +Flags: HMW +TeX: 84 0 +LayerCount: 2 +Fore +SplineSet +46 723 m 0 + 546 723 l 0 + 546 650 l 0 + 333 650 l 0 + 333 -1 l 0 + 251 -1 l 0 + 251 650 l 0 + 46 650 l 0 + 46 723 l 0 +EndSplineSet +EndChar + +StartChar: hyphen +Encoding: 45 45 60 +Width: 600 +Flags: HMW +TeX: 104 0 +LayerCount: 2 +Fore +SplineSet +92 403 m 0 + 509 403 l 0 + 509 326 l 0 + 92 326 l 0 + 92 403 l 0 +EndSplineSet +EndChar + +StartChar: exclam +Encoding: 33 33 61 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +SplineSet +356.002 55.4912 m 0 + 356.002 17.7 325.296 -13.0169 287.479 -13.0169 c 0 + 249.672 -13.0169 218.954 17.6866 218.954 55.4935 c 0 + 218.954 93.2861 249.66 124.002 287.478 124.002 c 0 + 325.284 124.002 356.002 93.2972 356.002 55.4912 c 0 +289.272 774.001 m 0 + 311.02 774.001 335.403 759.407 344.346 724.32 c 0 + 346.091 717.475 348.76 704.489 348.76 677.25 c 0 + 348.76 632.978 340.895 589.116 338 545 c 0 + 317 225 l 0 + 259 225 l 0 + 242 545 l 0 + 237.955 621.137 230.565 649.274 230.565 686.67 c 0 + 230.565 708.378 233.144 724.012 238.462 736.818 c 0 + 248.803 761.721 269.202 774.001 289.272 774.001 c 0 +EndSplineSet +EndChar + +StartChar: exclamdown +Encoding: 161 161 62 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 61 33 N -1 0 0 -1 574.958 760.985 2 +EndChar + +StartChar: U +Encoding: 85 85 63 +Width: 600 +Flags: HMW +TeX: 85 0 +LayerCount: 2 +Fore +SplineSet +68 722 m 0 + 159 722 l 0 + 159.791 720.163 160.2 718.172 160.2 716.15 c 0 + 160.2 709.235 155.631 704.498 152.571 700.195 c 0 + 148.296 694.182 148 690.266 148 685 c 0 + 148 248 l 0 + 148 212.142 148.701 177.155 165.336 141.578 c 0 + 191.299 86.0528 245.805 55.9211 303.067 55.9211 c 0 + 359.414 55.9211 413.783 85.3437 440.467 140.549 c 0 + 458.225 177.288 459 213.693 459 251 c 0 + 459 722 l 0 + 536 722 l 0 + 536 253 l 0 + 536 200.192 534.408 150.173 507.085 99.8136 c 0 + 466.018 24.1247 384.91 -13.0732 301.461 -13.0732 c 0 + 216.265 -13.0732 136.155 24.9771 96.1412 99.2172 c 0 + 69.4091 148.814 68 197.96 68 249 c 0 + 68 249 l 0 + 68 722 l 0 +EndSplineSet +EndChar + +StartChar: numbersign +Encoding: 35 35 64 +Width: 600 +Flags: HMW +TeX: 110 0 +LayerCount: 2 +Fore +SplineSet +211 723 m 5 + 281 726 l 5 + 256.94 527.366 l 5 + 384.587 528.891 l 5 + 407 717 l 5 + 479 720 l 5 + 455.758 529.742 l 5 + 561 531 l 5 + 555 475 l 5 + 448.941 473.939 l 5 + 425.118 278.915 l 5 + 540 281 l 5 + 534 227 l 5 + 418.548 225.134 l 5 + 393 16 l 5 + 323 12 l 5 + 348.259 223.998 l 5 + 219.943 221.924 l 5 + 195 16 l 5 + 127 13 l 5 + 151.587 220.82 l 5 + 39 219 l 5 + 44 272 l 5 + 157.887 274.066 l 5 + 181.217 471.262 l 5 + 55 470 l 5 + 59 525 l 5 + 187.757 526.539 l 5 + 211 723 l 5 +250.228 471.952 m 5 + 226.409 275.31 l 5 + 354.65 277.637 l 5 + 377.955 473.23 l 5 + 250.228 471.952 l 5 +EndSplineSet +EndChar + +StartChar: j +Encoding: 106 106 65 +Width: 600 +Flags: HMW +TeX: 106 0 +LayerCount: 2 +Fore +SplineSet +156 530 m 4 + 437 530 l 4 + 437 37 l 4 + 437 -8.68478 435.772 -52.1052 413.163 -96.3812 c 4 + 377.277 -166.657 303.238 -202.181 227.699 -202.181 c 4 + 162.017 -202.181 103.902 -175.027 66 -128 c 4 + 120 -56 l 4 + 127.204 -61.9473 125.358 -69.4816 130.11 -77.2483 c 4 + 134.378 -84.2222 169.009 -130.016 233.016 -130.016 c 4 + 277.791 -130.016 319.506 -106.298 339.459 -63.2398 c 4 + 352.497 -35.1019 353 -7.27543 353 21 c 4 + 353 461 l 4 + 156 461 l 4 + 156 530 l 4 +396.003 760 m 4 + 429.171 760 456.019 733.28 456.019 700.493 c 4 + 456.019 667.727 429.182 640.992 395.99 640.992 c 4 + 362.818 640.992 335.981 667.716 335.981 700.486 c 4 + 335.981 733.264 362.822 760 396.003 760 c 4 +EndSplineSet +EndChar + +StartChar: x +Encoding: 120 120 66 +Width: 600 +Flags: HMW +TeX: 120 0 +LayerCount: 2 +Fore +SplineSet +430 530 m 1 + 515 530 l 1 + 343.447 272.196 l 1 + 538 0 l 1 + 443 0 l 1 + 297.06 205.835 l 1 + 159 0 l 1 + 65 0 l 1 + 250.856 269.049 l 1 + 68 530 l 1 + 159 530 l 1 + 297.737 333.918 l 1 + 430 530 l 1 +EndSplineSet +EndChar + +StartChar: G +Encoding: 71 71 67 +Width: 600 +Flags: HMW +TeX: 71 0 +LayerCount: 2 +Fore +SplineSet +331.256 729.021 m 0 + 420.211 729.021 499.721 682.82 541 608 c 0 + 484 550 l 0 + 474.934 555.815 472.124 564.988 468.568 572.778 c 0 + 446.485 621.163 395.191 658.068 330.753 658.068 c 0 + 269.931 658.068 205.563 624.733 168.312 554.634 c 0 + 140.066 501.479 131.993 436.71 131.993 369.475 c 0 + 131.993 293.213 140.467 191.911 200.744 123.216 c 0 + 240.013 78.4622 291.335 59.9971 338.046 59.9971 c 0 + 381.069 59.9971 427.485 75.1275 468 104 c 0 + 468 276 l 0 + 337 276 l 0 + 337 346 l 0 + 543 346 l 0 + 543 64 l 0 + 474.935 13.8821 397.763 -11.0487 330.884 -11.0487 c 0 + 204.891 -11.0487 51.8871 79.1096 51.8871 352.371 c 0 + 51.8871 669.165 235.235 729.021 331.256 729.021 c 0 +EndSplineSet +EndChar + +StartChar: k +Encoding: 107 107 68 +Width: 600 +Flags: HMW +TeX: 107 0 +LayerCount: 2 +Fore +SplineSet +87 770 m 0 + 182 770 l 0 + 183.286 762.176 178.153 756.852 175.466 753.359 c 0 + 171.419 748.094 171 745.015 171 740 c 0 + 171 286 l 0 + 436 532 l 0 + 456.53 526.949 477.704 526 498 526 c 0 + 528 526 l 0 + 305 316 l 0 + 565 -1 l 0 + 562.299 -0.982364 559.597 -0.973546 556.896 -0.973546 c 0 + 501.401 -0.973546 457 -5 457 -5 c 0 + 241 265 l 0 + 171 200 l 0 + 171 -1 l 0 + 87 -1 l 0 + 87 770 l 0 +EndSplineSet +EndChar + +StartChar: z +Encoding: 122 122 69 +Width: 600 +Flags: HMW +TeX: 122 0 +LayerCount: 2 +Fore +SplineSet +92 530 m 0 + 504 530 l 0 + 504 473 l 0 + 181 71 l 0 + 496 71 l 0 + 512.142 71 516.579 80.1398 531 78 c 0 + 531 -1 l 0 + 68 -1 l 0 + 68 56 l 0 + 396 457 l 0 + 92 457 l 0 + 92 530 l 0 +EndSplineSet +EndChar + +StartChar: dollar +Encoding: 36 36 70 +Width: 600 +Flags: HMW +TeX: 100 0 +LayerCount: 2 +Fore +SplineSet +282 754 m 1 + 357 754 l 1 + 357.544 752.762 357.825 751.416 357.825 750.046 c 0 + 357.825 741.462 350 741.128 350 730 c 2 + 350 685.53 l 1 + 418.468 678.631 479.448 647.798 522 597 c 1 + 472 534 l 1 + 469.529 534.647 466.405 536.859 465.998 542.031 c 0 + 465.734 545.385 466.586 548.59 464.873 552.132 c 0 + 464.366 553.181 463.571 554.432 459.966 558.804 c 0 + 435.884 588.015 400.197 609.606 350 617.169 c 1 + 350 394.007 l 1 + 376.209 385.213 402.685 376.233 426.693 365.906 c 0 + 451.098 355.408 542.789 316.114 542.789 210.306 c 0 + 542.789 127.201 481.207 35.8962 350 18.7898 c 1 + 350 -54 l 1 + 282 -54 l 1 + 282 16.6512 l 1 + 202.131 21.6382 130.573 53.0648 79 109 c 1 + 129 178 l 1 + 134.731 175.387 134.178 168.719 134.1 167.269 c 0 + 133.829 162.202 133.224 159.078 137.667 154.35 c 0 + 170.199 119.732 221.081 90.2105 282 83.4419 c 1 + 282 338.141 l 1 + 260.848 345.221 239.279 353.278 218.422 363.137 c 0 + 121.008 409.184 101.838 474.448 101.838 516.644 c 0 + 101.838 600.059 175.207 670.816 282 684.586 c 1 + 282 754 l 1 +350 316.849 m 1 + 350 85.8432 l 1 + 424.317 100.222 467.128 152.561 467.128 204.903 c 0 + 467.128 228.695 458.246 267.247 409.599 293.705 c 0 + 393.686 302.36 373.118 309.563 350 316.849 c 1 +282 418.096 m 1 + 282 618.618 l 1 + 209.129 610.103 178.407 566.678 178.407 526.615 c 0 + 178.407 501.336 190.349 466.609 241.42 437.196 c 0 + 253.404 430.294 267.16 424.024 282 418.096 c 1 +EndSplineSet +EndChar + +StartChar: A +Encoding: 65 65 71 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +SplineSet +27 -1 m 0 + 282 735 l 0 + 291 735 l 0 + 570 0 l 0 + 486 0 l 0 + 406 211 l 0 + 177 211 l 0 + 107 -1 l 0 + 27 -1 l 0 +388 274 m 0 + 286 549 l 0 + 193 274 l 0 + 388 274 l 0 +EndSplineSet +EndChar + +StartChar: C +Encoding: 67 67 72 +Width: 600 +Flags: HMW +TeX: 67 0 +LayerCount: 2 +Fore +SplineSet +331.618 728 m 0 + 427.542 728 514.176 672.042 553 585 c 0 + 476 547 l 0 + 470.67 550.736 470.716 557.019 470.716 558.375 c 0 + 470.716 561.257 471.207 564.142 471.207 567.016 c 0 + 471.207 572.403 469.516 575.396 467.216 579.368 c 0 + 438.075 629.699 385.397 663.168 328.882 663.168 c 0 + 226.816 663.168 135.987 555.779 135.987 363.969 c 0 + 135.987 168.839 229.418 57.9939 335.655 57.9939 c 0 + 392.317 57.9939 449.702 90.8843 483 146 c 0 + 543 107 l 0 + 497.694 32.979 417.217 -12.0016 331.109 -12.0016 c 0 + 212.178 -12.0016 56.9666 77.8506 56.9666 356.807 c 0 + 56.9666 645.838 219.327 728 331.618 728 c 0 +EndSplineSet +EndChar + +StartChar: B +Encoding: 66 66 73 +Width: 600 +Flags: HMW +TeX: 66 0 +LayerCount: 2 +Fore +SplineSet +66 722 m 0 + 271 722 l 0 + 315.399 722 360.704 721.5 405.879 701.856 c 0 + 473.724 672.354 511 610.49 511 545.61 c 0 + 511 476.391 468.788 413.433 404 387 c 0 + 484.894 359.735 539.123 283.98 539.123 199.903 c 0 + 539.123 125.489 496.411 54.7898 418.712 21.7722 c 0 + 368.818 0.569996 319.11 0 270 0 c 0 + 66 0 l 0 + 66 722 l 0 +146 653 m 0 + 146 423 l 0 + 259 423 l 0 + 291.145 423 325.727 423.132 358.963 437.515 c 0 + 404.424 457.189 429.169 496.927 429.169 538.138 c 0 + 429.169 579.684 403.799 620.586 355.923 639.925 c 0 + 323.833 652.887 290.834 653 260 653 c 0 + 146 653 l 0 +146 355 m 0 + 146 71 l 0 + 284 71 l 0 + 315.204 71 345.804 71.5467 376.985 85.5968 c 0 + 426.877 108.078 454.347 156.379 454.347 208.01 c 0 + 454.347 260.227 425.928 311.754 372.336 337.19 c 0 + 336.297 354.296 300.473 355 264 355 c 0 + 146 355 l 0 +EndSplineSet +EndChar + +StartChar: bracketleft +Encoding: 91 91 74 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +SplineSet +162 776 m 0 + 493 776 l 0 + 493 707 l 0 + 236 707 l 0 + 236 -37 l 0 + 494 -37 l 0 + 494 -103 l 0 + 162 -103 l 0 + 162 776 l 0 +EndSplineSet +EndChar + +StartChar: bracketright +Encoding: 93 93 75 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +Refer: 74 91 S -1 0 0 1 600 0 2 +EndChar + +StartChar: parenleft +Encoding: 40 40 76 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +464 772 m 4 + 499 701 l 4 + 495.074 698.763 491.329 698.611 489.669 698.611 c 4 + 485.073 698.611 481.395 699.932 477.323 699.932 c 4 + 472.717 699.932 469.928 698.14 466.835 696.315 c 4 + 331.453 616.467 251.273 468.859 251.273 303.345 c 4 + 251.273 123.314 344.63 -46.9685 503 -139 c 4 + 465 -200 l 4 + 281.456 -103.658 170.68 88.9922 170.68 299.462 c 4 + 170.68 511.567 284.678 693.118 464 772 c 4 +EndSplineSet +EndChar + +StartChar: parenright +Encoding: 41 41 77 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +100 699 m 0 + 122 771 l 0 + 310.266 684.352 432 496.633 432 290.289 c 0 + 432 82.1043 308.169 -110.384 116 -202 c 0 + 94 -132 l 0 + 250.594 -49.1168 350.028 112.597 350.028 286.978 c 0 + 350.028 458.955 253.152 617.58 100 699 c 0 +EndSplineSet +EndChar + +StartChar: three +Encoding: 51 51 78 +Width: 600 +Flags: HMW +TeX: 116 0 +LayerCount: 2 +Fore +SplineSet +486.039 541.353 m 0 + 486.039 471.159 442.787 409.132 378 385 c 0 + 452.906 357.628 502.026 284.533 502.026 198.625 c 0 + 502.026 86.4453 418.041 -12.1905 279.723 -12.1905 c 0 + 207.414 -12.1905 138.424 16.1652 90 70 c 0 + 151 143 l 0 + 161.292 132.464 156.135 121.234 165.975 110.147 c 0 + 171.105 104.367 211.734 61.2614 278.997 61.2614 c 0 + 363.525 61.2614 424.303 129.155 424.303 208.449 c 0 + 424.303 294.507 352.456 345.579 254.688 345.579 c 0 + 242.418 345.579 230.159 344.711 218 343 c 0 + 218 408 l 0 + 286.501 408.15 319.346 420.748 332.04 426.323 c 0 + 382.02 448.274 409.043 495.946 409.043 539.93 c 0 + 409.043 600.917 357.627 652.425 283.533 652.425 c 0 + 238.887 652.425 192.677 633.092 159 597 c 0 + 114 647 l 0 + 159.315 696.504 222.364 724.29 287.492 724.29 c 0 + 401.687 724.29 486.039 639.912 486.039 541.353 c 0 +EndSplineSet +EndChar + +StartChar: D +Encoding: 68 68 79 +Width: 600 +Flags: HMW +TeX: 68 0 +LayerCount: 2 +Fore +SplineSet +72 722 m 0 + 241 722 l 0 + 304.677 722 356.645 717.434 409.104 683.3 c 0 + 501.966 622.876 543.181 501.213 543.181 362.199 c 0 + 543.181 204.202 486.7 81.1929 383.192 27.9784 c 0 + 332.292 1.81019 284.391 -1 227 -1 c 0 + 72 -1 l 0 + 72 722 l 0 +149 653 m 0 + 149 63 l 0 + 223 63 l 0 + 268.397 63 312.737 65.0195 358.002 95.5625 c 0 + 415.69 134.488 461.352 213.696 461.352 351.331 c 0 + 461.352 455.017 438.945 557.739 371.85 613.352 c 0 + 327.165 650.39 281.491 653 236 653 c 0 + 149 653 l 0 +EndSplineSet +EndChar + +StartChar: E +Encoding: 69 69 80 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +SplineSet +78 723 m 0 + 521 723 l 0 + 521 651 l 0 + 155 651 l 0 + 155 414 l 0 + 457 414 l 0 + 457 340 l 0 + 155 340 l 0 + 155 72 l 0 + 518 72 l 0 + 518 0 l 0 + 78 0 l 0 + 78 723 l 0 +EndSplineSet +EndChar + +StartChar: V +Encoding: 86 86 81 +Width: 600 +Flags: HMW +TeX: 86 0 +LayerCount: 2 +Fore +SplineSet +39 723 m 0 + 124 723 l 0 + 309 168 l 0 + 484 722 l 0 + 564 722 l 0 + 322 -5 l 0 + 285 -5 l 0 + 39 723 l 0 +EndSplineSet +EndChar + +StartChar: percent +Encoding: 37 37 82 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +463 722 m 0 + 541 722 l 0 + 137 0 l 0 + 63 0 l 0 + 463 722 l 0 +171.904 735.106 m 0 + 242.474 735.106 302.16 670.55 302.16 582.187 c 0 + 302.16 496.123 243.528 431.982 172.952 431.982 c 0 + 101.84 431.982 42.8516 496.911 42.8516 583.448 c 0 + 42.8516 672.526 103.042 735.106 171.904 735.106 c 0 +170.33 674.005 m 0 + 147.48 674.005 112.978 656.124 112.978 587.43 c 0 + 112.978 508.953 151.261 493.911 172.149 493.911 c 0 + 195.202 493.911 229.092 512.141 229.092 579.148 c 0 + 229.092 661.667 189.098 674.005 170.33 674.005 c 0 +569.018 138.593 m 0 + 569.018 51.7449 509.983 -12.1238 439.695 -12.1238 c 0 + 369.049 -12.1238 309.98 52.0529 309.98 138.262 c 0 + 309.98 225.089 369.219 289.001 439.589 289.001 c 0 + 510.127 289.001 569.018 224.871 569.018 138.593 c 0 +439.32 229.005 m 0 + 414.436 229.005 378.994 208.941 378.994 138.34 c 0 + 378.994 69.8907 413.149 46.7696 440.303 46.7696 c 0 + 465.114 46.7696 500.009 66.7942 500.009 135.903 c 0 + 500.009 210.33 463.157 229.005 439.32 229.005 c 0 +EndSplineSet +EndChar + +StartChar: J +Encoding: 74 74 83 +Width: 600 +Flags: HMW +TeX: 74 0 +LayerCount: 2 +Fore +SplineSet +209 722 m 0 + 539 722 l 0 + 539 654 l 0 + 428 654 l 0 + 428 242 l 0 + 428 189.714 427.529 134.891 399.871 83.1312 c 0 + 366.41 20.5134 303.824 -13.1014 235.465 -13.1014 c 0 + 171.621 -13.1014 109.768 15.8267 67 67 c 0 + 121 133 l 0 + 127.875 126.68 123.023 118.695 128.162 112.068 c 0 + 130.663 108.842 176.362 58.6812 236.758 58.6812 c 0 + 271.444 58.6812 302.787 75.9435 322.107 104.722 c 0 + 348.989 144.764 348 196.3 348 241 c 0 + 348 654 l 0 + 209 654 l 0 + 209 722 l 0 +EndSplineSet +EndChar + +StartChar: K +Encoding: 75 75 84 +Width: 600 +Flags: HMW +TeX: 75 0 +LayerCount: 2 +Fore +SplineSet +59 723 m 0 + 156 723 l 0 + 157.286 715.176 152.153 709.852 149.466 706.359 c 0 + 145.419 701.094 145 698.015 145 693 c 0 + 145 389 l 0 + 447 728 l 0 + 466.858 722.945 487.384 722 507 722 c 0 + 537 722 l 0 + 264 410 l 0 + 556 -1 l 0 + 498.81 -0.826198 453 -5 453 -5 c 0 + 202 361 l 0 + 145 299 l 0 + 145 0 l 0 + 59 0 l 0 + 59 723 l 0 +EndSplineSet +EndChar + +StartChar: P +Encoding: 80 80 85 +Width: 600 +Flags: HMW +TeX: 80 0 +LayerCount: 2 +Fore +SplineSet +78 722 m 0 + 298 722 l 0 + 344.56 722 389.35 720.81 434.624 697.494 c 0 + 502.828 662.37 538.016 591.718 538.016 518.699 c 0 + 538.016 445.503 502.883 376.352 436.114 342.409 c 0 + 392.262 320.116 348.977 319 304 319 c 0 + 304 319 l 0 + 162 319 l 0 + 162 0 l 0 + 78 0 l 0 + 78 722 l 0 +162 646 m 0 + 161 390 l 0 + 307 390 l 0 + 335.466 390 362.993 390.678 390.831 404.763 c 0 + 432.659 425.926 455.003 468.944 455.003 514.986 c 0 + 455.003 561.985 431.629 607.921 386.619 630.5 c 0 + 357.19 645.263 328.165 646 298 646 c 0 + 162 646 l 0 +EndSplineSet +EndChar + +StartChar: question +Encoding: 63 63 86 +Width: 600 +Flags: HMW +TeX: 113 0 +LayerCount: 2 +Fore +SplineSet +381.002 51.4929 m 0 + 381.002 15.0088 350.552 -15.046 312.441 -15.046 c 0 + 274.415 -15.046 243.952 14.9803 243.952 51.509 c 0 + 243.952 87.9628 274.383 118.002 312.462 118.002 c 0 + 350.556 118.002 381.002 87.961 381.002 51.4929 c 0 +84 650 m 0 + 134.425 727.691 220.637 771.06 307.402 771.06 c 0 + 438.699 771.06 513.24 674.633 513.24 566.639 c 0 + 513.24 457.756 436.646 413.666 398.404 379.676 c 0 + 350.692 337.269 348 302.835 348 262 c 0 + 348 214 l 0 + 272 214 l 0 + 272 262 l 0 + 272 314.014 275.26 354.806 326.449 411.013 c 0 + 361.471 449.468 421.576 496.796 421.576 572.709 c 0 + 421.576 641.182 368.948 695.153 299.634 695.153 c 0 + 241.046 695.153 179.542 656.112 143 595 c 0 + 84 650 l 0 +EndSplineSet +EndChar + +StartChar: at +Encoding: 64 64 87 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +514 35 m 0 + 465.464 3.64213 409.094 -13.0048 351.681 -13.0048 c 0 + 207.208 -13.0048 45.979 94.7502 45.979 363.717 c 0 + 45.979 626.559 197.939 733 324.448 733 c 0 + 408.454 733 485.773 686.98 523.017 604.767 c 0 + 548.262 549.038 549 493.218 549 438 c 0 + 549 203 l 0 + 479 203 l 0 + 479 247 l 0 + 450.306 212.734 407.914 192.94 363.251 192.94 c 0 + 280.295 192.94 212.67 260.162 212.67 343.965 c 0 + 212.67 406.432 250.973 468.115 322.793 496.582 c 0 + 368.543 514.716 414.747 515 459 515 c 0 + 476 515 l 0 + 475.939 600.733 407.704 671.014 321.098 671.014 c 0 + 220.711 671.014 112.988 575.649 112.988 367.243 c 0 + 112.988 141.221 246.229 52.9323 358.489 52.9323 c 0 + 402.842 52.9323 446.203 66.182 483 91 c 0 + 514 35 l 0 +479 457 m 0 + 460 457 l 0 + 418.559 457 369.9 456.608 330.805 429.771 c 0 + 299.601 408.352 284.927 377.014 284.927 347.37 c 0 + 284.927 297.233 325.741 256.964 376.598 256.964 c 0 + 410.056 256.964 444.081 274.841 462.01 309.68 c 0 + 480.087 344.808 479 389.066 479 435 c 0 + 479 457 l 0 +EndSplineSet +EndChar + +StartChar: bar +Encoding: 124 124 88 +Width: 600 +Flags: HMW +TeX: 98 0 +LayerCount: 2 +Fore +SplineSet +261 756 m 0 + 339 756 l 0 + 339 -175 l 0 + 261 -175 l 0 + 261 756 l 0 +EndSplineSet +EndChar + +StartChar: asciitilde +Encoding: 126 126 89 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +116 396 m 4 + 58 434 l 4 + 92.198 492.034 151.499 538.051 217.153 538.051 c 4 + 312.781 538.051 343.146 450.999 409.264 450.999 c 4 + 447.27 450.999 474.649 480.653 508 526 c 4 + 561 482 l 4 + 530.811 436.285 473.381 375.377 400.536 375.377 c 4 + 306.617 375.377 282.907 467.595 212.175 467.595 c 4 + 179.423 467.595 145.323 443.982 116 396 c 4 +EndSplineSet +EndChar + +StartChar: asciicircum +Encoding: 94 94 90 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +118 425 m 0 + 295 722 l 0 + 320 722 l 0 + 477 426 l 0 + 415 397 l 0 + 303 600 l 0 + 176 397 l 0 + 118 425 l 0 +EndSplineSet +EndChar + +StartChar: cent +Encoding: 162 162 91 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +SplineSet +340 723 m 1 + 418 715 l 1 + 418.775 707.498 415.212 701.298 413.826 698.827 c 0 + 410.853 693.526 409.047 690.934 408 683 c 2 + 395.457 587.822 l 1 + 458.442 575.242 504.754 541.294 533 498 c 1 + 482 432 l 1 + 476.607 435.758 476.706 442.016 476.706 443.549 c 0 + 476.706 450.099 478.707 455.066 472.749 462.134 c 0 + 457.796 479.871 428.657 504.643 386.192 517.517 c 1 + 332.752 112 l 1 + 333.469 111.999 l 2 + 389.462 111.999 444.705 135.589 485 177 c 1 + 527 121 l 1 + 477.291 66.4244 406.711 37.9886 331.604 37.9886 c 0 + 328.725 37.9886 325.862 38.0286 323.014 38.1081 c 1 + 306 -91 l 1 + 239 -83 l 1 + 255.422 48.0539 l 1 + 141.433 79.5748 66 182.291 66 315.836 c 0 + 66 471.215 168.407 585.207 323.673 592.709 c 1 + 340 723 l 1 +265.044 124.836 m 1 + 315.274 525.684 l 1 + 219.938 519.993 147.95 447.755 147.95 326.544 c 0 + 147.95 225.647 194.972 152.96 265.044 124.836 c 1 +EndSplineSet +EndChar + +StartChar: euro +Encoding: 164 8364 92 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +548 665 m 5 + 519 586 l 5 + 510.733 592.758 515.379 602.068 509.042 609.779 c 4 + 507.922 611.142 464.815 661.167 386.755 661.167 c 4 + 317.566 661.167 233.594 620.979 199.483 502.334 c 4 + 197.686 496.082 195.746 488.698 193.828 480 c 5 + 480 480 l 5 + 455 413 l 5 + 184.084 413 l 5 + 182.441 393.403 181.417 370.757 181.417 344.613 c 4 + 181.417 336.225 181.561 328.021 181.852 320 c 5 + 420 320 l 5 + 394 253 l 5 + 188.48 253 l 5 + 196.603 205.904 211.936 166.8 235.532 134.868 c 4 + 276.315 79.6765 335.261 56.791 388.936 56.791 c 4 + 435.098 56.791 479.134 73.5085 513 104 c 5 + 546 46 l 5 + 501.68 7.4161 444.786 -13.1265 384.233 -13.1265 c 4 + 290.458 -13.1265 145.304 38.4687 114.986 253 c 5 + 48 253 l 5 + 63 320 l 5 + 109.56 320 l 5 + 109.4 326.06 109.319 332.225 109.319 338.496 c 4 + 109.319 363.479 110.295 388.448 112.538 413 c 5 + 48 413 l 5 + 63 480 l 5 + 122.297 480 l 5 + 130.798 521.099 144.028 559.766 163.557 593.831 c 4 + 222.805 697.179 318.974 727.394 391.356 727.394 c 4 + 452.52 727.394 507.764 705.737 548 665 c 5 +EndSplineSet +EndChar + +StartChar: sterling +Encoding: 163 163 93 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +494 663 m 1 + 443 599 l 1 + 433.543 605.934 434.27 615.246 427.512 622.673 c 0 + 422.593 628.078 390.006 656.128 341.348 656.128 c 0 + 279.173 656.128 217.781 609.4 217.781 512.955 c 0 + 217.781 488.175 221.729 463.315 227.168 438 c 1 + 342 438 l 1 + 342 372 l 1 + 242.811 372 l 1 + 251.234 336.143 258.537 298.852 258.537 259.182 c 0 + 258.537 201.957 243.517 148.5 216 104 c 1 + 226.25 105.791 236.644 106.675 247.063 106.675 c 0 + 324.103 106.675 372.006 58.9164 438.359 58.9164 c 0 + 470.325 58.9164 500.468 70.8547 524 91 c 1 + 555 31 l 1 + 528.906 10.2532 484.714 -17.1633 434.141 -17.1633 c 0 + 360.259 -17.1633 311.803 34.666 227.673 34.666 c 0 + 203.994 34.666 159.283 30.2658 85 -9 c 1 + 55 57 l 1 + 108.912 81.9053 122.949 87.4528 141.287 115.98 c 0 + 167.053 156.062 181.214 204.698 181.214 256.851 c 0 + 181.214 296.572 172.952 334.482 163.82 372 c 1 + 88 372 l 1 + 88 438 l 1 + 148.325 438 l 1 + 143.399 462.328 139.93 486.842 139.93 511.928 c 0 + 139.93 641.884 235.856 722.006 343.371 722.006 c 0 + 398.585 722.006 452.418 701.138 494 663 c 1 +EndSplineSet +EndChar + +StartChar: Y +Encoding: 89 89 94 +Width: 600 +Flags: HMW +TeX: 89 0 +LayerCount: 2 +Fore +SplineSet +43 723 m 0 + 135 723 l 0 + 312 372 l 0 + 472 722 l 0 + 558 722 l 0 + 353 285 l 0 + 353 0 l 0 + 265 0 l 0 + 265 285 l 0 + 43 723 l 0 +EndSplineSet +EndChar + +StartChar: yen +Encoding: 165 165 95 +Width: 600 +Flags: HMW +TeX: 121 0 +LayerCount: 2 +Fore +SplineSet +52 723 m 1 + 142 723 l 1 + 310 421 l 1 + 464 722 l 1 + 550 722 l 1 + 348 342 l 1 + 348 318 l 1 + 504 318 l 1 + 504 252 l 1 + 348 252 l 1 + 348 179 l 1 + 504 179 l 1 + 504 114 l 1 + 348 114 l 1 + 348 0 l 1 + 269 0 l 1 + 269 114 l 1 + 107 114 l 1 + 107 179 l 1 + 269 179 l 1 + 269 252 l 1 + 107 252 l 1 + 107 318 l 1 + 269 318 l 1 + 269 342 l 1 + 52 723 l 1 +EndSplineSet +EndChar + +StartChar: Z +Encoding: 90 90 96 +Width: 600 +Flags: HMW +TeX: 90 0 +LayerCount: 2 +Fore +SplineSet +82 722 m 0 + 528 722 l 0 + 527 665 l 0 + 170 71 l 0 + 511 71 l 0 + 527.142 71 531.579 80.1398 546 78 c 0 + 546 -1 l 0 + 68 -1 l 0 + 68 56 l 0 + 432 649 l 0 + 82 649 l 0 + 82 722 l 0 +EndSplineSet +EndChar + +StartChar: Q +Encoding: 81 81 97 +Width: 600 +Flags: HMW +TeX: 81 0 +LayerCount: 2 +Fore +SplineSet +300.491 656.024 m 0 + 221.775 656.024 122.96 585.888 122.96 373.877 c 0 + 122.96 144.877 220.551 63.9921 305.427 63.9921 c 0 + 366.012 63.9921 478.121 108.342 478.121 348.259 c 0 + 478.121 408.965 473.721 479.175 448.587 540.782 c 0 + 413.795 626.06 351.323 656.024 300.491 656.024 c 0 +556.015 357.88 m 0 + 556.015 294.497 551.45 205.023 513.096 127.795 c 0 + 473.396 47.8558 408.806 4.43529 343.02 -7.54866 c 1 + 344.367 -47.6073 355.333 -95.0859 427.899 -95.0859 c 0 + 453.816 -95.0859 485.178 -90.5919 522 -89 c 1 + 520 -168 l 1 + 436.632 -167.285 386.166 -172.61 341.235 -150.307 c 0 + 288.619 -124.19 270.811 -74.3879 271.79 -8.40479 c 1 + 166.776 8.0711 43.9994 105.441 43.9994 361.966 c 0 + 43.9994 646.356 196.451 730 303.805 730 c 0 + 383.023 730 465.547 686.019 512.626 592.269 c 0 + 551.227 515.402 556.015 426.335 556.015 357.88 c 0 +EndSplineSet +EndChar + +StartChar: thorn +Encoding: 254 254 98 +Width: 600 +Flags: HMW +TeX: 116 0 +LayerCount: 2 +Fore +SplineSet +80 770 m 0 + 172 770 l 0 + 172.534 754.226 164 750.539 164 732 c 0 + 164 448 l 0 + 199.965 505.862 263.255 541 331.196 541 c 0 + 435.346 541 546.008 457.517 546.008 270.69 c 0 + 546.008 76.5707 432.1 -14.1497 323.885 -14.1497 c 0 + 259.582 -14.1497 200.339 17.6548 165 70 c 0 + 165 -193 l 0 + 80 -193 l 0 + 80 770 l 0 +300.599 469.911 m 0 + 247.269 469.911 198.023 440.745 177.865 393.197 c 0 + 166.21 365.704 163.875 333.505 163.875 288.853 c 0 + 163.875 212.177 163.543 168.56 179.045 132.849 c 0 + 199.943 84.7085 249.872 59.8372 300.077 59.8372 c 0 + 349.666 59.8372 459.207 86.5412 459.207 253.487 c 0 + 459.207 445.62 347.069 469.911 300.599 469.911 c 0 +EndSplineSet +EndChar + +StartChar: questiondown +Encoding: 191 191 99 +Width: 600 +Flags: HMW +TeX: 113 0 +LayerCount: 2 +Fore +Refer: 86 63 N -1 0 0 -1 601.159 755.969 2 +EndChar + +StartChar: plusminus +Encoding: 177 177 100 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +63 93 m 4 + 540 93 l 4 + 540 20 l 4 + 63 20 l 4 + 63 93 l 4 +EndSplineSet +Refer: 28 43 N 1 0 0 1 0 60 2 +EndChar + +StartChar: R +Encoding: 82 82 101 +Width: 600 +Flags: HMW +TeX: 82 0 +LayerCount: 2 +Fore +SplineSet +75 722 m 0 + 288 722 l 0 + 334.667 722 380.248 720.95 425.988 697.719 c 0 + 492.448 663.965 528.143 596.481 528.143 523.978 c 0 + 528.143 428.394 468.499 345.903 381 322 c 0 + 548 0 l 0 + 457 0 l 0 + 297 319 l 0 + 157 319 l 0 + 157 0 l 0 + 75 0 l 0 + 75 722 l 0 +157 646 m 0 + 157 390 l 0 + 297 390 l 0 + 325.466 390 352.993 390.678 380.831 404.763 c 0 + 422.659 425.926 445.003 468.944 445.003 514.986 c 0 + 445.003 561.985 421.629 607.921 376.619 630.5 c 0 + 347.19 645.263 318.165 646 288 646 c 0 + 157 646 l 0 +EndSplineSet +EndChar + +StartChar: X +Encoding: 88 88 102 +Width: 600 +Flags: HMW +TeX: 88 0 +LayerCount: 2 +Fore +SplineSet +449 723 m 1 + 530 723 l 1 + 347.292 370.084 l 1 + 552 0 l 1 + 461 0 l 1 + 300.474 286.156 l 1 + 146 0 l 1 + 57 0 l 1 + 254.441 368.201 l 1 + 61 723 l 1 + 148 723 l 1 + 300.153 448.564 l 1 + 449 723 l 1 +EndSplineSet +EndChar + +StartChar: six +Encoding: 54 54 103 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +342.659 730.138 m 0 + 401.412 730.138 458.584 705.809 501 664 c 0 + 445 602 l 0 + 434.368 609.82 434.59 620.671 427.517 628.077 c 0 + 423.092 632.711 391.165 658.246 343.16 658.246 c 0 + 291.254 658.246 172.411 625.987 168 379 c 0 + 199.898 432.999 258.013 466.137 321.005 466.137 c 0 + 423.075 466.137 519.08 379.808 519.08 229.538 c 0 + 519.08 80.8581 422.752 -12.0026 312.997 -12.0026 c 0 + 248.704 -12.0026 184.458 20.3794 142.414 83.8806 c 0 + 96.0423 153.919 87.8103 244.182 87.8103 328.725 c 0 + 87.8103 398.015 94.4787 482.075 118.688 550.855 c 0 + 163.122 677.091 256.592 730.138 342.659 730.138 c 0 +313.429 395.091 m 0 + 259.837 395.091 204.549 357.227 172 298 c 0 + 162.434 163.097 228.337 59.9447 316.419 59.9447 c 0 + 377.654 59.9447 440.168 112.511 440.168 225.41 c 0 + 440.168 349.842 371.467 395.091 313.429 395.091 c 0 +EndSplineSet +EndChar + +StartChar: nine +Encoding: 57 57 104 +Width: 600 +Flags: HMW +TeX: 110 0 +LayerCount: 2 +Fore +SplineSet +261.675 -12.1561 m 0 + 202.075 -12.1561 144.572 11.7985 102 54 c 0 + 158 116 l 0 + 170.321 108.179 167.108 95.6999 176.888 88.125 c 0 + 177.128 87.939 212.027 61.8787 263.838 61.8787 c 0 + 315.736 61.8787 375.697 88.07 406.577 161.072 c 0 + 414.19 179.068 432.572 227.741 436 340 c 0 + 402.346 291.195 346.701 261.958 287.116 261.958 c 0 + 182.228 261.958 88.9944 351.151 88.9944 489.856 c 0 + 88.9944 629.773 183.329 729 295.648 729 c 0 + 371.017 729 454.143 682.757 491.757 572.33 c 0 + 508.564 522.989 516.664 460.639 516.664 370.261 c 0 + 516.664 252.09 498.421 189.45 485.749 156.035 c 0 + 442.004 40.6809 349.796 -12.1561 261.675 -12.1561 c 0 +294.989 332.729 m 0 + 346.985 332.729 400.082 367.207 432 421 c 0 + 444.812 566.747 376.145 657.043 293.961 657.043 c 0 + 228.457 657.043 167.969 598.264 167.969 493.195 c 0 + 167.969 385.709 230.618 332.729 294.989 332.729 c 0 +EndSplineSet +EndChar + +StartChar: seven +Encoding: 55 55 105 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +101 722 m 0 + 510 722 l 0 + 510 677 l 0 + 461.138 565.327 415.446 452.266 373 338 c 0 + 331.553 226.425 293.2 113.7 258 0 c 0 + 167 0 l 0 + 209.792 129.784 255.811 258.503 305 386 c 0 + 338.534 472.918 373.54 559.268 410 645 c 0 + 101 645 l 0 + 101 722 l 0 +EndSplineSet +EndChar + +StartChar: W +Encoding: 87 87 106 +Width: 600 +Flags: HMW +TeX: 87 0 +LayerCount: 2 +Fore +SplineSet +30 722 m 0 + 105 722 l 0 + 183 234 l 0 + 299 669 l 0 + 324 669 l 0 + 441 232 l 0 + 507 722 l 0 + 575 722 l 0 + 461 -5 l 0 + 429 -5 l 0 + 305 472 l 0 + 179 -5 l 0 + 146 -5 l 0 + 30 722 l 0 +EndSplineSet +EndChar + +StartChar: acute +Encoding: 260 180 107 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +348 810 m 4 + 421 761 l 4 + 304 605 l 4 + 246 640 l 4 + 348 810 l 4 +EndSplineSet +EndChar + +StartChar: aacute +Encoding: 225 225 108 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: agrave +Encoding: 224 224 109 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 130 715 S 1 0 0 1 0 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: acircumflex +Encoding: 226 226 110 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 137 710 S 1 0 0 1 8 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: atilde +Encoding: 227 227 111 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 11 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: adieresis +Encoding: 228 228 112 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 15 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: aring +Encoding: 229 229 113 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +Refer: 161 730 S 1 0 0 1 0 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: egrave +Encoding: 232 232 114 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 130 715 S 1 0 0 1 0 0 2 +Refer: 9 101 N 1 0 0 1 0 0 2 +EndChar + +StartChar: eacute +Encoding: 233 233 115 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 9 101 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ecircumflex +Encoding: 234 234 116 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 137 710 S 1 0 0 1 0 0 2 +Refer: 9 101 N 1 0 0 1 0 0 2 +EndChar + +StartChar: edieresis +Encoding: 235 235 117 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 2 0 2 +Refer: 9 101 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ograve +Encoding: 242 242 118 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +Refer: 130 715 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: oacute +Encoding: 243 243 119 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ocircumflex +Encoding: 244 244 120 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +Refer: 137 710 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: otilde +Encoding: 245 245 121 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: odieresis +Encoding: 246 246 122 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: oslash +Encoding: 248 248 123 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +301.758 470.103 m 0 + 220.795 470.103 144.985 397.575 144.985 267.806 c 0 + 144.985 210.232 159.811 162.64 183.62 127.42 c 1 + 362.111 455.844 l 1 + 342.74 465.435 322.083 470.103 301.758 470.103 c 0 +543.113 262.304 m 0 + 543.113 86.8043 430.326 -14 304.969 -14 c 0 + 267.109 -14 230.757 -4.85803 198.107 11.9174 c 1 + 151 -74 l 1 + 91 -43 l 1 + 142.317 51.4236 l 1 + 90.4093 100.283 56.8677 173.482 56.8677 260.578 c 0 + 56.8677 424.14 172.53 541.005 307.44 541.005 c 0 + 338.595 541.005 369.418 534.573 397.992 521.866 c 1 + 441 601 l 1 + 503 568 l 1 + 456.732 483.613 l 1 + 508.189 437.145 543.113 362.872 543.113 262.304 c 0 +416.343 409.949 m 1 + 234.443 78.1878 l 1 + 256.267 64.9671 280.584 57.9927 305.614 57.9927 c 0 + 382.884 57.9927 459.167 125.6 459.167 258.844 c 0 + 459.167 325.471 442.141 375.404 416.343 409.949 c 1 +EndSplineSet +EndChar + +StartChar: ugrave +Encoding: 249 249 124 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +Refer: 130 715 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uacute +Encoding: 250 250 125 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ucircumflex +Encoding: 251 251 126 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +Refer: 137 710 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: udieresis +Encoding: 252 252 127 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: yacute +Encoding: 253 253 128 +Width: 600 +Flags: HMW +TeX: 121 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 23 121 S 1 0 0 1 0 0 2 +EndChar + +StartChar: ydieresis +Encoding: 255 255 129 +Width: 600 +Flags: HMW +TeX: 121 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 0 0 2 +Refer: 23 121 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uni02CB +Encoding: 259 715 130 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 107 180 S -1 0 0 1 640 0 2 +EndChar + +StartChar: igrave +Encoding: 236 236 131 +Width: 600 +Flags: HMW +TeX: 105 0 +LayerCount: 2 +Fore +Refer: 130 715 S 1 0 0 1 -50 0 2 +Refer: 136 305 N 1 0 0 1 0 0 2 +EndChar + +StartChar: iacute +Encoding: 237 237 132 +Width: 600 +Flags: HMW +TeX: 105 0 +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 136 305 N 1 0 0 1 0 0 2 +EndChar + +StartChar: icircumflex +Encoding: 238 238 133 +Width: 600 +Flags: HMW +TeX: 105 0 +LayerCount: 2 +Fore +Refer: 137 710 S 1 0 0 1 -14 0 2 +Refer: 136 305 N 1 0 0 1 0 0 2 +EndChar + +StartChar: idieresis +Encoding: 239 239 134 +Width: 600 +Flags: HMW +TeX: 105 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -2 0 2 +Refer: 136 305 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ntilde +Encoding: 241 241 135 +Width: 600 +Flags: HMW +TeX: 110 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 -6 0 2 +Refer: 6 110 N 1 0 0 1 0 0 2 +EndChar + +StartChar: dotlessi +Encoding: 272 305 136 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +133 530 m 0 + 345 530 l 0 + 345 67 l 0 + 469 67 l 0 + 469 0 l 0 + 126 0 l 0 + 126 67 l 0 + 261 67 l 0 + 261 462 l 0 + 133 462 l 0 + 133 530 l 0 +EndSplineSet +EndChar + +StartChar: circumflex +Encoding: 261 710 137 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +165 631 m 0 + 294 794 l 0 + 319 794 l 0 + 447 630 l 0 + 393 590 l 0 + 303 709 l 0 + 209 591 l 0 + 165 631 l 0 +EndSplineSet +EndChar + +StartChar: tilde +Encoding: 262 732 138 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +167 646 m 0 + 115 683 l 0 + 157.86 750.837 200.854 783.268 246.029 783.268 c 0 + 292.862 783.268 323.97 749.067 338.861 733.55 c 0 + 357.642 713.979 375.041 696.93 396.658 696.93 c 0 + 425.237 696.93 438.799 723.991 464 758 c 0 + 507 712 l 0 + 466.944 662.14 435.39 629.754 392.65 629.754 c 0 + 325.264 629.754 293.884 717.432 242.844 717.432 c 0 + 212.153 717.432 194.763 690.786 167 646 c 0 +EndSplineSet +EndChar + +StartChar: dieresis +Encoding: 266 168 139 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +257.019 711.498 m 0 + 257.019 679.211 230.789 652.981 198.502 652.981 c 0 + 166.212 652.981 139.981 679.209 139.981 711.499 c 0 + 139.981 743.789 166.21 770.019 198.5 770.019 c 0 + 230.79 770.019 257.019 743.789 257.019 711.498 c 0 +463.002 711.512 m 0 + 463.002 679.168 436.956 652.991 405.005 652.991 c 0 + 373.061 652.991 346.998 679.155 346.998 711.514 c 0 + 346.998 743.862 373.052 770.035 405.008 770.035 c 0 + 436.936 770.035 463.002 743.877 463.002 711.512 c 0 +EndSplineSet +EndChar + +StartChar: scaron +Encoding: 168 353 140 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +Refer: 143 711 S 1 0 0 1 0 0 2 +Refer: 3 115 N 1 0 0 1 0 0 2 +EndChar + +StartChar: zcaron +Encoding: 184 382 141 +Width: 600 +Flags: HMW +TeX: 122 0 +LayerCount: 2 +Fore +Refer: 143 711 S 1 0 0 1 0 0 2 +Refer: 69 122 N 1 0 0 1 0 0 2 +EndChar + +StartChar: periodcentered +Encoding: 183 183 142 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +Refer: 24 46 S 1 0 0 1 0 330 2 +EndChar + +StartChar: caron +Encoding: 271 711 143 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 137 710 S -1 0 0 -1 612 1394 2 +EndChar + +StartChar: germandbls +Encoding: 223 223 144 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +SplineSet +74 0 m 4 + 74 490 l 4 + 74 542.807 74.667 596.235 98.2086 649.711 c 4 + 133.73 730.4 208.298 775.004 287.299 775.004 c 4 + 402.905 775.004 497.21 681.294 497.21 571.108 c 4 + 497.21 504.487 461.9 445.294 405 416 c 4 + 491.891 389.079 548.006 305.6 548.006 209.32 c 4 + 548.006 83.4294 454.191 -12.0295 335.412 -12.0295 c 4 + 292.776 -12.0295 250.921 0.470711 215 24 c 4 + 256 89 l 4 + 278.149 71.5086 305.639 61.9655 334.044 61.9655 c 4 + 407.901 61.9655 471.132 125.491 471.132 209.399 c 4 + 471.132 270.281 438.461 323.526 394.789 350.882 c 4 + 362.072 371.375 330.752 374 293 374 c 4 + 258 374 l 4 + 258 440 l 4 + 291 440 l 4 + 308.302 440 324.828 440.514 344.201 449.183 c 4 + 387.876 468.726 418.115 518.564 418.115 573.125 c 4 + 418.115 649.497 360.647 708.194 291.766 708.194 c 4 + 253.833 708.194 213.869 689.799 186.719 650.367 c 4 + 153.729 602.454 153 543.204 153 492 c 4 + 153 0 l 4 + 74 0 l 4 +EndSplineSet +EndChar + +StartChar: paragraph +Encoding: 182 182 145 +Width: 600 +Flags: HMW +TeX: 112 0 +LayerCount: 2 +Fore +SplineSet +515 771 m 0 + 515 -79 l 0 + 448 -79 l 0 + 448 705 l 0 + 360 705 l 0 + 360 -79 l 0 + 291 -79 l 0 + 291 373 l 0 + 173.556 380.691 83.9422 470.146 83.9422 574.545 c 0 + 83.9422 645.65 125.968 713.383 202.879 746.684 c 0 + 258.505 770.77 316.231 771 370 771 c 0 + 515 771 l 0 +EndSplineSet +EndChar + +StartChar: section +Encoding: 167 167 146 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +SplineSet +488 676 m 1 + 423 618 l 1 + 414.502 624.421 416.792 633.708 413.888 641.763 c 0 + 404.459 667.917 369.872 709.915 308.352 709.915 c 0 + 247.31 709.915 202.994 669.159 202.994 620.922 c 0 + 202.994 597.432 213.725 561.524 264.348 534.753 c 0 + 297.607 517.164 341.067 507.397 387.737 485.112 c 0 + 468.614 446.493 494.176 395.665 494.176 353.922 c 0 + 494.176 305.481 458.969 262.529 408.539 241.879 c 1 + 459.313 207.384 483.175 156.542 483.175 107.276 c 0 + 483.175 16.9904 402.922 -63.0207 285.774 -63.0207 c 0 + 208.624 -63.0207 133.499 -27.5045 85 36 c 1 + 146 107 l 1 + 154.994 103.32 153.114 93.2219 155.624 86.7075 c 0 + 159.14 77.5825 198.684 13.7598 286.023 13.7598 c 0 + 356.942 13.7598 400.23 57.0391 400.23 105.026 c 0 + 400.23 132.111 386.388 163.982 346.982 187.299 c 0 + 298.949 215.721 233.162 219.874 175.365 254.027 c 0 + 123.913 284.431 101.679 326.186 101.679 366.086 c 0 + 101.679 418.429 140.913 463.115 196.205 482.822 c 1 + 140.944 517.145 118.9 567.71 118.9 613.632 c 0 + 118.9 701.981 199.381 778.269 307.936 778.269 c 0 + 384.595 778.269 452.277 738.832 488 676 c 1 +238.744 461.796 m 1 + 207.924 451.724 185.96 423.141 185.96 389.457 c 0 + 185.96 363.602 199.372 327.898 248.47 303.876 c 0 + 283.42 286.776 323.54 281.479 365.239 264.586 c 1 + 390.576 277.358 407.453 303.587 407.453 333.72 c 0 + 407.453 360.138 394.181 398.165 340.303 424.753 c 0 + 310.54 439.44 274.629 447.456 238.744 461.796 c 1 +EndSplineSet +EndChar + +StartChar: copyright +Encoding: 169 169 147 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +SplineSet +313.62 491.091 m 0 + 386.544 491.091 443.024 445.507 458 384 c 0 + 398 361 l 0 + 391.517 368.856 395.372 377.023 393.506 384.631 c 0 + 391.425 393.116 373.381 433.152 316.115 433.152 c 0 + 261.422 433.152 207.997 399.047 207.997 326.991 c 0 + 207.997 256.911 256.399 201.947 317.234 201.947 c 0 + 353.531 201.947 386.837 222.046 404 254 c 0 + 455 220 l 0 + 422.956 171.427 369.074 140.974 312.13 140.974 c 0 + 217.884 140.974 142.846 222.734 142.846 319.43 c 0 + 142.846 418.338 220.235 491.091 313.62 491.091 c 0 +306.307 21.8879 m 0 + 152.945 21.8879 25.7487 152.286 25.7487 317.375 c 0 + 25.7487 483.34 153.371 614.02 306.766 614.02 c 0 + 459.736 614.02 587.017 483.767 587.017 318.262 c 0 + 587.017 152.432 459.471 21.8879 306.307 21.8879 c 0 +78.726 317.799 m 0 + 78.726 179.711 182.936 71.9098 307.826 71.9098 c 0 + 432.331 71.9098 537.005 179.647 537.005 318.685 c 0 + 537.005 457.352 432.659 565 308.142 565 c 0 + 183.437 565 78.726 457.059 78.726 317.799 c 0 +EndSplineSet +EndChar + +StartChar: registered +Encoding: 174 174 148 +Width: 600 +Flags: HMW +TeX: 114 0 +LayerCount: 2 +Fore +SplineSet +306.307 21.8879 m 4 + 152.945 21.8879 25.7487 152.286 25.7487 317.375 c 4 + 25.7487 483.34 153.371 614.02 306.766 614.02 c 4 + 459.736 614.02 587.017 483.767 587.017 318.262 c 4 + 587.017 152.432 459.471 21.8879 306.307 21.8879 c 4 +78.726 317.799 m 4 + 78.726 179.711 182.936 71.9098 307.826 71.9098 c 4 + 432.331 71.9098 537.005 179.647 537.005 318.685 c 4 + 537.005 457.352 432.659 565 308.142 565 c 4 + 183.437 565 78.726 457.059 78.726 317.799 c 4 +190 154 m 4 + 190 492 l 4 + 299 492 l 4 + 324.843 492 351.991 491.821 378.649 480.542 c 4 + 417.745 464 439 429.492 439 393.729 c 4 + 439 352.65 411.132 316.256 371 305 c 4 + 446 160 l 4 + 391 152 l 4 + 319 297 l 4 + 243 297 l 4 + 243 154 l 4 + 190 154 l 4 +243 445 m 4 + 243 343 l 4 + 303 343 l 4 + 322.021 343 344.797 342.906 363.189 354.544 c 4 + 378.83 364.441 386.001 379.476 386.001 393.691 c 4 + 386.001 408.753 377.925 424.775 360.288 434.695 c 4 + 341.595 445.21 319.037 445 300 445 c 4 + 243 445 l 4 +EndSplineSet +EndChar + +StartChar: uni00B9 +Encoding: 185 185 149 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +356 733 m 0 + 356 293 l 0 + 282 293 l 0 + 282 641 l 0 + 170 612 l 0 + 151 648 l 0 + 306 733 l 0 + 356 733 l 0 +EndSplineSet +EndChar + +StartChar: guilsinglleft +Encoding: 273 8249 150 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +178 293 m 0 + 354 464 l 0 + 399 416 l 0 + 259 279 l 0 + 407 117 l 0 + 361 71 l 0 + 178 266 l 0 + 178 293 l 0 +EndSplineSet +EndChar + +StartChar: guillemotleft +Encoding: 171 171 151 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +Refer: 150 8249 S 1 0 0 1 120 0 2 +Refer: 150 8249 S 1 0 0 1 -90 0 2 +EndChar + +StartChar: guilsinglright +Encoding: 274 8250 152 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 150 8249 N -1 0 0 1 585 0 2 +EndChar + +StartChar: guillemotright +Encoding: 187 187 153 +Width: 600 +Flags: HMW +TeX: 103 0 +LayerCount: 2 +Fore +Refer: 151 171 N -1 0 0 1 615 0 2 +EndChar + +StartChar: logicalnot +Encoding: 172 172 154 +Width: 600 +Flags: HMW +TeX: 108 0 +LayerCount: 2 +Fore +SplineSet +116 402 m 0 + 490 402 l 0 + 490 182 l 0 + 416 182 l 0 + 416 329 l 0 + 116 329 l 0 + 116 402 l 0 +EndSplineSet +EndChar + +StartChar: softhyphen +Encoding: 173 173 155 +Width: 600 +Flags: HMW +TeX: 115 0 +LayerCount: 2 +Fore +Refer: 60 45 N 1 0 0 1 0 0 2 +EndChar + +StartChar: degree +Encoding: 176 176 156 +Width: 600 +Flags: HMW +TeX: 100 0 +LayerCount: 2 +Fore +SplineSet +463.001 584.452 m 0 + 463.001 498.746 392.958 428.902 306.439 428.902 c 0 + 219.963 428.902 149.901 498.735 149.901 584.477 c 0 + 149.901 670.167 219.932 740.008 306.436 740.008 c 0 + 392.955 740.008 463.001 670.157 463.001 584.452 c 0 +307.636 679.001 m 0 + 260.52 679.001 220.977 638.292 220.977 585.822 c 0 + 220.977 533.609 260.369 492.878 307.592 492.878 c 0 + 354.564 492.878 394.083 533.556 394.083 586.131 c 0 + 394.083 638.327 354.712 679.001 307.636 679.001 c 0 +EndSplineSet +EndChar + +StartChar: uni00B2 +Encoding: 178 178 157 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +139 642 m 0 + 173.775 702.486 238.827 738.288 309.097 738.288 c 0 + 401.336 738.288 464.001 678.771 464.001 608.561 c 0 + 464.001 553.7 426.301 516.004 409.841 500.834 c 0 + 363.816 458.417 299.741 428.352 235 356 c 0 + 446 356 l 0 + 451.284 356 453.692 356.741 458.392 360.794 c 0 + 460.8 362.871 466.479 368.496 474 366 c 0 + 474 293 l 0 + 150 293 l 0 + 150 344 l 0 + 214.555 433.275 299.669 489.778 334.371 517.996 c 0 + 367.994 545.338 394.114 573.311 394.114 608.166 c 0 + 394.114 644.932 362.276 678.917 306.876 678.917 c 0 + 262.373 678.917 224.551 655.762 204.174 629.982 c 0 + 197.924 622.076 198.745 616.904 193 606 c 0 + 139 642 l 0 +EndSplineSet +EndChar + +StartChar: eth +Encoding: 240 240 158 +Width: 600 +Flags: HMW +TeX: 101 0 +LayerCount: 2 +Fore +SplineSet +305.228 470.011 m 0 + 226.957 470.011 144.996 405.543 144.996 269.224 c 0 + 144.996 134.476 222.952 57.9969 306.097 57.9969 c 0 + 371.358 57.9969 459.002 107.826 459.002 268.758 c 0 + 459.002 429.627 365.393 470.011 305.228 470.011 c 0 +411.85 660.892 m 1 + 482.806 580.388 543.317 462.269 543.317 293.321 c 0 + 543.317 230.904 536.102 156.905 498.489 94.5252 c 0 + 455.932 23.9469 383.677 -14.0061 306.684 -14.0061 c 0 + 172.735 -14.0061 56.7783 98.7597 56.7783 258.02 c 0 + 56.7783 417.046 169.434 541.31 298.018 541.31 c 0 + 351.944 541.31 401.981 518.882 437 481 c 1 + 413.678 540.162 379.782 593.873 337.517 639.819 c 1 + 190 598 l 1 + 169 653 l 1 + 289.257 685.865 l 1 + 253.708 715.612 213.989 740.637 171 760 c 1 + 265 779 l 1 + 294.809 762.216 330.445 738.683 366.105 706.867 c 1 + 491 741 l 1 + 511 689 l 1 + 411.85 660.892 l 1 +EndSplineSet +EndChar + +StartChar: Eth +Encoding: 208 208 159 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +SplineSet +101 722 m 0 + 263 722 l 0 + 325.631 722 375.745 716.402 426.079 679.13 c 0 + 512.98 614.782 550.114 487.96 550.114 365.114 c 0 + 550.114 211.219 490.967 72.9828 379.857 21.249 c 0 + 338.865 2.16283 300.228 -1 249 -1 c 0 + 101 -1 l 0 + 101 722 l 0 +176 654 m 0 + 176 66 l 0 + 245 66 l 0 + 286.258 66 324.723 68.2387 365.552 95.7969 c 0 + 435.377 142.927 472.256 240.81 472.256 355.09 c 0 + 472.256 435.567 454.827 524.974 411.342 584.517 c 0 + 362.022 652.05 302.634 654 258 654 c 0 + 176 654 l 0 +45 416 m 0 + 297 416 l 0 + 297 349 l 0 + 45 349 l 0 + 45 416 l 0 +EndSplineSet +EndChar + +StartChar: Thorn +Encoding: 222 222 160 +Width: 600 +Flags: HMW +TeX: 84 0 +LayerCount: 2 +Fore +SplineSet +78 722 m 0 + 169 722 l 0 + 169.521 720.466 169.785 718.85 169.785 717.216 c 0 + 169.785 710.792 165.82 706.356 163.318 702.38 c 0 + 160.184 697.398 160 694.17 160 690 c 0 + 160 586 l 0 + 298 586 l 0 + 344.584 586 389.359 584.805 434.624 561.494 c 0 + 502.828 526.371 538.016 455.718 538.016 382.699 c 0 + 538.016 309.503 502.883 240.352 436.114 206.409 c 0 + 392.262 184.116 348.977 183 304 183 c 0 + 160 183 l 0 + 160 0 l 0 + 78 0 l 0 + 78 722 l 0 +160 510 m 0 + 160 254 l 0 + 307 254 l 0 + 335.466 254 362.993 254.678 390.831 268.763 c 0 + 432.659 289.926 455.003 332.944 455.003 378.986 c 0 + 455.003 425.985 431.629 471.921 386.619 494.5 c 0 + 357.19 509.263 328.165 510 298 510 c 0 + 160 510 l 0 +EndSplineSet +EndChar + +StartChar: ring +Encoding: 268 730 161 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +413.005 700.997 m 0 + 413.005 645.145 366.039 598.958 306.924 598.958 c 0 + 247.95 598.958 200.921 645.101 200.921 701.065 c 0 + 200.921 756.856 247.86 803.005 306.911 803.005 c 0 + 366.013 803.005 413.005 756.837 413.005 700.997 c 0 +259.914 701.774 m 0 + 259.914 672.11 281.627 648.896 307.995 648.896 c 0 + 334.032 648.896 356.035 671.837 356.035 702.068 c 0 + 356.035 731.828 334.332 755.012 308.022 755.012 c 0 + 282 755.012 259.914 732.072 259.914 701.774 c 0 +EndSplineSet +EndChar + +StartChar: Aring +Encoding: 197 197 162 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 161 730 S 1 0 0 1 -19 118 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Agrave +Encoding: 192 192 163 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 195 -1 S 1 0 0 1 -30 138 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Aacute +Encoding: 193 193 164 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Acircumflex +Encoding: 194 194 165 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 190 -1 N 1 0 0 1 -14 143 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Atilde +Encoding: 195 195 166 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 -5 146 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Adieresis +Encoding: 196 196 167 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -13 144 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Egrave +Encoding: 200 200 168 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +Refer: 195 -1 S 1 0 0 1 -30 138 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Eacute +Encoding: 201 201 169 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 0 138 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ecircumflex +Encoding: 202 202 170 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +Refer: 190 -1 S 1 0 0 1 -4 143 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Edieresis +Encoding: 203 203 171 +Width: 600 +Flags: HMW +TeX: 69 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -5 144 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Igrave +Encoding: 204 204 172 +Width: 600 +Flags: HMW +TeX: 73 0 +LayerCount: 2 +Fore +Refer: 195 -1 S 1 0 0 1 -30 138 2 +Refer: 4 73 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Iacute +Encoding: 205 205 173 +Width: 600 +Flags: HMW +TeX: 73 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 0 138 2 +Refer: 4 73 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Icircumflex +Encoding: 206 206 174 +Width: 600 +Flags: HMW +TeX: 73 0 +LayerCount: 2 +Fore +Refer: 190 -1 S 1 0 0 1 -15 143 2 +Refer: 4 73 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Idieresis +Encoding: 207 207 175 +Width: 600 +Flags: HMW +TeX: 73 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -9 144 2 +Refer: 4 73 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ograve +Encoding: 210 210 176 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +Refer: 195 -1 S 1 0 0 1 -30 138 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Oacute +Encoding: 211 211 177 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 0 138 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ocircumflex +Encoding: 212 212 178 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +Refer: 190 -1 S 1 0 0 1 -1 143 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Otilde +Encoding: 213 213 179 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 0 146 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Odieresis +Encoding: 214 214 180 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -5 144 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ugrave +Encoding: 217 217 181 +Width: 600 +Flags: HMW +TeX: 85 0 +LayerCount: 2 +Fore +Refer: 195 -1 S 1 0 0 1 -30 138 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Uacute +Encoding: 218 218 182 +Width: 600 +Flags: HMW +TeX: 85 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 0 138 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ucircumflex +Encoding: 219 219 183 +Width: 600 +Flags: HMW +TeX: 85 0 +LayerCount: 2 +Fore +Refer: 190 -1 S 1 0 0 1 -1 143 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Udieresis +Encoding: 220 220 184 +Width: 600 +Flags: HMW +TeX: 85 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 5 144 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Yacute +Encoding: 221 221 185 +Width: 600 +Flags: HMW +TeX: 89 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 0 138 2 +Refer: 94 89 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Scaron +Encoding: 166 352 186 +Width: 600 +Flags: HMW +TeX: 83 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 14 143 2 +Refer: 50 83 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Zcaron +Encoding: 180 381 187 +Width: 600 +Flags: HMW +TeX: 90 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 8 143 2 +Refer: 96 90 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ntilde +Encoding: 209 209 188 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 138 732 S 1 0 0 1 0 146 2 +Refer: 46 78 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ydieresis +Encoding: 190 376 189 +Width: 600 +Flags: HMW +TeX: 89 0 +LayerCount: 2 +Fore +Refer: 139 168 S 1 0 0 1 -5 144 2 +Refer: 94 89 N 1 0 0 1 0 0 2 +EndChar + +StartChar: circumflex.cap +Encoding: 275 -1 190 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +142 659 m 0 + 294 774 l 0 + 319 774 l 0 + 462 661 l 0 + 424 617 l 0 + 304 699 l 0 + 175 620 l 0 + 142 659 l 0 +EndSplineSet +EndChar + +StartChar: caron.cap +Encoding: 276 -1 191 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 190 -1 N -1 0 0 -1 604 1391 2 +EndChar + +StartChar: ae +Encoding: 230 230 192 +Width: 600 +Flags: HMW +TeX: 97 0 +LayerCount: 2 +Fore +SplineSet +46 477 m 0 + 78.8401 518.176 128.534 541.042 179.797 541.042 c 0 + 236.11 541.042 284.02 513.302 309 469 c 0 + 334.856 513.703 382.031 541.063 431.036 541.063 c 0 + 472.731 541.063 518.654 520.729 547.495 473.472 c 0 + 578.346 422.921 578 363.164 578 311 c 0 + 578 267 l 0 + 337 257 l 0 + 337 203 l 0 + 337 175.493 338.021 151.766 349.064 126.614 c 0 + 368.654 81.9912 411.522 54.9866 456.731 54.9866 c 0 + 490.681 54.9866 522.098 70.3702 542 97 c 0 + 583 49 l 0 + 550.251 9.72841 501.736 -13.0005 450.565 -13.0005 c 0 + 391.56 -13.0005 336.63 17.1888 305 67 c 0 + 280.108 17.8701 229.631 -13.1551 174.237 -13.1551 c 0 + 90.7707 -13.1551 21.8352 56.2141 21.8352 143.282 c 0 + 21.8352 202.576 54.9902 266.973 127.653 299.766 c 0 + 170.84 319.256 212.144 320.928 240 322 c 0 + 266 323 l 0 + 266 353 l 0 + 266 374.299 265.203 393.531 258.429 412.515 c 0 + 244.402 451.823 210.556 476.08 174.377 476.08 c 0 + 141.829 476.08 108.382 456.741 87 426 c 0 + 46 477 l 0 +266 254 m 0 + 241 253 l 0 + 211.382 251.816 180.822 251.083 151.425 236.018 c 0 + 113.557 216.612 95.9804 181.173 95.9804 148.063 c 0 + 95.9804 97.6227 135.259 57.9703 182.206 57.9703 c 0 + 213.618 57.9703 245.532 76.2592 258.599 111.796 c 0 + 268.711 139.296 266 169.723 266 210 c 0 + 266 254 l 0 +337 323 m 0 + 511 330 l 0 + 511 353 l 0 + 511 376.887 510.557 401.019 500.259 424.945 c 0 + 486.37 457.213 459.423 476.188 430.019 476.188 c 0 + 401.442 476.188 375.8 458.055 358.925 432.777 c 0 + 338.424 402.068 337 371.27 337 343 c 0 + 337 323 l 0 +EndSplineSet +EndChar + +StartChar: oe +Encoding: 189 339 193 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +197.072 540.057 m 0 + 240.284 540.057 279.952 520.667 305 487 c 0 + 334.471 520.96 377.351 540.072 422.223 540.072 c 0 + 475.912 540.072 535.759 511.906 562.005 440.15 c 0 + 580.682 389.088 578 326.96 578 269 c 0 + 578 256 l 0 + 314 256 l 0 + 314.609 182.929 318.122 148.32 330.688 119.841 c 0 + 351.232 73.2809 394.067 53.9506 437.272 53.9506 c 0 + 470.728 53.9506 512.336 65.2296 542 99 c 0 + 583 49 l 0 + 544.141 8.97946 490.715 -13.6292 434.895 -13.6292 c 0 + 386.721 -13.6292 340.059 3.2209 303 34 c 0 + 271.715 5.40179 230.291 -13.0256 188.332 -13.0256 c 0 + 142.262 -13.0256 83.7901 10.4289 49.2458 81.4235 c 0 + 21.2947 138.868 16.9924 213.135 16.9924 274.024 c 0 + 16.9924 327.287 21.0077 390.061 49.5869 444.004 c 0 + 83.9791 508.918 142.432 540.057 197.072 540.057 c 0 +315 322 m 0 + 509 322 l 0 + 509 332 l 0 + 509 366.277 509.724 402.65 491.454 433.147 c 0 + 473.764 462.676 442.71 476.791 412.738 476.791 c 0 + 382.558 476.791 345.109 462.072 327.261 414.077 c 0 + 324.697 407.181 313.856 377.196 315 322 c 0 +86.9292 285.092 m 0 + 86.9292 245.957 89.3121 188.587 103.747 142.737 c 0 + 123.421 80.2444 163.532 57.8299 198.359 57.8299 c 0 + 227.31 57.8299 256.518 74.2456 256.518 103.197 c 0 + 256.518 118.213 241.952 172.81 241.952 273.514 c 0 + 241.952 359.739 252.376 403.185 252.376 419.746 c 0 + 252.376 450.246 226.518 470.076 196.284 470.076 c 0 + 163.481 470.076 128.259 447.486 107.574 402.839 c 0 + 89.1704 363.117 86.9292 317.746 86.9292 285.092 c 0 +EndSplineSet +EndChar + +StartChar: acute.cap +Encoding: 278 -1 194 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +387 779 m 0 + 433 698 l 0 + 237 627 l 0 + 210 675 l 0 + 387 779 l 0 +EndSplineSet +EndChar + +StartChar: grave.cap +Encoding: 277 -1 195 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 N -1 0 0 1 637 0 2 +EndChar + +StartChar: ordfeminine +Encoding: 170 170 196 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +152 656 m 0 + 193.633 703.845 253.099 721.283 307.799 721.283 c 0 + 370.636 721.283 423.692 696.264 447.562 644.964 c 0 + 459.785 618.695 461 592.461 461 562 c 0 + 461 309 l 0 + 388 309 l 0 + 388 348 l 0 + 353.62 315.567 309.294 297.999 264.37 297.999 c 0 + 184.05 297.999 127.995 354.534 127.995 418.965 c 0 + 127.995 457.362 148.672 500.379 196.972 526.099 c 0 + 248.841 553.719 312.645 551 370 551 c 0 + 387 551 l 0 + 387 565 l 0 + 387 584.588 386.635 605.218 374.201 624.596 c 0 + 361.1 645.014 336.794 659.022 300.518 659.022 c 0 + 260.387 659.022 218.034 643.693 192 608 c 0 + 152 656 l 0 +390 491 m 0 + 371 491 l 0 + 340.994 491 302.242 493.162 271.69 487.742 c 0 + 220.555 478.672 202.865 447.25 202.865 422.155 c 0 + 202.865 389.707 231.214 360.688 275.85 360.688 c 0 + 311.446 360.688 343.688 377.899 364.269 397.046 c 0 + 389.322 420.354 390 444.06 390 471 c 0 + 390 491 l 0 +98 239 m 0 + 503 239 l 0 + 503 176 l 0 + 98 176 l 0 + 98 239 l 0 +EndSplineSet +EndChar + +StartChar: ordmasculine +Encoding: 186 186 197 +Width: 600 +Flags: HMW +TeX: 111 0 +LayerCount: 2 +Fore +SplineSet +301.826 721.011 m 0 + 385.223 721.011 470.107 653.808 470.107 514.756 c 0 + 470.107 364.793 379.364 296.94 294.598 296.94 c 0 + 202.824 296.94 120.827 374.446 120.827 500.869 c 0 + 120.827 633.779 205.502 721.011 301.826 721.011 c 0 +190.986 506.214 m 0 + 190.986 409.196 244.9 363.925 296.394 363.925 c 0 + 345.93 363.925 401 406.473 401 506.207 c 0 + 401 605.509 349.544 656 296.205 656 c 0 + 243.333 656 190.986 606.057 190.986 506.214 c 0 +98 239 m 0 + 503 239 l 0 + 503 176 l 0 + 98 176 l 0 + 98 239 l 0 +EndSplineSet +EndChar + +StartChar: uni02C9 +Encoding: 263 713 198 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +153 720 m 0 + 447 720 l 0 + 447 655 l 0 + 153 655 l 0 + 153 720 l 0 +EndSplineSet +EndChar + +StartChar: macron +Encoding: 175 175 199 +Width: 600 +Flags: HMW +TeX: 109 0 +LayerCount: 2 +Fore +Refer: 198 713 N 1 0 0 1 0 0 2 +EndChar + +StartChar: omacron +Encoding: 279 333 200 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 198 713 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: cedilla +Encoding: 269 184 201 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +313 0 m 0 + 363 0 l 0 + 357 -55 l 0 + 376 -56 l 0 + 390.785 -56.7788 405.994 -57.7164 420.883 -64.9414 c 0 + 442.973 -75.6606 455.07 -96.4917 455.07 -118.956 c 0 + 455.07 -160.352 414.433 -205.092 329.389 -205.092 c 0 + 284.871 -205.092 235.296 -192.447 192 -162 c 0 + 221 -114 l 0 + 257.397 -143.353 301.031 -155.011 336.064 -155.011 c 0 + 381.118 -155.011 389.002 -136.826 389.002 -126.739 c 0 + 389.002 -119.915 385.46 -112.176 376.38 -106.611 c 0 + 363.902 -98.9638 347.2 -99 334 -99 c 0 + 300 -99 l 0 + 313 0 l 0 +EndSplineSet +EndChar + +StartChar: ccedilla +Encoding: 231 231 202 +Width: 600 +Flags: HMW +TeX: 99 0 +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 0 0 2 +Refer: 1 99 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ccedilla +Encoding: 199 199 203 +Width: 600 +Flags: HMW +TeX: 67 0 +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 0 0 2 +Refer: 72 67 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uni00B3 +Encoding: 179 179 204 +Width: 600 +Flags: HMW +TeX: 117 0 +LayerCount: 2 +Fore +SplineSet +308.545 739.11 m 0 + 394.884 739.11 460.209 681.247 460.209 614.55 c 0 + 460.209 572.151 433.428 536.235 395 524 c 0 + 444.061 515.328 480.001 473.423 480.001 424.669 c 0 + 480.001 348.943 397.312 290.99 304.904 290.99 c 0 + 241.699 290.99 181.599 318.471 140 366 c 0 + 194 426 l 0 + 204.212 415.153 199.361 404.247 210.154 393.714 c 0 + 216.257 387.757 251.225 355.987 306.079 355.987 c 0 + 362.89 355.987 408.454 389.769 408.454 431.009 c 0 + 408.454 452.324 395.326 495.101 306.637 495.101 c 0 + 294.627 495.101 283.183 494.368 272 493 c 0 + 272 551 l 0 + 279.636 550.27 287.301 549.894 294.972 549.894 c 0 + 370.889 549.894 391.54 582.897 391.54 609.502 c 0 + 391.54 644.172 357.159 678.038 305.041 678.038 c 0 + 265.85 678.038 224.827 658.777 197 624 c 0 + 155 667 l 0 + 193.931 713.015 250.216 739.11 308.545 739.11 c 0 +EndSplineSet +EndChar + +StartChar: divide +Encoding: 247 247 205 +Width: 600 +Flags: HMW +TeX: 100 0 +LayerCount: 2 +Fore +SplineSet +92 403 m 0 + 509 403 l 0 + 509 326 l 0 + 92 326 l 0 + 92 403 l 0 +358 540.992 m 0 + 358 512.297 334.695 488.972 305.98 488.972 c 0 + 277.279 488.972 253.962 512.289 253.962 540.99 c 0 + 253.962 569.692 277.277 593.01 305.98 593.01 c 0 + 334.693 593.01 358 569.686 358 540.992 c 0 +358.01 183.993 m 0 + 358.01 155.275 334.682 131.943 305.964 131.943 c 0 + 277.243 131.943 253.913 155.271 253.913 183.992 c 0 + 253.913 212.712 277.242 236.04 305.963 236.04 c 0 + 334.68 236.04 358.01 212.71 358.01 183.993 c 0 +EndSplineSet +EndChar + +StartChar: Oslash +Encoding: 216 216 206 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +SplineSet +300.361 654.01 m 0 + 224.496 654.01 123.971 587.911 123.971 372.659 c 0 + 123.971 281.791 139.578 215.128 163.473 167.742 c 1 + 399.758 612.324 l 1 + 368.854 641.994 332.534 654.01 300.361 654.01 c 0 +556.008 359.504 m 0 + 556.008 296.095 551.428 206.273 513.069 128.645 c 0 + 465.538 32.4568 382.426 -11.0151 304.485 -11.0151 c 0 + 261.834 -11.0151 213.304 2.30387 169.786 34.9718 c 1 + 112 -73 l 1 + 52 -42 l 1 + 119.616 85.2228 l 1 + 75.1957 143.737 43.9996 232.717 43.9996 362.113 c 0 + 43.9996 645.884 196.081 730 303.761 730 c 0 + 349.84 730 397.121 715.105 437.897 684.085 c 1 + 491 784 l 1 + 553 751 l 1 + 488.971 631.363 l 1 + 497.238 619.916 504.885 607.435 511.792 593.902 c 0 + 551.172 516.748 556.008 427.05 556.008 359.504 c 0 +443.911 547.169 m 1 + 208.342 107.012 l 1 + 238.634 79.4207 273.138 67.987 304.834 67.987 c 0 + 353.415 67.987 409.354 95.4457 442.765 165.717 c 0 + 472.354 227.951 475.085 301.614 475.085 348.897 c 0 + 475.085 410.01 471.386 479.154 446.984 539.849 c 2 + 443.911 547.169 l 1 +EndSplineSet +EndChar + +StartChar: multiply +Encoding: 215 215 207 +Width: 600 +Flags: HMW +TeX: 109 0 +LayerCount: 2 +Fore +SplineSet +453 583 m 1 + 508 532 l 1 + 357.683 376.932 l 1 + 505 221 l 1 + 451 168 l 1 + 304.762 322.338 l 1 + 160 173 l 1 + 108 224 l 1 + 253.994 375.919 l 1 + 108 530 l 1 + 163 583 l 1 + 306.764 430.829 l 1 + 453 583 l 1 +EndSplineSet +EndChar + +StartChar: AE +Encoding: 198 198 208 +Width: 600 +Flags: HMW +TeX: 65 0 +LayerCount: 2 +Fore +SplineSet +242 723 m 0 + 571 723 l 0 + 571 651 l 0 + 370 651 l 0 + 372 414 l 0 + 541 414 l 0 + 541 340 l 0 + 373 340 l 0 + 375 72 l 0 + 568 72 l 0 + 568 0 l 0 + 302 0 l 0 + 302 196 l 0 + 151 196 l 0 + 89 0 l 0 + 15 0 l 0 + 242 723 l 0 +302 651 m 0 + 289 651 l 0 + 168 263 l 0 + 302 263 l 0 + 302 651 l 0 +EndSplineSet +EndChar + +StartChar: OE +Encoding: 188 338 209 +Width: 600 +Flags: HMW +TeX: 79 0 +LayerCount: 2 +Fore +SplineSet +303 690 m 0 + 303 723 l 0 + 571 723 l 0 + 571 651 l 0 + 375 651 l 0 + 375 414 l 0 + 541 414 l 0 + 541 340 l 0 + 375 340 l 0 + 375 72 l 0 + 568 72 l 0 + 568 0 l 0 + 302 0 l 0 + 302 36 l 0 + 278.697 7.88689 244.099 -8.08716 207.296 -8.08716 c 0 + 150.139 -8.08716 80.2583 30.5805 47.0562 139.126 c 0 + 42.7406 153.235 20.7902 225.823 20.7902 361.821 c 0 + 20.7902 459.095 28.5992 542.924 59.6634 615.563 c 0 + 98.0648 705.359 160.916 732.002 207.762 732.002 c 0 + 243.981 732.002 278.474 716.617 303 690 c 0 +94.9751 375.779 m 0 + 94.9751 343.461 94.9497 221.604 127.295 142.578 c 0 + 153.346 78.9291 191.363 62.9836 217.46 62.9836 c 0 + 257.506 62.9836 290.624 98.6049 302 150 c 0 + 302 562 l 0 + 289.634 601.236 259.887 665.004 207.671 665.004 c 0 + 173.506 665.004 138.571 636.141 117.537 573.058 c 0 + 110.441 551.779 94.9751 498.335 94.9751 375.779 c 0 +EndSplineSet +EndChar + +StartChar: currency +Encoding: 280 164 210 +Width: 600 +Flags: HMWO +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +300.7 516.248 m 0 + 236.708 516.248 184.352 463.893 184.352 399.9 c 0 + 184.352 335.907 236.708 283.553 300.7 283.553 c 0 + 364.693 283.553 417.049 335.907 417.049 399.9 c 0 + 417.049 463.893 364.693 516.248 300.7 516.248 c 0 +88.9004 569.9 m 1 + 130.1 611.1 l 1 + 195.483 545.717 l 1 + 225.127 567.202 261.503 579.9 300.7 579.9 c 0 + 339.284 579.9 375.133 567.597 404.52 546.719 c 1 + 468.9 611.1 l 1 + 510.1 569.9 l 1 + 446.011 505.811 l 1 + 467.803 476.042 480.7 439.404 480.7 399.9 c 0 + 480.7 360.703 468.002 324.327 446.517 294.683 c 1 + 510.1 231.1 l 1 + 468.9 189.9 l 1 + 405.22 253.58 l 1 + 375.704 232.4 339.591 219.9 300.7 219.9 c 0 + 261.196 219.9 224.558 232.797 194.789 254.589 c 1 + 130.1 189.9 l 1 + 88.9004 231.1 l 1 + 153.881 296.08 l 1 + 133.003 325.467 120.7 361.316 120.7 399.9 c 0 + 120.7 438.791 133.2 474.904 154.38 504.42 c 1 + 88.9004 569.9 l 1 +EndSplineSet +EndChar + +StartChar: brokenbar +Encoding: 281 166 211 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +261 756 m 0 + 339 756 l 0 + 339 342 l 0 + 261 342 l 0 + 261 756 l 0 +339 -175 m 0 + 261 -175 l 0 + 261 227 l 0 + 339 227 l 0 + 339 -175 l 0 +EndSplineSet +EndChar + +StartChar: onehalf +Encoding: 283 189 212 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 274 8260 S 1 0 0 1 0 0 2 +Refer: 157 178 N 0.8 0 0 0.8 201.3 -318.872 2 +Refer: 149 185 N 0.8 0 0 0.8 -107.4 198.6 2 +EndChar + +StartChar: nonbreakingspace +Encoding: 160 160 213 +Width: 600 +Flags: HMW +TeX: 110 0 +LayerCount: 2 +EndChar + +StartChar: ogonek +Encoding: 270 731 214 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +422 0 m 0 + 499 0 l 0 + 460.042 -34.9926 431.396 -66.5962 421.556 -77.7406 c 0 + 413.412 -86.9647 402.048 -100.705 402.048 -117.842 c 0 + 402.048 -135.64 414.849 -150.797 435.947 -150.797 c 0 + 443.138 -150.797 451.677 -149.114 463.857 -144.679 c 0 + 481.957 -138.087 493.634 -130.111 501 -124 c 0 + 501 -177 l 0 + 478.28 -196.689 449.7 -204.002 420.9 -204.002 c 0 + 360.858 -204.002 330.051 -171.745 330.051 -133.094 c 0 + 330.051 -95.7614 361.962 -49.529 422 0 c 0 +EndSplineSet +EndChar + +StartChar: Aogonek +Encoding: 285 260 215 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 214 731 S 1 0 0 1 72 0 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Lcaron +Encoding: 287 317 216 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 56 8217 S 0.8 0 0 0.8 206.515 136.393 2 +Refer: 52 76 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Sacute +Encoding: 288 346 217 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 50 83 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Scedilla +Encoding: 289 350 218 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 -37 0 2 +Refer: 50 83 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Tcaron +Encoding: 290 356 219 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 8 143 2 +Refer: 59 84 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Zacute +Encoding: 291 377 220 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 96 90 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Zdotaccent +Encoding: 292 379 221 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 222 729 S 1 0 0 1 0 147 2 +Refer: 96 90 N 1 0 0 1 0 0 2 +EndChar + +StartChar: dotaccent +Encoding: 265 729 222 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +SplineSet +305.003 760 m 0 + 338.171 760 365.019 733.28 365.019 700.493 c 0 + 365.019 667.727 338.182 640.992 304.99 640.992 c 0 + 271.818 640.992 244.981 667.716 244.981 700.486 c 0 + 244.981 733.264 271.822 760 305.003 760 c 0 +EndSplineSet +EndChar + +StartChar: Racute +Encoding: 293 340 223 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 101 82 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Abreve +Encoding: 294 258 224 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 241 728 S 1 0 0 1 -11 160 2 +Refer: 71 65 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Lacute +Encoding: 295 313 225 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 52 76 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Cacute +Encoding: 296 262 226 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 72 67 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ccaron +Encoding: 297 268 227 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 27 143 2 +Refer: 72 67 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Eogonek +Encoding: 298 280 228 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 214 731 S 1 0 0 1 17 0 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ecaron +Encoding: 299 282 229 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 8 143 2 +Refer: 80 69 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Dcaron +Encoding: 300 270 230 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 -22 143 2 +Refer: 79 68 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Dcroat +Encoding: 301 272 231 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 159 208 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Nacute +Encoding: 302 323 232 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 194 -1 S 1 0 0 1 -20 138 2 +Refer: 46 78 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ncaron +Encoding: 303 327 233 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 8 143 2 +Refer: 46 78 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Ohungarumlaut +Encoding: 304 336 234 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 270 -1 S 1 0 0 1 0 0 2 +Refer: 42 79 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Rcaron +Encoding: 305 344 235 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 191 -1 S 1 0 0 1 8 143 2 +Refer: 101 82 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Uring +Encoding: 306 366 236 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 161 730 S 1 0 0 1 -4 118 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Uhungarumlaut +Encoding: 307 368 237 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 270 -1 S 1 0 0 1 0 0 2 +Refer: 63 85 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Tcedilla +Encoding: 308 354 238 +Width: 600 +Flags: HMW +TeX: 78 0 +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 -44 0 2 +Refer: 59 84 N 1 0 0 1 0 0 2 +EndChar + +StartChar: aogonek +Encoding: 309 261 239 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 214 731 S 1 0 0 1 14 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: hungarumlaut +Encoding: 267 733 240 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 -90 0 2 +Refer: 107 180 N 1 0 0 1 90 0 2 +EndChar + +StartChar: breve +Encoding: 264 728 241 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +169 749 m 0 + 195.428 707.212 242.085 666.993 299.32 666.993 c 0 + 347.638 666.993 397.467 696.856 437 748 c 0 + 470 700 l 0 + 430.784 646.838 369.515 606.983 299.498 606.983 c 0 + 236.205 606.983 172.965 640.673 127 696 c 0 + 169 749 l 0 +EndSplineSet +EndChar + +StartChar: eng +Encoding: 332 331 242 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +SplineSet +89 0 m 0 + 89 529 l 0 + 174 529 l 0 + 174 436 l 0 + 212.871 495.002 278.12 542.003 349.957 542.003 c 0 + 410.281 542.003 464.544 508.129 490.899 448.568 c 0 + 509.729 406.014 510 362.334 510 321 c 0 + 510 65 l 0 + 510 16.919 509.539 -32.1813 489.487 -81.4966 c 0 + 457.36 -160.511 387.101 -203.685 314.113 -203.685 c 0 + 273.194 -203.685 233.402 -190.084 201 -165 c 0 + 241 -87 l 0 + 248.911 -88.73 247.814 -97.6079 250.927 -102.004 c 0 + 253.743 -105.982 279.85 -126.182 316.013 -126.182 c 0 + 347.932 -126.182 381.001 -110.476 402.714 -76.7224 c 0 + 427.982 -37.4432 428 10.8898 428 52 c 0 + 428 319 l 0 + 428 356.393 427.762 401.823 399.11 436.061 c 0 + 380.097 458.781 353.908 469.58 327.341 469.58 c 0 + 271.362 469.58 220.49 422.787 200.308 395.893 c 0 + 178.287 366.55 174 340.651 174 305 c 0 + 174 0 l 0 + 89 0 l 0 +EndSplineSet +EndChar + +StartChar: abreve +Encoding: 310 259 243 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 241 728 S 1 0 0 1 10 0 2 +Refer: 0 97 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ccaron +Encoding: 311 269 244 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 1 99 N 1 0 0 1 0 0 2 +Refer: 143 711 S 1 0 0 1 0 0 2 +EndChar + +StartChar: dcaron +Encoding: 312 271 245 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +368 452 m 0 + 368 771 l 0 + 447 771 l 0 + 447 49 l 0 + 447 32.9912 447.786 16.2109 452 0 c 0 + 369 0 l 0 + 364.758 12.8477 364 26.4229 364 39 c 0 + 364 85 l 0 + 331.672 29.4834 274.151 -12.0137 209.492 -12.0137 c 0 + 97.8574 -12.0137 9.99902 105.708 9.99902 268.875 c 0 + 9.99902 443.625 112.897 543.229 220.226 543.229 c 0 + 283.503 543.229 340.554 507.905 368 452 c 0 +224.355 475.159 m 0 + 149.202 475.159 90.9316 392.789 90.9316 278.779 c 0 + 90.9316 171.018 142.046 61.8809 227.748 61.8809 c 0 + 273.537 61.8809 313.653 94.3154 335.296 129.689 c 0 + 358.192 167.108 361.312 207.25 361.312 255.021 c 0 + 361.312 325.707 359.835 363.117 343.567 397.269 c 0 + 320.504 445.688 266.849 475.159 224.355 475.159 c 0 +EndSplineSet +Refer: 56 8217 N 0.8 0 0 0.8 306.515 186.393 2 +EndChar + +StartChar: eogonek +Encoding: 313 281 246 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +309.849 542.279 m 0 + 396.962 542.279 495.692 495.772 519.469 353.277 c 0 + 524.642 322.276 526.146 288.58 523 253 c 1 + 147.298 253 l 1 + 153.598 94.4857 256.131 55.4411 326.953 55.4411 c 0 + 379.589 55.4411 429.496 76.3575 464 115 c 1 + 510 70 l 1 + 469 19 l 2 + 429.072 -30.6685 396.601 -67.9568 396.601 -101.807 c 0 + 396.601 -127.998 415.588 -147.006 441.833 -147.006 c 0 + 447.913 -147.006 467.621 -146.296 501 -125 c 1 + 500 -182 l 1 + 478.223 -193.942 451.111 -202.754 423.732 -202.754 c 0 + 365.924 -202.754 327.823 -164.029 327.823 -116.525 c 0 + 327.823 -82.2885 349.347 -41.4463 392 -1 c 1 + 366.185 -8.27677 339.549 -12.0058 312.827 -12.0058 c 0 + 173.799 -12.0058 66.4395 87.3647 66.4395 261.323 c 0 + 66.4395 451.743 183.571 542.279 309.849 542.279 c 0 +150.008 317 m 1 + 441 317 l 1 + 450.942 402.839 389.68 478.169 303.883 478.169 c 0 + 247.072 478.169 166.495 441.85 150.008 317 c 1 +EndSplineSet +EndChar + +StartChar: lcaron +Encoding: 314 318 247 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 56 8217 S 0.8 0 0 0.8 266.515 186.393 2 +Refer: 7 108 N 1 0 0 1 -20 0 2 +EndChar + +StartChar: lacute +Encoding: 315 314 248 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 7 108 N 1 0 0 1 0 0 2 +Refer: 194 -1 S 1 0 0 1 -20 188 2 +EndChar + +StartChar: nacute +Encoding: 316 324 249 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 6 110 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ncaron +Encoding: 317 328 250 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 143 711 S 1 0 0 1 0 0 2 +Refer: 6 110 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ohungarumlaut +Encoding: 318 337 251 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 240 733 S 1 0 0 1 0 0 2 +Refer: 5 111 N 1 0 0 1 0 0 2 +EndChar + +StartChar: rcaron +Encoding: 319 345 252 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 143 711 S 1 0 0 1 0 0 2 +Refer: 16 114 N 1 0 0 1 0 0 2 +EndChar + +StartChar: sacute +Encoding: 320 347 253 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 3 115 N 1 0 0 1 0 0 2 +EndChar + +StartChar: scedilla +Encoding: 322 351 254 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 -30 0 2 +Refer: 3 115 N 1 0 0 1 0 0 2 +EndChar + +StartChar: tcedilla +Encoding: 323 355 255 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 201 184 S 1 0 0 1 20 0 2 +Refer: 8 116 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uring +Encoding: 324 367 256 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 161 730 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uhungarumlaut +Encoding: 325 369 257 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 240 733 S 1 0 0 1 0 0 2 +Refer: 15 117 N 1 0 0 1 0 0 2 +EndChar + +StartChar: zdot +Encoding: 326 380 258 +Width: 600 +Flags: HMWO +LayerCount: 2 +Fore +Refer: 69 122 S 1 0 0 1 0 0 2 +Refer: 222 729 N 1 0 0 1 0 0 2 +EndChar + +StartChar: dotlessj +Encoding: 331 567 259 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +SplineSet +156 530 m 0 + 437 530 l 0 + 437 37 l 0 + 437 -8.68478 435.772 -52.1052 413.163 -96.3812 c 0 + 377.277 -166.657 303.238 -202.181 227.699 -202.181 c 0 + 162.017 -202.181 103.902 -175.027 66 -128 c 0 + 120 -56 l 0 + 127.204 -61.9473 125.358 -69.4816 130.11 -77.2483 c 0 + 134.378 -84.2222 169.009 -130.016 233.016 -130.016 c 0 + 277.791 -130.016 319.506 -106.298 339.459 -63.2398 c 0 + 352.497 -35.1019 353 -7.27543 353 21 c 0 + 353 461 l 0 + 156 461 l 0 + 156 530 l 0 +EndSplineSet +EndChar + +StartChar: kgreenlandic +Encoding: 330 312 260 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +SplineSet +87 529 m 0 + 182 529 l 0 + 182.131 528.206 182.196 527.403 182.196 526.598 c 0 + 182.196 519.678 177.642 515.346 174.831 511.514 c 0 + 171.215 506.587 171 503.254 171 499 c 0 + 171 286 l 0 + 436 532 l 0 + 456.53 526.949 477.704 526 498 526 c 0 + 528 526 l 0 + 305 316 l 0 + 565 -1 l 0 + 562.299 -0.982364 559.597 -0.973546 556.896 -0.973546 c 0 + 501.401 -0.973546 457 -5 457 -5 c 0 + 241 265 l 0 + 171 200 l 0 + 171 -1 l 0 + 87 -1 l 0 + 87 529 l 0 +EndSplineSet +EndChar + +StartChar: quotesinglbase +Encoding: 333 8218 261 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 25 44 N 1 0 0 1 0 0 2 +EndChar + +StartChar: quotedblright +Encoding: 335 8221 262 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 56 8217 S 1 0 0 1 -120 0 2 +Refer: 56 8217 N 1 0 0 1 120 0 2 +EndChar + +StartChar: quotedblbase +Encoding: 336 8222 263 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 56 8217 S 1 0 0 1 120 -620 2 +Refer: 56 8217 N 1 0 0 1 -120 -620 2 +EndChar + +StartChar: quotedblleft +Encoding: 334 8220 264 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 57 8216 S 1 0 0 1 120 0 2 +Refer: 57 8216 N 1 0 0 1 -120 0 2 +EndChar + +StartChar: ellipsis +Encoding: 337 8230 265 +Width: 600 +Flags: MW +LayerCount: 2 +Fore +Refer: 24 46 S 1 0 0 1 200 0 2 +Refer: 24 46 N 1 0 0 1 -200 0 2 +Refer: 24 46 N 1 0 0 1 0 0 2 +EndChar + +StartChar: uparrow +Encoding: 338 8593 266 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +78 468 m 1 + 295 742 l 1 + 320 742 l 1 + 521 466 l 1 + 463 427 l 1 + 340 593.819 l 1 + 340 -39 l 1 + 263 -39 l 1 + 263 594.4 l 1 + 128 427 l 1 + 78 468 l 1 +EndSplineSet +EndChar + +StartChar: downarrow +Encoding: 339 8595 267 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 266 8593 N -1 0 0 -1 599 703 2 +EndChar + +StartChar: visiblespace +Encoding: 340 9251 268 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +66 81 m 0 + 120 81 l 0 + 120 -24 l 0 + 478 -24 l 0 + 478 81 l 0 + 534 81 l 0 + 534 -76 l 0 + 66 -76 l 0 + 66 81 l 0 +EndSplineSet +EndChar + +StartChar: r.serif +Encoding: 341 -1 269 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +85 529 m 4 + 244 529 l 4 + 241 427 l 4 + 273.808 493.49 340.052 541.496 416.28 541.496 c 4 + 465.614 541.496 515.474 521.475 553 484 c 4 + 514 404 l 4 + 505.563 412.004 501.879 420.625 495.327 429.3 c 4 + 481.446 447.681 452.813 469.759 411.236 469.759 c 4 + 371.703 469.759 324.688 449.297 282.848 390.04 c 4 + 241.434 331.385 241 295.589 241 267 c 4 + 241 62 l 4 + 352 62 l 4 + 352 -1 l 4 + 83 -1 l 4 + 83 62 l 4 + 158 62 l 4 + 158 462 l 4 + 85 462 l 4 + 85 529 l 4 +EndSplineSet +EndChar + +StartChar: hungarumlaut.cap +Encoding: 343 -1 270 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +486 939 m 0 + 540 864 l 0 + 371 747 l 0 + 334 795 l 0 + 486 939 l 0 +280 939 m 0 + 334 864 l 0 + 165 747 l 0 + 128 795 l 0 + 280 939 l 0 +EndSplineSet +EndChar + +StartChar: uni2074 +Encoding: 344 8308 271 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +360 743 m 0 + 405 743 l 0 + 405 459 l 0 + 478 459 l 0 + 478 404 l 0 + 405 404 l 0 + 405 292 l 0 + 339 292 l 0 + 339 405 l 0 + 128 405 l 0 + 128 446 l 0 + 360 743 l 0 +340 630 m 0 + 204 459 l 0 + 340 459 l 0 + 340 630 l 0 +EndSplineSet +EndChar + +StartChar: onequarter +Encoding: 282 188 272 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 274 8260 S 1 0 0 1 0 0 2 +Refer: 271 8308 N 0.8 0 0 0.8 178.6 -314.5 2 +Refer: 149 185 N 0.8 0 0 0.8 -107.4 198.6 2 +EndChar + +StartChar: threequarters +Encoding: 284 190 273 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 274 8260 S 1 0 0 1 6 0 2 +Refer: 204 179 N 0.8 0 0 0.8 -90.9999 201.01 2 +Refer: 271 8308 N 0.8 0 0 0.8 178.6 -314.5 2 +EndChar + +StartChar: fraction +Encoding: 345 8260 274 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +98 -19 m 29 + 461 770 l 29 + 516 739 l 29 + 152 -49 l 29 + 98 -19 l 29 +EndSplineSet +EndChar + +StartChar: lslash +Encoding: 327 322 275 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +108 770 m 1 + 342 770 l 1 + 342 428.9 l 1 + 417 455 l 2 + 429 459 437 464 448 472 c 1 + 448 387 l 1 + 342 351.164 l 1 + 342 67 l 1 + 498 67 l 1 + 498 0 l 1 + 101 0 l 1 + 101 67 l 1 + 258 67 l 1 + 258 322.765 l 1 + 167 292 l 1 + 167 368 l 1 + 258 399.668 l 1 + 258 703 l 1 + 108 703 l 1 + 108 770 l 1 +EndSplineSet +EndChar + +StartChar: Lslash +Encoding: 286 321 276 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +95 722 m 1 + 189 722 l 1 + 189.172 720.866 189.256 719.721 189.256 718.572 c 0 + 189.256 703.818 179 701.431 179 683 c 2 + 179 380.515 l 1 + 371 443 l 2 + 381.223 446.327 390.329 449.186 401 454 c 1 + 401 380 l 1 + 179 308.815 l 1 + 179 69 l 1 + 527 69 l 1 + 527 -1 l 1 + 95 -1 l 1 + 95 281.88 l 1 + 33 262 l 1 + 33 333 l 1 + 95 353.178 l 1 + 95 722 l 1 +EndSplineSet +EndChar + +StartChar: Eng +Encoding: 346 330 277 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +69 0 m 0 + 69 722 l 0 + 154 722 l 0 + 154 628 l 0 + 195.063 692.14 265.789 735.013 341.737 735.013 c 0 + 413.041 735.013 477.286 696.601 508.242 629.025 c 0 + 529.38 582.882 530 536.67 530 491 c 0 + 530 491 l 0 + 530 203 l 0 + 530 162.878 529.279 123.251 510.426 83.1621 c 0 + 481.76 22.2073 421.615 -12.2234 354.689 -12.2234 c 0 + 319.213 -12.2234 284.072 -2.51385 253 16 c 0 + 294 88 l 0 + 300.652 84.108 301.561 78.1418 306.406 74.6071 c 0 + 308.777 72.8775 330.155 60.3705 357.435 60.3705 c 0 + 390.135 60.3705 419.596 78.287 435.091 111.214 c 0 + 447.894 138.419 448 169.63 448 197 c 0 + 448 489 l 0 + 448 522.737 448.069 561.745 430.159 597.471 c 0 + 409.568 638.545 370.917 662.054 327.377 662.054 c 0 + 264.705 662.054 206.267 613.375 180.496 576.603 c 0 + 158.142 544.705 154 516.425 154 478 c 0 + 154 0 l 0 + 69 0 l 0 +EndSplineSet +EndChar + +StartChar: dcroat +Encoding: 347 273 278 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +280.638 475.041 m 0 + 219.729 475.041 134.873 433.439 134.873 282.731 c 0 + 134.873 108.363 223.935 61.8091 283.87 61.8091 c 0 + 339.081 61.8091 393.871 98.7178 414.26 162.214 c 0 + 422.843 188.943 425.29 218.613 425.29 258.526 c 0 + 425.29 317.62 422.953 347.168 416.391 371.787 c 0 + 395.442 450.383 327.053 475.041 280.638 475.041 c 0 +510.157 630 m 1 + 511 49 l 2 + 511.023 32.976 511.825 16.2095 516 0 c 1 + 433 0 l 1 + 428.758 12.8474 428 26.4226 428 39 c 2 + 428 85 l 1 + 394.754 25.5822 332.198 -11.7426 264.502 -11.7426 c 0 + 162.172 -11.7426 53.9989 73.6686 53.9989 269.088 c 0 + 53.9989 471.408 175.85 543.089 276.756 543.089 c 0 + 349.905 543.089 406.551 506.411 432 452 c 1 + 432 630 l 1 + 344 630 l 1 + 344 692 l 1 + 432 692 l 1 + 432 771 l 1 + 521 771 l 1 + 521.429 763.115 517.033 757.358 514.644 753.665 c 0 + 510.515 747.282 509.991 744.04 510 738 c 2 + 510.067 692 l 1 + 561 692 l 1 + 561 630 l 1 + 510.157 630 l 1 +EndSplineSet +EndChar + +StartChar: Gbreve +Encoding: 348 286 279 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 241 728 S 1 0 0 1 10 167 2 +Refer: 67 71 N 1 0 0 1 0 0 2 +EndChar + +StartChar: Idotaccent +Encoding: 349 304 280 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 222 729 S 1 0 0 1 -20 157 2 +Refer: 4 73 N 1 0 0 1 0 0 2 +EndChar + +StartChar: cacute +Encoding: 321 263 281 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 1 99 N 1 0 0 1 0 0 2 +EndChar + +StartChar: ecaron +Encoding: 328 283 282 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 143 711 S 1 0 0 1 0 0 2 +Refer: 9 101 N 1 0 0 1 0 0 2 +EndChar + +StartChar: gbreve +Encoding: 342 287 283 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 241 728 S 1 0 0 1 10 0 2 +Refer: 13 103 N 1 0 0 1 0 0 2 +EndChar + +StartChar: racute +Encoding: 350 341 284 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 16 114 N 1 0 0 1 0 0 2 +EndChar + +StartChar: zacute +Encoding: 352 378 285 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 107 180 S 1 0 0 1 0 0 2 +Refer: 69 122 N 1 0 0 1 0 0 2 +EndChar + +StartChar: tcaron +Encoding: 351 357 286 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +Refer: 56 8217 S 0.8 0 0 0.8 276.515 226.393 2 +Refer: 8 116 N 1 0 0 1 -30 0 2 +EndChar + +StartChar: bullet +Encoding: 353 8226 287 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +405.001 343.496 m 0 + 405.001 290.47 361.103 246.968 306.461 246.968 c 0 + 251.887 246.968 207.967 290.437 207.967 343.507 c 0 + 207.967 396.512 251.854 440.001 306.474 440.001 c 0 + 361.085 440.001 405.001 396.528 405.001 343.496 c 0 +EndSplineSet +EndChar + +StartChar: florin +Encoding: 354 402 288 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +566 719 m 1 + 528 642 l 1 + 524.387 642.014 519.832 644.287 518.495 650.917 c 0 + 517.585 655.43 518.381 658.903 515.477 665.038 c 0 + 504.735 687.73 476.304 714.31 438.015 714.31 c 0 + 408.828 714.31 375.637 697.84 356.674 655.963 c 0 + 340.302 619.806 338.928 575.492 336 539 c 2 + 328.378 444 l 1 + 471 444 l 1 + 471 378 l 1 + 323.082 378 l 1 + 295 28 l 2 + 290.863 -23.5551 284.654 -73.9088 257.475 -120.242 c 0 + 224.265 -176.855 172.982 -203.002 125.302 -203.002 c 0 + 89.2414 -203.002 55.0861 -188.068 31 -162 c 1 + 78 -88 l 1 + 84.9954 -91.4507 87.1891 -97.9286 90.1488 -102.751 c 0 + 96.5551 -113.189 111.389 -124.965 131.92 -124.965 c 0 + 150.936 -124.965 174.229 -114.524 191.263 -83.2958 c 0 + 210.753 -47.5643 214.363 -4.0862 217 31 c 2 + 243.075 378 l 1 + 103 378 l 1 + 103 444 l 1 + 248.035 444 l 1 + 256 550 l 2 + 259.285 593.711 263.037 638.828 284.817 682.438 c 0 + 316.683 746.244 375.812 780 436.757 780 c 0 + 486.409 780 533.918 757.602 566 719 c 1 +EndSplineSet +EndChar + +StartChar: dagger +Encoding: 355 8224 289 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +261 756 m 1 + 339 756 l 1 + 339 529 l 1 + 531 529 l 1 + 531 460 l 1 + 339 460 l 1 + 339 -175 l 1 + 261 -175 l 1 + 261 460 l 1 + 67 460 l 1 + 67 529 l 1 + 261 529 l 1 + 261 756 l 1 +EndSplineSet +EndChar + +StartChar: daggerdbl +Encoding: 356 8225 290 +Width: 600 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +261 756 m 1 + 339 756 l 1 + 339 529 l 1 + 531 529 l 1 + 531 460 l 1 + 339 460 l 1 + 339 140 l 1 + 531 140 l 1 + 531 71 l 1 + 339 71 l 1 + 339 -175 l 1 + 261 -175 l 1 + 261 71 l 1 + 67 71 l 1 + 67 140 l 1 + 261 140 l 1 + 261 460 l 1 + 67 460 l 1 + 67 529 l 1 + 261 529 l 1 + 261 756 l 1 +EndSplineSet +EndChar + +StartChar: trademark +Encoding: 357 8482 291 +Width: 600 +VWidth: 1157 +Flags: HMW +LayerCount: 2 +Fore +SplineSet +286.552 735.33 m 5 + 286.552 689.01 l 5 + 182.332 689.01 l 5 + 182.332 370.56 l 5 + 130.222 370.56 l 5 + 130.222 689.01 l 5 + 30.6338 689.01 l 5 + 30.6338 735.33 l 5 + 286.552 735.33 l 5 +360.664 735.33 m 5 + 444.04 567.42 l 5 + 466.042 609.108 466.042 609.108 487.465 651.375 c 132 + 508.888 693.642 508.888 693.642 530.89 735.33 c 5 + 569.104 735.33 l 5 + 569.104 370.56 l 5 + 520.468 370.56 l 5 + 520.468 619.53 l 5 + 503.098 588.264 503.098 588.264 485.149 556.419 c 132 + 467.2 524.574 467.2 524.574 450.988 494.466 c 5 + 432.46 495.624 l 5 + 368.77 619.53 l 5 + 368.77 370.56 l 5 + 320.134 370.56 l 5 + 320.134 735.33 l 5 + 360.664 735.33 l 5 +EndSplineSet +EndChar + +StartChar: zero.noslash +Encoding: 358 -1 292 +Width: 600 +Flags: HW +LayerCount: 2 +Fore +SplineSet +517.025 357.799 m 4 + 517.025 137.688 423.592 -13.0208 297.523 -13.0208 c 4 + 183.255 -13.0208 82.8194 113.451 82.8194 341.437 c 4 + 82.8194 574.873 173.246 727.004 299.955 727.004 c 4 + 420.815 727.004 517.025 585.161 517.025 357.799 c 4 +299.205 656.004 m 4 + 273.981 656.004 230.75 644.394 201.424 580.18 c 4 + 177.708 528.251 159.966 454.416 159.966 351.701 c 4 + 159.966 277.625 175.139 200.382 194.564 153.681 c 4 + 226.53 76.8272 272.306 60.9815 302.777 60.9815 c 4 + 329.251 60.9815 369.189 73.0652 399.83 130.196 c 4 + 432.501 191.111 442.125 283.781 442.125 342.506 c 4 + 442.125 419.575 425.889 514.517 403.194 568.433 c 4 + 372.393 641.605 328.293 656.004 299.205 656.004 c 4 +EndSplineSet +EndChar + +StartChar: .notdef +Encoding: 0 -1 293 +Width: 600 +Flags: HW +LayerCount: 2 +EndChar +EndChars +EndSplineFont diff --git a/extlib/inconsolata/OFL_1.1.txt b/extlib/inconsolata/OFL_1.1.txt new file mode 100644 index 00000000..f1a20ac1 --- /dev/null +++ b/extlib/inconsolata/OFL_1.1.txt @@ -0,0 +1,97 @@ +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/extlib/inconsolata/textest.pdf b/extlib/inconsolata/textest.pdf new file mode 100644 index 00000000..923aa349 Binary files /dev/null and b/extlib/inconsolata/textest.pdf differ diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 6f94c714..7b9bf0d7 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -69,16 +69,20 @@ def get_media_type_and_manager(filename): ''' Get the media type and manager based on a filename ''' - for media_type, manager in get_media_managers(): - if filename.find('.') > 0: - # Get the file extension - ext = os.path.splitext(filename)[1].lower() - else: - raise InvalidFileType( - _('Could not find any file extension in "{filename}"').format( - filename=filename)) + if filename.find('.') > 0: + # Get the file extension + ext = os.path.splitext(filename)[1].lower() + else: + raise Exception( + _(u'Could not extract any file extension from "{filename}"').format( + filename=filename)) + for media_type, manager in get_media_managers(): # Omit the dot from the extension and match it against # the media manager if ext[1:] in manager['accepted_extensions']: return media_type, manager + else: + raise FileTypeNotSupported( + # TODO: Provide information on which file types are supported + _(u'Sorry, I don\'t support that file type :(')) diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py new file mode 100644 index 00000000..21b31d0e --- /dev/null +++ b/mediagoblin/media_types/ascii/__init__.py @@ -0,0 +1,27 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.media_types.ascii.processing import process_ascii + + +MEDIA_MANAGER = { + "human_readable": "ASCII", + "processor": process_ascii, # alternately a string, + # 'mediagoblin.media_types.image.processing'? + "display_template": "mediagoblin/media_displays/ascii.html", + "default_thumb": "images/media_thumbs/ascii.jpg", + "accepted_extensions": [ + "txt"]} diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py new file mode 100644 index 00000000..39c75a19 --- /dev/null +++ b/mediagoblin/media_types/ascii/asciitoimage.py @@ -0,0 +1,172 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import Image +import ImageFont +import ImageDraw +import logging +import pkg_resources +import os + +_log = logging.getLogger(__name__) + +class AsciiToImage(object): + ''' + Converter of ASCII art into image files, preserving whitespace + + kwargs: + - font: Path to font file + default: fonts/Inconsolata.otf + - font_size: Font size, ``int`` + default: 11 + ''' + + # Font file path + _font = None + + _font_size = 11 + + # ImageFont instance + _if = None + + # ImageFont + _if_dims = None + + # Image instance + _im = None + + def __init__(self, **kw): + if kw.get('font'): + self._font = kw.get('font') + else: + self._font = pkg_resources.resource_filename( + 'mediagoblin.media_types.ascii', + os.path.join('fonts', 'Inconsolata.otf')) + + if kw.get('font_size'): + self._font_size = kw.get('font_size') + + _log.info('Setting font to {0}, size {1}'.format( + self._font, + self._font_size)) + + self._if = ImageFont.truetype( + self._font, + self._font_size) + + # ,-,-^-'-^'^-^'^-'^-. + # ( I am a wall socket )Oo, ___ + # `-.,.-.,.-.-.,.-.--' ' ` + # Get the size, in pixels of the '.' character + self._if_dims = self._if.getsize('.') + # `---' + + def convert(self, text, destination): + # TODO: Detect if text is a file-like, if so, act accordingly + im = self._create_image(text) + + # PIL's Image.save will handle both file-likes and paths + if im.save(destination): + _log.info('Saved image in {0}'.format( + destination)) + + def _create_image(self, text): + ''' + Write characters to a PIL image canvas. + + TODO: + - Character set detection and decoding, + http://pypi.python.org/pypi/chardet + ''' + # TODO: Account for alternative line endings + lines = text.split('\n') + + line_lengths = [len(i) for i in lines] + + # Calculate destination size based on text input and character size + im_dims = ( + max(line_lengths) * self._if_dims[0], + len(line_lengths) * self._if_dims[1]) + + _log.info('Destination image dimensions will be {0}'.format( + im_dims)) + + im = Image.new( + 'RGBA', + im_dims, + (255, 255, 255, 0)) + + draw = ImageDraw.Draw(im) + + char_pos = [0, 0] + + for line in lines: + line_length = len(line) + + _log.debug('Writing line at {0}'.format(char_pos)) + + for _pos in range(0, line_length): + char = line[_pos] + + px_pos = self._px_pos(char_pos) + + _log.debug('Writing character "{0}" at {1} (px pos {2}'.format( + char, + char_pos, + px_pos)) + + draw.text( + px_pos, + char, + font=self._if, + fill=(0, 0, 0, 255)) + + char_pos[0] += 1 + + # Reset X position, increment Y position + char_pos[0] = 0 + char_pos[1] += 1 + + return im + + def _px_pos(self, char_pos): + ''' + Helper function to calculate the pixel position based on + character position and character dimensions + ''' + px_pos = [0, 0] + for index, val in zip(range(0, len(char_pos)), char_pos): + px_pos[index] = char_pos[index] * self._if_dims[index] + + return px_pos + + +if __name__ == "__main__": + import urllib + txt = urllib.urlopen('file:///home/joar/Dropbox/ascii/install-all-the-dependencies.txt') + + _log.setLevel(logging.DEBUG) + logging.basicConfig() + + converter = AsciiToImage() + + converter.convert(txt.read(), '/tmp/test.png') + + ''' + im, x, y, duration = renderImage(h, 10) + print "Rendered image in %.5f seconds" % duration + im.save('tldr.png', "PNG") + ''' diff --git a/mediagoblin/media_types/ascii/fonts/Inconsolata.otf b/mediagoblin/media_types/ascii/fonts/Inconsolata.otf new file mode 120000 index 00000000..4e742b5e --- /dev/null +++ b/mediagoblin/media_types/ascii/fonts/Inconsolata.otf @@ -0,0 +1 @@ +../../../../extlib/inconsolata/Inconsolata.otf \ No newline at end of file diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py new file mode 100644 index 00000000..a74690c1 --- /dev/null +++ b/mediagoblin/media_types/ascii/processing.py @@ -0,0 +1,93 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +import asciitoimage +import chardet +import os +import Image + +from mediagoblin import mg_globals as mgg +from mediagoblin.processing import create_pub_filepath, THUMB_SIZE + + +def process_ascii(entry): + ''' + Code to process a txt file + ''' + workbench = mgg.workbench_manager.create_workbench() + # Conversions subdirectory to avoid collisions + conversions_subdir = os.path.join( + workbench.dir, 'conversions') + os.mkdir(conversions_subdir) + + queued_filepath = entry['queued_media_file'] + queued_filename = workbench.localized_file( + mgg.queue_store, queued_filepath, + 'source') + + queued_file = file(queued_filename, 'rb') + + with queued_file: + queued_file_charset = chardet.detect(queued_file.read()) + + queued_file.seek(0) # Rewind the queued file + + thumb_filepath = create_pub_filepath( + entry, 'thumbnail.png') + + tmp_thumb_filename = os.path.join( + conversions_subdir, thumb_filepath[-1]) + + converter = asciitoimage.AsciiToImage() + + thumb = converter._create_image( + queued_file.read()) + + with file(tmp_thumb_filename, 'w') as thumb_file: + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + thumb.save(thumb_file) + + mgg.public_store.copy_local_to_storage( + tmp_thumb_filename, thumb_filepath) + + queued_file.seek(0) + + original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + + with mgg.public_store.get_file(original_filepath, 'wb') \ + as original_file: + original_file.write(queued_file.read()) + + + queued_file.seek(0) # Rewind *again* + + unicode_filepath = create_pub_filepath(entry, 'unicode.txt') + + with mgg.public_store.get_file(unicode_filepath, 'wb') \ + as unicode_file: + unicode_file.write( + unicode(queued_file.read().decode( + queued_file_charset['encoding'])).encode( + 'ascii', + 'xmlcharrefreplace')) + + mgg.queue_store.delete_file(queued_filepath) + entry['queued_media_file'] = [] + media_files_dict = entry.setdefault('media_files', {}) + media_files_dict['thumb'] = thumb_filepath + media_files_dict['unicode'] = unicode_filepath + media_files_dict['original'] = original_filepath + + entry.save() diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index ecdd0474..382ba88a 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -402,3 +402,15 @@ table.media_panel th { margin-top: 10px; margin-left: 10px; } + +/* ASCII art */ + +@font-face { + font-family: Inconsolata; + src: local('Inconsolata'), url('../fonts/Inconsolata.otf') format('opentype') +} + +.ascii-wrapper pre { + font-family: Inconsolata, monospace; + line-height: 1em; +} \ No newline at end of file diff --git a/mediagoblin/static/fonts/Inconsolata.otf b/mediagoblin/static/fonts/Inconsolata.otf new file mode 120000 index 00000000..777be657 --- /dev/null +++ b/mediagoblin/static/fonts/Inconsolata.otf @@ -0,0 +1 @@ +../../../extlib/inconsolata/Inconsolata.otf \ No newline at end of file diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 4e4c7c43..443d0e52 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -128,9 +128,13 @@ def submit_start(request): return redirect(request, "mediagoblin.user_pages.user_home", user=request.user.username) - except InvalidFileType, exc: + except Exception as e: + ''' + This section is intended to catch exceptions raised in + mediagobling.media_types + ''' submit_form.file.errors.append( - _(u'Invalid file type.')) + e) return render_to_response( request, diff --git a/mediagoblin/templates/mediagoblin/media_displays/ascii.html b/mediagoblin/templates/mediagoblin/media_displays/ascii.html new file mode 100644 index 00000000..9e77066a --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_displays/ascii.html @@ -0,0 +1,40 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% extends 'mediagoblin/user_pages/media.html' %} + +{% block mediagoblin_media %} +
    +
    +      {%- autoescape False -%}
    +      {{- request.app.public_store.get_file(
    +             media['media_files']['unicode']).read()|string -}}
    +      {%- endautoescape -%}
    +    
    +
    + {% if 'original' in media.media_files %} +

    + + {%- trans -%} + Original + {%- endtrans -%} + +

    + {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/media_displays/image.html b/mediagoblin/templates/mediagoblin/media_displays/image.html index ad60fa94..94420e89 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/image.html +++ b/mediagoblin/templates/mediagoblin/media_displays/image.html @@ -1 +1,19 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + {% extends 'mediagoblin/user_pages/media.html' %} diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index ada50e28..fc08f963 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -1,3 +1,21 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + {% extends 'mediagoblin/user_pages/media.html' %} {% block mediagoblin_media %} diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 7c372745..4a0543a8 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -1,3 +1,4 @@ + # GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. # @@ -16,6 +17,7 @@ import urlparse import pkg_resources +import re from nose.tools import assert_equal, assert_true, assert_false @@ -216,7 +218,8 @@ class TestSubmission: context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] form = context['submit_form'] - assert form.file.errors == [u'Invalid file type.'] + assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0])) + assert len(form.file.errors) == 1 # NOTE: The following 2 tests will ultimately fail, but they # *will* pass the initial form submission step. Instead, -- cgit v1.2.3 From 4601c30c2e80734cf3a18472c2e29a7f920b9604 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 31 Dec 2011 22:57:08 +0100 Subject: Fixed submission error handling and broken tests - Fixed broken test_auth test - Fixed error handling on submission, it now raises the exception if it is not explicitly relevant to file submission. --- mediagoblin/media_types/__init__.py | 2 +- mediagoblin/submit/views.py | 12 +++++++++--- mediagoblin/tests/test_auth.py | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 7b9bf0d7..e7eb1dde 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -73,7 +73,7 @@ def get_media_type_and_manager(filename): # Get the file extension ext = os.path.splitext(filename)[1].lower() else: - raise Exception( + raise InvalidFileType( _(u'Could not extract any file extension from "{filename}"').format( filename=filename)) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 443d0e52..60693bd6 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -31,7 +31,8 @@ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.processing import mark_entry_failed, ProcessMedia from mediagoblin.messages import add_message, SUCCESS -from mediagoblin.media_types import get_media_type_and_manager, InvalidFileType +from mediagoblin.media_types import get_media_type_and_manager, \ + InvalidFileType, FileTypeNotSupported @require_active_login @@ -133,8 +134,13 @@ def submit_start(request): This section is intended to catch exceptions raised in mediagobling.media_types ''' - submit_form.file.errors.append( - e) + + if isinstance(e, InvalidFileType) or \ + isinstance(e, FileTypeNotSupported): + submit_form.file.errors.append( + e) + else: + raise return render_to_response( request, diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 9b0dea66..e54ffa5a 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -233,9 +233,9 @@ def test_register_views(test_app): ## Did we redirect to the proper page? Use the right template? assert_equal( urlparse.urlsplit(response.location)[2], - '/auth/forgot_password/email_sent/') + '/auth/login/') assert template.TEMPLATE_TEST_CONTEXT.has_key( - 'mediagoblin/auth/fp_email_sent.html') + 'mediagoblin/auth/login.html') ## Make sure link to change password is sent by email assert len(mail.EMAIL_TEST_INBOX) == 1 -- cgit v1.2.3 From 7fc782bb6d63cef234ff1a4dad29175afb6d8be5 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 18:11:39 +0100 Subject: Disable horizontal resize for text areas. --- mediagoblin/static/css/base.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 382ba88a..98b77967 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -193,6 +193,7 @@ text-align: center; } textarea#comment_content { + resize: vertical; width: 634px; height: 90px; border: none; @@ -256,6 +257,10 @@ textarea#comment_content { width: 20px; } +textarea#description { + resize: vertical; +} + /* comments */ .comment_author { @@ -413,4 +418,4 @@ table.media_panel th { .ascii-wrapper pre { font-family: Inconsolata, monospace; line-height: 1em; -} \ No newline at end of file +} -- cgit v1.2.3 From ce86b1d5afd21283719146a367b05352d290032f Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 18:12:18 +0100 Subject: Remove border-bottom from media_specs --- mediagoblin/static/css/base.css | 1 - 1 file changed, 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 98b77967..e58a7368 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -303,7 +303,6 @@ h2.media_title { p.media_specs { font-size: 0.9em; border-top: 1px solid #222; - border-bottom: 1px solid #222; padding: 10px 0px; color: #888; } -- cgit v1.2.3 From f5d837fe4a0ad5f08b48e0cd69fddb37e81d1514 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 18:14:39 +0100 Subject: Forgot this one. Also disable horizontal resize for the bio field --- mediagoblin/static/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index e58a7368..76e37c1b 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -257,7 +257,7 @@ textarea#comment_content { width: 20px; } -textarea#description { +textarea#description, textarea#bio { resize: vertical; } -- cgit v1.2.3 From 415077a743400f9d9fa476b37c5b3aff4683f942 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 1 Jan 2012 17:24:02 +0100 Subject: Factor out check_db_migrations_current When initializing the database connection the current mongo based setup checked for new migrations and warned about them. This was mongo specific so factor'd it out into a more generic check_db_migrations_current function in the mongo backend. Also created a dummy one in the sql backend. --- mediagoblin/db/mongo/open.py | 23 +++++++++++++++++++++++ mediagoblin/db/open.py | 3 ++- mediagoblin/db/sql/open.py | 4 ++++ mediagoblin/init/__init__.py | 24 +++--------------------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/mediagoblin/db/mongo/open.py b/mediagoblin/db/mongo/open.py index 63889292..8016ced9 100644 --- a/mediagoblin/db/mongo/open.py +++ b/mediagoblin/db/mongo/open.py @@ -18,6 +18,7 @@ import pymongo import mongokit from paste.deploy.converters import asint from mediagoblin.db.mongo import models +from mediagoblin.db.util import MigrationManager def connect_database_from_config(app_config, use_pymongo=False): @@ -53,3 +54,25 @@ def setup_connection_and_db_from_config(app_config, use_pymongo=False): models.register_models(connection) return (connection, db) + + +def check_db_migrations_current(db): + # This MUST be imported so as to set up the appropriate migrations! + from mediagoblin.db.mongo import migrations + + # Init the migration number if necessary + migration_manager = MigrationManager(db) + migration_manager.install_migration_version_if_missing() + + # Tiny hack to warn user if our migration is out of date + if not migration_manager.database_at_latest_migration(): + db_migration_num = migration_manager.database_current_migration() + latest_migration_num = migration_manager.latest_migration() + if db_migration_num < latest_migration_num: + print ( + "*WARNING:* Your migrations are out of date, " + "maybe run ./bin/gmg migrate?") + elif db_migration_num > latest_migration_num: + print ( + "*WARNING:* Your migrations are out of date... " + "in fact they appear to be from the future?!") diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py index a92a6ada..32827fcb 100644 --- a/mediagoblin/db/open.py +++ b/mediagoblin/db/open.py @@ -14,4 +14,5 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.mongo.open import setup_connection_and_db_from_config +from mediagoblin.db.mongo.open import \ + setup_connection_and_db_from_config, check_db_migrations_current diff --git a/mediagoblin/db/sql/open.py b/mediagoblin/db/sql/open.py index 57feaf50..c682bd3b 100644 --- a/mediagoblin/db/sql/open.py +++ b/mediagoblin/db/sql/open.py @@ -27,3 +27,7 @@ def setup_connection_and_db_from_config(app_config): Session.configure(bind=engine) return "dummy conn", DatabaseMaster(engine) + + +def check_db_migrations_current(db): + pass diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index 5f7f83d4..23c1c26d 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -23,8 +23,8 @@ from mediagoblin.init.config import ( read_mediagoblin_config, generate_validation_report) from mediagoblin import mg_globals from mediagoblin.mg_globals import setup_globals -from mediagoblin.db.open import setup_connection_and_db_from_config -from mediagoblin.db.util import MigrationManager +from mediagoblin.db.open import setup_connection_and_db_from_config, \ + check_db_migrations_current from mediagoblin.workbench import WorkbenchManager from mediagoblin.storage import storage_system_from_config @@ -56,28 +56,10 @@ def setup_global_and_app_config(config_path): def setup_database(): app_config = mg_globals.app_config - # This MUST be imported so as to set up the appropriate migrations! - from mediagoblin.db.mongo import migrations - # Set up the database connection, db = setup_connection_and_db_from_config(app_config) - # Init the migration number if necessary - migration_manager = MigrationManager(db) - migration_manager.install_migration_version_if_missing() - - # Tiny hack to warn user if our migration is out of date - if not migration_manager.database_at_latest_migration(): - db_migration_num = migration_manager.database_current_migration() - latest_migration_num = migration_manager.latest_migration() - if db_migration_num < latest_migration_num: - print ( - "*WARNING:* Your migrations are out of date, " - "maybe run ./bin/gmg migrate?") - elif db_migration_num > latest_migration_num: - print ( - "*WARNING:* Your migrations are out of date... " - "in fact they appear to be from the future?!") + check_db_migrations_current(db) setup_globals( db_connection=connection, -- cgit v1.2.3 From d8db95e4b72ae30c368aeba41993004b95bc7412 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 19:00:56 +0100 Subject: Remove fp_email_sent.html and refs to it --- mediagoblin/auth/routing.py | 4 ---- .../templates/mediagoblin/auth/fp_email_sent.html | 28 ---------------------- 2 files changed, 32 deletions(-) delete mode 100644 mediagoblin/templates/mediagoblin/auth/fp_email_sent.html diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 365ccfaa..699ecbe1 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -39,8 +39,4 @@ auth_routes = [ Route('mediagoblin.auth.fp_changed_success', '/forgot_password/changed_success/', template='mediagoblin/auth/fp_changed_success.html', - controller='mediagoblin.views:simple_template_render'), - Route('mediagoblin.auth.fp_email_sent', - '/forgot_password/email_sent/', - template='mediagoblin/auth/fp_email_sent.html', controller='mediagoblin.views:simple_template_render')] diff --git a/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html b/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html deleted file mode 100644 index 69aac6b3..00000000 --- a/mediagoblin/templates/mediagoblin/auth/fp_email_sent.html +++ /dev/null @@ -1,28 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% block mediagoblin_content %} -

    - {% trans -%} - Check your inbox. We sent an email with a URL for changing your password. - {%- endtrans %} -

    - -{% endblock %} - -- cgit v1.2.3 From 35149b11247846506b31ef3cd6647b659b18f352 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 19:13:23 +0100 Subject: Remove fp_changed_success.html, use log in page + notification message instead --- mediagoblin/auth/routing.py | 6 +---- mediagoblin/auth/views.py | 6 ++++- .../mediagoblin/auth/fp_changed_success.html | 27 ---------------------- 3 files changed, 6 insertions(+), 33 deletions(-) delete mode 100644 mediagoblin/templates/mediagoblin/auth/fp_changed_success.html diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 699ecbe1..ea9388c5 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -35,8 +35,4 @@ auth_routes = [ controller='mediagoblin.auth.views:forgot_password'), Route('mediagoblin.auth.verify_forgot_password', '/forgot_password/verify/', - controller='mediagoblin.auth.views:verify_forgot_password'), - Route('mediagoblin.auth.fp_changed_success', - '/forgot_password/changed_success/', - template='mediagoblin/auth/fp_changed_success.html', - controller='mediagoblin.views:simple_template_render')] + controller='mediagoblin.auth.views:verify_forgot_password')] diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index f707ecbe..88dc40ad 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -324,7 +324,11 @@ def verify_forgot_password(request): user.fp_token_expire = None user.save() - return redirect(request, 'mediagoblin.auth.fp_changed_success') + messages.add_message( + request, + messages.INFO, + _("You can now log in using your new password.")) + return redirect(request, 'mediagoblin.auth.login') else: return render_to_response( request, diff --git a/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html b/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html deleted file mode 100644 index 7cea312d..00000000 --- a/mediagoblin/templates/mediagoblin/auth/fp_changed_success.html +++ /dev/null @@ -1,27 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -#} -{% extends "mediagoblin/base.html" %} - -{% block mediagoblin_content %} -

    - {% trans -%} - Your password has been changed. Try to log in now. - {%- endtrans %} -

    -{% endblock %} - -- cgit v1.2.3 From 445d811043c5cb8b801b91604da6e3967d7ba3b7 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 1 Jan 2012 19:20:38 +0100 Subject: Fix unit tests for new forget password flow After changing the password, the login page is now shown. It contains a message. (we can't test for that easily currently. There is a bug open on this problem.) At least for the login page being shown now. --- mediagoblin/tests/test_auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index e54ffa5a..411b4539 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -291,7 +291,7 @@ def test_register_views(test_app): 'token': parsed_get_params['token']}) response.follow() assert template.TEMPLATE_TEST_CONTEXT.has_key( - 'mediagoblin/auth/fp_changed_success.html') + 'mediagoblin/auth/login.html') ## Verify step 2.2 of password-change works -- login w/ new password success template.clear_test_template_context() -- cgit v1.2.3 From ada0642e5a619a3dce4050db535eb065e0cdc798 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 22:58:32 +0100 Subject: Seperate jQuery bit that was still in media.html --- mediagoblin/static/js/comment_show.js | 9 +++++++++ mediagoblin/templates/mediagoblin/user_pages/media.html | 13 ++----------- 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 mediagoblin/static/js/comment_show.js diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js new file mode 100644 index 00000000..2212b9ad --- /dev/null +++ b/mediagoblin/static/js/comment_show.js @@ -0,0 +1,9 @@ +$(document).ready(function(){ + $('#form_comment').hide(); + $('#button_addcomment').click(function(){ + $(this).fadeOut('fast'); + $('#form_comment').slideDown(function(){ + $('#comment_content').focus(); + }); + }); +}); diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 4c255112..ca650f63 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -23,17 +23,8 @@ {% block title %}{{ media.title }} — {{ super() }}{% endblock %} {% block mediagoblin_head %} - + {% endblock mediagoblin_head %} {% block mediagoblin_content %} -- cgit v1.2.3 From 010fe2d71bf8b1c47c12234466d759561df18355 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 15:55:33 +0100 Subject: sql convert: Use more library functions 1. Use the new setup_connection_and_db_from_config in the sql backend. 2. Use sql and mongo specific functions wherever appropiate instead of the generic "db.X" one. This makes the converter more indepedent of the current backend choice. --- mediagoblin/db/sql/convert.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index c6bed1e9..6698b767 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -1,13 +1,12 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - from mediagoblin.init import setup_global_and_app_config, setup_database -from mediagoblin.db.util import ObjectId +from mediagoblin.db.mongo.util import ObjectId from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment, Tag, MediaTag) - -# Session = sessionmaker() +from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \ + sql_connect +from mediagoblin.db.mongo.open import setup_connection_and_db_from_config as \ + mongo_connect from mediagoblin.db.sql.base import Session @@ -125,14 +124,13 @@ def convert_media_comments(mk_db): def main(): - engine = create_engine('sqlite:///mediagoblin.db', echo=True) - Session.configure(bind=engine) + global_config, app_config = setup_global_and_app_config("mediagoblin.ini") - setup_global_and_app_config("mediagoblin.ini") + sql_conn, sql_db = sql_connect({'sql_engine': 'sqlite:///mediagoblin.db'}) - mk_conn, mk_db = setup_database() + mk_conn, mk_db = mongo_connect(app_config) - Base.metadata.create_all(engine) + Base.metadata.create_all(sql_db.engine) convert_users(mk_db) Session.remove() -- cgit v1.2.3 From 228c4470f40d66e8b9383321d44d89e2a1c0ecad Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 4 Jan 2012 11:57:08 +0100 Subject: Dot-Notation for MediaEntry.media_files --- mediagoblin/gmg_commands/import_export.py | 4 ++-- mediagoblin/media_types/video/processing.py | 6 +++--- mediagoblin/templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- mediagoblin/templates/mediagoblin/media_displays/ascii.html | 4 ++-- mediagoblin/templates/mediagoblin/media_displays/video.html | 4 ++-- mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++-- .../templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +- mediagoblin/templates/mediagoblin/utils/object_gallery.html | 2 +- mediagoblin/tools/files.py | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index eda41f4c..7f699429 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -65,7 +65,7 @@ def _import_media(db, args): args._cache_path['queue']) for entry in db.MediaEntry.find(): - for name, path in entry['media_files'].items(): + for name, path in entry.media_files.items(): _log.info('Importing: {0} - {1}'.format( entry.title, name)) @@ -207,7 +207,7 @@ def _export_media(db, args): args._cache_path['queue']) for entry in db.MediaEntry.find(): - for name, path in entry['media_files'].items(): + for name, path in entry.media_files.items(): _log.info(u'Exporting {0} - {1}'.format( entry.title, name)) diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 7d261226..c260cfd6 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -74,7 +74,7 @@ def process_video(entry): tmp_dst.read()) _log.debug('Saved medium') - entry['media_files']['webm_640'] = medium_filepath + entry.media_files['webm_640'] = medium_filepath # Save the width and height of the transcoded video entry.media_data['video'] = { @@ -94,7 +94,7 @@ def process_video(entry): tmp_thumb.read()) _log.debug('Saved thumbnail') - entry['media_files']['thumb'] = thumbnail_filepath + entry.media_files['thumb'] = thumbnail_filepath if video_config['keep_original']: # Push original file to public storage @@ -111,7 +111,7 @@ def process_video(entry): original_file.write(queued_file.read()) _log.debug('Saved original') - entry['media_files']['original'] = original_filepath + entry.media_files['original'] = original_filepath mgg.queue_store.delete_file(queued_filepath) diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html index 124d0313..06062cd3 100644 --- a/mediagoblin/templates/mediagoblin/edit/attachments.html +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -27,7 +27,7 @@

    Editing attachments for {{ media.title }}

    + media.media_files['thumb']) }}" />
    {% if media.attachment_files|count %} diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index 2dfaddc8..024a2b4d 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -29,7 +29,7 @@

    {% trans media_title=media.title %}Editing {{ media_title }}{% endtrans %}

    + media.media_files['thumb']) }}" />
    {{ wtforms_util.render_divs(form) }}
    diff --git a/mediagoblin/templates/mediagoblin/media_displays/ascii.html b/mediagoblin/templates/mediagoblin/media_displays/ascii.html index 9e77066a..6b40bf08 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/ascii.html +++ b/mediagoblin/templates/mediagoblin/media_displays/ascii.html @@ -23,14 +23,14 @@
           {%- autoescape False -%}
           {{- request.app.public_store.get_file(
    -             media['media_files']['unicode']).read()|string -}}
    +             media.media_files['unicode']).read()|string -}}
           {%- endautoescape -%}
         
    {% if 'original' in media.media_files %}

    + media.media_files['original']) }}"> {%- trans -%} Original {%- endtrans -%} diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index fc08f963..6b5e7a0e 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -27,7 +27,7 @@ preload="auto" data-setup="">

    {%- trans -%}Sorry, this video will not work because @@ -42,7 +42,7 @@ {% if 'original' in media.media_files %}

    + media.media_files['original']) }}"> {%- trans -%} Original {%- endtrans -%} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index ca650f63..d52f544f 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -36,9 +36,9 @@ {# if there's a medium file size, that means the medium size # isn't the original... so link to the original! #} - {% if media['media_files'].has_key('medium') %} + {% if media.media_files.has_key('medium') %} + media.media_files['original']) }}"> Image for {{ media.title }} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index 6c483769..408bca05 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -34,7 +34,7 @@


    diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index b8155f03..5f628dc7 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -31,7 +31,7 @@ {%- elif loop.last %} thumb_entry_last{% endif %}">
    + entry.media_files['thumb']) }}" /> {% if entry.title %}
    diff --git a/mediagoblin/tools/files.py b/mediagoblin/tools/files.py index e0bf0569..10f1d994 100644 --- a/mediagoblin/tools/files.py +++ b/mediagoblin/tools/files.py @@ -23,7 +23,7 @@ def delete_media_files(media): Arguments: - media: A MediaEntry document """ - for listpath in media['media_files'].itervalues(): + for listpath in media.media_files.itervalues(): mg_globals.public_store.delete_file( listpath) -- cgit v1.2.3 From 049284b1da87c1fcb21a8b5585890364eb8e0735 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 13 Dec 2011 10:49:51 +0100 Subject: Dot-Notation for MediaEntry.state --- mediagoblin/processing.py | 2 +- mediagoblin/tests/test_submission.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index 7dd5cc7d..cbac8030 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -64,7 +64,7 @@ class ProcessMedia(Task): except ImportError, exc: mark_entry_failed(entry[u'_id'], exc) - entry['state'] = u'processed' + entry.state = u'processed' entry.save() def on_failure(self, exc, task_id, args, kwargs, einfo): diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 4a0543a8..2b17c515 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -240,7 +240,7 @@ class TestSubmission: entry = mg_globals.database.MediaEntry.find_one( {'title': 'Malicious Upload 2'}) - assert_equal(entry['state'], 'failed') + assert_equal(entry.state, 'failed') assert_equal( entry['fail_error'], u'mediagoblin.processing:BadMediaFail') @@ -260,7 +260,7 @@ class TestSubmission: entry = mg_globals.database.MediaEntry.find_one( {'title': 'Malicious Upload 3'}) - assert_equal(entry['state'], 'failed') + assert_equal(entry.state, 'failed') assert_equal( entry['fail_error'], u'mediagoblin.processing:BadMediaFail') -- cgit v1.2.3 From 8545cfc97d9336b100881bd3ebafd4a5f4882dd3 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 13 Dec 2011 11:18:39 +0100 Subject: Dot-Notation for MediaEntry.queued_media_file --- mediagoblin/media_types/image/processing.py | 4 ++-- mediagoblin/media_types/video/processing.py | 2 +- mediagoblin/submit/views.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index e493eb2b..cf90388f 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -37,7 +37,7 @@ def process_image(entry): workbench.dir, 'conversions') os.mkdir(conversions_subdir) - queued_filepath = entry['queued_media_file'] + queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') @@ -98,7 +98,7 @@ def process_image(entry): original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) - entry['queued_media_file'] = [] + entry.queued_media_file = [] media_files_dict = entry.setdefault('media_files', {}) media_files_dict['thumb'] = thumb_filepath media_files_dict['original'] = original_filepath diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index c260cfd6..49a50647 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -45,7 +45,7 @@ def process_video(entry): workbench = mgg.workbench_manager.create_workbench() - queued_filepath = entry['queued_media_file'] + queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file( mgg.queue_store, queued_filepath, 'source') diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 60693bd6..dd273c7f 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -89,7 +89,7 @@ def submit_start(request): queue_file.write(request.POST['file'].file.read()) # Add queued filename to the entry - entry['queued_media_file'] = queue_filepath + entry.queued_media_file = queue_filepath # We generate this ourselves so we know what the taks id is for # retrieval later. -- cgit v1.2.3 From 9c196287ad26f52acb38d6c37560848da23151a6 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 4 Jan 2012 17:48:16 +0100 Subject: Add Markdown for submit page, edit page, profile edit page; thus fixing ticket #690 --- mediagoblin/edit/forms.py | 12 ++++++++++-- mediagoblin/submit/forms.py | 5 ++++- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- mediagoblin/templates/mediagoblin/utils/wtforms.html | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index f9cc92bf..406de3f8 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -23,7 +23,11 @@ class EditForm(wtforms.Form): title = wtforms.TextField( _('Title'), [wtforms.validators.Length(min=0, max=500)]) - description = wtforms.TextAreaField('Description of this work') + description = wtforms.TextAreaField( + _('Description of this work'), + description=_("""You can use + + Markdown for formatting.""")) tags = wtforms.TextField( _('Tags'), [tag_length_validator], @@ -40,7 +44,11 @@ class EditForm(wtforms.Form): class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField( _('Bio'), - [wtforms.validators.Length(min=0, max=500)]) + [wtforms.validators.Length(min=0, max=500)], + description=_( + """You can use + + Markdown for formatting.""")) url = wtforms.TextField( _('Website'), [wtforms.validators.Optional(), diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index e21b00ee..7ef3638f 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -27,7 +27,10 @@ class SubmitStartForm(wtforms.Form): _('Title'), [wtforms.validators.Length(min=0, max=500)]) description = wtforms.TextAreaField( - _('Description of this work')) + _('Description of this work'), + description=_("""You can use + + Markdown for formatting.""")) tags = wtforms.TextField( _('Tags'), [tag_length_validator], diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index d52f544f..9b331789 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -96,7 +96,7 @@ user= media.get_uploader.username, media=media._id) }}" method="POST" id="form_comment">

    - {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %} + {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %}

    {{ wtforms_util.render_divs(comment_form) }}
    diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index cc30388f..3517b5c3 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -29,7 +29,7 @@ {% endfor %} {%- endif %} {% if field.description -%} -

    {{ _(field.description) }}

    +

    {{ _(field.description)|safe }}

    {%- endif %}
    {%- endmacro %} -- cgit v1.2.3 From 6a59a8abd49d921c2316fb4bd4cddf55a322b2fb Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 2 Jan 2012 16:02:02 +0100 Subject: Import MigrationManager from mongo in mongo backend. Inside the mongo db backend, use the mongo MigrationManager. This is hopefully the last reference to the generic MigrationManager reference on db.util. --- mediagoblin/db/mongo/open.py | 2 +- mediagoblin/db/util.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/mongo/open.py b/mediagoblin/db/mongo/open.py index 8016ced9..48c909d9 100644 --- a/mediagoblin/db/mongo/open.py +++ b/mediagoblin/db/mongo/open.py @@ -18,7 +18,7 @@ import pymongo import mongokit from paste.deploy.converters import asint from mediagoblin.db.mongo import models -from mediagoblin.db.util import MigrationManager +from mediagoblin.db.mongo.util import MigrationManager def connect_database_from_config(app_config, use_pymongo=False): diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 3fd96a1d..1df9494c 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -14,5 +14,5 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.mongo.util import (MigrationManager, ObjectId, InvalidId, +from mediagoblin.db.mongo.util import (ObjectId, InvalidId, DESCENDING) -- cgit v1.2.3 From f1cdd278e7cf195e485567ed0d0d8a90cad81e48 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 4 Jan 2012 23:48:55 +0100 Subject: f691: Use StrictUndefined for templates and fix some issues References to undefined variables in templates were silently ignored/converted to None/empty strings. This makes coding lazy stuff easy, but it makes catching typos harder. (It would have catched one of the SQL things earlier!) But on the other hand it might make the current templates error out everywhere. In fact, early testing has shown two instances, that errored out. Those are fixed with this commit too. If this turns out to make things more complex and useless than actually solving any problems, it can easily be dropped again. --- mediagoblin/templates/mediagoblin/user_pages/media.html | 5 +++-- mediagoblin/templates/mediagoblin/user_pages/user.html | 3 ++- mediagoblin/tools/template.py | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 9b331789..4b5c9337 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -60,8 +60,9 @@ {% trans date=media.created.strftime("%Y-%m-%d") -%} Added on {{ date }}. {%- endtrans %} - {% if media['uploader'] == request.user._id or - request.user['is_admin'] %} + {% if request.user and + (media.uploader == request.user._id or + request.user.is_admin) %} {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.get_uploader.username, media= media._id) %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index b952e88c..78bbaf8c 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -113,7 +113,8 @@ {% else %}
    {% include "mediagoblin/utils/profile.html" %} - {% if request.user._id == user._id or request.user.is_admin %} + {% if request.user and + (request.user._id == user._id or request.user.is_admin) %} {%- trans %}Edit profile{% endtrans -%} diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index d0400347..54a40de6 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -41,8 +41,11 @@ def get_jinja_env(template_loader, locale): if SETUP_JINJA_ENVS.has_key(locale): return SETUP_JINJA_ENVS[locale] + # jinja2.StrictUndefined will give exceptions on references + # to undefined/unknown variables in templates. template_env = jinja2.Environment( loader=template_loader, autoescape=True, + undefined=jinja2.StrictUndefined, extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape']) template_env.install_gettext_callables( -- cgit v1.2.3 From c8071fa591ad148fbffdabc4d6dd71f5666c2172 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 00:17:45 +0100 Subject: Create edit_account.html --- mediagoblin/edit/forms.py | 23 ++++++----- mediagoblin/edit/routing.py | 5 ++- mediagoblin/edit/views.py | 40 +++++++++++++++---- .../templates/mediagoblin/edit/edit_account.html | 45 ++++++++++++++++++++++ 4 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/edit/edit_account.html diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 406de3f8..df219011 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -37,7 +37,7 @@ class EditForm(wtforms.Form): _('Slug'), [wtforms.validators.Required(message=_("The slug can't be empty"))], description=_( - "The title part of this media's URL. " + "The title part of this media's address. " "You usually don't need to change this.")) @@ -52,20 +52,19 @@ class EditProfileForm(wtforms.Form): url = wtforms.TextField( _('Website'), [wtforms.validators.Optional(), - wtforms.validators.URL(message='Improperly formed URL')]) + wtforms.validators.URL(message="""This address contains errors""")]) + + +class EditAccountForm(wtforms.Form): old_password = wtforms.PasswordField( _('Old password'), - [wtforms.validators.Optional()]) + [wtforms.validators.Required()], + description=_( + "Enter your old password to prove you own this account.")) new_password = wtforms.PasswordField( - _('New Password'), - [wtforms.validators.Optional(), - wtforms.validators.Length(min=6, max=30), - wtforms.validators.EqualTo( - 'confirm_password', - 'Passwords must match.')]) - confirm_password = wtforms.PasswordField( - 'Confirm password', - [wtforms.validators.Optional()]) + _('New password'), + [wtforms.validators.Required(), + wtforms.validators.Length(min=6, max=30)]) class EditAttachmentsForm(wtforms.Form): diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py index 34e9fd80..5216f7ca 100644 --- a/mediagoblin/edit/routing.py +++ b/mediagoblin/edit/routing.py @@ -20,4 +20,7 @@ from routes.route import Route edit_routes = [ # Media editing view handled in user_pages/routing.py Route('mediagoblin.edit.profile', '/profile/', - controller="mediagoblin.edit.views:edit_profile")] + controller="mediagoblin.edit.views:edit_profile"), + Route('mediagoblin.edit.account', '/account/', + controller="mediagoblin.edit.views:edit_account") + ] diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 4cb98c15..bae85c5d 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -161,6 +161,35 @@ def edit_profile(request): url=user.get('url'), bio=user.get('bio')) + if request.method == 'POST' and form.validate(): + user.url = unicode(request.POST['url']) + user.bio = unicode(request.POST['bio']) + + user.bio_html = cleaned_markdown_conversion(user['bio']) + + user.save() + + messages.add_message(request, + messages.SUCCESS, + _("Profile changes saved")) + return redirect(request, + 'mediagoblin.user_pages.user_home', + user=user['username']) + + return render_to_response( + request, + 'mediagoblin/edit/edit_profile.html', + {'user': user, + 'form': form}) + + +@require_active_login +def edit_account(request): + edit_username = request.GET.get('username') + user = request.user + + form = forms.EditAccountForm(request.POST) + if request.method == 'POST' and form.validate(): password_matches = auth_lib.bcrypt_check_password( request.POST['old_password'], @@ -172,30 +201,25 @@ def edit_profile(request): return render_to_response( request, - 'mediagoblin/edit/edit_profile.html', + 'mediagoblin/edit/edit_account.html', {'user': user, 'form': form}) - user.url = unicode(request.POST['url']) - user.bio = unicode(request.POST['bio']) - if password_matches: user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['new_password']) - user.bio_html = cleaned_markdown_conversion(user['bio']) - user.save() messages.add_message(request, messages.SUCCESS, - _("Profile edited!")) + _("Account settings saved")) return redirect(request, 'mediagoblin.user_pages.user_home', user=user['username']) return render_to_response( request, - 'mediagoblin/edit/edit_profile.html', + 'mediagoblin/edit/edit_account.html', {'user': user, 'form': form}) diff --git a/mediagoblin/templates/mediagoblin/edit/edit_account.html b/mediagoblin/templates/mediagoblin/edit/edit_account.html new file mode 100644 index 00000000..0a564161 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/edit/edit_account.html @@ -0,0 +1,45 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} +{% extends "mediagoblin/base.html" %} + +{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} + +{% block mediagoblin_head %} + +{% endblock mediagoblin_head %} + +{% block mediagoblin_content %} + + +
    +

    + {%- trans username=user.username -%} + Changing {{ username }}'s account settings + {%- endtrans %} +

    + {{ wtforms_util.render_divs(form) }} +
    + + {{ csrf_token }} +
    +
    + +{% endblock %} -- cgit v1.2.3 From 1c53f98c09a5ccd7acd320be8230d8980fc77dea Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 00:18:29 +0100 Subject: Add change-account-settings link to user.html --- mediagoblin/templates/mediagoblin/user_pages/user.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 78bbaf8c..c93db8b0 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -120,6 +120,11 @@ {%- trans %}Edit profile{% endtrans -%}
    {% endif %} + {% if request.user._id == user._id %} + + {%- trans %}Change account settings{% endtrans -%} + + {% endif %}
    {% endif %} -- cgit v1.2.3 From 4a24500aa43fcf5bca59c12049af34b7935977a0 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 5 Jan 2012 14:46:27 +0100 Subject: Fix more StrictUndefined issues --- mediagoblin/templates/mediagoblin/user_pages/user.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index c93db8b0..6b5c2b21 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -90,7 +90,7 @@

    {% if not user.url and not user.bio %} - {% if request.user._id == user._id %} + {% if request.user and (request.user._id == user._id) %}

    {% trans %}Here's a spot to tell others about yourself.{% endtrans %} @@ -120,7 +120,7 @@ {%- trans %}Edit profile{% endtrans -%} {% endif %} - {% if request.user._id == user._id %} + {% if request.user and (request.user._id == user._id) %} {%- trans %}Change account settings{% endtrans -%} -- cgit v1.2.3 From 49af00e491a7ec6b920a3780254f2203ae47fbe5 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 5 Jan 2012 14:47:15 +0100 Subject: Make show-password-js work for change password too The show password js depends on the password field to have an id of "password". So give it a proper id. Also fixed the label generation for the case of field.name and field.id being different. --- mediagoblin/edit/forms.py | 3 ++- mediagoblin/templates/mediagoblin/utils/wtforms.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index df219011..09955874 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -64,7 +64,8 @@ class EditAccountForm(wtforms.Form): new_password = wtforms.PasswordField( _('New password'), [wtforms.validators.Required(), - wtforms.validators.Length(min=6, max=30)]) + wtforms.validators.Length(min=6, max=30)], + id="password") class EditAttachmentsForm(wtforms.Form): diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 3517b5c3..44b27bb8 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -19,7 +19,7 @@ {# Generically render a field #} {% macro render_field_div(field) %} {% if field.label.text -%} -

    +

    {%- endif %}
    {{ field }} -- cgit v1.2.3 From b48abba3036bb08ad05c469bc37481cc16420ed8 Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 5 Jan 2012 14:54:03 +0100 Subject: Fix Unit Tests for new password changing --- mediagoblin/tests/test_edit.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index 0cf71e9b..55f34b42 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -34,12 +34,10 @@ def test_change_password(test_app): # test that the password can be changed # template.clear_test_template_context() test_app.post( - '/edit/profile/', { - 'bio': u'', - 'url': u'', + '/edit/account/', { 'old_password': 'toast', 'new_password': '123456', - 'confirm_password': '123456'}) + }) # test_user has to be fetched again in order to have the current values test_user = mg_globals.database.User.one({'username': 'chris'}) @@ -50,12 +48,10 @@ def test_change_password(test_app): # is wrong # template.clear_test_template_context() test_app.post( - '/edit/profile/', { - 'bio': u'', - 'url': u'', + '/edit/account/', { 'old_password': 'toast', 'new_password': '098765', - 'confirm_password': '098765'}) + }) test_user = mg_globals.database.User.one({'username': 'chris'}) -- cgit v1.2.3 From 34b4090cbf1f6ea62b9127f0ac96e748ad22b668 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 15:58:03 +0100 Subject: Always show 'Change account settings' link --- mediagoblin/templates/mediagoblin/user_pages/user.html | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 6b5c2b21..a50849b0 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -100,7 +100,6 @@ class="button_action"> {%- trans %}Edit profile{% endtrans -%} -
    {% else %}

    @@ -108,7 +107,6 @@ This user hasn't filled in their profile (yet). {%- endtrans %}

    -
    {% endif %} {% else %}
    @@ -120,11 +118,12 @@ {%- trans %}Edit profile{% endtrans -%} {% endif %} - {% if request.user and (request.user._id == user._id) %} - - {%- trans %}Change account settings{% endtrans -%} - - {% endif %} + {% endif %} + + {% if request.user and (request.user._id == user._id) %} + + {%- trans %}Change account settings{% endtrans -%} +
    {% endif %} -- cgit v1.2.3 From 7df9f45c32d7fd2ae5ae6c137ebf96437f764323 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 21:36:24 +0100 Subject: Several changes for mobile layout --- mediagoblin/static/css/base.css | 32 ++++++++--------------------- mediagoblin/templates/mediagoblin/base.html | 1 + mediagoblin/templates/mediagoblin/root.html | 2 +- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 8ed94e36..e89ce8a2 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -85,18 +85,14 @@ input, textarea { /* website structure */ .mediagoblin_body { - position: relative; - min-height: 100%; - margin-left: auto; - margin-right: auto; - width: 960px; + margin: auto; + width: 96%; + max-width: 960px; } .mediagoblin_header { width: 100%; height: 36px; - margin-left: 10px; - margin-right: 10px; padding-top: 14px; margin-bottom: 20px; border-bottom: 1px solid #333; @@ -118,16 +114,12 @@ a.mediagoblin_logo { .mediagoblin_content { width: 100%; - margin-left: 10px; - margin-right: 10px; padding-bottom: 74px; } .mediagoblin_footer { width: 100%; height: 30px; - margin-left: 10px; - margin-right: 10px; border-top: 1px solid #333; bottom: 0px; padding-top: 8px; @@ -253,16 +245,17 @@ text-align: center; background-color: #222; background-image: url("../images/background_lines.png"); background-repeat: repeat-x; - width: 340px; - padding: 30px 60px; - margin-left: auto; - margin-right: auto; + padding: 3% 5%; display: block; float: none; + width: 90%; + max-width: 340px; + margin-left: auto; + margin-right: auto; } .form_box_xl { - width: 460px; + max-width: 460px; } .edit_box { @@ -452,15 +445,8 @@ table.media_panel th { @media screen and (max-width: 960px) { .mediagoblin_body { - width: 100%; } .mediagoblin_footer { - position: fixed; - left: 0px; - top: 100px; - width: 50px; - height: 20px; - background-color: #f00; } } diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 870a4861..f3912752 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -19,6 +19,7 @@ + {% block title %}{{ app_config['html_title'] }}{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 300570ad..3f834572 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -23,8 +23,8 @@ {% if request.user %}

    {% trans %}Explore{% endtrans %}

    {% else %} -

    {% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}

    +

    {% trans %}This site is running MediaGoblin, an extraordinarily great piece of media hosting software.{% endtrans %}

    {% trans %}To add your own media, place comments, save your favourites and more, you can log in with your MediaGoblin account.{% endtrans %}

    {% if allow_registration %} -- cgit v1.2.3 From ee0b9ea282cf5d0ee3f8743477ec61e6b408b9da Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 21:52:28 +0100 Subject: Remove last 960.gs leftover; fix classes for edit forms --- mediagoblin/templates/mediagoblin/edit/edit.html | 4 ++-- mediagoblin/templates/mediagoblin/edit/edit_account.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit_profile.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index 14200466..fc6b1605 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -25,7 +25,7 @@ user= media.get_uploader.username, media= media._id) }}" method="POST" enctype="multipart/form-data"> -
    +

    {% trans media_title=media.title %}Editing {{ media_title }}{% endtrans %}

    -
    +

    {%- trans username=user.username -%} Changing {{ username }}'s account settings diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index d6461757..97c03e37 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -24,7 +24,7 @@
    -
    +

    {%- trans username=user.username -%} Editing {{ username }}'s profile -- cgit v1.2.3 From a91e4e07e716891b95b5f91b86d123fd9a221525 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 22:46:21 +0100 Subject: Add closing bracket so the whole thing doesn't break down --- mediagoblin/static/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index f4359791..d8fc86bf 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -237,6 +237,7 @@ textarea#comment_content { border: none; background-color: #f1f1f1; padding: 3px; +} .clear { clear: both; -- cgit v1.2.3 From 7945cd21ba6aa7063fc54bc6f91457a3be65ecb3 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 23:36:16 +0100 Subject: * Rename mediagoblin_header, mediagoblin_body, mediagoblin_footer, mediagoblin_header_right, mediagoblin_logo * Add html5shiv for older browsers * Small size fix (940px instead of 960pgx) --- extlib/html5shiv/MIT.txt | 20 ++++++++++++++++++++ extlib/html5shiv/html5shiv.js | 3 +++ mediagoblin/static/css/base.css | 14 +++++++------- mediagoblin/static/js/extlib/html5shiv.js | 1 + mediagoblin/templates/mediagoblin/base.html | 24 +++++++++++++----------- 5 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 extlib/html5shiv/MIT.txt create mode 100644 extlib/html5shiv/html5shiv.js create mode 120000 mediagoblin/static/js/extlib/html5shiv.js diff --git a/extlib/html5shiv/MIT.txt b/extlib/html5shiv/MIT.txt new file mode 100644 index 00000000..5a2aeb47 --- /dev/null +++ b/extlib/html5shiv/MIT.txt @@ -0,0 +1,20 @@ +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extlib/html5shiv/html5shiv.js b/extlib/html5shiv/html5shiv.js new file mode 100644 index 00000000..8de0ff54 --- /dev/null +++ b/extlib/html5shiv/html5shiv.js @@ -0,0 +1,3 @@ +// HTML5 Shiv v3 | @jon_neal @afarkas @rem | MIT/GPL2 Licensed +// Uncompressed source: https://github.com/aFarkas/html5shiv +(function(a,b){var c=function(a){return a.innerHTML="",a.childNodes.length===1}(b.createElement("a")),d=function(a,b,c){return b.appendChild(a),(c=(c?c(a):a.currentStyle).display)&&b.removeChild(a)&&c==="block"}(b.createElement("nav"),b.documentElement,a.getComputedStyle),e={elements:"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),shivDocument:function(a){a=a||b;if(a.documentShived)return;a.documentShived=!0;var f=a.createElement,g=a.createDocumentFragment,h=a.getElementsByTagName("head")[0],i=function(a){f(a)};c||(e.elements.join(" ").replace(/\w+/g,i),a.createElement=function(a){var b=f(a);return b.canHaveChildren&&e.shivDocument(b.document),b},a.createDocumentFragment=function(){return e.shivDocument(g())});if(!d&&h){var j=f("div");j.innerHTML=["x"].join(""),h.insertBefore(j.lastChild,h.firstChild)}return a}};e.shivDocument(b),a.html5=e})(this,document) \ No newline at end of file diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d8fc86bf..54de5a5b 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -84,13 +84,13 @@ input, textarea { /* website structure */ -.mediagoblin_body { +.container { margin: auto; width: 96%; - max-width: 960px; + max-width: 940px; } -.mediagoblin_header { +header { width: 100%; height: 36px; padding-top: 14px; @@ -98,17 +98,17 @@ input, textarea { border-bottom: 1px solid #333; } -.mediagoblin_header_right { +.header_right { float: right; } -a.mediagoblin_logo { +a.logo { color: #fff; font-weight: bold; margin-right: 8px; } -.mediagoblin_logo img { +.logo img { vertical-align: middle; } @@ -117,7 +117,7 @@ a.mediagoblin_logo { padding-bottom: 74px; } -.mediagoblin_footer { +footer { width: 100%; height: 30px; border-top: 1px solid #333; diff --git a/mediagoblin/static/js/extlib/html5shiv.js b/mediagoblin/static/js/extlib/html5shiv.js new file mode 120000 index 00000000..ca7358c7 --- /dev/null +++ b/mediagoblin/static/js/extlib/html5shiv.js @@ -0,0 +1 @@ +../../../../extlib/html5shiv/html5shiv.js \ No newline at end of file diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index f3912752..82ee41b7 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -29,22 +29,24 @@ href="{{ request.staticdirect('/css/video-js.css') }}"/> - + + {% block mediagoblin_head %} {% endblock mediagoblin_head %} {% block mediagoblin_body %} -
    +
    {% block mediagoblin_header %} -
    +
    {% block mediagoblin_logo %} - - {% endblock %} + {% endblock mediagoblin_logo %} {% if request.user and request.user.status == 'active' %} @@ -52,7 +54,7 @@ {% endif %} {% block mediagoblin_header_title %}{% endblock %} -
    +
    {% if request.user %} {# the following link should only appear when verification is needed #} {% if request.user.status == "needs_email_verification" %} @@ -72,7 +74,7 @@ {% trans %}Log in{% endtrans %} {% endif %}
    -
    +
    {% endblock %}
    {% include "mediagoblin/utils/messages.html" %} @@ -80,12 +82,12 @@ {% endblock mediagoblin_content %}
    {% block mediagoblin_footer %} - - {% endblock %} + + {% endblock mediagoblin_footer %} {% endblock mediagoblin_body %}
    -- cgit v1.2.3 From 173999a7e44aac11c8a2d4a7bf61f709b3822f79 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 6 Jan 2012 13:34:25 +0100 Subject: Resize image below 660px width --- mediagoblin/static/css/base.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 54de5a5b..eac956f1 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -479,3 +479,12 @@ table.media_panel th { font-family: Inconsolata, monospace; line-height: 1em; } + +@media screen and (max-width: 660px) { + .media_pane { + width: 100%; + } + img.media_image { + width: 100%; + } +} -- cgit v1.2.3 From 7646e695bfbfc403deecdf3068abd3b453d6fef0 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 6 Jan 2012 13:44:00 +0100 Subject: Fix div breaking in user.html; add media query bits --- mediagoblin/static/css/base.css | 15 ++++++++++++++- mediagoblin/templates/mediagoblin/user_pages/user.html | 6 +++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index eac956f1..c2d45a1b 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -480,11 +480,24 @@ table.media_panel th { line-height: 1em; } -@media screen and (max-width: 660px) { +/* Media queries and other responsivisivity */ +@media screen and (max-width: 680px) { .media_pane { width: 100%; + margin: 0px; } img.media_image { width: 100%; } } + +@media screen and (max-width: 960px) { + .profile_sidebar { + width: 100%; + margin: 0px; + } + .profile_showcase { + width: 100%; + margin: 0px; + } +} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index c8eb9026..0937f97a 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -120,12 +120,12 @@ {% endif %} {% endif %} - {% if request.user and (request.user._id == user._id) %} + {% if request.user and (request.user._id == user._id) %} {%- trans %}Change account settings{% endtrans -%} -
    - {% endif %} + {% endif %} +
    {% if media_entries.count() %}
    -- cgit v1.2.3 From b957cba0cb9b6de33f9d50001a381ea94d9de57a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 6 Jan 2012 19:56:50 +0100 Subject: First push with new style (includes css file, logo image, fonts) --- docs/source/conf.py | 2 +- docs/source/themes/mg/static/fonts/Lato-Bold.ttf | Bin 0 -> 93224 bytes .../themes/mg/static/fonts/Lato-BoldItalic.ttf | Bin 0 -> 81936 bytes docs/source/themes/mg/static/fonts/Lato-Italic.ttf | Bin 0 -> 83680 bytes .../source/themes/mg/static/fonts/Lato-Regular.ttf | Bin 0 -> 96044 bytes docs/source/themes/mg/static/fonts/OFL_1.1.txt | 97 ++++++++++++++ docs/source/themes/mg/static/logo_docs.png | Bin 0 -> 6522 bytes docs/source/themes/mg/static/mg.css | 145 +++++++++++++++++++++ docs/source/themes/mg/theme.conf | 4 +- 9 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 docs/source/themes/mg/static/fonts/Lato-Bold.ttf create mode 100644 docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf create mode 100644 docs/source/themes/mg/static/fonts/Lato-Italic.ttf create mode 100644 docs/source/themes/mg/static/fonts/Lato-Regular.ttf create mode 100644 docs/source/themes/mg/static/fonts/OFL_1.1.txt create mode 100644 docs/source/themes/mg/static/logo_docs.png create mode 100644 docs/source/themes/mg/static/mg.css diff --git a/docs/source/conf.py b/docs/source/conf.py index dce254a1..3014e592 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -111,7 +111,7 @@ html_theme_path = ['themes'] # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = 'logo_docs.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 diff --git a/docs/source/themes/mg/static/fonts/Lato-Bold.ttf b/docs/source/themes/mg/static/fonts/Lato-Bold.ttf new file mode 100644 index 00000000..bc3529fc Binary files /dev/null and b/docs/source/themes/mg/static/fonts/Lato-Bold.ttf differ diff --git a/docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf b/docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf new file mode 100644 index 00000000..2cf5ae0d Binary files /dev/null and b/docs/source/themes/mg/static/fonts/Lato-BoldItalic.ttf differ diff --git a/docs/source/themes/mg/static/fonts/Lato-Italic.ttf b/docs/source/themes/mg/static/fonts/Lato-Italic.ttf new file mode 100644 index 00000000..11ca3eb6 Binary files /dev/null and b/docs/source/themes/mg/static/fonts/Lato-Italic.ttf differ diff --git a/docs/source/themes/mg/static/fonts/Lato-Regular.ttf b/docs/source/themes/mg/static/fonts/Lato-Regular.ttf new file mode 100644 index 00000000..26ce1002 Binary files /dev/null and b/docs/source/themes/mg/static/fonts/Lato-Regular.ttf differ diff --git a/docs/source/themes/mg/static/fonts/OFL_1.1.txt b/docs/source/themes/mg/static/fonts/OFL_1.1.txt new file mode 100644 index 00000000..f1a20ac1 --- /dev/null +++ b/docs/source/themes/mg/static/fonts/OFL_1.1.txt @@ -0,0 +1,97 @@ +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (), +with Reserved Font Name . +Copyright (c) , (). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/source/themes/mg/static/logo_docs.png b/docs/source/themes/mg/static/logo_docs.png new file mode 100644 index 00000000..92879965 Binary files /dev/null and b/docs/source/themes/mg/static/logo_docs.png differ diff --git a/docs/source/themes/mg/static/mg.css b/docs/source/themes/mg/static/mg.css new file mode 100644 index 00000000..3a0a1336 --- /dev/null +++ b/docs/source/themes/mg/static/mg.css @@ -0,0 +1,145 @@ +@import url("basic.css"); + +/* text fonts and styles */ + +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 700; + src: local('Lato Bold'), local('Lato-Bold'), url('fonts/Lato-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 400; + src: local('Lato Italic'), local('Lato-Italic'), url('fonts/Lato-Italic.ttf') format('truetype'); +} +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 700; + src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('fonts/Lato-BoldItalic.ttf') format('truetype'); +} +@font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url('fonts/Lato-Regular.ttf') format('truetype'); +} + +body { + font: 16px 'Lato',Helvetica,Arial,sans-serif; + background-color: #FCFCFC; + color: #3C3C3C; + margin: 0; + padding: 0; +} + +h1, h2, h3, h4, h5, h6 { + border-bottom: 1px solid #CCCCCC; + background: none; + color: black; + font-weight: bold; + padding-bottom: 0.17em; + padding-top: 0.5em; +} + +h1 { + font-size: 1.875em; +} + +h2 { + font-size: 1.375em; +} + +h3, h4, h5, h6 { + font-size: 1.125em; +} + +p { + font-weight: normal; + margin: 0.4em 0 0.5em; +} + +a { + color: #499776; +} + +a:visited { + color: #2A5744; +} + +a:active { + color: #65D1A3; +} + +h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { + text-decoration: none; +} + +div.topic, pre { + background-color: #F1F1F1; + border: 1px dashed #ccc; + color: black; + line-height: 1.1em; + padding: 1em; +} + +code, tt { + font: 14px monospace,"Courier New"; + background-color: #FFFFDD; + border: thin solid #bbb; + padding-left: 5px; + padding-right: 5px; +} + +pre { + font: 14px monospace,"Courier New"; +} + +div.related a, div.related a:visited, div.related a:active { + color: #86D4B1; +} + +/* layout */ + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 60px 0 0 230px; +} + +div.body { + padding: 0 20px 30px 20px; +} + +div.footer { + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 20px; +} + +div.sphinxsidebar ul { + margin: 10px 10px 10px 0; + padding: 0; +} + +div.related { + line-height: 30px; + font-size: 90%; + width: 100%; + background-color: #161616; + color: #C3C3C3; +} + +p.logo { + margin-bottom: 20px; +} diff --git a/docs/source/themes/mg/theme.conf b/docs/source/themes/mg/theme.conf index f4fbd8cc..dd58038a 100644 --- a/docs/source/themes/mg/theme.conf +++ b/docs/source/themes/mg/theme.conf @@ -1,5 +1,5 @@ [theme] -inherit = default -stylesheet = default.css +inherit = basic +stylesheet = mg.css pygments_style = sphinx -- cgit v1.2.3 From 242509239fddf9ebb904dc9c174da522f3bdc8b7 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 6 Jan 2012 23:58:43 +0100 Subject: New docs logo, small css changes --- docs/source/themes/mg/static/logo_docs.png | Bin 6522 -> 6626 bytes docs/source/themes/mg/static/mg.css | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/themes/mg/static/logo_docs.png b/docs/source/themes/mg/static/logo_docs.png index 92879965..99f04cc7 100644 Binary files a/docs/source/themes/mg/static/logo_docs.png and b/docs/source/themes/mg/static/logo_docs.png differ diff --git a/docs/source/themes/mg/static/mg.css b/docs/source/themes/mg/static/mg.css index 3a0a1336..3fa842cd 100644 --- a/docs/source/themes/mg/static/mg.css +++ b/docs/source/themes/mg/static/mg.css @@ -109,7 +109,7 @@ div.documentwrapper { } div.bodywrapper { - margin: 60px 0 0 230px; + margin: 0 0 0 270px; } div.body { @@ -124,7 +124,7 @@ div.footer { } div.sphinxsidebarwrapper { - padding: 10px 5px 0 20px; + padding: 10px 5px 0 30px; } div.sphinxsidebar ul { @@ -141,5 +141,5 @@ div.related { } p.logo { - margin-bottom: 20px; + margin-top: 30px; } -- cgit v1.2.3 From 0788e48c0ec4b0f32867d32e31ab6b204ee0df8e Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 7 Jan 2012 00:04:38 +0100 Subject: Increase docs sidebar width --- docs/source/themes/mg/static/mg.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/themes/mg/static/mg.css b/docs/source/themes/mg/static/mg.css index 3fa842cd..b9355a5d 100644 --- a/docs/source/themes/mg/static/mg.css +++ b/docs/source/themes/mg/static/mg.css @@ -123,6 +123,10 @@ div.footer { font-size: 75%; } +div.sphinxsidebar { + width: 240px; +} + div.sphinxsidebarwrapper { padding: 10px 5px 0 30px; } -- cgit v1.2.3 From 3a4d8b9713bb55e4ad831ad9da3f0f23d8aaed1c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 Jan 2012 13:47:33 -0600 Subject: Committing present MediaGoblin translations before pushing extracted messages --- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 27 ++-- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 170 +++++++++++++--------- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 28 ++-- 3 files changed, 132 insertions(+), 93 deletions(-) diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index 8d1e2711..ba5c639d 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: +# , 2011. # , 2011. # , 2011. # , 2011. @@ -14,8 +15,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2011-12-29 17:39+0000\n" +"Last-Translator: ianux \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -109,7 +110,7 @@ msgstr "Tags" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Séparez les tags par des virgules." #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -253,6 +254,8 @@ msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"Ce site fait tourner MediaGoblin, un " +"logiciel d'hébergement de média extraordinairement génial." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -420,27 +423,27 @@ msgstr "Médias de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Par %(username)s le %(date)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Poster un commentaire" #: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "à" #: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Poster le commentaire !" #: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Éditer" #: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" +msgstr "Effacer" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -578,7 +581,7 @@ msgstr "Anciens" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Aller à la page :" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" @@ -598,11 +601,11 @@ msgstr "Je suis sûr de vouloir supprimer cela" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Oups, votre commentaire était vide." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Votre commentaire a été posté !" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index c1778676..7b63a859 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: -# , 2011. +# , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2012-01-04 18:42+0000\n" +"Last-Translator: schendje \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -21,7 +21,7 @@ msgstr "" #: mediagoblin/processing.py:143 msgid "Invalid file given for media type." -msgstr "" +msgstr "Verkeerd bestandsformaat voor mediatype opgegeven." #: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 msgid "Username" @@ -41,7 +41,7 @@ msgstr "Bevestig wachtwoord" #: mediagoblin/auth/forms.py:39 msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" +msgstr "Typ het hier nog een keer om spelfouten te voorkomen." #: mediagoblin/auth/forms.py:42 msgid "Email address" @@ -57,7 +57,7 @@ msgstr "Sorry, er bestaat al een gebruiker met die naam." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Sorry, een gebruiker met dat e-mailadres bestaat al." #: mediagoblin/auth/views.py:179 msgid "" @@ -74,10 +74,12 @@ msgstr "De verificatie sleutel of gebruikers-ID is onjuist" #: mediagoblin/auth/views.py:203 msgid "You must be logged in so we know who to send the email to!" msgstr "" +"Je moet ingelogd zijn, anders weten we niet waar we de e-mail naartoe moeten" +" sturen!" #: mediagoblin/auth/views.py:211 msgid "You've already verified your email address!" -msgstr "" +msgstr "Je hebt je e-mailadres al geverifieerd!" #: mediagoblin/auth/views.py:224 msgid "Resent your verification email." @@ -88,6 +90,8 @@ msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +"Email kon niet verstuurd worden omdat je gebruikersnaam inactief is of omdat" +" je e-mailadres nog niet geverifieerd is." #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" @@ -99,20 +103,22 @@ msgstr "Etiket" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "Scheidt labels met komma's." #: mediagoblin/edit/forms.py:33 msgid "Slug" -msgstr "" +msgstr "Slug" #: mediagoblin/edit/forms.py:34 msgid "The slug can't be empty" -msgstr "" +msgstr "De slug kan niet leeg zijn" #: mediagoblin/edit/forms.py:35 msgid "" "The title part of this media's URL. You usually don't need to change this." msgstr "" +"Het titeldeel van het adres van deze media. Meestal hoef je dit niet aan te " +"passen." #: mediagoblin/edit/forms.py:42 msgid "Bio" @@ -124,15 +130,15 @@ msgstr "Website" #: mediagoblin/edit/forms.py:49 msgid "Old password" -msgstr "" +msgstr "Oud wachtwoord" #: mediagoblin/edit/forms.py:52 msgid "New Password" -msgstr "" +msgstr "Nieuw wachtwoord" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." -msgstr "" +msgstr "Er bestaat al een met die slug voor deze gebruiker." #: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." @@ -147,15 +153,15 @@ msgstr "" #: mediagoblin/edit/views.py:171 msgid "Wrong password" -msgstr "" +msgstr "Verkeerd wachtwoord" #: mediagoblin/edit/views.py:192 msgid "Profile edited!" -msgstr "" +msgstr "Profiel aangepast!" #: mediagoblin/media_types/__init__.py:65 msgid "Could not find any file extension in \"{filename}\"" -msgstr "" +msgstr "Kon geen bestandsformaat voor \"{filename}\" vinden" #: mediagoblin/submit/forms.py:25 msgid "File" @@ -163,7 +169,7 @@ msgstr "Bestand" #: mediagoblin/submit/forms.py:30 msgid "Description of this work" -msgstr "" +msgstr "Beschrijving van dit werk" #: mediagoblin/submit/views.py:49 msgid "You must provide a file." @@ -175,29 +181,31 @@ msgstr "Mooizo! Toegevoegd!" #: mediagoblin/submit/views.py:133 msgid "Invalid file type." -msgstr "" +msgstr "Ongeldig bestandstype" #: mediagoblin/templates/mediagoblin/404.html:21 msgid "Oops!" -msgstr "" +msgstr "Oeps!" #: mediagoblin/templates/mediagoblin/404.html:24 msgid "There doesn't seem to be a page at this address. Sorry!" -msgstr "" +msgstr "Het lijkt erop dat er geen pagina bestaat op dit adres. Sorry!" #: mediagoblin/templates/mediagoblin/404.html:26 msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." msgstr "" +"Als je zeker weet dat het adres klopt is de pagina misschien verplaatst of " +"verwijderd." #: mediagoblin/templates/mediagoblin/404.html:32 msgid "Image of 404 goblin stressing out" -msgstr "" +msgstr "Afbeelding van de 404 goblin onder stress" #: mediagoblin/templates/mediagoblin/base.html:49 msgid "MediaGoblin logo" -msgstr "" +msgstr "MediaGoblin logo" #: mediagoblin/templates/mediagoblin/base.html:54 msgid "Submit media" @@ -205,11 +213,11 @@ msgstr "Voeg media toe" #: mediagoblin/templates/mediagoblin/base.html:65 msgid "Verify your email!" -msgstr "" +msgstr "Verifieer je e-mailadres!" #: mediagoblin/templates/mediagoblin/base.html:72 msgid "log out" -msgstr "" +msgstr "uitloggen" #: mediagoblin/templates/mediagoblin/base.html:75 #: mediagoblin/templates/mediagoblin/auth/login.html:27 @@ -222,30 +230,37 @@ msgid "" "Powered by MediaGoblin, a GNU project" msgstr "" +"Aangedreven door <a " +"href=\"http://mediagoblin.org\">MediaGoblin</a> , een <a " +"href=\"http://gnu.org/\">GNU-project</a>" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" -msgstr "" +msgstr "Verkennen" #: mediagoblin/templates/mediagoblin/root.html:27 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Hoi, welkom op deze MediaGoblin website!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"Deze website draait MediaGoblin, een " +"buitengewoon goed stuk software voor mediahosting." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Om je eigen media toe te voegen, berichten te plaatsen, favorieten op te " +"slaan en meer, kun je inloggen met je MediaGoblin account." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Heb je er nog geen? Het is heel eenvoudig!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -254,14 +269,17 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Creëer een account op deze website\n" +" of\n" +" Gebruik MediaGoblin op je eigen server" #: mediagoblin/templates/mediagoblin/root.html:44 msgid "Most recent media" -msgstr "" +msgstr "Nieuwste media" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 msgid "Enter your new password" -msgstr "" +msgstr "Voer je nieuwe wachtwoord in" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 #: mediagoblin/templates/mediagoblin/submit/start.html:30 @@ -270,20 +288,22 @@ msgstr "Voeg toe" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Wachtwoord herstellen" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Stuur instructies" #: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 msgid "Your password has been changed. Try to log in now." -msgstr "" +msgstr "Je wachtwoord is veranderd. Probeer om opnieuw in te loggen." #: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 msgid "" "Check your inbox. We sent an email with a URL for changing your password." msgstr "" +"Check je inbox. Er is een e-mail verstuurd waarmee je je wachtwoord kunt " +"veranderen." #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -298,10 +318,17 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Hoi %(username)s,\n" +"\n" +"Om je wachtwoord voor GNU MediaGoblin te veranderen, moet je dit adres in je webbrowser openen:\n" +"\n" +"%(verification_url)s\n" +"\n" +"Als je denkt dat dit niet klopt, kun je deze e-mail gewoon negeren." #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" -msgstr "" +msgstr "Inloggen is mislukt!" #: mediagoblin/templates/mediagoblin/auth/login.html:35 msgid "Don't have an account yet?" @@ -313,7 +340,7 @@ msgstr "Maak er hier een!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" -msgstr "" +msgstr "Wachtwoord vergeten?" #: mediagoblin/templates/mediagoblin/auth/register.html:27 msgid "Create an account!" @@ -321,7 +348,7 @@ msgstr "Maak een account aan!" #: mediagoblin/templates/mediagoblin/auth/register.html:31 msgid "Create" -msgstr "" +msgstr "Creëer" #: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19 #, python-format @@ -360,11 +387,11 @@ msgstr "Het profiel aanpassen van %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Media met het label: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/video.html:19 msgid "Original" -msgstr "" +msgstr "Origineel" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Submit yer media" @@ -373,7 +400,7 @@ msgstr "Voeg media toe" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "Media van %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format @@ -383,57 +410,57 @@ msgstr "Media van %(username)s " #: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "Door %(username)s op %(date)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "Plaats een bericht" #: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "op" #: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "Plaats bericht!" #: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "Pas aan" #: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" +msgstr "Verwijderen" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" -msgstr "" +msgstr "Zeker weten dat je %(title)s wil verwijderen?" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50 msgid "Delete Permanently" -msgstr "" +msgstr "Permanent verwijderen" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "" +msgstr "Mediaverwerkingspaneel" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" +msgstr "Hier kun je de status zien van de media die verwerkt worden." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "" +msgstr "Media te verwerken" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "" +msgstr "Geen media om te verwerken" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "" +msgstr "Deze toevoegingen konden niet verwerkt worden:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:31 #: mediagoblin/templates/mediagoblin/user_pages/user.html:89 @@ -448,11 +475,11 @@ msgstr "Sorry, die gebruiker kon niet worden gevonden." #: mediagoblin/templates/mediagoblin/user_pages/user.html:50 #: mediagoblin/templates/mediagoblin/user_pages/user.html:70 msgid "Email verification needed" -msgstr "" +msgstr "Emailverificatie is nodig" #: mediagoblin/templates/mediagoblin/user_pages/user.html:53 msgid "Almost done! Your account still needs to be activated." -msgstr "" +msgstr "Bijna klaar! Je account moet nog geactiveerd worden." #: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" @@ -474,6 +501,8 @@ msgid "" "Someone has registered an account with this username, but it still has to be" " activated." msgstr "" +"Iemand heeft een account met deze gebruikersnaam gemaakt, maar hij moet nog " +"geactiveerd worden." #: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format @@ -486,7 +515,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." -msgstr "" +msgstr "Hier is een plekje om anderen over jezelf te vertellen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 #: mediagoblin/templates/mediagoblin/user_pages/user.html:119 @@ -495,7 +524,7 @@ msgstr "Profiel aanpassen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:107 msgid "This user hasn't filled in their profile (yet)." -msgstr "" +msgstr "Deze gebruiker heeft zijn of haar profiel (nog) niet ingevuld." #: mediagoblin/templates/mediagoblin/user_pages/user.html:133 #, python-format @@ -507,42 +536,44 @@ msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" +"Dit is waar je nieuwe media zal verschijnen, maar het lijkt erop dat je nog " +"niets heb toegevoegd." #: mediagoblin/templates/mediagoblin/user_pages/user.html:152 msgid "Add media" -msgstr "" +msgstr "Voeg media toe" #: mediagoblin/templates/mediagoblin/user_pages/user.html:158 msgid "There doesn't seem to be any media here yet..." -msgstr "" +msgstr "Het lijkt erop dat er nog geen media is." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" -msgstr "" +msgstr "feed icoon" #: mediagoblin/templates/mediagoblin/utils/feed_link.html:23 msgid "Atom feed" -msgstr "" +msgstr "Atom feed" #: mediagoblin/templates/mediagoblin/utils/pagination.html:40 msgid "Newer" -msgstr "" +msgstr "Nieuwer" #: mediagoblin/templates/mediagoblin/utils/pagination.html:46 msgid "Older" -msgstr "" +msgstr "Ouder" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "Ga naar pagina:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" -msgstr "" +msgstr "Gelabeld met" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "and" -msgstr "" +msgstr "en" #: mediagoblin/user_pages/forms.py:24 msgid "Comment" @@ -550,26 +581,29 @@ msgstr "Commentaar" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -msgstr "" +msgstr "Ik weet zeker dat ik dit wil verwijderen." #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Oeps, je bericht was leeg." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Je bericht is geplaatst!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Je hebt deze media verwijderd." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" +"Deze media was niet verwijderd omdat je niet hebt aangegeven dat je het " +"zeker weet." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" +"Je staat op het punt de media van iemand anders te verwijderen. Pas op." diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 70622590..2864ef8a 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -4,14 +4,14 @@ # # Translators: # , 2011. -# Harry Chen , 2011. +# Harry Chen , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2012-01-03 16:35+0000\n" +"Last-Translator: Harry Chen \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,7 +98,7 @@ msgstr "標籤" #: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 msgid "Seperate tags by commas." -msgstr "" +msgstr "用逗點分開標籤。" #: mediagoblin/edit/forms.py:33 msgid "Slug" @@ -234,6 +234,8 @@ msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"此網站正運行 媒體怪獸(MediaGoblin), " +"他是一個超讚的媒體分享架站軟體." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" @@ -394,27 +396,27 @@ msgstr "%(username)s的媒體檔案" #: mediagoblin/templates/mediagoblin/user_pages/media.html:57 #, python-format msgid "By %(username)s on %(date)s" -msgstr "" +msgstr "由 %(username)s 於 %(date)s" #: mediagoblin/templates/mediagoblin/user_pages/media.html:67 msgid "Post a comment" -msgstr "" +msgstr "刊登評論" #: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "at" -msgstr "" +msgstr "在" #: mediagoblin/templates/mediagoblin/user_pages/media.html:102 msgid "Post comment!" -msgstr "" +msgstr "刊登評論!" #: mediagoblin/templates/mediagoblin/user_pages/media.html:124 msgid "Edit" -msgstr "" +msgstr "編輯" #: mediagoblin/templates/mediagoblin/user_pages/media.html:130 msgid "Delete" -msgstr "" +msgstr "刪除" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -541,7 +543,7 @@ msgstr "舊一點" #: mediagoblin/templates/mediagoblin/utils/pagination.html:50 msgid "Go to page:" -msgstr "" +msgstr "跳到頁數:" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "Tagged with" @@ -561,11 +563,11 @@ msgstr "我確定我想要刪除" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "啊,你的留言是空的。" #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "你的留言已經刊登!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -- cgit v1.2.3 From bcd50908d2849dff5a466b15db65112779cb85e2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 7 Jan 2012 13:48:12 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 12717 -> 14396 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 319 +++++++++------- mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo | Bin 11505 -> 13397 bytes mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po | 311 ++++++++++------ mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11802 -> 13692 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 360 ++++++++++-------- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 304 ++++++++++------ mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 11749 -> 13543 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 348 ++++++++++-------- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 12120 -> 13891 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 349 ++++++++++-------- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 12304 -> 12357 bytes mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo | Bin 11238 -> 13161 bytes mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po | 303 ++++++++++------ mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo | Bin 11622 -> 13574 bytes mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 361 +++++++++++------- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 11879 -> 13736 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 309 ++++++++++------ mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 11394 -> 11670 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 10933 -> 12901 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 321 +++++++++------- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 11350 -> 13279 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 341 ++++++++++------- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 11882 -> 13685 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 348 ++++++++++-------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 15457 -> 16681 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 348 ++++++++++-------- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo | Bin 11993 -> 13900 bytes mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 423 +++++++++++++--------- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 11439 -> 13350 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 311 ++++++++++------ mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 11335 -> 13259 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 303 ++++++++++------ mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 11538 -> 13448 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 321 +++++++++------- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 11527 -> 13409 bytes mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 305 ++++++++++------ mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 11190 -> 11198 bytes 38 files changed, 3640 insertions(+), 2345 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index 02dfa29a..1a7267e5 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index 61abc63f..c53fc387 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -25,27 +25,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "اسم المستخدم" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "كلمة السر" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "يجب أن تتطابق كلمتا السر." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "أكّد كلمة السر" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "اكتبها مرة أخرى هنا للتأكد من عدم وجود أخطاء إملائية." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "عنوان البريد الإلكتروني" @@ -61,7 +49,7 @@ msgstr "عذرًا، لقد اختار مستخدم آخر هذا الاسم." msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -69,23 +57,28 @@ msgstr "" "تم التحقق من بريدك الإلكتروني. يمكنك الآن الولوج، وتحرير ملفك الشخصي، ونشر " "الصور!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "مفتاح التحقق أو معرف المستخدم خاطئ" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "أعدنا إرسال رسالة التحقق." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -93,47 +86,76 @@ msgstr "" "تعذر إرسال رسالة استعادة كلمة السر لأن اسم المستخدم معطل أو لأننا لم نتحقق " "من بريدك الإلكتروني." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "العنوان" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "وصف هذا العمل." + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "الوسوم" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "المسار" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "لا يمكن ترك المسار فارغًا" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"الجزء الذي يمثل عنوان الملف في المسار. لا حاجة إلى تغيير محتوى هذه الخانة " -"عادةً." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "السيرة" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "الموقع الإلكتروني" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -148,39 +170,43 @@ msgstr "أنت تحرّر وسائط مستخدم آخر. كن حذرًا أثن msgid "You are editing a user's profile. Proceed with caution." msgstr "أنت تحرّر ملف مستخدم آخر. كن حذرًا أثناء العملية." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "الملف" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "وصف هذا العمل." - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "يجب أن تضع ملفًا." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "يا سلام! نُشرَت!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "صورة قزم مرتبك" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "ويحي!" @@ -195,33 +221,30 @@ msgid "" msgstr "" "إن كنت متأكدًا من صحة العنوان فربما تكون الصفحة التي تريدها نُقلت أو حُذفت." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "صورة قزم مرتبك" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "شعار ميدياغوبلن" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "أرسل وسائط" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "أضف وسائط" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "لِج" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -231,7 +254,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -255,22 +278,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "أحدث الوسائط" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "أدخل كلمة سرك الجديدة" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "أرسل" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -280,15 +302,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "لقد غُيرت كلمة سرك. جرّب الولوج الآن." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "تفقد بريدك الإلكتروني. لقد أرسلنا رسالة بها وصلة لتغيير كلمة سرك." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -326,11 +339,11 @@ msgstr "أنشئ حسابًا هنا!" msgid "Forgot your password?" msgstr "أنسيت كلمة سرك؟" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "أنشئ حسابًا!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "أنشئ" @@ -362,10 +375,16 @@ msgid "Cancel" msgstr "ألغِ" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "احفظ التغييرات" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -377,13 +396,32 @@ msgstr "تحرير ملف %(username)s الشخصي" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "انشر وسائطك" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -395,29 +433,55 @@ msgstr "" msgid "%(username)s's media" msgstr "وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -502,30 +566,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "هذه زاوية لتخبر الآخرين فيها عن نفسك." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "حرِّر الملف الشخصي" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "لم يعبئ هذا العضو بيانات ملفه بعد." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "أظهِر كل وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "هنا ستظهر وسائطك، ولكن يبدو أنك لم تضف شيئًا بعد." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "أضف وسائط" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "لا يبدو أنه توجد أي وسائط هنا حتى الآن..." @@ -537,30 +602,36 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "الأحدث" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "الأقدم" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "علِّق" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "أنا متأكد من رغبتي بحذف هذا العمل" diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo index 34179a53..45f2331f 100644 Binary files a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po index 9609cb34..a5d6732b 100644 --- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -24,27 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Aquest tipus de fitxer no és vàlid." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nom d'usuari" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Contrasenya" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Les contrasenyes han de coincidir" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Confirmeu la contrasenya" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Adreça electrònica" @@ -60,7 +48,7 @@ msgstr "Lamentablement aquest usuari ja existeix." msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -68,68 +56,104 @@ msgstr "" "Ja s'ha verificat la vostra adreça electrònica. Ara podeu entrar, editar el " "vostre perfil i penjar imatge!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" "La clau de verificació o la identificació de l'usuari no són correctes." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Torna'm a enviar el correu de verificació" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Títol" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Etiquetes" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Lloc web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -144,39 +168,43 @@ msgstr "Esteu editant fitxers d'un altre usuari. Aneu amb compte." msgid "You are editing a user's profile. Proceed with caution." msgstr "Esteu editant el perfil d'un usuari. Aneu amb compte" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fitxer" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Heu d'escollir un fitxer." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Visca! S'ha enviat!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Imatge de la pantalla 404, el goblin no sap què fer..." -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Ups!" @@ -192,33 +220,30 @@ msgstr "" "Si esteu convençut que l'adreça és correcta, pot ser que la pàgina que " "cerqueu s'hagi canviat d'ubicació o s'hagi eliminat." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Imatge de la pantalla 404, el goblin no sap què fer..." - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Logo de mediagoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Envia fitxers" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Tots els fitxers" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entra" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -228,7 +253,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -252,22 +277,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Envia" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -277,15 +301,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -316,11 +331,11 @@ msgstr "Creeu-ne un aquí!" msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Creeu un compte!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Crea" @@ -352,10 +367,16 @@ msgid "Cancel" msgstr "Cancel·la" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Desa els canvis" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -367,13 +388,32 @@ msgstr "" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Envieu els vostres fitxers" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -385,29 +425,55 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -494,30 +560,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Edita el perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Aquest usuari encara no ha escrit res al seu perfil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "View all of %(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Tots els fitxers" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -529,30 +596,36 @@ msgstr "Icona RSS" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Comentari" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index a01abf9c..4f4bbfda 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index e2765357..1fb472f0 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,6 +8,7 @@ # Elrond , 2011. # , 2011. # Jan-Christoph Borchardt , 2011. +# Jan-Christoph Borchardt , 2011. # , 2011. # , 2011. # Rafael Maguiña , 2011. @@ -16,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-06 21:16+0000\n" -"Last-Translator: gandaro \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -31,27 +32,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Die Datei stimmt nicht mit dem gewählten Medientyp überein." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Benutzername" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Passwort" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Passwörter müssen übereinstimmen." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Passwort wiederholen" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Hier nochmal eintragen, um Tippfehler zu verhindern." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "E-Mail-Adresse" @@ -67,7 +56,7 @@ msgstr "Leider gibt es bereits einen Benutzer mit diesem Namen." msgid "Sorry, a user with that email address already exists." msgstr "Leider gibt es bereits einen Benutzer mit dieser E-Mail-Adresse." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -75,23 +64,28 @@ msgstr "" "Deine E-Mail-Adresse wurde bestätigt. Du kannst dich nun anmelden, Dein " "Profil bearbeiten und Bilder hochladen!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Der Bestätigungsschlüssel oder die Nutzernummer ist falsch." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" -msgstr "" +msgstr "Du musst angemeldet sein, damit wir wissen, wer die Email bekommt." -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Deine E-Mail-Adresse wurde bereits bestätigt." -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Bestätigungs-E-Mail wurde erneut versandt." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -100,48 +94,77 @@ msgstr "" "weil dein Benutzername inaktiv oder deine E-Mail-Adresse noch nicht " "verifiziert ist." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Beschreibung des Werkes" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Markierungen" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Kurztitel" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Bitte gib einen Kurztitel ein" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"Der Titelteil der Medienadresse. Normalerweise muss hier nichts geändert " -"werden." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Biographie" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Webseite" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Altes Passwort" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Neues Passwort" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -155,39 +178,43 @@ msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Falsches Passwort" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Das Profil wurde aktualisiert" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Datei" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Beschreibung des Werkes" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Du musst eine Datei angeben." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Yeeeaaah! Geschafft!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Ungültiger Dateityp." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Bild eines angespannten Goblins" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Hoppla!" @@ -203,33 +230,30 @@ msgstr "" "Wenn du sicher bist, dass die Adresse stimmt, wurde die Seite eventuell " "verschoben oder gelöscht." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Bild eines angespannten Goblins" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "MediaGoblin-Logo" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Medien hochladen" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Medien hinzufügen" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "Bitte bestätige deine E-Mail-Adresse!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "Abmelden" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Anmelden" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -241,46 +265,49 @@ msgstr "" msgid "Explore" msgstr "Entdecke" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Hallo du, willkommen auf dieser MediaGoblin-Seite!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"Diese Seite läuft mit MediaGoblin, " +"einer großartigen Software für Medienhosting." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Melde dich mit deinem MediaGoblin-Konto an, um eigene Medien hinzuzufügen, " +"zu kommentieren, Favoriten zu speichern und mehr." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Hast du noch keinen? Das geht ganz einfach!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Neuste Medien" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Neues Passwort eingeben" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Bestätigen" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -288,18 +315,7 @@ msgstr "Passwort wiederherstellen" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Dein Passwort wurde geändert. Versuche dich jetzt einzuloggen." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Überprüfe deinen Posteingang. Wir haben dir eine E-Mail mit einem Link " -"geschickt, mit dem du dein Passwort ändern kannst." +msgstr "Anleitung senden" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -338,11 +354,11 @@ msgstr "Registriere dich hier!" msgid "Forgot your password?" msgstr "Passwort vergessen?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Neues Konto registrieren!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Registrieren" @@ -373,10 +389,16 @@ msgid "Cancel" msgstr "Abbrechen" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Änderungen speichern" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -386,15 +408,34 @@ msgstr "%(username)ss Profil bearbeiten" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr ": %(tag_name)s" +msgstr "Medien markiert mit: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" +msgstr "Original" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Medien hochladen" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -406,30 +447,56 @@ msgstr "%(username)ss Medien" msgid "%(username)s's media" msgstr "%(username)ss Medien" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Von %(username)s am %(date)s" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" +msgstr "Bearbeiten" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" +msgstr "Löschen" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" -msgstr "Bearbeiten" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" -msgstr "Löschen" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "bei" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -520,30 +587,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "Hier kannst du Anderen etwas über dich erzählen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Profil bearbeiten" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Dieser Benutzer hat (noch) keine Daten in seinem Profil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Alle Medien von %(username)s anschauen" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Hier erscheinen deine Medien. Sobald du etwas hochgeladen hast." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Medien hinzufügen" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Scheinbar gibt es hier noch nichts …" @@ -555,29 +623,35 @@ msgstr "Feed-Symbol" msgid "Atom feed" msgstr "Atom-Feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Neuere" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Ältere" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" +msgstr "Zu Seite:" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Markiert mit" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "und" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Kommentar" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" @@ -585,19 +659,21 @@ msgstr "Ja, wirklich löschen" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Ohh, der Kommentar war leer." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Dein Kommentar wurde gesendet!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Du hast das Medium gelöscht." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" +"Das Medium wurde nicht gelöscht. Du musst ankreuzen, dass du es wirklich " +"löschen möchtest." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 17e6873c..3584cd4f 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -1,14 +1,14 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2011. +# FIRST AUTHOR , 2012. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -21,27 +21,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "" @@ -57,72 +45,110 @@ msgstr "" msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your " "profile, and submit images!" msgstr "" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or " "your account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 -msgid "The title part of this media's URL. You usually don't need to change this." +#: mediagoblin/edit/forms.py:39 +msgid "" +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -137,39 +163,43 @@ msgstr "" msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/submit/forms.py:25 -msgid "File" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" +#: mediagoblin/submit/forms.py:25 +msgid "File" msgstr "" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "" @@ -183,33 +213,30 @@ msgid "" "has been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -219,7 +246,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -244,23 +271,22 @@ msgstr "" msgid "" "Create an " "account at this site\n" -" or\n" -" Set up MediaGoblin on " "your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 @@ -271,14 +297,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -309,11 +327,11 @@ msgstr "" msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "" @@ -339,10 +357,16 @@ msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -354,12 +378,31 @@ msgstr "" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 @@ -372,29 +415,55 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown " +"for formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -475,30 +544,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -510,28 +580,34 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "View more media tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "or" msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 3e0a84bf..d0c5f2bf 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index c3c29b89..6536f4d5 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -10,9 +10,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-06 20:04+0000\n" -"Last-Translator: aleksejrs \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -25,27 +25,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "La provizita dosiero ne konformas al la informtipo." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Uzantnomo" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Pasvorto" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Pasvortoj devas esti egalaj." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Retajpu pasvorton" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Retajpu ĝin por certigi, ke ne okazis mistajpoj." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Retpoŝtadreso" @@ -61,7 +49,7 @@ msgstr "Bedaŭrinde, uzanto kun tiu nomo jam ekzistas." msgid "Sorry, a user with that email address already exists." msgstr "Ni bedaŭras, sed konto kun tiu retpoŝtadreso jam ekzistas." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -69,23 +57,28 @@ msgstr "" "Via retpoŝtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian " "profilon, kaj alŝuti bildojn!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "La kontrol-kodo aŭ la uzantonomo ne estas korekta" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "Vi devas esti ensalutita, por ke ni sciu, al kiu sendi la retleteron!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Vi jam konfirmis vian retpoŝtadreson!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Resendi vian kontrol-mesaĝon." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -93,48 +86,77 @@ msgstr "" "Ni ne povas sendi pasvortsavan retleteron, ĉar aŭ via konto estas neaktiva, " "aŭ ĝia retpoŝtadreso ne estis konfirmita." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titolo" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Priskribo de ĉi tiu verko" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Etikedoj" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Dividu la etikedojn per komoj." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "La distingiga adresparto" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "La distingiga adresparto ne povas esti malplena" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"La parto de la dosieradreso, bazita sur la dosiertitolo. Ordinare ne necesas" -" ĝin ŝanĝi." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Retejo" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "La malnova pasvorto" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "La nova pasvorto" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -148,39 +170,43 @@ msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." msgid "You are editing a user's profile. Proceed with caution." msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Malĝusta pasvorto" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "La profilŝanĝo faritas!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "Ŝajnas, ke en «{filename}» mankas dosiernoma finaĵo" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Dosiero" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Priskribo de ĉi tiu verko" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Vi devas provizi dosieron." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Hura! Alŝutitas!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Netaŭga dosiertipo." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Bildo de 404-koboldo penŝvitanta." -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Oj!" @@ -196,33 +222,30 @@ msgstr "" "Se vi estas certa, ke la adreso estas ĝusta, eble la serĉata de vi paĝo " "estis movita aŭ forigita." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Bildo de 404-koboldo penŝvitanta." - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Emblemo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Alŝuti aŭd-vid-dosieron" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Aldoni dosieron" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "Konfirmu viecon de la retpoŝtadreso!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "elsaluti" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Ensaluti" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -234,7 +257,7 @@ msgstr "" msgid "Explore" msgstr "Ĉirkaŭrigardi" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaĝaro!" @@ -263,25 +286,21 @@ msgstr "Ĉu vi ankoraŭ ne havas tian? Ne malĝoju!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Kreu konton en ĉi tiu retejo\n" -" aŭ\n" -" Ekfunkciigu MediaGoblin’on en via propra servilo" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Laste aldonitaj dosieroj" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Enigu vian novan pasvorton" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Alŝuti" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -291,17 +310,6 @@ msgstr "Ekhavo de nova pasvorto" msgid "Send instructions" msgstr "Sendi instrukcion" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Via pasvorto estis ŝanĝita. Nun provu ensaluti." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Kontrolu vian retleterujon. Ni sendis retleteron kun retadreso por ŝanĝo de " -"via pasvorto." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -339,11 +347,11 @@ msgstr "Kreu ĝin ĉi tie!" msgid "Forgot your password?" msgstr "Ĉu vi forgesis vian pasvorton?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Kreu konton!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Krei" @@ -374,10 +382,16 @@ msgid "Cancel" msgstr "Nuligi" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Konservi ŝanĝojn" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -389,13 +403,32 @@ msgstr "Redaktado de l’profilo de %(username)s'" msgid "Media tagged with: %(tag_name)s" msgstr "Dosieroj kun etikedo: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Originalo" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Alŝutu vian aŭd-vid-dosieron" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -407,31 +440,57 @@ msgstr "Dosieroj de %(username)s" msgid "%(username)s's media" msgstr "Dosieroj de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Afiŝita de %(username)s je %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Afiŝi komenton" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "je" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Afiŝi la komenton!" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Ŝanĝi" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Forigi" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "je" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -519,31 +578,32 @@ msgid "Here's a spot to tell others about yourself." msgstr "Jen estas spaceto por rakonti pri vi al aliaj." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Redakti profilon" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Ĉi tiu uzanto ne jam aldonis informojn pri si." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Rigardi ĉiujn dosierojn de %(username)s'" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Ĝuste ĉi tie aperos viaj dosieroj, sed vi ŝajne ankoraŭ nenion alŝutis." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Aldoni dosieron" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Ĉi tie ŝajne estas ankoraŭ neniuj dosieroj…" @@ -555,29 +615,35 @@ msgstr "flusimbolo" msgid "Atom feed" msgstr "Atom-a informfluo" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Plinovaj" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Malplinovaj" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Iri al paĝo:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Markita per: " +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "kaj" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Komento" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index 0f7f4026..b9f8eeed 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index 406e1923..ab8c6b3f 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -15,9 +15,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-05 23:20+0000\n" -"Last-Translator: manolinux \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -30,28 +30,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Archivo inválido para el formato seleccionado." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nombre de usuario" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Contraseña" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Las contraseñas deben coincidir." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Confirma tu contraseña" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" -"Escriba de nuevo aquí para asegurarse de que no hay faltas de ortografía." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Dirección de correo electrónico" @@ -67,7 +54,7 @@ msgstr "Lo sentimos, ya existe un usuario con ese nombre." msgid "Sorry, a user with that email address already exists." msgstr "Lo sentimos, ya existe un usuario con esa dirección de email." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -75,26 +62,31 @@ msgstr "" "Tu dirección de correo electrónico ha sido verificada. ¡Ahora puedes " "ingresar, editar tu perfil, y enviar imágenes!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" "La clave de verificación o la identificación de usuario son incorrectas" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" "¡Debes iniciar sesión para que podamos saber a quién le enviamos el correo " "electrónico!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "¡Ya has verificado tu dirección de correo!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Se reenvió tu correo electrónico de verificación." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -103,48 +95,77 @@ msgstr "" "porque su nombre de usuario está inactivo o la dirección de su cuenta de " "correo electrónico no ha sido verificada." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Descripción de esta obra" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Separa las etiquetas con comas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Ficha" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "La ficha no puede estar vacía" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"La parte del título de la URL de este contenido. Normalmente no necesitas " -"cambiar esto." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Sitio web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Vieja contraseña" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Nueva contraseña" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -158,39 +179,43 @@ msgstr "Estás editando el contenido de otro usuario. Proceder con precaución." msgid "You are editing a user's profile. Proceed with caution." msgstr "Estás editando un perfil de usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Contraseña incorrecta" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "¡Perfil editado!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "No se pudo encontrar la extensión del archivo en \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Archivo" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Descripción de esta obra" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Debes proporcionar un archivo." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "¡Yujú! ¡Enviado!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Tipo de archivo inválido." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Imagen de 404 goblin estresándose" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "¡Ups!" @@ -206,33 +231,30 @@ msgstr "" "Si estás seguro que la dirección es correcta, puede ser que la pagina haya " "sido movida o borrada." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Imagen de 404 goblin estresándose" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Logo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Enviar contenido" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Añadir contenido" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "¡Verifica tu email!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "Cerrar sesión" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Conectarse" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -244,7 +266,7 @@ msgstr "" msgid "Explore" msgstr "Explorar" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Hola, ¡bienvenido a este sitio de MediaGoblin!" @@ -273,25 +295,21 @@ msgstr "¿Aún no tienes una? ¡Es fácil!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Crea una cuenta en este sitio\n" -" o\n" -" Instala MediaGoblin en tu propio servidor" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "El contenido más reciente" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Ingrese su nueva contraseña" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Enviar" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -301,17 +319,6 @@ msgstr "Recuperar contraseña" msgid "Send instructions" msgstr "Enviar instrucciones" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Se cambió tu contraseña. Intenta iniciar sesión ahora." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Revisa tu bandeja de entrada. Te enviamos un correo electrónico con una URL " -"para cambiar tu contraseña." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -349,11 +356,11 @@ msgstr "¡Crea una aquí!" msgid "Forgot your password?" msgstr "¿Olvidaste tu contraseña?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "¡Crea una cuenta!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Crear" @@ -384,10 +391,16 @@ msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Guardar cambios" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -399,13 +412,32 @@ msgstr "Editando el perfil de %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "Contenido etiquetado con: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Original" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Envía tu contenido" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -417,31 +449,57 @@ msgstr "Contenidos de %(username)s" msgid "%(username)s's media" msgstr "Contenido de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Por %(username)s en %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Pon un comentario." - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "en" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "¡Pon un comentario!" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Editar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Borrar" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "en" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -530,31 +588,32 @@ msgid "Here's a spot to tell others about yourself." msgstr "Aquí hay un lugar para que le cuentes a los demás sobre tí." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Este usuario (todavia) no ha completado su perfil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Ver todo el contenido de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Aquí es donde tú contenido estará, pero parece que aún no has agregado nada." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Añadir contenido" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Parece que aún no hay ningún contenido aquí..." @@ -566,29 +625,35 @@ msgstr "ícono feed" msgid "Atom feed" msgstr "Atom feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Recientes" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Antiguas" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Ir a la página:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Etiquetado con" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "y" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Comentario" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index ed1ea35d..b805cca5 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo index c0a1ecb6..94b378d2 100644 Binary files a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po index 512635e3..56f74573 100644 --- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nomine de usator" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Contrasigno" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Adresse de e-posta" @@ -59,73 +47,109 @@ msgstr "" msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titulo" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -140,39 +164,43 @@ msgstr "" msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/submit/forms.py:25 -msgid "File" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" +#: mediagoblin/submit/forms.py:25 +msgid "File" msgstr "" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "" @@ -186,33 +214,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Initiar session" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -222,7 +247,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -246,21 +271,20 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 @@ -271,15 +295,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -310,11 +325,11 @@ msgstr "" msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Crear un conto!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "" @@ -340,10 +355,16 @@ msgid "Cancel" msgstr "Cancellar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -355,12 +376,31 @@ msgstr "" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 @@ -373,29 +413,55 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -478,30 +544,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -513,30 +580,36 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Commento" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo index 1319a605..d5fb3eac 100644 Binary files a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po index 96d1f0a2..6a8b8b65 100644 --- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -1,15 +1,16 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: +# , 2011. # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "documento non valido come tipo multimediale." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nome utente" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Password" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Le password devono coincidere" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Conferma password" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Scrivilo ancora qui per assicurarti che non ci siano errori" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Indirizzo email" @@ -57,9 +46,9 @@ msgstr "Spiacente, esiste già un utente con quel nome" #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Siamo spiacenti, un utente con quell'indirizzo email esiste già." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -67,67 +56,106 @@ msgstr "" "Il tuo indirizzo email è stato verificato. Puoi ora fare login, modificare " "il tuo profilo, e inserire immagini!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "La chiave di verifica o l'id utente è sbagliato" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" +"Devi entrare col tuo profilo così possiamo sapere a chi inviare l'email!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" -msgstr "" +msgstr "Hai già verificato il tuo indirizzo email!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Rispedisci email di verifica" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +"Impossibile inviare l'email di recupero password perchè il tuo nome utente è" +" inattivo o il tuo account email non è stato verificato." + +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titolo" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Descrizione di questo lavoro" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Tags" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" +msgstr "Password vecchia" + +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -144,39 +172,43 @@ msgstr "" msgid "You are editing a user's profile. Proceed with caution." msgstr "Stai modificando il profilo di un utente. Procedi con attenzione." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" +msgstr "Password errata" + +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Documento" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Descrizione di questo lavoro" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Devi specificare un documento." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Evviva! " -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Immagine di 404 folletti che stressano" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Oops!" @@ -192,33 +224,30 @@ msgstr "" "Se sei sicuro che l'indirizzo è corretto, forse la pagina che stai cercando " "è stata spostata o cancellata." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Immagine di 404 folletti che stressano" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Inoltra file multimediale" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Aggiungi documenti multimediali" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" -msgstr "" +msgstr "Verifica la tua email!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" -msgstr "" +msgstr "disconnettiti" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Accedi" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -230,63 +259,58 @@ msgstr "" msgid "Explore" msgstr "Esplora" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Ciao, benvenuto a questo sito MediaGoblin!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." msgstr "" +"questo sito sta utilizzando Mediagoblin, un ottimo programma di " +"media hosting." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." msgstr "" +"Per aggiungere i tuoi file, scrivere commenti, salvare i tuoi preferiti e " +"altro, devi entrare col tuo profilo MediaGoblin." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Non ne hai già uno? E' semplice!" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Documenti multimediali più recenti" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Inserisci la tua nuova password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Conferma" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Recupera Password" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" +msgstr "Invia istruzioni" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -301,6 +325,14 @@ msgid "" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" msgstr "" +"Ciao %(username)s,\n" +"per cambiare la tua password MediaGoblin apri il seguente URL\n" +"nel tuo web browser:\n" +"\n" +"%(verification_url)s\n" +"\n" +"Se pensi che sia un errore, ignora semplicemente questa email e continua ad essere \n" +"un goblin felice!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" @@ -318,11 +350,11 @@ msgstr "Creane uno qui!" msgid "Forgot your password?" msgstr "Hai dimenticato la password?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Crea un account!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Crea" @@ -353,10 +385,16 @@ msgid "Cancel" msgstr "Annulla" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salva i cambiamenti" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -366,49 +404,94 @@ msgstr "Stai modificando il profilo di %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "file taggato con:%(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" +msgstr "Originale" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" msgstr "" #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Inoltra documento multimediale" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "file di %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "Documenti multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" +msgstr "Modifica" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" +msgstr "Elimina" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "a" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -496,20 +579,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Ecco un posto dove raccontare agli altri di te." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Modifica profilo" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Questo utente non ha (ancora) compilato il proprio profilo." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Visualizza tutti i file multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -517,11 +604,8 @@ msgstr "" "Questo è dove i tuoi documenti multimediali appariranno, ma sembra che tu " "non abbia ancora aggiunto niente." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Aggiungi documenti multimediali" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Non sembra ci sia ancora nessun documento multimediali qui.." @@ -533,49 +617,56 @@ msgstr "feed icon" msgid "Atom feed" msgstr "Atom feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Più nuovo" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Più vecchio" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" +msgstr "Vai alla pagina:" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Commento" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Sono sicuro di volerlo cancellare" #: mediagoblin/user_pages/views.py:155 msgid "Oops, your comment was empty." -msgstr "" +msgstr "Oops, il tuo commento era vuoto." #: mediagoblin/user_pages/views.py:161 msgid "Your comment has been posted!" -msgstr "" +msgstr "Il tuo commento è stato aggiunto!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "" +msgstr "Hai cancellato il file" #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" +"Il file non è stato eliminato perchè non hai confermato di essere sicuro." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 39f3595b..21aeed26 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 3198eed9..7ed8652b 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "ユーザネーム" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "パスワード" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "パスワードが一致している必要があります。" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "パスワードを確認" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "メールアドレス" @@ -59,73 +47,109 @@ msgstr "申し訳ありませんが、その名前を持つユーザーがすで msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "メアドが確認されています。これで、ログインしてプロファイルを編集し、画像を提出することができます!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "検証キーまたはユーザーIDが間違っています" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "検証メールを再送しました。" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "タイトル" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "タグ" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "スラグ" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "スラグは必要です。" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "自己紹介" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "URL" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -140,39 +164,43 @@ msgstr "あなたは、他のユーザーのメディアを編集しています msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "ファイル" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "ファイルを提供する必要があります。" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "投稿終了!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "" @@ -186,33 +214,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "コンテンツを投稿" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "ログイン" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -222,7 +247,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -246,22 +271,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "送信" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -271,15 +295,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -310,11 +325,11 @@ msgstr "ここで作成!" msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "アカウントを作成!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "" @@ -345,10 +360,16 @@ msgid "Cancel" msgstr "キャンセル" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "投稿する" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -360,13 +381,32 @@ msgstr "%(username)sさんのプロフィールを編集中" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "コンテンツを投稿" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -378,29 +418,55 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -483,30 +549,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "プロフィールを編集" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "%(username)sさんのコンテンツをすべて見る" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -518,28 +585,34 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "View more media tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "or" msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index 842bfb9b..4d03c586 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index c07f42be..11b00041 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index 0b0c2a27..dcc82f90 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Ugyldig fil for mediatypen." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Brukarnamn" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Passord" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Passorda må vera like." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Gjenta passord" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Skriv passordet omatt for å unngå stavefeil." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Epost" @@ -59,7 +47,7 @@ msgstr "Ein konto med dette brukarnamnet finst allereide." msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -67,68 +55,104 @@ msgstr "" "Kontoen din er stadfesta. Du kan no logga inn, endra profilen din og lasta " "opp filer." -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Stadfestingsnykelen eller brukar-ID-en din er feil." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Send ein ny stadfestingsepost." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" "Kunne ikkje senda epost. Brukarnamnet ditt er inaktivt eller uverifisert." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Tittel" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Skildring av mediefila" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Merkelappar" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Nettnamn" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Nettnamnet kan ikkje vera tomt" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." -msgstr "Nettnamnet (adressetittel) for mediefila di. Trengst ikkje endrast." +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Presentasjon" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Heimeside" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -143,39 +167,43 @@ msgstr "Trå varsamt, du endrar nokon andre sine mediefiler." msgid "You are editing a user's profile. Proceed with caution." msgstr "Trå varsamt, du endrar nokon andre sin profil." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fil" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Skildring av mediefila" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Du må velja ei fil." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Johoo! Opplasta!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Bilete av stressa 404-tusse." -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Oops." @@ -191,33 +219,30 @@ msgstr "" "Er du sikker på at adressa er korrekt, so er sida truleg flytta eller " "sletta." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Bilete av stressa 404-tusse." - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Last opp" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Legg til mediefiler" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logg inn" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -229,7 +254,7 @@ msgstr "" msgid "Explore" msgstr "Utforsk" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -253,22 +278,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Nyaste mediefiler" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Fyll inn passord" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Send" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -278,17 +302,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Passordet endra. Prøv å logga inn no." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Sjekk innboksen din. Me har sendt deg ein epost med ei netadresse for " -"passordendring." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -326,11 +339,11 @@ msgstr "Lag ein!" msgid "Forgot your password?" msgstr "Gløymd passordet?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Lag ein konto." -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Opprett" @@ -361,10 +374,16 @@ msgid "Cancel" msgstr "Bryt av" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Lagra" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -376,13 +395,32 @@ msgstr "Endrar profilen til %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Last opp" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -394,29 +432,55 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -501,30 +565,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "Her kan du fortelja om deg sjølv." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Endra profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Brukaren har ikkje fylt ut profilen sin (enno)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Sjå alle %(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Her kjem mediefilene dine." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Legg til mediefiler" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Ser ikkje ut til at det finst nokon mediefiler her nett no." @@ -536,30 +601,36 @@ msgstr " " msgid "Atom feed" msgstr "Atom-kjelde" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Nyare" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Eldre" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Innspel" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Eg er sikker eg vil sletta dette" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 87e62764..5b7445f7 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index f1c044d2..11400a2f 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 23:32+0000\n" -"Last-Translator: osc \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,28 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Arquivo inválido para esse tipo de mídia" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nome de Usuário" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Senha" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Senhas devem ser iguais." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Confirmar senha" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" -"Digite novamente aqui para ter certeza que não houve erros de digitação" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Endereço de email" @@ -61,7 +48,7 @@ msgstr "Desculpe, um usuário com este nome já existe." msgid "Sorry, a user with that email address already exists." msgstr "Desculpe, um usuário com esse email já esta cadastrado" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -69,23 +56,28 @@ msgstr "" "O seu endereço de e-mail foi verificado. Você pode agora fazer login, editar" " seu perfil, e enviar imagens!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "A chave de verificação ou nome usuário estão incorretos." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr " " -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Você já verifico seu email!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "O email de verificação foi reenviado." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -93,47 +85,77 @@ msgstr "" "Não foi possível enviar o email de recuperação de senha, pois seu nome de " "usuário está inativo ou o email da sua conta não foi confirmado." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Descrição desse trabalho" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Separar tags por virgulas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Arquivo" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "O arquivo não pode estar vazio" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"A parte título da URL dessa mídia. Geralmente não é necessário alterar isso." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Website" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Senha antiga" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Nova Senha" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -147,39 +169,43 @@ msgstr "Você está editando a mídia de outro usuário. Tenha cuidado." msgid "You are editing a user's profile. Proceed with caution." msgstr "Você está editando um perfil de usuário. Tenha cuidado." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Senha errada" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Perfil editado!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr " " +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" + +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Arquivo" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Descrição desse trabalho" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Você deve fornecer um arquivo." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Eba! Enviado!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Tipo de arquivo inválido." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Imagem do goblin 404 aparecendo" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Oops" @@ -195,33 +221,30 @@ msgstr "" "Se você está certo de que o endereço está correto, talvez a página que " "esteja procurando tenha sido apagada ou mudou de endereço" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Imagem do goblin 404 aparecendo" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Enviar mídia" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Adicionar mídia" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "Verifique seu email!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "Sair" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entrar" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -233,7 +256,7 @@ msgstr "" msgid "Explore" msgstr "Explorar" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Olá, bemvindo ao site de MediaGoblin." @@ -257,22 +280,21 @@ msgstr " " #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Mídia mais recente" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Digite sua nova senha" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Enviar" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -282,17 +304,6 @@ msgstr "Recuperar senha" msgid "Send instructions" msgstr "Mandar instruções" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Sua senha foi alterada. Tente entrar agora." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Verifique sua caixa de entrada. Mandamos um email com a URL para troca da " -"senha" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -331,11 +342,11 @@ msgstr "Crie uma aqui!" msgid "Forgot your password?" msgstr "Esqueceu sua senha?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Criar uma conta!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Criar" @@ -366,10 +377,16 @@ msgid "Cancel" msgstr "Cancelar" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salvar mudanças" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -381,13 +398,32 @@ msgstr "Editando perfil de %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Original" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Envie sua mídia" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -399,31 +435,57 @@ msgstr "" msgid "%(username)s's media" msgstr "Mídia de %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Postar um comentário" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Postar comentário!" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Editar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Apagar" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -509,20 +571,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Aqui é o lugar onde você fala de si para os outros." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Editar perfil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Esse usuário não preencheu seu perfil (ainda)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Ver todas as mídias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -530,11 +596,8 @@ msgstr "" "Aqui é onde sua mídia vai aparecer, mas parece que você não adicionou nada " "ainda." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Adicionar mídia" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Aparentemente não há nenhuma mídia aqui ainda..." @@ -546,29 +609,35 @@ msgstr "ícone feed" msgid "Atom feed" msgstr "Atom feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Mais novo" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Mais velho" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Ir a página:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "e" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Comentário" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index e0a70ea9..5a711266 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index b747fc3a..4981e988 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 18:41+0000\n" -"Last-Translator: gap \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,27 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Formatul fișierului nu corespunde cu tipul de media selectat." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nume de utilizator" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Parolă" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Parolele trebuie să fie identice." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Reintrodu parola" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Introdu parola din nou pentru verificare." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Adresa de e-mail" @@ -60,7 +48,7 @@ msgstr "Ne pare rău, există deja un utilizator cu același nume." msgid "Sorry, a user with that email address already exists." msgstr "Există deja un utilizator înregistrat cu această adresă de e-mail." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -68,23 +56,28 @@ msgstr "" "Adresa ta de e-mail a fost verificată. Poți să te autentifici, să îți " "completezi profilul și să trimiți imagini!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Cheie de verificare sau user ID incorect." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "Trebuie să fii autentificat ca să știm cui să trimitem mesajul!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Adresa ta de e-mail a fost deja verificată!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "E-mail-ul de verificare a fost retrimis." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -92,48 +85,77 @@ msgstr "" "E-mailul pentru recuperarea parolei nu a putut fi trimis deoarece contul tău" " e inactiv sau adresa ta de e-mail nu a fost verificată." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titlu" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Descrierea acestui fișier" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Tag-uri" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Desparte tag-urile prin virgulă." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Identificator" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Identificatorul nu poate să lipsească" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"Partea din adresa acestui fișier corespunzătoare titlului. De regulă nu " -"trebuie modificată." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Biografie" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Sit Web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Vechea parolă" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Noua parolă" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -148,39 +170,43 @@ msgstr "Editezi fișierul unui alt utilizator. Se recomandă prudență." msgid "You are editing a user's profile. Proceed with caution." msgstr "Editezi profilul unui utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Parolă incorectă" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Profilul a fost modificat!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "Nu pot extrage extensia din „{filename}”" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" + +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fișier" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Descrierea acestui fișier" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Trebuie să selectezi un fișier." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Ura! Trimis!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Tip de fișier incompatibil." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Imagine cu elful 404 stresat." -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Hopa!" @@ -196,33 +222,30 @@ msgstr "" "Dacă ești sigur că adresa e corectă, poate că pagina pe care o cauți a fost " "mutată sau ștearsă." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Imagine cu elful 404 stresat." - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Transmite un fișier media" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Trimite fișier" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "Verifică adresa de e-mail!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "ieșire" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Autentificare" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -234,7 +257,7 @@ msgstr "" msgid "Explore" msgstr "Explorează" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Salut, bine ai venit pe acest site MediaGoblin!" @@ -262,25 +285,21 @@ msgstr "Încă nu ai unul? E simplu!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Creează un cont pe acest site\n" -" sau\n" -" Instalează MediaGoblin pe propriul tău server" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Cele mai recente fișiere" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Introdu noua parolă" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Trimite" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -290,17 +309,6 @@ msgstr "Recuperează parola" msgid "Send instructions" msgstr "Trimite instrucțiuni" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Parola a fost schimbată. Încearcă să te autentifici acum." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Verifică-ți căsuța de e-mail. Ți-am trimis un mesaj cu link-ul pentru " -"schimbarea parolei." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -338,11 +346,11 @@ msgstr "Creează-l aici!" msgid "Forgot your password?" msgstr "Ai uitat parola?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Creează un cont!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Creează" @@ -373,10 +381,16 @@ msgid "Cancel" msgstr "Anulare" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Salvează modificările" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -388,13 +402,32 @@ msgstr "Editare profil %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "Fișier etichetat cu tag-urile: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Original" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Trimite fișierele tale media" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -406,31 +439,57 @@ msgstr "Fișierele lui %(username)s" msgid "%(username)s's media" msgstr "Fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "De %(username)s la %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Scrie un comentariu" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "la" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Trimite comentariul" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Editare" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Șterge" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "la" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -515,20 +574,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Aici poți spune altora ceva despre tine." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Editare profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Acest utilizator nu și-a completat (încă) profilul." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Vezi toate fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -536,11 +599,8 @@ msgstr "" "Aici vor apărea fișierele tale media, dar se pare că încă nu ai trimis " "nimic." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Trimite fișier" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Nu pare să existe niciun fișier media deocamdată..." @@ -552,29 +612,35 @@ msgstr "icon feed" msgid "Atom feed" msgstr "feed Atom" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Mai noi" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Mai vechi" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Salt la pagina:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Tag-uri" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "și" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Scrie un comentariu" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 7e62de83..3ddb0c8e 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 098ea38c..38748a97 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 19:58+0000\n" -"Last-Translator: aleksejrs \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Неправильный формат файла." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Логин" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Пароль" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Пароли должны совпадать." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Подтвердите пароль" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Наберите его ещё раз здесь, чтобы избежать опечаток." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Адрес электронной почты" @@ -61,7 +49,7 @@ msgstr "" "Сожалеем, но на этот адрес электронной почты уже зарегистрирована другая " "учётная запись." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -69,23 +57,28 @@ msgstr "" "Адрес вашей электронной потвержден. Вы теперь можете войти и начать " "редактировать свой профиль и загружать новые изображения!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Неверный ключ проверки или идентификатор пользователя" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "Вам надо представиться, чтобы мы знали, кому отправлять сообщение!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Вы уже потвердили свой адрес электронной почты!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Переслать сообщение с подтверждением аккаунта." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -94,48 +87,77 @@ msgstr "" "учётная запись неактивна, либо указанный в ней адрес электронной почты не " "был подтверждён." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Название" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Описание этого произведения" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Метки" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Разделяйте метки запятыми." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Отличительная часть адреса" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Отличительная часть адреса необходима" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"Часть адреса этого файла, производная от его названия. Её обычно не нужно " -"изменять." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Биография" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Сайт" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Старый пароль" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Новый пароль" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -150,39 +172,43 @@ msgstr "Вы редактируете файлы другого пользова msgid "You are editing a user's profile. Proceed with caution." msgstr "Вы редактируете профиль пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Неправильный пароль" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Профиль изменён!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "В «{filename}» не обнаружено расширение имени файла" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Файл" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Описание этого произведения" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Вы должны загрузить файл." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Ура! Файл загружен!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Неподходящий тип файла." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Изображение 404 нервничающего гоблина" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Ой!" @@ -196,33 +222,30 @@ msgid "" " been moved or deleted." msgstr "Возможно, страница, которую вы ищете, была удалена или переехала." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Изображение 404 нервничающего гоблина" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Символ MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Загрузить файл" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Добавить файлы" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "Подтвердите ваш адрес электронной почты!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "завершение сеанса" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Войти" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -234,7 +257,7 @@ msgstr "" msgid "Explore" msgstr "Смотреть" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Привет! Добро пожаловать на наш MediaGoblin’овый сайт!" @@ -263,25 +286,21 @@ msgstr "У вас её ещё нет? Не проблема!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Создайте учётную запись на этом сайте\n" -" или\n" -" Установите MediaGoblin на собственный сервер" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Самые новые файлы" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Введите свой новый пароль" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Подтвердить" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -291,17 +310,6 @@ msgstr "Сброс пароля" msgid "Send instructions" msgstr "Отправить инструкцию" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Ваш пароль изменён. Теперь попробуйте представиться." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Проверьте свой электронный почтовый ящик. Мы отправили сообщение с адресом " -"для изменения Вашего пароля." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -341,11 +349,11 @@ msgstr "Создайте здесь!" msgid "Forgot your password?" msgstr "Забыли свой пароль?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Создать аккаунт!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Создать" @@ -376,10 +384,16 @@ msgid "Cancel" msgstr "Отменить" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Сохранить изменения" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -391,13 +405,32 @@ msgstr "Редактирование профиля %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "Файлы с меткой: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Оригинал" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Загрузить файл(ы)" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -409,31 +442,57 @@ msgstr "Файлы %(username)s" msgid "%(username)s's media" msgstr "Файлы пользователя %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Загружено %(username)s %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Оставить комментарий" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "в" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Разместить комментарий!" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Изменить" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Удалить" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "в" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -520,30 +579,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "Здесь вы можете рассказать о себе." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Редактировать профиль" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Это пользователь не заполнил свой профайл (пока)." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Смотреть все файлы %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Ваши файлы появятся здесь, когда вы их добавите." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Добавить файлы" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Пока что тут файлов нет…" @@ -555,29 +615,35 @@ msgstr "значок ленты" msgid "Atom feed" msgstr "лента в формате Atom" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Более новые" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Более старые" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Перейти к странице:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Метки:" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "и" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Комментарий" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo index 5ab7befa..2d3f505f 100644 Binary files a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index 34cf1679..53ad3080 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-10 23:09+0000\n" -"Last-Translator: martin \n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Odovzdaný nesprávny súbor pre daný typ média." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Prihlasovacie meno" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Heslo" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Heslá sa musia zhodovať." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Potvrdiť heslo" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Prepíš ho sem opätovne kvôli uisteniu, že nedošlo k preklepu." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "E-mailová adresa" @@ -59,7 +47,7 @@ msgstr "Prepáč, rovnaké prihlasovacie meno už niekto používa." msgid "Sorry, a user with that email address already exists." msgstr "Prepáč, používateľ s rovnakou e-mailovou adresou už existuje." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -67,70 +55,108 @@ msgstr "" "Tvoja e-mailová adresa bola úspešne overená. Môžeš sa hneď prihlásiť, " "upraviť svoj profil a vkladať výtvory! " -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" -msgstr "Nesprávny overovací kľúč alebo používateľské ID" +msgstr "Nesprávny overovací kľúč alebo používateľský identifikátor" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" -msgstr "Aby sme ti mohli zaslať e-mail, je potrebné byť prihláseným!" +msgstr "" +"Aby sme ti mohli zaslať e-mailovú správu, je potrebné byť prihláseným!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Tvoja e-mailová adresa už bola raz overená!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." -msgstr "Opätovne zaslať overovaciu správu." +msgstr "Opätovne zaslať overovaciu správu na e-mail." + +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" -"Nebolo ti možné zaslať správu ohľadom obnovy hesla, nakoľko je tvoje " -"používateľské meno buď neaktívne alebo e-mailová adresa účtu neoverená." +"Nebolo ti možné zaslať e-mailovú správu ohľadom obnovy hesla, nakoľko je " +"tvoje používateľské meno buď neaktívne alebo e-mailová adresa účtu " +"neoverená." + +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Nadpis" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Charakteristika tohto diela" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" -msgstr "Štítky" +msgstr "Značky" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Oddeľ štítky pomocou čiarky." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Unikátna časť adresy" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" -msgstr "Unikátna časť adresy musí byť vyplnená" +msgstr "Unikátna časť adresy nesmie byť prázdna" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." -msgstr "Titulná časť URL odkazu média. Zvyčajne to meniť nemusíš." +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Webstránka" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "Staré heslo" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Nové heslo" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" +msgstr "" #: mediagoblin/edit/views.py:65 msgid "An entry with that slug already exists for this user." @@ -138,45 +164,49 @@ msgstr "Položku s rovnakou unikátnou časťou adresy už niekde máš." #: mediagoblin/edit/views.py:86 msgid "You are editing another user's media. Proceed with caution." -msgstr "Upravuješ médiá niekoho iného. Pristupuj opatrne." +msgstr "Upravuješ médiá niekoho iného. Dbaj na to." #: mediagoblin/edit/views.py:156 msgid "You are editing a user's profile. Proceed with caution." -msgstr "Upravuješ používateľský profil. Pristupuj opatrne." +msgstr "Upravuješ používateľský profil. Dbaj na to." + +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "Nesprávne heslo" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Profil upravený!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "Nebolo možné nájsť žiadnu príponu v súbore \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Súbor" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Charakteristika diela" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." -msgstr "Poskytni súbor." +msgstr "Musíš poskytnúť súbor." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Juchú! Úspešne vložené!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Nesprávny typ súboru." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Obrázok stresujúceho goblina pri chybovom kóde č. 404" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Ajaj!" @@ -192,33 +222,30 @@ msgstr "" "Ak vieš s istotou, že adresa je správna, tak najskôr bola hľadaná stánka " "presunutá alebo zmazaná." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Obrázok stresujúceho goblina pri chybovom kóde č. 404" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Vložiť výtvor" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Pridať výtvor" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" -msgstr "Over si e-mail!" +msgstr "Over si e-mailovú adresu!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" -msgstr "odhlásenie" +msgstr "odhlásiť sa" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prihlásenie" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -230,7 +257,7 @@ msgstr "" msgid "Explore" msgstr "Preskúmať" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Ahoj, vitaj na tejto MediaGoblin stránke!" @@ -258,25 +285,21 @@ msgstr "Ešte žiaden nemáš? Je to jednoduché!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"<a class=\"header_submit_highlight\" href=\"%(register_url)s\">Vytvoriť bezplatný účet</a>\n" -" alebo\n" -" <a class=\"header_submit\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Sprevádzkovať MediaGoblin na vlastnom serveri</a>" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Najčerstvejšie výtvory" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Vlož svoje nové heslo" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Vložiť" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -284,18 +307,7 @@ msgstr "Obnoviť heslo" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "Zaslať inštrukcie" - -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Heslo ti bolo zmenené. Skús sa prihlásiť teraz." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Skontroluj si e-mailovú schránku. Bol ti zaslaná správa s URL odkazom pre " -"zmenu tvojho hesla." +msgstr "Zaslať postup" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -312,12 +324,11 @@ msgid "" msgstr "" "Ahoj %(username)s,\n" "\n" -"pre zmenu svojho hesla k GNU MediaGoblin účtu, otvor nasledujúci URL odkaz vo \n" -"svojom prehliadači:\n" +"pre zmenu svojho hesla k GNU MediaGoblin účtu, otvor nasledujúci odkaz vo svojom prehliadači:\n" "\n" "%(verification_url)s\n" "\n" -"Pokiaľ si myslíš, že došlo k omylu, tak jednoducho ignoruj túto správu a neprestávaj byť šťastným goblinom!" +"Pokiaľ si myslíš, že došlo k omylu, tak jednoducho ignoruj túto správu a buď šťastným goblinom!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" @@ -329,17 +340,17 @@ msgstr "Ešte nemáš účet?" #: mediagoblin/templates/mediagoblin/auth/login.html:36 msgid "Create one here!" -msgstr "Vytvoriť jeden tu!" +msgstr "Vytvor si jeden tu!" #: mediagoblin/templates/mediagoblin/auth/login.html:42 msgid "Forgot your password?" msgstr "Zabudnuté heslo?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Vytvoriť účet!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Vytvoriť" @@ -355,7 +366,7 @@ msgid "" msgstr "" "Ahoj %(username)s,\n" "\n" -"pre aktiváciu tvojho GNU MediaGoblin účtu, otvor nasledujúci URL odkaz vo\n" +"pre aktiváciu tvojho GNU MediaGoblin účtu, otvor nasledujúci odkaz vo\n" "svojom prehliadači:\n" "\n" "%(verification_url)s" @@ -371,10 +382,16 @@ msgid "Cancel" msgstr "Zrušiť" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Uložiť zmeny" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -384,51 +401,96 @@ msgstr "Úprava profilu, ktorý vlastní %(username)s" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "Výtvory označené s: %(tag_name)s" +msgstr "Výtvory označené ako: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Originál" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Vlož svoj výtvor" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "Výtvory používateľa %(username)s" +msgstr "Výtvory, ktoré vlastní %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" -msgstr "Výtvory, ktoré vlastní %(username)s" +msgstr "Výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Od %(username)s v čase %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Zaslať komentár" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "o" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Zaslať komentár!" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 msgid "Edit" msgstr "Upraviť" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 msgid "Delete" msgstr "Odstrániť" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "o" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -440,24 +502,24 @@ msgstr "Odstrániť navždy" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22 msgid "Media processing panel" -msgstr "Sekcia spracovania médií" +msgstr "Sekcia spracovania výtvorov" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "Tu môžeš sledovať priebeh spracovania médií pre svoju galériu." +msgstr "Tu môžeš sledovať priebeh spracovania výtvorov pre svoju galériu." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" -msgstr "Médiá v procese spracovania" +msgstr "Výtvory sa spracúvajú" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46 msgid "No media in-processing" -msgstr "Žiadne médiá v procese spracovania" +msgstr "Žiadne výtvory sa nespracúvajú" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50 msgid "These uploads failed to process:" -msgstr "Nasledovné vloženia neprešli spracovaním:" +msgstr "Nasledovné nahratia neprešli spracovaním:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:31 #: mediagoblin/templates/mediagoblin/user_pages/user.html:89 @@ -467,7 +529,7 @@ msgstr "Profil, ktorý vlastní %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:43 msgid "Sorry, no such user found." -msgstr "Prepáč, používateľské meno nenájdené." +msgstr "Prepáč, zadané používateľské meno nenájdené." #: mediagoblin/templates/mediagoblin/user_pages/user.html:50 #: mediagoblin/templates/mediagoblin/user_pages/user.html:70 @@ -481,7 +543,7 @@ msgstr "Takmer hotovo! Ešte ti musí byť aktivovaný účet." #: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." -msgstr "E-mailová správa s popisom ako to spraviť, by mala onedlho doraziť." +msgstr "E-mailová správa s popisom ako to spraviť, by mal zanedlho doraziť." #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" @@ -489,7 +551,7 @@ msgstr "V prípade, že sa tak nestalo:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" -msgstr "Opätovne zaslať overovaciu správu" +msgstr "Opätovne zaslať overovaciu správu na e-mail" #: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" @@ -505,41 +567,42 @@ msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." msgstr "" -"Pokiaľ si to ty, ale už nemáš overovaciu správu, tak sa môžeš prihlásiť a preposlať si ju." #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." -msgstr "Povedz tu o sebe ostatným." +msgstr "Miesto, kde smieš povedať čo to o sebe ostatným." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Upraviť profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." -msgstr "Dotyčná osoba ešte nevyplnila svoj profil (zatiaľ)." +msgstr "Dotyčný používateľ ešte nevyplnil svoj profil (zatiaľ)." + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Zhliadnuť všetky výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" "Všetky tvoje výtvory sa objavia práve tu, ale zatiaľ nemáš nič pridané." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Pridať výtvor" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." -msgstr "Najskôr tu ešte nebudú žiadne výtvory..." +msgstr "Najskôr sa tu ešte nenachádzajú žiadne výtvory..." #: mediagoblin/templates/mediagoblin/utils/feed_link.html:21 msgid "feed icon" @@ -549,29 +612,35 @@ msgstr "ikona čítačky" msgid "Atom feed" msgstr "Čítačka Atom" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Novšie" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Staršie" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" -msgstr "Ísť na stránku:" +msgstr "Prejsť na stránku:" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Označené s" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "a" - -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Komentár" +msgid "or" +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" @@ -587,14 +656,14 @@ msgstr "Tvoj komentár bol zaslaný!" #: mediagoblin/user_pages/views.py:183 msgid "You deleted the media." -msgstr "Výtvor bol odstránený tebou." +msgstr "Výtvor bol tebou odstránený." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "Výtvor nebol odstránený, nakoľko chýbala tvoja konfirmácia." +msgstr "Výtvor nebol odstránený, nakoľko chýbalo tvoje potvrdenie." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." -msgstr "Chystáš sa odstrániť výtvory niekoho iného. Pristupuj opatrne." +msgstr "Chystáš sa odstrániť výtvory niekoho iného. Dbaj na to." diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 9ad54a83..73bb4113 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index ffd2c04c..c5d3104c 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Za vrsto vsebine je bila podana napačna datoteka." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Uporabniško ime" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Geslo" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Gesli morata biti enaki." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Potrdite geslo" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "E-poštni naslov" @@ -59,7 +47,7 @@ msgstr "Oprostite, uporabnik s tem imenom že obstaja." msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -67,67 +55,103 @@ msgstr "" "Vaš e-poštni naslov je bil potrjen. Sedaj se lahko prijavite, uredite svoj " "profil in pošljete slike." -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Potrditveni ključ ali uporabniška identifikacija je napačna" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Ponovno pošiljanje potrditvene e-pošte." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Naslov" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Oznake" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Oznaka" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Oznaka ne sme biti prazna" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Biografija" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Spletna stran" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -142,39 +166,43 @@ msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Datoteka" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Podati morate datoteko." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Juhej! Poslano." -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Slika napake 404 s paničnim škratom" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Opa!" @@ -190,33 +218,30 @@ msgstr "" "Če ste v točnost naslova prepričani, je bila iskana stran morda premaknjena " "ali pa izbrisana." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Slika napake 404 s paničnim škratom" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "Logotip MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Pošlji vsebino" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Dodaj vsebino" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prijava" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -226,7 +251,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -250,22 +275,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Pošlji" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -275,15 +299,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -314,11 +329,11 @@ msgstr "Ustvarite si ga." msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Ustvarite račun." -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Ustvari" @@ -350,10 +365,16 @@ msgid "Cancel" msgstr "Prekliči" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Shrani spremembe" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -365,13 +386,32 @@ msgstr "Urejanje profila – %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Pošljite svojo vsebino" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -383,29 +423,55 @@ msgstr "" msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -492,30 +558,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "Na tem mestu lahko drugim poveste nekaj o sebi." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Uredi profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Ta uporabnik še ni izpolnil svojega profila." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Prikaži vso vsebino uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "Tu bo prikazana vaša vsebina, a trenutno še niste dodali nič." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Dodaj vsebino" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Videti je, da tu še ni nobene vsebine ..." @@ -527,30 +594,36 @@ msgstr "Ikona vira" msgid "Atom feed" msgstr "Ikona Atom" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Komentar" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index ece8989f..2a99cb53 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index 942f7203..cdfdad05 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -22,27 +22,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "" @@ -58,73 +46,109 @@ msgstr "" msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -139,39 +163,43 @@ msgstr "" msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/submit/forms.py:25 -msgid "File" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" +#: mediagoblin/submit/forms.py:25 +msgid "File" msgstr "" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "" @@ -185,33 +213,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -221,7 +246,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -245,21 +270,20 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 @@ -270,15 +294,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -309,11 +324,11 @@ msgstr "" msgid "Forgot your password?" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "" @@ -339,10 +354,16 @@ msgid "Cancel" msgstr "" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -354,12 +375,31 @@ msgstr "" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 @@ -372,29 +412,55 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -477,30 +543,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -512,28 +579,34 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" +#: mediagoblin/templates/mediagoblin/utils/tags.html:20 +msgid "View more media tagged with" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/tags.html:25 +msgid "or" msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index c6cf0df9..d647e373 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index e195ad70..acace870 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -24,27 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Ogiltig fil för mediatypen." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Användarnamn" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Lösenord" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Lösenorden måste vara identiska." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Bekräfta lösenord" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Skriv in det igen för att undvika stavfel." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "E-postadress" @@ -60,7 +48,7 @@ msgstr "En användare med det användarnamnet finns redan." msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -68,23 +56,28 @@ msgstr "" "Din e-postadress är verifierad. Du kan nu logga in, redigera din profil och " "ladda upp filer!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "Verifieringsnyckeln eller användar-IDt är fel." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Skickade ett nytt verifierings-email." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -92,45 +85,76 @@ msgstr "" "Kunde inte skicka e-poståterställning av lösenord eftersom ditt användarnamn" " är inaktivt eller kontots e-postadress har inte verifierats." +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "Beskrivning av verket" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "Taggar" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "Sökvägsnamn" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "Sökvägsnamnet kan inte vara tomt" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." -msgstr "Sökvägstitlen för din media. Du brukar inte behöva ändra denna." +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "Presentation" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "Hemsida" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -145,39 +169,43 @@ msgstr "Var försiktig, du redigerar någon annans inlägg." msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" +msgstr "" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" #: mediagoblin/submit/forms.py:25 msgid "File" msgstr "Fil" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Beskrivning av verket" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "Du måste ange en fil" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "Tjohoo! Upladdat!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Bild av stressat 404-troll." -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Ojoj!" @@ -193,33 +221,30 @@ msgstr "" "Om du är säker på att adressen stämmer så kanske sidan du letar efter har " "flyttats eller tagits bort." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Bild av stressat 404-troll." - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "MediaGoblin-logotyp" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Ladda upp" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Lägg till media" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logga in" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -231,7 +256,7 @@ msgstr "" msgid "Explore" msgstr "Utforska" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -255,22 +280,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Senast medier" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Fyll i ditt lösenord" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Skicka" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -280,17 +304,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Ditt lösenord är nu ändrat. Testa att logga in nu." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Kolla din inkorg. Vi har skickat ett e-postmeddelande med en webbadress för " -"att ändra ditt lösenord." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -329,11 +342,11 @@ msgstr "Skapa ett här!" msgid "Forgot your password?" msgstr "Glömt ditt lösenord?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Skapa ett konto!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Skapa" @@ -364,10 +377,16 @@ msgid "Cancel" msgstr "Avbryt" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Spara ändringar" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -379,13 +398,32 @@ msgstr "Redigerar %(username)ss profil" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Ladda upp" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -397,29 +435,55 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)ss media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -508,20 +572,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Här kan du berätta för andra om dig själv." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Redigera profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Den här användaren har inte fyllt i sin profilsida ännu." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Se all media från %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -529,11 +597,8 @@ msgstr "" "Här kommer din media att dyka upp, du verkar inte ha lagt till någonting " "ännu." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Lägg till media" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Det verkar inte finnas någon media här ännu." @@ -545,30 +610,36 @@ msgstr "feed-ikon" msgid "Atom feed" msgstr "Atom-feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Nyare" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Äldre" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Kommentar" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Jag är säker på att jag vill radera detta" diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo index cd9fab9f..5480404c 100644 Binary files a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po index f7bbd6ac..14e12315 100644 --- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-04 16:23+0000\n" +"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"PO-Revision-Date: 2012-01-07 19:44+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "వాడుకరి పేరు" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "సంకేతపదం" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "ఈమెయిలు చిరునామా" @@ -59,73 +47,109 @@ msgstr "" msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "" +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + #: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 msgid "Title" msgstr "శీర్షిక" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +msgid "Description of this work" +msgstr "" + +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." +#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:37 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:38 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:39 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:46 msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:48 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:53 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:60 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:62 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:65 +msgid "New password" msgstr "" #: mediagoblin/edit/views.py:65 @@ -140,39 +164,43 @@ msgstr "" msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:174 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:200 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" +#: mediagoblin/edit/views.py:216 +msgid "Account settings saved" msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" msgstr "" -#: mediagoblin/submit/forms.py:25 -msgid "File" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" +#: mediagoblin/submit/forms.py:25 +msgid "File" msgstr "" -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:50 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:128 msgid "Woohoo! Submitted!" msgstr "" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "" @@ -186,33 +214,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:48 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" +#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:64 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:71 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:74 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:86 msgid "" "Powered by MediaGoblin, a GNU project" @@ -222,7 +247,7 @@ msgstr "" msgid "Explore" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "" @@ -246,22 +271,21 @@ msgstr "" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "దాఖలు చెయ్యి" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -271,15 +295,6 @@ msgstr "" msgid "Send instructions" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -310,11 +325,11 @@ msgstr "" msgid "Forgot your password?" msgstr "మీ సంకేతపదాన్ని మర్చిపోయారా?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "" @@ -340,10 +355,16 @@ msgid "Cancel" msgstr "రద్దుచేయి" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "మార్పులను భద్రపరచు" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -355,12 +376,31 @@ msgstr "" msgid "Media tagged with: %(tag_name)s" msgstr "" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 @@ -373,29 +413,55 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 #, python-format -msgid "By %(username)s on %(date)s" +msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +msgid "Delete" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#, python-format +msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#, python-format +msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 -msgid "Edit" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 -msgid "Delete" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +msgid "" +"Type your comment here. You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +msgid "at" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 @@ -478,30 +544,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "" @@ -513,30 +580,36 @@ msgstr "" msgid "Atom feed" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" +msgid "View more media tagged with" msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" +msgid "or" msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "వ్యాఖ్య" - #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index 6dda94b7..a7820c49 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ -- cgit v1.2.3 From f42e49c3ad1c446e7899e7b76cd7fa381d5bba7c Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 5 Jan 2012 00:18:17 +0100 Subject: Add DB Mixin classes and use them A bunch of functions on the db objects are really more like "utility functions": They could live outside the classes and be called "by hand" passing the appropiate reference. They usually only use the public API of the object and rarely use database related stuff. Goals: - First, simple: Share the code with the SQL objects, so that the code doesn't need to be duplicated. - Second, it might unclutter the db models and make them more into "model only" stuff. - Doesn't really hurt. --- mediagoblin/db/mixin.py | 90 ++++++++++++++++++++++++++++++++++++++++++ mediagoblin/db/mongo/models.py | 63 ++--------------------------- mediagoblin/db/sql/models.py | 5 ++- 3 files changed, 97 insertions(+), 61 deletions(-) create mode 100644 mediagoblin/db/mixin.py diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py new file mode 100644 index 00000000..4fb325d2 --- /dev/null +++ b/mediagoblin/db/mixin.py @@ -0,0 +1,90 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +""" +This module contains some Mixin classes for the db objects. + +A bunch of functions on the db objects are really more like +"utility functions": They could live outside the classes +and be called "by hand" passing the appropiate reference. +They usually only use the public API of the object and +rarely use database related stuff. + +These functions now live here and get "mixed in" into the +real objects. +""" + +from mediagoblin.auth import lib as auth_lib +from mediagoblin.tools import common + + +class UserMixin(object): + def check_login(self, password): + """ + See if a user can login with this password + """ + return auth_lib.bcrypt_check_password( + password, self.pw_hash) + + +class MediaEntryMixin(object): + def get_display_media(self, media_map, + fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): + """ + Find the best media for display. + + Args: + - media_map: a dict like + {u'image_size': [u'dir1', u'dir2', u'image.jpg']} + - fetch_order: the order we should try fetching images in + + Returns: + (media_size, media_path) + """ + media_sizes = media_map.keys() + + for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: + if media_size in media_sizes: + return media_map[media_size] + + def main_mediafile(self): + pass + + def url_for_self(self, urlgen): + """ + Generate an appropriate url for ourselves + + Use a slug if we have one, else use our '_id'. + """ + uploader = self.get_uploader + + if self.get('slug'): + return urlgen( + 'mediagoblin.user_pages.media_home', + user=uploader.username, + media=self.slug) + else: + return urlgen( + 'mediagoblin.user_pages.media_home', + user=uploader.username, + media=unicode(self._id)) + + def get_fail_exception(self): + """ + Get the exception that's appropriate for this error + """ + if self['fail_error']: + return common.import_component(self['fail_error']) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 5de59c12..906d2849 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -18,12 +18,12 @@ import datetime from mongokit import Document -from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals from mediagoblin.db.mongo import migrations from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination -from mediagoblin.tools import url, common +from mediagoblin.tools import url +from mediagoblin.db.mixin import UserMixin, MediaEntryMixin ################### # Custom validators @@ -34,7 +34,7 @@ from mediagoblin.tools import url, common ######## -class User(Document): +class User(Document, UserMixin): """ A user of MediaGoblin. @@ -89,15 +89,8 @@ class User(Document): 'status': u'needs_email_verification', 'is_admin': False} - def check_login(self, password): - """ - See if a user can login with this password - """ - return auth_lib.bcrypt_check_password( - password, self.pw_hash) - -class MediaEntry(Document): +class MediaEntry(Document, MediaEntryMixin): """ Record of a piece of media. @@ -224,28 +217,6 @@ class MediaEntry(Document): return self.db.MediaComment.find({ 'media_entry': self._id}).sort('created', order) - def get_display_media(self, media_map, - fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): - """ - Find the best media for display. - - Args: - - media_map: a dict like - {u'image_size': [u'dir1', u'dir2', u'image.jpg']} - - fetch_order: the order we should try fetching images in - - Returns: - (media_size, media_path) - """ - media_sizes = media_map.keys() - - for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: - if media_size in media_sizes: - return media_map[media_size] - - def main_mediafile(self): - pass - def generate_slug(self): self.slug = url.slugify(self.title) @@ -255,25 +226,6 @@ class MediaEntry(Document): if duplicate: self.slug = "%s-%s" % (self._id, self.slug) - def url_for_self(self, urlgen): - """ - Generate an appropriate url for ourselves - - Use a slug if we have one, else use our '_id'. - """ - uploader = self.get_uploader - - if self.get('slug'): - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=self.slug) - else: - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=unicode(self._id)) - def url_to_prev(self, urlgen): """ Provide a url to the previous entry from this user, if there is one @@ -301,13 +253,6 @@ class MediaEntry(Document): def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) - def get_fail_exception(self): - """ - Get the exception that's appropriate for this error - """ - if self['fail_error']: - return common.import_component(self['fail_error']) - class MediaComment(Document): """ diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 31a6ed3b..95821b4f 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -7,6 +7,7 @@ from sqlalchemy import ( from sqlalchemy.orm import relationship from mediagoblin.db.sql.base import GMGTableBase +from mediagoblin.db.mixin import UserMixin, MediaEntryMixin Base = declarative_base(cls=GMGTableBase) @@ -24,7 +25,7 @@ class SimpleFieldAlias(object): setattr(instance, self.fieldname, val) -class User(Base): +class User(Base, UserMixin): __tablename__ = "users" id = Column(Integer, primary_key=True) @@ -48,7 +49,7 @@ class User(Base): _id = SimpleFieldAlias("id") -class MediaEntry(Base): +class MediaEntry(Base, MediaEntryMixin): __tablename__ = "media_entries" id = Column(Integer, primary_key=True) -- cgit v1.2.3 From 7cbbf3e75b2dc67068ec270e53249d95224a86cc Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 9 Jan 2012 14:22:28 +0100 Subject: Create a default logging config paste uses paste.ini to configure python's logging module. Until now, there was NO config, not even a useful default one. This means: any messages went away unseen. Not good. The new default logs everything to stderr at level INFO and higher. Maybe not the best, but a good starting point. --- paste.ini | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/paste.ini b/paste.ini index c729e41d..13c15209 100644 --- a/paste.ini +++ b/paste.ini @@ -19,6 +19,28 @@ use = egg:mediagoblin#app filter-with = beaker config = %(here)s/mediagoblin_local.ini %(here)s/mediagoblin.ini +[loggers] +keys = root + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-7.7s [%(name)s] %(message)s + [app:publicstore_serve] use = egg:Paste#static document_root = %(here)s/user_dev/media/public/ -- cgit v1.2.3 From 1b876ac2ea58830b187463dd3de75299fa257212 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 9 Jan 2012 14:26:01 +0100 Subject: Warn about unknown staticdirect paths. Use pkg_resource to check for the existence of any files referenced by staticdirect. If they don't exist, warn about this. This might raise false warnings in the future for more advanced setups. --- mediagoblin/staticdirect.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mediagoblin/staticdirect.py b/mediagoblin/staticdirect.py index c6d2b374..2bddb160 100644 --- a/mediagoblin/staticdirect.py +++ b/mediagoblin/staticdirect.py @@ -14,9 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import pkg_resources -import urlparse - #################################### # Staticdirect infrastructure. # Borrowed largely from cc.engine @@ -26,7 +23,9 @@ import urlparse #################################### import pkg_resources -import urlparse +import logging + +_log = logging.getLogger(__name__) class StaticDirect(object): @@ -37,6 +36,10 @@ class StaticDirect(object): if filepath in self.cache: return self.cache[filepath] + if not pkg_resources.resource_exists('mediagoblin', + 'static' + filepath): + _log.info("StaticDirect resource %r not found locally", + filepath) static_direction = self.cache[filepath] = self.get(filepath) return static_direction -- cgit v1.2.3 From 1dc7f28d2476135f9548a92ec1147659f1a4e810 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 9 Jan 2012 14:33:57 +0100 Subject: Fix reset.css reference and drop link to video-js.css 1. reset.css was moved to /css/extlib/ some time ago. So update the staticdirect link to it. 2. We don't have video-js.css (any more?). Drop link to it. --- mediagoblin/templates/mediagoblin/base.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 82ee41b7..5335ebe3 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -22,11 +22,9 @@ {% block title %}{{ app_config['html_title'] }}{% endblock %} + href="{{ request.staticdirect('/css/extlib/reset.css') }}"/> - -- cgit v1.2.3 From c2d6792ddb8d968e0c93a7cdd1da7bdae3b5fa36 Mon Sep 17 00:00:00 2001 From: Elrond Date: Tue, 10 Jan 2012 12:52:01 +0100 Subject: Test Suite: Enable attachments, add failing test attachments are an optional part. But it doesn't hurt to enable them in the test suite at all. Also (with enabled attachmemtns) the main media view fails, if one isn't logged in (joar found it!). So add a simple (currently failing) test for this. --- mediagoblin/tests/test_mgoblin_app.ini | 3 +++ mediagoblin/tests/test_submission.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index 2525a4f9..c91ed92b 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -7,6 +7,9 @@ db_name = __mediagoblin_tests__ # tag parsing tags_max_length = 50 +# So we can start to test attachments: +allow_attachments = True + # Celery shouldn't be set up by the application as it's setup via # mediagoblin.init.celery.from_celery celery_setup_elsewhere = true diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 2b17c515..b3c11249 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -51,11 +51,17 @@ class TestSubmission: self.test_user = test_user + self.login() + + def login(self): self.test_app.post( '/auth/login/', { 'username': u'chris', 'password': 'toast'}) + def logout(self): + self.test_app.get('/auth/logout/') + def test_missing_fields(self): # Test blank form # --------------- @@ -95,6 +101,14 @@ class TestSubmission: assert template.TEMPLATE_TEST_CONTEXT.has_key( 'mediagoblin/user_pages/user.html') + # Make sure the media view is at least reachable, logged in... + self.test_app.get('/u/chris/m/normal-upload-1/') + # ... and logged out too. + self.logout() + self.test_app.get('/u/chris/m/normal-upload-1/') + # Log back in for the remaining tests. + self.login() + # Test PNG # -------- template.clear_test_template_context() -- cgit v1.2.3 From 914b8bcde3e01c2dd3e5679fb7733fc194b34d68 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 13:12:14 +0100 Subject: Added check for request.user to media.html attachment-related conditional --- mediagoblin/templates/mediagoblin/user_pages/media.html | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 10525f4c..583e4ebd 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -158,6 +158,7 @@

{% endif %} {% if app_config['allow_attachments'] + and request.user and (media.uploader == request.user._id or request.user.is_admin) %}

-- cgit v1.2.3 From 1df68a3524d92caee5601a8acc011ac8e1fe16d4 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Thu, 5 Jan 2012 18:48:23 +0100 Subject: Fixed #724 and added extra infos to the atom feed (author uri and links to the html version of each entry) --- mediagoblin/db/mongo/models.py | 8 +++++--- mediagoblin/listings/views.py | 24 ++++++++++++++++++++---- mediagoblin/user_pages/views.py | 28 ++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 5de59c12..f1e8eae6 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -255,7 +255,7 @@ class MediaEntry(Document): if duplicate: self.slug = "%s-%s" % (self._id, self.slug) - def url_for_self(self, urlgen): + def url_for_self(self, urlgen, **extra_args): """ Generate an appropriate url for ourselves @@ -267,12 +267,14 @@ class MediaEntry(Document): return urlgen( 'mediagoblin.user_pages.media_home', user=uploader.username, - media=self.slug) + media=self.slug, + **extra_args) else: return urlgen( 'mediagoblin.user_pages.media_home', user=uploader.username, - media=unicode(self._id)) + media=unicode(self._id), + **extra_args) def url_to_prev(self, urlgen): """ diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index 3ecf06f4..ca8e8229 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -77,17 +77,33 @@ def tag_atom_feed(request): cursor = cursor.sort('created', DESCENDING) cursor = cursor.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) + """ + ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) + """ feed = AtomFeed( "MediaGoblin: Feed for tag '%s'" % tag_slug, feed_url=request.url, - url=request.host_url) - + id='tag:'+request.host+',2011:gallery.tag-%s' % tag_slug, + links=[{'href': request.urlgen( + 'mediagoblin.listings.tags_listing', + qualified=True, tag=tag_slug ), + 'rel': 'alternate', + 'type': 'text/html'}]) for entry in cursor: feed.add(entry.get('title'), entry.get('description_html'), + id=entry.url_for_self(request.urlgen,qualified=True), content_type='html', - author=entry.get_uploader.username, + author={'name': entry.get_uploader.username, + 'uri': request.urlgen( + 'mediagoblin.user_pages.user_home', + qualified=True, user=entry.get_uploader.username)}, updated=entry.get('created'), - url=entry.url_for_self(request.urlgen)) + links=[{ + 'href':entry.url_for_self( + request.urlgen, + qualified=True), + 'rel': 'alternate', + 'type': 'text/html'}]) return feed.get_response() diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index f721f012..a234722f 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -225,17 +225,37 @@ def atom_feed(request): .sort('created', DESCENDING) \ .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) - feed = AtomFeed(request.matchdict['user'], + """ + ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) + """ + feed = AtomFeed( + "MediaGoblin: Feed for user '%s'" % request.matchdict['user'], feed_url=request.url, - url=request.host_url) + id='tag:'+request.host+',2011:gallery.user-'+request.matchdict['user'], + links=[{ + 'href': request.urlgen( + 'mediagoblin.user_pages.user_home', + qualified=True,user=request.matchdict['user']), + 'rel': 'alternate', + 'type': 'text/html'}]) for entry in cursor: feed.add(entry.get('title'), entry.get('description_html'), + id=entry.url_for_self(request.urlgen,qualified=True), content_type='html', - author=request.matchdict['user'], + author={ + 'name': entry.get_uploader.username, + 'uri': request.urlgen( + 'mediagoblin.user_pages.user_home', + qualified=True, user=entry.get_uploader.username)}, updated=entry.get('created'), - url=entry.url_for_self(request.urlgen)) + links=[{ + 'href': entry.url_for_self( + request.urlgen, + qualified=True), + 'rel': 'alternate', + 'type': 'text/html'}]) return feed.get_response() -- cgit v1.2.3 From cb7ae1e4331f3521b2028388c3d4ff2555d61eb3 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 11 Jan 2012 11:16:35 +0100 Subject: Fix url_for_self mixup Move changes from mongo/models:url_for_self back into mixin:url_for_self. --- mediagoblin/db/mixin.py | 8 +++++--- mediagoblin/db/mongo/models.py | 21 --------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 4fb325d2..5145289e 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -63,7 +63,7 @@ class MediaEntryMixin(object): def main_mediafile(self): pass - def url_for_self(self, urlgen): + def url_for_self(self, urlgen, **extra_args): """ Generate an appropriate url for ourselves @@ -75,12 +75,14 @@ class MediaEntryMixin(object): return urlgen( 'mediagoblin.user_pages.media_home', user=uploader.username, - media=self.slug) + media=self.slug, + **extra_args) else: return urlgen( 'mediagoblin.user_pages.media_home', user=uploader.username, - media=unicode(self._id)) + media=unicode(self._id), + **extra_args) def get_fail_exception(self): """ diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index d9b5a570..906d2849 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -226,27 +226,6 @@ class MediaEntry(Document, MediaEntryMixin): if duplicate: self.slug = "%s-%s" % (self._id, self.slug) - def url_for_self(self, urlgen, **extra_args): - """ - Generate an appropriate url for ourselves - - Use a slug if we have one, else use our '_id'. - """ - uploader = self.get_uploader - - if self.get('slug'): - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=self.slug, - **extra_args) - else: - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=unicode(self._id), - **extra_args) - def url_to_prev(self, urlgen): """ Provide a url to the previous entry from this user, if there is one -- cgit v1.2.3 From 0ab21f981a8a170f5bf4e83f7d56d3ed8fdae467 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 20:04:41 +0100 Subject: Dot-Notation: Some random places --- mediagoblin/auth/views.py | 2 +- mediagoblin/edit/views.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 88dc40ad..c04a49a7 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -205,7 +205,7 @@ def resend_activation(request): return redirect(request, 'mediagoblin.auth.login') - if request.user["email_verified"]: + if request.user.email_verified: messages.add_message( request, messages.ERROR, diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index bae85c5d..ec748028 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -46,7 +46,7 @@ def edit_media(request, media): title=media.title, slug=media.slug, description=media.description, - tags=media_tags_as_string(media['tags'])) + tags=media_tags_as_string(media.tags)) form = forms.EditForm( request.POST, @@ -165,7 +165,7 @@ def edit_profile(request): user.url = unicode(request.POST['url']) user.bio = unicode(request.POST['bio']) - user.bio_html = cleaned_markdown_conversion(user['bio']) + user.bio_html = cleaned_markdown_conversion(user.bio) user.save() @@ -193,7 +193,7 @@ def edit_account(request): if request.method == 'POST' and form.validate(): password_matches = auth_lib.bcrypt_check_password( request.POST['old_password'], - user['pw_hash']) + user.pw_hash) if (request.POST['old_password'] or request.POST['new_password']) and not \ password_matches: @@ -206,7 +206,7 @@ def edit_account(request): 'form': form}) if password_matches: - user['pw_hash'] = auth_lib.bcrypt_gen_password_hash( + user.pw_hash = auth_lib.bcrypt_gen_password_hash( request.POST['new_password']) user.save() @@ -216,7 +216,7 @@ def edit_account(request): _("Account settings saved")) return redirect(request, 'mediagoblin.user_pages.user_home', - user=user['username']) + user=user.username) return render_to_response( request, -- cgit v1.2.3 From 02db7e0a83fc06eaa8e96888f6c9e4fb44e7cbe2 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 31 Dec 2011 23:01:34 +0100 Subject: Add MediaFile table and related infrastructure. - This adds a new SQL table field type for path tuples. They're stored as '/' separated unicode strings. - Uses it to implement a MediaFile table. - Add relationship and proxy fields on MediaEntry to give a nice media_files "view" there. - Let the converter fill the MediaFile. --- mediagoblin/db/sql/convert.py | 7 ++++++- mediagoblin/db/sql/extratypes.py | 18 ++++++++++++++++++ mediagoblin/db/sql/models.py | 27 +++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 mediagoblin/db/sql/extratypes.py diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 6698b767..88614fd4 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -2,7 +2,7 @@ from mediagoblin.init import setup_global_and_app_config, setup_database from mediagoblin.db.mongo.util import ObjectId from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment, - Tag, MediaTag) + Tag, MediaTag, MediaFile) from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \ sql_connect from mediagoblin.db.mongo.open import setup_connection_and_db_from_config as \ @@ -70,6 +70,11 @@ def convert_media_entries(mk_db): session.flush() add_obj_ids(entry, new_entry) + for key, value in entry.media_files.iteritems(): + new_file = MediaFile(name=key, file_path=value) + new_file.media_entry = new_entry.id + Session.add(new_file) + session.commit() session.close() diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py new file mode 100644 index 00000000..88f556d9 --- /dev/null +++ b/mediagoblin/db/sql/extratypes.py @@ -0,0 +1,18 @@ +from sqlalchemy.types import TypeDecorator, Unicode + + +class PathTupleWithSlashes(TypeDecorator): + "Represents a Tuple of strings as a slash separated string." + + impl = Unicode + + def process_bind_param(self, value, dialect): + if value is not None: + assert len(value), "Does not support empty lists" + value = '/'.join(value) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = tuple(value.split('/')) + return value diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 95821b4f..91092f33 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -5,7 +5,10 @@ from sqlalchemy import ( Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint) from sqlalchemy.orm import relationship +from sqlalchemy.orm.collections import attribute_mapped_collection +from sqlalchemy.ext.associationproxy import association_proxy +from mediagoblin.db.sql.extratypes import PathTupleWithSlashes from mediagoblin.db.sql.base import GMGTableBase from mediagoblin.db.mixin import UserMixin, MediaEntryMixin @@ -65,7 +68,7 @@ class MediaEntry(Base, MediaEntryMixin): fail_error = Column(Unicode) fail_metadata = Column(UnicodeText) - queued_media_file = Column(Unicode) + queued_media_file = Column(PathTupleWithSlashes) queued_task_id = Column(Unicode) @@ -75,13 +78,33 @@ class MediaEntry(Base, MediaEntryMixin): get_uploader = relationship(User) + media_files_helper = relationship("MediaFile", + collection_class=attribute_mapped_collection("name"), + cascade="all, delete-orphan" + ) + media_files = association_proxy('media_files_helper', 'file_path', + creator=lambda k,v: MediaFile(name=k, file_path=v) + ) + ## TODO - # media_files # media_data # attachment_files # fail_error +class MediaFile(Base): + __tablename__ = "mediafiles" + + media_entry = Column( + Integer, ForeignKey(MediaEntry.id), + nullable=False, primary_key=True) + name = Column(Unicode, primary_key=True) + file_path = Column(PathTupleWithSlashes) + + def __repr__(self): + return "" % (self.name, self.file_path) + + class Tag(Base): __tablename__ = "tags" -- cgit v1.2.3 From 5b1a7bae3c8e56ea9b512dcbba6b8a512304a956 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Wed, 11 Jan 2012 15:48:37 +0100 Subject: Added PuSH capability --- mediagoblin/config_spec.ini | 3 +++ mediagoblin/submit/views.py | 14 ++++++++++++++ mediagoblin/user_pages/views.py | 20 ++++++++++++++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index eb22bc1b..226356d9 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -50,6 +50,9 @@ allow_attachments = boolean(default=False) # Cookie stuff csrf_cookie_name = string(default='mediagoblin_csrftoken') +# Push stuff +push_enabled = boolean(default=True) +push_url = string(default='https://pubsubhubbub.appspot.com/') [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index dd273c7f..d5aa60fa 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -20,6 +20,7 @@ from os.path import splitext from cgi import FieldStorage from celery import registry +import urllib,urllib2 from werkzeug.utils import secure_filename @@ -125,6 +126,19 @@ def submit_start(request): # re-raise the exception raise + if mg_globals.app_config["push_enabled"]: + feed_url=request.urlgen( + 'mediagoblin.user_pages.atom_feed', + qualified=True,user=request.user.username) + hubparameters = { + 'hub.mode': 'publish', + 'hub.url': feed_url} + huburl = mg_globals.app_config["push_url"] + hubdata = urllib.urlencode(hubparameters) + hubheaders = {"Content-type": "application/x-www-form-urlencoded"} + hubrequest = urllib2.Request(huburl, hubdata,hubheaders) + hubresponse = urllib2.urlopen(hubrequest) + add_message(request, SUCCESS, _('Woohoo! Submitted!')) return redirect(request, "mediagoblin.user_pages.user_home", diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index a234722f..ee7cfe0f 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -228,16 +228,24 @@ def atom_feed(request): """ ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI) """ + atomlinks = [{ + 'href': request.urlgen( + 'mediagoblin.user_pages.user_home', + qualified=True,user=request.matchdict['user']), + 'rel': 'alternate', + 'type': 'text/html' + }]; + if mg_globals.app_config["push_enabled"]: + atomlinks.append({ + 'rel': 'hub', + 'href': mg_globals.app_config["push_url"]}) + feed = AtomFeed( "MediaGoblin: Feed for user '%s'" % request.matchdict['user'], feed_url=request.url, id='tag:'+request.host+',2011:gallery.user-'+request.matchdict['user'], - links=[{ - 'href': request.urlgen( - 'mediagoblin.user_pages.user_home', - qualified=True,user=request.matchdict['user']), - 'rel': 'alternate', - 'type': 'text/html'}]) + links=atomlinks) + for entry in cursor: feed.add(entry.get('title'), -- cgit v1.2.3 From f502a89b6dad993a44088a84c9f441fdc74189f8 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Wed, 11 Jan 2012 16:11:23 +0100 Subject: Default is now PuSH disabled --- mediagoblin/config_spec.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 226356d9..d692f205 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -51,8 +51,8 @@ allow_attachments = boolean(default=False) csrf_cookie_name = string(default='mediagoblin_csrftoken') # Push stuff -push_enabled = boolean(default=True) -push_url = string(default='https://pubsubhubbub.appspot.com/') +push_enabled = boolean(default=False) +push_url = string(default='') [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") -- cgit v1.2.3 From 7f251b037bd5207652ca73f556e90b9633786a3c Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Thu, 12 Jan 2012 00:00:28 +0100 Subject: As suggested by Elrond, we use only one setting --- mediagoblin/config_spec.ini | 1 - mediagoblin/submit/views.py | 2 +- mediagoblin/user_pages/views.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index d692f205..b8e7b193 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -51,7 +51,6 @@ allow_attachments = boolean(default=False) csrf_cookie_name = string(default='mediagoblin_csrftoken') # Push stuff -push_enabled = boolean(default=False) push_url = string(default='') [storage:publicstore] diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index d5aa60fa..de280422 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -126,7 +126,7 @@ def submit_start(request): # re-raise the exception raise - if mg_globals.app_config["push_enabled"]: + if mg_globals.app_config["push_url"]: feed_url=request.urlgen( 'mediagoblin.user_pages.atom_feed', qualified=True,user=request.user.username) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index ee7cfe0f..2d4eac69 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -235,7 +235,7 @@ def atom_feed(request): 'rel': 'alternate', 'type': 'text/html' }]; - if mg_globals.app_config["push_enabled"]: + if mg_globals.app_config["push_url"]: atomlinks.append({ 'rel': 'hub', 'href': mg_globals.app_config["push_url"]}) -- cgit v1.2.3 From bb025ebda14297b721f8816d13980a477f62bca6 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Thu, 12 Jan 2012 11:05:05 +0100 Subject: As per spec, we permit to have more then 1 hub --- mediagoblin/config_spec.ini | 2 +- mediagoblin/submit/views.py | 12 +++++++----- mediagoblin/user_pages/views.py | 9 +++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index b8e7b193..dc286a27 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -51,7 +51,7 @@ allow_attachments = boolean(default=False) csrf_cookie_name = string(default='mediagoblin_csrftoken') # Push stuff -push_url = string(default='') +push_urls = string_list(default=list()) [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index de280422..65243ca1 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -126,18 +126,20 @@ def submit_start(request): # re-raise the exception raise - if mg_globals.app_config["push_url"]: + if mg_globals.app_config["push_urls"]: feed_url=request.urlgen( 'mediagoblin.user_pages.atom_feed', qualified=True,user=request.user.username) hubparameters = { 'hub.mode': 'publish', 'hub.url': feed_url} - huburl = mg_globals.app_config["push_url"] hubdata = urllib.urlencode(hubparameters) - hubheaders = {"Content-type": "application/x-www-form-urlencoded"} - hubrequest = urllib2.Request(huburl, hubdata,hubheaders) - hubresponse = urllib2.urlopen(hubrequest) + hubheaders = { + "Content-type": "application/x-www-form-urlencoded", + "Connection": "close"} + for huburl in mg_globals.app_config["push_urls"]: + hubrequest = urllib2.Request(huburl, hubdata,hubheaders) + hubresponse = urllib2.urlopen(hubrequest) add_message(request, SUCCESS, _('Woohoo! Submitted!')) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2d4eac69..29360e23 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -235,10 +235,11 @@ def atom_feed(request): 'rel': 'alternate', 'type': 'text/html' }]; - if mg_globals.app_config["push_url"]: - atomlinks.append({ - 'rel': 'hub', - 'href': mg_globals.app_config["push_url"]}) + if mg_globals.app_config["push_urls"]: + for push_url in mg_globals.app_config["push_urls"]: + atomlinks.append({ + 'rel': 'hub', + 'href': push_url}) feed = AtomFeed( "MediaGoblin: Feed for user '%s'" % request.matchdict['user'], -- cgit v1.2.3 From 20659de2344ccb8d14f8deaeaf9628d84a966e5a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 Jan 2012 17:38:20 +0100 Subject: Add CC0 license header to Sphinx MediaGoblin theme (mg.css) --- docs/source/themes/mg/static/mg.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/source/themes/mg/static/mg.css b/docs/source/themes/mg/static/mg.css index b9355a5d..96344df4 100644 --- a/docs/source/themes/mg/static/mg.css +++ b/docs/source/themes/mg/static/mg.css @@ -1,3 +1,15 @@ +/* + +MediaGoblin theme - MediaGoblin-style Sphinx documentation theme + +Written in 2012 by Jef van Schendel + +To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. + +You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . + +*/ + @import url("basic.css"); /* text fonts and styles */ -- cgit v1.2.3 From fafec727402ef3fa4d806b200f1d86cb91cd6362 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 13 Jan 2012 23:23:02 +0100 Subject: Remove unnecessary piece of text in media.html. Fix "Markdown text" indentation so they are the same. --- mediagoblin/edit/forms.py | 7 +++---- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 09955874..5c191fba 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -45,10 +45,9 @@ class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField( _('Bio'), [wtforms.validators.Length(min=0, max=500)], - description=_( - """You can use - - Markdown for formatting.""")) + description=_("""You can use + + Markdown for formatting.""")) url = wtforms.TextField( _('Website'), [wtforms.validators.Optional(), diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 583e4ebd..865a94ab 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -97,7 +97,7 @@ user= media.get_uploader.username, media=media._id) }}" method="POST" id="form_comment">

- {% trans %}Type your comment here. You can use Markdown for formatting.{% endtrans %} + {% trans %}You can use Markdown for formatting.{% endtrans %}

{{ wtforms_util.render_divs(comment_form) }}
-- cgit v1.2.3 From 762d4a0c48e582dba78a27f1a42e367d3f14a891 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 13 Jan 2012 23:38:21 +0100 Subject: Fix request.user==None error If one isn't logged in and views the profile of a user without media, one gets a problem, because request.user is None and has no _id attribute. Fix this. --- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 0937f97a..d3b4021d 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -145,7 +145,7 @@ {% include "mediagoblin/utils/feed_link.html" %}
{% else %} - {% if request.user._id == user._id %} + {% if request.user and (request.user._id == user._id) %}

{% trans -%} -- cgit v1.2.3 From 4670ff1c56ed58591945bbf665bbd9d7f72b71a9 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 13 Jan 2012 20:26:36 -0600 Subject: Simple translation update script --- devtools/update_translations.sh | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 devtools/update_translations.sh diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh new file mode 100644 index 00000000..1708e7e0 --- /dev/null +++ b/devtools/update_translations.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +# exit if anything fails +set -e + +echo "==> checking out master" +git checkout master + +echo "==> pulling git master" +git pull + +echo "==> pulling present translations" +./bin/tx pull -a +git add mediagoblin/i18n/ +git commit -m "Committing present MediaGoblin translations before pushing extracted messages" + +echo "==> Extracting translations" +./bin/pybabel extract -F babel.ini -o mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po . + +echo "==> Pushing extracted translations to Transifex" +./bin/tx push -s + +# gets the new strings added to all files +echo "==> Re-Pulling translations from Transifex" +./bin/tx pull -a + +echo "==> Compiling .mo files" +./bin/pybabel compile -D mediagoblin -d mediagoblin/i18n/ + +echo "==> Committing to git" +git add mediagoblin/i18n/ +git commit -m "Committing extracted and compiled translations" -- cgit v1.2.3 From 1b5bbc0a8522b384084345cbb4f4917a8db015bf Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 13 Jan 2012 20:27:53 -0600 Subject: make this script executable --- devtools/update_translations.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 devtools/update_translations.sh diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh old mode 100644 new mode 100755 -- cgit v1.2.3 From 9c947004139d0d0ae5a879cd4c120891f8a8d51e Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 14 Jan 2012 12:54:16 +0100 Subject: Move maketarball.sh into devtools/ Now that there is a devtools directory, use it! --- devtools/maketarball.sh | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ maketarball.sh | 178 ------------------------------------------------ 2 files changed, 178 insertions(+), 178 deletions(-) create mode 100755 devtools/maketarball.sh delete mode 100755 maketarball.sh diff --git a/devtools/maketarball.sh b/devtools/maketarball.sh new file mode 100755 index 00000000..5f17e578 --- /dev/null +++ b/devtools/maketarball.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +# usage: maketarball [-drh] REVISH +# +# Creates a tarball of the repository at rev REVISH. + +# If -d is passed in, then it adds the date to the directory name. +# +# If -r is passed in, then it does some additional things required +# for a release-ready tarball. +# +# If -h is passed in, shows help and exits. +# +# Examples: +# +# ./maketarball v0.0.2 +# ./maketarball -d master +# ./maketarball -r v0.0.2 + + +USAGE="Usage: $0 -h | [-dr] REVISH" + +REVISH="none" +PREFIX="none" +NOWDATE="" +RELEASE="no" + +while getopts ":dhr" opt; +do + case "$opt" in + h) + echo "$USAGE" + echo "" + echo "Creates a tarball of the repository at rev REVISH." + echo "" + echo " -h Shows this help message" + echo " -d Includes date in tar file name and directory" + echo " -r Performs other release-related actions" + exit 0 + ;; + d) + NOWDATE=`date "+%Y-%m-%d-"` + shift $((OPTIND-1)) + ;; + r) + RELEASE="yes" + shift $((OPTIND-1)) + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + echo "$USAGE" >&2 + ;; + esac +done + +if [[ -z "$1" ]]; then + echo "$USAGE"; + exit 1; +fi + +REVISH=$1 +PREFIX="$NOWDATE$REVISH" + +# convert PREFIX to all lowercase and nix the v from tag names. +PREFIX=`echo "$PREFIX" | tr '[A-Z]' '[a-z]' | sed s/v//` + +# build the filename base minus the .tar.gz stuff--this is also +# the directory in the tarball. +FNBASE="mediagoblin-$PREFIX" + +STARTDIR=`pwd` + +function cleanup { + pushd $STARTDIR + + if [[ -e tmp ]] + then + echo "+ cleaning up tmp/" + rm -rf tmp + fi + popd +} + +echo "+ Building tarball from: $REVISH" +echo "+ Using prefix: $PREFIX" +echo "+ Release?: $RELEASE" + +echo "" + +if [[ -e tmp ]] +then + echo "+ there's an existing tmp/. please remove it." + exit 1 +fi + +mkdir $STARTDIR/tmp +echo "+ generating archive...." +git archive \ + --format=tar \ + --prefix=$FNBASE/ \ + $REVISH > tmp/$FNBASE.tar + +if [[ $? -ne 0 ]] +then + echo "+ git archive command failed. See above text for reason." + cleanup + exit 1 +fi + + +if [[ $RELEASE = "yes" ]] +then + pushd tmp/ + tar -xvf $FNBASE.tar + + pushd $FNBASE + pushd docs + + echo "+ generating html docs" + make html + if [[ $? -ne 0 ]] + then + echo "+ sphinx docs generation failed. See above text for reason." + cleanup + exit 1 + fi + + # NOTE: this doesn't work for gmg prior to v0.0.4. + echo "+ generating texinfo docs (doesn't work prior to v0.0.4)" + make info + popd + + echo "+ moving docs to the right place" + if [[ -e docs/build/html/ ]] + then + mv docs/build/html/ docs/html/ + mv docs/build/texinfo/ docs/texinfo/ + + rm -rf docs/build/ + rm -rf docs/source/mgext/*.pyc + else + # this is the old directory structure pre-0.0.4 + mv docs/_build/html/ docs/html/ + + rm -rf docs/_build/ + rm -rf docs/mgext/*.pyc + fi + + popd + + tar -cvf $FNBASE.tar $FNBASE + popd +fi + + +echo "+ compressing...." +gzip tmp/$FNBASE.tar + +echo "+ archive at tmp/$FNBASE.tar.gz" + +echo "+ done." diff --git a/maketarball.sh b/maketarball.sh deleted file mode 100755 index 5f17e578..00000000 --- a/maketarball.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash - -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -# usage: maketarball [-drh] REVISH -# -# Creates a tarball of the repository at rev REVISH. - -# If -d is passed in, then it adds the date to the directory name. -# -# If -r is passed in, then it does some additional things required -# for a release-ready tarball. -# -# If -h is passed in, shows help and exits. -# -# Examples: -# -# ./maketarball v0.0.2 -# ./maketarball -d master -# ./maketarball -r v0.0.2 - - -USAGE="Usage: $0 -h | [-dr] REVISH" - -REVISH="none" -PREFIX="none" -NOWDATE="" -RELEASE="no" - -while getopts ":dhr" opt; -do - case "$opt" in - h) - echo "$USAGE" - echo "" - echo "Creates a tarball of the repository at rev REVISH." - echo "" - echo " -h Shows this help message" - echo " -d Includes date in tar file name and directory" - echo " -r Performs other release-related actions" - exit 0 - ;; - d) - NOWDATE=`date "+%Y-%m-%d-"` - shift $((OPTIND-1)) - ;; - r) - RELEASE="yes" - shift $((OPTIND-1)) - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - echo "$USAGE" >&2 - ;; - esac -done - -if [[ -z "$1" ]]; then - echo "$USAGE"; - exit 1; -fi - -REVISH=$1 -PREFIX="$NOWDATE$REVISH" - -# convert PREFIX to all lowercase and nix the v from tag names. -PREFIX=`echo "$PREFIX" | tr '[A-Z]' '[a-z]' | sed s/v//` - -# build the filename base minus the .tar.gz stuff--this is also -# the directory in the tarball. -FNBASE="mediagoblin-$PREFIX" - -STARTDIR=`pwd` - -function cleanup { - pushd $STARTDIR - - if [[ -e tmp ]] - then - echo "+ cleaning up tmp/" - rm -rf tmp - fi - popd -} - -echo "+ Building tarball from: $REVISH" -echo "+ Using prefix: $PREFIX" -echo "+ Release?: $RELEASE" - -echo "" - -if [[ -e tmp ]] -then - echo "+ there's an existing tmp/. please remove it." - exit 1 -fi - -mkdir $STARTDIR/tmp -echo "+ generating archive...." -git archive \ - --format=tar \ - --prefix=$FNBASE/ \ - $REVISH > tmp/$FNBASE.tar - -if [[ $? -ne 0 ]] -then - echo "+ git archive command failed. See above text for reason." - cleanup - exit 1 -fi - - -if [[ $RELEASE = "yes" ]] -then - pushd tmp/ - tar -xvf $FNBASE.tar - - pushd $FNBASE - pushd docs - - echo "+ generating html docs" - make html - if [[ $? -ne 0 ]] - then - echo "+ sphinx docs generation failed. See above text for reason." - cleanup - exit 1 - fi - - # NOTE: this doesn't work for gmg prior to v0.0.4. - echo "+ generating texinfo docs (doesn't work prior to v0.0.4)" - make info - popd - - echo "+ moving docs to the right place" - if [[ -e docs/build/html/ ]] - then - mv docs/build/html/ docs/html/ - mv docs/build/texinfo/ docs/texinfo/ - - rm -rf docs/build/ - rm -rf docs/source/mgext/*.pyc - else - # this is the old directory structure pre-0.0.4 - mv docs/_build/html/ docs/html/ - - rm -rf docs/_build/ - rm -rf docs/mgext/*.pyc - fi - - popd - - tar -cvf $FNBASE.tar $FNBASE - popd -fi - - -echo "+ compressing...." -gzip tmp/$FNBASE.tar - -echo "+ archive at tmp/$FNBASE.tar.gz" - -echo "+ done." -- cgit v1.2.3 From 52fc51f6a9b6379d39d391bd54473eebb6d23cd5 Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 13 Jan 2012 22:59:14 +0100 Subject: Drop sessions with invalid ObjectIds The session can contain invalid objectids when switching a more or less live instance (with logged in users) from mongo to sql or vice versa. So drop the complete session and force the user to login again. --- mediagoblin/tools/request.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py index b1cbe119..7e193125 100644 --- a/mediagoblin/tools/request.py +++ b/mediagoblin/tools/request.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.util import ObjectId +from mediagoblin.db.util import ObjectId, InvalidId def setup_user_in_request(request): """ @@ -25,13 +25,17 @@ def setup_user_in_request(request): request.user = None return - user = None - user = request.app.db.User.one( - {'_id': ObjectId(request.session['user_id'])}) + try: + oid = ObjectId(request.session['user_id']) + except InvalidId: + user = None + else: + user = request.db.User.one({'_id': oid}) if not user: # Something's wrong... this user doesn't exist? Invalidate # this session. + print "Killing session for %r" % request.session['user_id'] request.session.invalidate() request.user = user -- cgit v1.2.3 From b6997919563ab2553e9dc4af1d4cb06c1544a5ce Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 15 Jan 2012 17:07:15 +0100 Subject: Small margin/font-weight fix --- mediagoblin/static/css/base.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index c2d45a1b..5b37a362 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -48,6 +48,7 @@ h1 { margin-top: 15px; color: #fff; font-size: 1.875em; + font-weight: bold; } h2 { @@ -63,6 +64,7 @@ h3 { p { margin-top: 0px; + margin-bottom: 20px; } a { -- cgit v1.2.3 From 62f2557cae03bd4675fc67a7775d3c715a2f2a62 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 15 Jan 2012 17:10:35 +0100 Subject: Another small text style fix --- mediagoblin/static/css/base.css | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 5b37a362..44c7cd0c 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -43,12 +43,18 @@ form { /* text styles */ +h1,h2,h3,p { + margin-bottom: 20px; +} + +h1,h2,h3 { + font-weight: bold; +} + h1 { - margin-bottom: 15px; margin-top: 15px; color: #fff; font-size: 1.875em; - font-weight: bold; } h2 { @@ -64,7 +70,6 @@ h3 { p { margin-top: 0px; - margin-bottom: 20px; } a { -- cgit v1.2.3 From 8c7701f9f1653cf4038143cfb7a497ae21edf108 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 15 Jan 2012 17:23:21 +0100 Subject: Small fix to simplify font style --- mediagoblin/static/css/base.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 44c7cd0c..efd7b561 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -32,8 +32,7 @@ body { padding: none; margin: 0px; height: 100%; - font: 16px "HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,sans-serif; - font-family:'Lato', sans-serif; + font: 16px 'Lato', 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif; } form { -- cgit v1.2.3 From 25b48323a86a1036112f2f33c889d5d12d5dee9c Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Tue, 17 Jan 2012 00:33:55 -0500 Subject: First crack at basic license support. --- mediagoblin/db/models.py | 9 +++++++++ mediagoblin/edit/forms.py | 5 ++++- mediagoblin/edit/views.py | 8 +++++++- mediagoblin/submit/forms.py | 5 ++++- mediagoblin/submit/views.py | 4 ++++ mediagoblin/templates/mediagoblin/user_pages/media.html | 2 ++ 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 0f5174cc..e085840e 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -24,6 +24,7 @@ from mediagoblin.db import migrations from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination from mediagoblin.tools import url, common +from mediagoblin.tools import licenses ################### # Custom validators @@ -158,6 +159,8 @@ class MediaEntry(Document): "unprocessed": uploaded but needs to go through processing for display "processed": processed and able to be displayed + - license: URI for entry's license + - queued_media_file: storage interface style filepath describing a file queued for processing. This is stored in the mg_globals.queue_store storage system. @@ -174,6 +177,7 @@ class MediaEntry(Document): - fail_error: path to the exception raised - fail_metadata: + """ __collection__ = 'media_entries' @@ -189,6 +193,7 @@ class MediaEntry(Document): 'plugin_data': dict, # plugins can dump stuff here. 'tags': [dict], 'state': unicode, + 'license': unicode, # License URI # For now let's assume there can only be one main file queued # at a time @@ -304,6 +309,10 @@ class MediaEntry(Document): if self['fail_error']: return common.import_component(self['fail_error']) + def get_license_data(self): + """Return license dict for requested license""" + return licenses.SUPPORTED_LICENSES[self['license']] + class MediaComment(Document): """ diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 7e71722c..3d1d9fd4 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -18,6 +18,7 @@ import wtforms from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING from mediagoblin.tools.translate import fake_ugettext_passthrough as _ +from mediagoblin.tools.licenses import licenses_as_choices class EditForm(wtforms.Form): title = wtforms.TextField( @@ -33,7 +34,9 @@ class EditForm(wtforms.Form): description=_( "The title part of this media's URL. " "You usually don't need to change this.")) - + license = wtforms.SelectField( + _('License'), + choices=licenses_as_choices()) class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField( diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a6ddb553..f92eabac 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -34,6 +34,7 @@ from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.text import ( clean_html, convert_to_tag_list_of_dicts, media_tags_as_string, cleaned_markdown_conversion) +from mediagoblin.tools.licenses import SUPPORTED_LICENSES @get_user_media_entry @require_active_login @@ -45,7 +46,8 @@ def edit_media(request, media): title=media['title'], slug=media['slug'], description=media['description'], - tags=media_tags_as_string(media['tags'])) + tags=media_tags_as_string(media['tags']), + license=media['license']) form = forms.EditForm( request.POST, @@ -71,6 +73,10 @@ def edit_media(request, media): media['description_html'] = cleaned_markdown_conversion( media['description']) + media['license'] = ( + unicode(request.POST.get('license')) + or '') + media['slug'] = unicode(request.POST['slug']) media.save() diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 25d6e304..be85b9a9 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -19,7 +19,7 @@ import wtforms from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import fake_ugettext_passthrough as _ - +from mediagoblin.tools.licenses import licenses_as_choices class SubmitStartForm(wtforms.Form): file = wtforms.FileField(_('File')) @@ -31,3 +31,6 @@ class SubmitStartForm(wtforms.Form): tags = wtforms.TextField( _('Tags'), [tag_length_validator]) + license = wtforms.SelectField( + _('License'), + choices=licenses_as_choices()) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 7134235e..ecfa9943 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -60,6 +60,10 @@ def submit_start(request): entry['description'] = unicode(request.POST.get('description')) entry['description_html'] = cleaned_markdown_conversion( entry['description']) + + entry['license'] = ( + unicode(request.POST.get('license')) + or '') entry['media_type'] = u'image' # heh entry['uploader'] = request.user['_id'] diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 11fa72cf..efbd7e53 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -171,6 +171,8 @@ {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} + + {% include "mediagoblin/utils/license.html" %}

{% else %}

{% trans %}Sorry, no such media found.{% endtrans %}

-- cgit v1.2.3 From 25bdf9b6578feb348745e6ac27fc4555e27077b9 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Tue, 17 Jan 2012 01:05:15 -0500 Subject: Fixed merge with upstream --- mediagoblin/db/mongo/models.py | 153 +++++++++++++---------------------------- 1 file changed, 47 insertions(+), 106 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index e085840e..906d2849 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -14,17 +14,16 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import datetime, uuid +import datetime from mongokit import Document -from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals -from mediagoblin.db import migrations -from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId +from mediagoblin.db.mongo import migrations +from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination -from mediagoblin.tools import url, common -from mediagoblin.tools import licenses +from mediagoblin.tools import url +from mediagoblin.db.mixin import UserMixin, MediaEntryMixin ################### # Custom validators @@ -35,7 +34,7 @@ from mediagoblin.tools import licenses ######## -class User(Document): +class User(Document, UserMixin): """ A user of MediaGoblin. @@ -63,22 +62,23 @@ class User(Document): - bio_html: biography of the user converted to proper HTML. """ __collection__ = 'users' + use_dot_notation = True structure = { 'username': unicode, 'email': unicode, 'created': datetime.datetime, - 'plugin_data': dict, # plugins can dump stuff here. + 'plugin_data': dict, # plugins can dump stuff here. 'pw_hash': unicode, 'email_verified': bool, 'status': unicode, 'verification_key': unicode, 'is_admin': bool, - 'url' : unicode, - 'bio' : unicode, # May contain markdown - 'bio_html': unicode, # May contain plaintext, or HTML - 'fp_verification_key': unicode, # forgotten password verification key - 'fp_token_expire': datetime.datetime + 'url': unicode, + 'bio': unicode, # May contain markdown + 'bio_html': unicode, # May contain plaintext, or HTML + 'fp_verification_key': unicode, # forgotten password verification key + 'fp_token_expire': datetime.datetime, } required_fields = ['username', 'created', 'pw_hash', 'email'] @@ -87,18 +87,10 @@ class User(Document): 'created': datetime.datetime.utcnow, 'email_verified': False, 'status': u'needs_email_verification', - 'verification_key': lambda: unicode(uuid.uuid4()), 'is_admin': False} - def check_login(self, password): - """ - See if a user can login with this password - """ - return auth_lib.bcrypt_check_password( - password, self['pw_hash']) - -class MediaEntry(Document): +class MediaEntry(Document, MediaEntryMixin): """ Record of a piece of media. @@ -130,7 +122,7 @@ class MediaEntry(Document): For example, images might contain some EXIF data that's not appropriate to other formats. You might store it like: - mediaentry['media_data']['exif'] = { + mediaentry.media_data['exif'] = { 'manufacturer': 'CASIO', 'model': 'QV-4000', 'exposure_time': .659} @@ -138,7 +130,7 @@ class MediaEntry(Document): Alternately for video you might store: # play length in seconds - mediaentry['media_data']['play_length'] = 340 + mediaentry.media_data['play_length'] = 340 ... so what's appropriate here really depends on the media type. @@ -159,8 +151,6 @@ class MediaEntry(Document): "unprocessed": uploaded but needs to go through processing for display "processed": processed and able to be displayed - - license: URI for entry's license - - queued_media_file: storage interface style filepath describing a file queued for processing. This is stored in the mg_globals.queue_store storage system. @@ -175,25 +165,24 @@ class MediaEntry(Document): critical to this piece of media but may be usefully relevant to people viewing the work. (currently unused.) - - fail_error: path to the exception raised - - fail_metadata: - + - fail_error: path to the exception raised + - fail_metadata: """ __collection__ = 'media_entries' + use_dot_notation = True structure = { 'uploader': ObjectId, 'title': unicode, 'slug': unicode, 'created': datetime.datetime, - 'description': unicode, # May contain markdown/up - 'description_html': unicode, # May contain plaintext, or HTML + 'description': unicode, # May contain markdown/up + 'description_html': unicode, # May contain plaintext, or HTML 'media_type': unicode, - 'media_data': dict, # extra data relevant to this media_type - 'plugin_data': dict, # plugins can dump stuff here. + 'media_data': dict, # extra data relevant to this media_type + 'plugin_data': dict, # plugins can dump stuff here. 'tags': [dict], 'state': unicode, - 'license': unicode, # License URI # For now let's assume there can only be one main file queued # at a time @@ -219,99 +208,50 @@ class MediaEntry(Document): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} - def get_comments(self): + def get_comments(self, ascending=False): + if ascending: + order = ASCENDING + else: + order = DESCENDING + return self.db.MediaComment.find({ - 'media_entry': self['_id']}).sort('created', DESCENDING) - - def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): - """ - Find the best media for display. - - Args: - - media_map: a dict like - {u'image_size': [u'dir1', u'dir2', u'image.jpg']} - - fetch_order: the order we should try fetching images in - - Returns: - (media_size, media_path) - """ - media_sizes = media_map.keys() - - for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: - if media_size in media_sizes: - return media_map[media_size] - - def main_mediafile(self): - pass + 'media_entry': self._id}).sort('created', order) def generate_slug(self): - self['slug'] = url.slugify(self['title']) + self.slug = url.slugify(self.title) duplicate = mg_globals.database.media_entries.find_one( - {'slug': self['slug']}) + {'slug': self.slug}) if duplicate: - self['slug'] = "%s-%s" % (self['_id'], self['slug']) - - def url_for_self(self, urlgen): - """ - Generate an appropriate url for ourselves - - Use a slug if we have one, else use our '_id'. - """ - uploader = self.uploader() - - if self.get('slug'): - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader['username'], - media=self['slug']) - else: - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader['username'], - media=unicode(self['_id'])) + self.slug = "%s-%s" % (self._id, self.slug) def url_to_prev(self, urlgen): """ Provide a url to the previous entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']}, - 'uploader': self['uploader'], + cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id}, + 'uploader': self.uploader, 'state': 'processed'}).sort( '_id', ASCENDING).limit(1) - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.uploader()['username'], - media=unicode(cursor[0]['slug'])) + for media in cursor: + return media.url_for_self(urlgen) def url_to_next(self, urlgen): """ Provide a url to the next entry from this user, if there is one """ - cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']}, - 'uploader': self['uploader'], + cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id}, + 'uploader': self.uploader, 'state': 'processed'}).sort( '_id', DESCENDING).limit(1) - if cursor.count(): - return urlgen('mediagoblin.user_pages.media_home', - user=self.uploader()['username'], - media=unicode(cursor[0]['slug'])) - - def uploader(self): - return self.db.User.find_one({'_id': self['uploader']}) - - def get_fail_exception(self): - """ - Get the exception that's appropriate for this error - """ - if self['fail_error']: - return common.import_component(self['fail_error']) + for media in cursor: + return media.url_for_self(urlgen) - def get_license_data(self): - """Return license dict for requested license""" - return licenses.SUPPORTED_LICENSES[self['license']] + @property + def get_uploader(self): + return self.db.User.find_one({'_id': self.uploader}) class MediaComment(Document): @@ -328,6 +268,7 @@ class MediaComment(Document): """ __collection__ = 'media_comments' + use_dot_notation = True structure = { 'media_entry': ObjectId, @@ -345,7 +286,8 @@ class MediaComment(Document): def media_entry(self): return self.db.MediaEntry.find_one({'_id': self['media_entry']}) - def author(self): + @property + def get_author(self): return self.db.User.find_one({'_id': self['author']}) @@ -360,4 +302,3 @@ def register_models(connection): Register all models in REGISTER_MODELS with this connection. """ connection.register(REGISTER_MODELS) - -- cgit v1.2.3 From 0bfb4dc249715a7a9617c23f42d63ff8aabfd2d9 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Tue, 17 Jan 2012 01:13:55 -0500 Subject: Added new files --- .../templates/mediagoblin/utils/license.html | 26 +++++++++ mediagoblin/tools/licenses.py | 62 ++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 mediagoblin/templates/mediagoblin/utils/license.html create mode 100644 mediagoblin/tools/licenses.py diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html new file mode 100644 index 00000000..0f7762bc --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -0,0 +1,26 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block license_content -%} +

License

+ {% if media['license'] %} + {{ media.get_license_data()['abbreviation'] }} + {% else %} + All rights reserved + {% endif %} +{% endblock %} diff --git a/mediagoblin/tools/licenses.py b/mediagoblin/tools/licenses.py new file mode 100644 index 00000000..cb137fa8 --- /dev/null +++ b/mediagoblin/tools/licenses.py @@ -0,0 +1,62 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +SUPPORTED_LICENSES = { + "": { + "name": "No license specified", + "abbreviation": "All rights reserved" + }, + "http://creativecommons.org/licenses/by/3.0/": { + "name": "Creative Commons Attribution Unported 3.0", + "abbreviation": "CC BY 3.0" + }, + "http://creativecommons.org/licenses/by-sa/3.0": { + "name": "Creative Commons Attribution-ShareAlike Unported 3.0", + "abbreviation": "CC BY-SA 3.0" + }, + "http://creativecommons.org/licenses/by-nd/3.0": { + "name": "Creative Commons Attribution-NoDerivs 3.0 Unported", + "abbreviation": "CC BY-ND 3.0" + }, + "http://creativecommons.org/licenses/by-nc/3.0": { + "name": "Creative Commons Attribution-NonCommercial Unported 3.0", + "abbreviation": "CC BY-NC 3.0" + }, + "http://creativecommons.org/licenses/by-nc-sa/3.0": { + "name": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported", + "abbreviation": "CC BY-NC-SA 3.0" + }, + "http://creativecommons.org/licenses/by-nc-nd/3.0": { + "name": "Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported", + "abbreviation": "CC BY-NC-ND 3.0" + }, + "http://creativecommons.org/publicdomain/zero/1.0/": { + "name": "Creative Commons CC0 1.0 Universal", + "abbreviation": "CC0 1.0" + }, + "http://creativecommons.org/publicdomain/mark/1.0/": { + "name": "Public Domain", + "abbreviation": "Public Domain" + }, +} + +def licenses_as_choices(): + license_list = [] + + for uri, data in SUPPORTED_LICENSES.items(): + license_list.append((uri, data["abbreviation"])) + + return license_list -- cgit v1.2.3 From a6c49d49dc1c15aedfdd7bc63a7b191ecb827787 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Tue, 17 Jan 2012 01:22:02 -0500 Subject: Fixed a syntax error in edit/views and added back in some missing license stuff from models --- mediagoblin/db/mongo/models.py | 9 ++++++++- mediagoblin/edit/views.py | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 906d2849..a95cde7d 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -22,7 +22,7 @@ from mediagoblin import mg_globals from mediagoblin.db.mongo import migrations from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination -from mediagoblin.tools import url +from mediagoblin.tools import url, licenses from mediagoblin.db.mixin import UserMixin, MediaEntryMixin ################### @@ -151,6 +151,8 @@ class MediaEntry(Document, MediaEntryMixin): "unprocessed": uploaded but needs to go through processing for display "processed": processed and able to be displayed + - license: URI for media's license. + - queued_media_file: storage interface style filepath describing a file queued for processing. This is stored in the mg_globals.queue_store storage system. @@ -183,6 +185,7 @@ class MediaEntry(Document, MediaEntryMixin): 'plugin_data': dict, # plugins can dump stuff here. 'tags': [dict], 'state': unicode, + 'license': unicode, # For now let's assume there can only be one main file queued # at a time @@ -249,6 +252,10 @@ class MediaEntry(Document, MediaEntryMixin): for media in cursor: return media.url_for_self(urlgen) + def get_license_data(self): + """Return license dict for requested license""" + return licenses.SUPPORTED_LICENSES[self['license']] + @property def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 6f4585cf..a3b269d8 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -47,8 +47,8 @@ def edit_media(request, media): title=media.title, slug=media.slug, description=media.description, - tags=media_tags_as_string(media.tags)) - license=media.license) + tags=media_tags_as_string(media.tags), + license=media.license)) form = forms.EditForm( request.POST, -- cgit v1.2.3 From 4225a677cad97825704ee00222c4771d36924c17 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Tue, 17 Jan 2012 01:23:21 -0500 Subject: Changed license.html to fit new layout better --- mediagoblin/templates/mediagoblin/utils/license.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 0f7762bc..31481018 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,7 +17,7 @@ #} {% block license_content -%} -

License

+ License: {% if media['license'] %} {{ media.get_license_data()['abbreviation'] }} {% else %} -- cgit v1.2.3 From 77b91efcc260cf5f4e7d2b544a02a12c51f45ad4 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Tue, 17 Jan 2012 22:42:36 +0100 Subject: We handle exceptions if PuSH fails --- mediagoblin/submit/views.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 65243ca1..91498b09 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -21,6 +21,7 @@ from cgi import FieldStorage from celery import registry import urllib,urllib2 +import logging from werkzeug.utils import secure_filename @@ -131,15 +132,24 @@ def submit_start(request): 'mediagoblin.user_pages.atom_feed', qualified=True,user=request.user.username) hubparameters = { - 'hub.mode': 'publish', - 'hub.url': feed_url} + 'hub.mode': 'publish', + 'hub.url': feed_url} hubdata = urllib.urlencode(hubparameters) hubheaders = { "Content-type": "application/x-www-form-urlencoded", "Connection": "close"} for huburl in mg_globals.app_config["push_urls"]: - hubrequest = urllib2.Request(huburl, hubdata,hubheaders) - hubresponse = urllib2.urlopen(hubrequest) + hubrequest = urllib2.Request(huburl, hubdata, hubheaders) + try: + hubresponse = urllib2.urlopen(hubrequest) + except urllib2.HTTPError as exc: + # This is not a big issue, the item will be fetched + # by the PuSH server next time we hit it + logging.getLogger(__name__).warning( + "push url %r gave error %r", huburl, exc.code) + except urllib2.URLError as exc: + logging.getLogger(__name__).warning( + "push url %r is unreachable %r", huburl, exc.reason) add_message(request, SUCCESS, _('Woohoo! Submitted!')) -- cgit v1.2.3 From c03d13cd791ac41db1be72e8a5d4d2eaa6cc6087 Mon Sep 17 00:00:00 2001 From: Michele Azzolari Date: Tue, 17 Jan 2012 23:15:47 +0100 Subject: Cleaned the code --- mediagoblin/submit/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 91498b09..33868785 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -23,6 +23,8 @@ from celery import registry import urllib,urllib2 import logging +_log = logging.getLogger(__name__) + from werkzeug.utils import secure_filename from mediagoblin.db.util import ObjectId @@ -145,10 +147,10 @@ def submit_start(request): except urllib2.HTTPError as exc: # This is not a big issue, the item will be fetched # by the PuSH server next time we hit it - logging.getLogger(__name__).warning( + _log.warning( "push url %r gave error %r", huburl, exc.code) except urllib2.URLError as exc: - logging.getLogger(__name__).warning( + _log.warning( "push url %r is unreachable %r", huburl, exc.reason) add_message(request, SUCCESS, _('Woohoo! Submitted!')) -- cgit v1.2.3 From 6fc8af3278173a0d1113dc0cf5525c2249f1d0bc Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 29 Dec 2011 11:07:58 +0100 Subject: sql/fake.py: Some fake objects/methods to calm the code sql/fake.py contains some fake classes and functions to calm the rest of the code base. Or provide super minimal implementations. Currently: - ObjectId "class": It's a function mostly doing int(first_arg) to convert string primary keys into integer primary keys. - InvalidId exception - DESCENING "constant" --- mediagoblin/db/sql/fake.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 mediagoblin/db/sql/fake.py diff --git a/mediagoblin/db/sql/fake.py b/mediagoblin/db/sql/fake.py new file mode 100644 index 00000000..ba11bfee --- /dev/null +++ b/mediagoblin/db/sql/fake.py @@ -0,0 +1,28 @@ +""" +This module contains some fake classes and functions to +calm the rest of the code base. Or provide super minimal +implementations. + +Currently: +- ObjectId "class": It's a function mostly doing + int(init_arg) to convert string primary keys into + integer primary keys. +- InvalidId exception +- DESCENDING "constant" +""" + + +DESCENDING = object() # a unique object for this "constant" + + +class InvalidId(Exception): + pass + + +def ObjectId(value=None): + if value is None: + return None + try: + return int(value) + except ValueError: + raise InvalidId("%r is an invalid id" % value) -- cgit v1.2.3 From 17c23e15e4c2dc120eaa3357e59ee8fdba55bf9e Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Wed, 18 Jan 2012 21:07:55 -0500 Subject: Moved get_license_data to mixin.py, added license to sql media model, added translation tags to license template. --- mediagoblin/db/mixin.py | 6 +++++- mediagoblin/db/mongo/models.py | 6 +----- mediagoblin/db/sql/models.py | 1 + mediagoblin/templates/mediagoblin/utils/license.html | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 5145289e..b0fecad3 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -28,7 +28,7 @@ real objects. """ from mediagoblin.auth import lib as auth_lib -from mediagoblin.tools import common +from mediagoblin.tools import common, licenses class UserMixin(object): @@ -90,3 +90,7 @@ class MediaEntryMixin(object): """ if self['fail_error']: return common.import_component(self['fail_error']) + + def get_license_data(self): + """Return license dict for requested license""" + return licenses.SUPPORTED_LICENSES[self.license] diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index a95cde7d..56ed7dcf 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -22,7 +22,7 @@ from mediagoblin import mg_globals from mediagoblin.db.mongo import migrations from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination -from mediagoblin.tools import url, licenses +from mediagoblin.tools import url from mediagoblin.db.mixin import UserMixin, MediaEntryMixin ################### @@ -252,10 +252,6 @@ class MediaEntry(Document, MediaEntryMixin): for media in cursor: return media.url_for_self(urlgen) - def get_license_data(self): - """Return license dict for requested license""" - return licenses.SUPPORTED_LICENSES[self['license']] - @property def get_uploader(self): return self.db.User.find_one({'_id': self.uploader}) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 91092f33..e07963ca 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -64,6 +64,7 @@ class MediaEntry(Base, MediaEntryMixin): description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? + license = Column(Unicode, nullable=False) fail_error = Column(Unicode) fail_metadata = Column(UnicodeText) diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 31481018..056c356e 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,10 +17,10 @@ #} {% block license_content -%} - License: - {% if media['license'] %} - {{ media.get_license_data()['abbreviation'] }} + {% trans %}License:{% endtrans %} + {% if media.license %} + {{ media.get_license_data().abbreviation }} {% else %} - All rights reserved + {% trans %}All rights reserved{% endtrans %} {% endif %} {% endblock %} -- cgit v1.2.3 From 97ec97dbc77373819939557ad20c72a0aced5d61 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Wed, 18 Jan 2012 21:21:49 -0500 Subject: Minor formatting and syntax fix. --- mediagoblin/edit/views.py | 3 ++- mediagoblin/submit/forms.py | 1 + mediagoblin/submit/views.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a3b269d8..cffb8a3c 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -37,6 +37,7 @@ from mediagoblin.tools.text import ( media_tags_as_string, cleaned_markdown_conversion) from mediagoblin.tools.licenses import SUPPORTED_LICENSES + @get_user_media_entry @require_active_login def edit_media(request, media): @@ -48,7 +49,7 @@ def edit_media(request, media): slug=media.slug, description=media.description, tags=media_tags_as_string(media.tags), - license=media.license)) + license=media.license) form = forms.EditForm( request.POST, diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 08234822..4ff52609 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -21,6 +21,7 @@ from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import fake_ugettext_passthrough as _ from mediagoblin.tools.licenses import licenses_as_choices + class SubmitStartForm(wtforms.Form): file = wtforms.FileField(_('File')) title = wtforms.TextField( diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index b91fdb8d..8911bf82 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -69,7 +69,7 @@ def submit_start(request): entry.description_html = cleaned_markdown_conversion( entry.description) - entry['license'] = ( + entry.license = ( unicode(request.POST.get('license')) or '') -- cgit v1.2.3 From 92edc74e9b1ac16009db60049bb381bfd901013a Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 18:20:20 +0100 Subject: Use custom query class A custom query class allows to add more methods on queries (read: "cursors"). This custom query class especially adds a .sort with a calling convention exactly like the mongo one. Makes a lot of existing code happy! --- mediagoblin/db/sql/base.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 40140327..082d498e 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -1,7 +1,27 @@ from sqlalchemy.orm import scoped_session, sessionmaker, object_session +from sqlalchemy.orm.query import Query +from sqlalchemy.sql.expression import desc +from mediagoblin.db.sql.fake import DESCENDING -Session = scoped_session(sessionmaker()) +def _get_query_model(query): + cols = query.column_descriptions + assert len(cols) == 1, "These functions work only on simple queries" + return cols[0]["type"] + + +class GMGQuery(Query): + def sort(self, key, direction): + key_col = getattr(_get_query_model(self), key) + if direction is DESCENDING: + key_col = desc(key_col) + return self.order_by(key_col) + + def skip(self, amount): + return self.offset(amount) + + +Session = scoped_session(sessionmaker(query_cls=GMGQuery)) def _fix_query_dict(query_dict): -- cgit v1.2.3 From fbad3a9fb9b0bd6b35d5906e96ead3485fa5f57a Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 20 Jan 2012 00:17:05 +0100 Subject: Add copyright header and a bit of pep8ification Nearly all the sql files missed a copyright header. So added it! And while there fixed a few pep8 things. --- mediagoblin/db/sql/base.py | 19 ++++++++++++++++++- mediagoblin/db/sql/convert.py | 17 +++++++++++++++++ mediagoblin/db/sql/extratypes.py | 17 +++++++++++++++++ mediagoblin/db/sql/fake.py | 19 ++++++++++++++++++- mediagoblin/db/sql/models.py | 33 +++++++++++++++++++++++++-------- mediagoblin/db/sql/open.py | 19 ++++++++++++++++++- 6 files changed, 113 insertions(+), 11 deletions(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 082d498e..6f45b21b 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + from sqlalchemy.orm import scoped_session, sessionmaker, object_session from sqlalchemy.orm.query import Query from sqlalchemy.sql.expression import desc @@ -49,7 +66,7 @@ class GMGTableBase(object): def get(self, key): return getattr(self, key) - def save(self, validate = True): + def save(self, validate=True): assert validate sess = object_session(self) if sess is None: diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 88614fd4..ac7a66c2 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + from mediagoblin.init import setup_global_and_app_config, setup_database from mediagoblin.db.mongo.util import ObjectId diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py index 88f556d9..33c9edee 100644 --- a/mediagoblin/db/sql/extratypes.py +++ b/mediagoblin/db/sql/extratypes.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + from sqlalchemy.types import TypeDecorator, Unicode diff --git a/mediagoblin/db/sql/fake.py b/mediagoblin/db/sql/fake.py index ba11bfee..482b85da 100644 --- a/mediagoblin/db/sql/fake.py +++ b/mediagoblin/db/sql/fake.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + """ This module contains some fake classes and functions to calm the rest of the code base. Or provide super minimal @@ -10,7 +27,7 @@ Currently: - InvalidId exception - DESCENDING "constant" """ - + DESCENDING = object() # a unique object for this "constant" diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 91092f33..aa63e34a 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + import datetime from sqlalchemy.ext.declarative import declarative_base @@ -41,8 +58,8 @@ class User(Base, UserMixin): verification_key = Column(Unicode) is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) - bio = Column(UnicodeText) # ?? - bio_html = Column(UnicodeText) # ?? + bio = Column(UnicodeText) # ?? + bio_html = Column(UnicodeText) # ?? fp_verification_key = Column(Unicode) fp_token_expire = Column(DateTime) @@ -60,11 +77,11 @@ class MediaEntry(Base, MediaEntryMixin): title = Column(Unicode, nullable=False) slug = Column(Unicode, nullable=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) - description = Column(UnicodeText) # ?? - description_html = Column(UnicodeText) # ?? + description = Column(UnicodeText) # ?? + description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) - state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? - + state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? + fail_error = Column(Unicode) fail_metadata = Column(UnicodeText) @@ -83,7 +100,7 @@ class MediaEntry(Base, MediaEntryMixin): cascade="all, delete-orphan" ) media_files = association_proxy('media_files_helper', 'file_path', - creator=lambda k,v: MediaFile(name=k, file_path=v) + creator=lambda k, v: MediaFile(name=k, file_path=v) ) ## TODO @@ -130,7 +147,7 @@ class MediaTag(Base): class MediaComment(Base): __tablename__ = "media_comments" - + id = Column(Integer, primary_key=True) media_entry = Column( Integer, ForeignKey('media_entries.id'), nullable=False) diff --git a/mediagoblin/db/sql/open.py b/mediagoblin/db/sql/open.py index c682bd3b..3c06c676 100644 --- a/mediagoblin/db/sql/open.py +++ b/mediagoblin/db/sql/open.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + from sqlalchemy import create_engine from mediagoblin.db.sql.base import Session @@ -8,7 +25,7 @@ class DatabaseMaster(object): def __init__(self, engine): self.engine = engine - for k,v in Base._decl_class_registry.iteritems(): + for k, v in Base._decl_class_registry.iteritems(): setattr(self, k, v) def commit(self): -- cgit v1.2.3 From 3c351460e1dbed9e789e363f1d5635160bce8d84 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 21 Jan 2012 19:24:36 +0100 Subject: Fix unit tests with new license support Make the license field in the forms optional and let them properly be defaulted to "". --- mediagoblin/edit/forms.py | 1 + mediagoblin/edit/views.py | 4 +--- mediagoblin/submit/forms.py | 1 + mediagoblin/submit/views.py | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index d49b9b28..3e3612fe 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -42,6 +42,7 @@ class EditForm(wtforms.Form): "You usually don't need to change this.")) license = wtforms.SelectField( _('License'), + [wtforms.validators.Optional(),], choices=licenses_as_choices()) class EditProfileForm(wtforms.Form): diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index cffb8a3c..62684dcf 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -75,9 +75,7 @@ def edit_media(request, media): media.description_html = cleaned_markdown_conversion( media.description) - media.license = ( - unicode(request.POST.get('license')) - or '') + media.license = unicode(request.POST.get('license', '')) media.slug = unicode(request.POST['slug']) diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 4ff52609..1ff59c18 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -39,4 +39,5 @@ class SubmitStartForm(wtforms.Form): "Separate tags by commas.")) license = wtforms.SelectField( _('License'), + [wtforms.validators.Optional(),], choices=licenses_as_choices()) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 8911bf82..832203a4 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -69,9 +69,7 @@ def submit_start(request): entry.description_html = cleaned_markdown_conversion( entry.description) - entry.license = ( - unicode(request.POST.get('license')) - or '') + entry.license = unicode(request.POST.get('license', '')) entry.uploader = request.user._id -- cgit v1.2.3 From 2788e6a16484330ce1091ae57a87a4da362936c6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:40:39 -0600 Subject: License "all rights reserved" default should be None/NULL, not empty string --- mediagoblin/db/mixin.py | 2 +- mediagoblin/db/mongo/migrations.py | 2 +- mediagoblin/db/sql/models.py | 2 +- mediagoblin/edit/views.py | 2 +- mediagoblin/submit/views.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index b0fecad3..d587ccb4 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -93,4 +93,4 @@ class MediaEntryMixin(object): def get_license_data(self): """Return license dict for requested license""" - return licenses.SUPPORTED_LICENSES[self.license] + return licenses.SUPPORTED_LICENSES[self.license or ""] diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py index f66ade2b..168fa530 100644 --- a/mediagoblin/db/mongo/migrations.py +++ b/mediagoblin/db/mongo/migrations.py @@ -114,4 +114,4 @@ def mediaentry_add_license(database): """ Add the 'license' field for entries that don't have it. """ - add_table_field(database, 'media_entries', 'license', '') + add_table_field(database, 'media_entries', 'license', None) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 53ac3d3f..507efe62 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -81,7 +81,7 @@ class MediaEntry(Base, MediaEntryMixin): description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? - license = Column(Unicode, nullable=False) + license = Column(Unicode) fail_error = Column(Unicode) fail_metadata = Column(UnicodeText) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 62684dcf..471968f7 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -75,7 +75,7 @@ def edit_media(request, media): media.description_html = cleaned_markdown_conversion( media.description) - media.license = unicode(request.POST.get('license', '')) + media.license = unicode(request.POST.get('license')) or None media.slug = unicode(request.POST['slug']) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 832203a4..f70e4ba5 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -69,7 +69,7 @@ def submit_start(request): entry.description_html = cleaned_markdown_conversion( entry.description) - entry.license = unicode(request.POST.get('license', '')) + entry.license = unicode(request.POST.get('license', "")) or None entry.uploader = request.user._id -- cgit v1.2.3 From ac014f04244243e9de1ebc152a90871161cb42a6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:41:07 -0600 Subject: Convert over the license field, too! --- mediagoblin/db/sql/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index ac7a66c2..260328c6 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -78,7 +78,7 @@ def convert_media_entries(mk_db): copy_attrs(entry, new_entry, ('title', 'slug', 'created', 'description', 'description_html', - 'media_type', 'state', + 'media_type', 'state', 'license', 'fail_error', 'queued_task_id',)) copy_reference_attr(entry, new_entry, "uploader") -- cgit v1.2.3 From 5d775ebd2f5dc4be1fb8751805465cc99f7cf0f7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:51:21 -0600 Subject: Provided a SORTED_SUPPORTED_LICENSES (but keep the old unsorted dict!) --- mediagoblin/tools/licenses.py | 69 +++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/mediagoblin/tools/licenses.py b/mediagoblin/tools/licenses.py index cb137fa8..44d8e494 100644 --- a/mediagoblin/tools/licenses.py +++ b/mediagoblin/tools/licenses.py @@ -14,44 +14,37 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -SUPPORTED_LICENSES = { - "": { - "name": "No license specified", - "abbreviation": "All rights reserved" - }, - "http://creativecommons.org/licenses/by/3.0/": { - "name": "Creative Commons Attribution Unported 3.0", - "abbreviation": "CC BY 3.0" - }, - "http://creativecommons.org/licenses/by-sa/3.0": { - "name": "Creative Commons Attribution-ShareAlike Unported 3.0", - "abbreviation": "CC BY-SA 3.0" - }, - "http://creativecommons.org/licenses/by-nd/3.0": { - "name": "Creative Commons Attribution-NoDerivs 3.0 Unported", - "abbreviation": "CC BY-ND 3.0" - }, - "http://creativecommons.org/licenses/by-nc/3.0": { - "name": "Creative Commons Attribution-NonCommercial Unported 3.0", - "abbreviation": "CC BY-NC 3.0" - }, - "http://creativecommons.org/licenses/by-nc-sa/3.0": { - "name": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported", - "abbreviation": "CC BY-NC-SA 3.0" - }, - "http://creativecommons.org/licenses/by-nc-nd/3.0": { - "name": "Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported", - "abbreviation": "CC BY-NC-ND 3.0" - }, - "http://creativecommons.org/publicdomain/zero/1.0/": { - "name": "Creative Commons CC0 1.0 Universal", - "abbreviation": "CC0 1.0" - }, - "http://creativecommons.org/publicdomain/mark/1.0/": { - "name": "Public Domain", - "abbreviation": "Public Domain" - }, -} +SORTED_SUPPORTED_LICENSES = [ + ("", + {"name": "No license specified", + "abbreviation": "All rights reserved"}), + ("http://creativecommons.org/licenses/by/3.0/", + {"name": "Creative Commons Attribution Unported 3.0", + "abbreviation": "CC BY 3.0"}), + ("http://creativecommons.org/licenses/by-sa/3.0", + {"name": "Creative Commons Attribution-ShareAlike Unported 3.0", + "abbreviation": "CC BY-SA 3.0"}), + ("http://creativecommons.org/licenses/by-nd/3.0", + {"name": "Creative Commons Attribution-NoDerivs 3.0 Unported", + "abbreviation": "CC BY-ND 3.0"}), + ("http://creativecommons.org/licenses/by-nc/3.0", + {"name": "Creative Commons Attribution-NonCommercial Unported 3.0", + "abbreviation": "CC BY-NC 3.0"}), + ("http://creativecommons.org/licenses/by-nc-sa/3.0", + {"name": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported", + "abbreviation": "CC BY-NC-SA 3.0"}), + ("http://creativecommons.org/licenses/by-nc-nd/3.0", + {"name": "Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported", + "abbreviation": "CC BY-NC-ND 3.0"}), + ("http://creativecommons.org/publicdomain/zero/1.0/", + {"name": "Creative Commons CC0 1.0 Universal", + "abbreviation": "CC0 1.0"}), + ("http://creativecommons.org/publicdomain/mark/1.0/", + {"name": "Public Domain", + "abbreviation": "Public Domain"})] + +SUPPORTED_LICENSES = dict(SORTED_SUPPORTED_LICENSES) + def licenses_as_choices(): license_list = [] -- cgit v1.2.3 From da6206c4beb2edb43398eaa06fc78f41d7088481 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:56:49 -0600 Subject: Oops, I broke teh all rights reserved ;) --- mediagoblin/edit/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 471968f7..cf7182e5 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -75,7 +75,7 @@ def edit_media(request, media): media.description_html = cleaned_markdown_conversion( media.description) - media.license = unicode(request.POST.get('license')) or None + media.license = unicode(request.POST.get('license', '')) or None media.slug = unicode(request.POST['slug']) -- cgit v1.2.3 From 2c1f1fd08b38f0715673d9f38e4703ae4041da69 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:58:03 -0600 Subject: Show the license list in sorted form --- mediagoblin/tools/licenses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tools/licenses.py b/mediagoblin/tools/licenses.py index 44d8e494..d67510fa 100644 --- a/mediagoblin/tools/licenses.py +++ b/mediagoblin/tools/licenses.py @@ -49,7 +49,7 @@ SUPPORTED_LICENSES = dict(SORTED_SUPPORTED_LICENSES) def licenses_as_choices(): license_list = [] - for uri, data in SUPPORTED_LICENSES.items(): + for uri, data in SORTED_SUPPORTED_LICENSES: license_list.append((uri, data["abbreviation"])) return license_list -- cgit v1.2.3 From ee4fb8125aef6cc4ba357b695483da51bed4310d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 17:00:42 -0600 Subject: Canonical license URIS for CC stuff should have a trailing slash. --- mediagoblin/tools/licenses.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/tools/licenses.py b/mediagoblin/tools/licenses.py index d67510fa..0ff6453b 100644 --- a/mediagoblin/tools/licenses.py +++ b/mediagoblin/tools/licenses.py @@ -21,19 +21,19 @@ SORTED_SUPPORTED_LICENSES = [ ("http://creativecommons.org/licenses/by/3.0/", {"name": "Creative Commons Attribution Unported 3.0", "abbreviation": "CC BY 3.0"}), - ("http://creativecommons.org/licenses/by-sa/3.0", + ("http://creativecommons.org/licenses/by-sa/3.0/", {"name": "Creative Commons Attribution-ShareAlike Unported 3.0", "abbreviation": "CC BY-SA 3.0"}), - ("http://creativecommons.org/licenses/by-nd/3.0", + ("http://creativecommons.org/licenses/by-nd/3.0/", {"name": "Creative Commons Attribution-NoDerivs 3.0 Unported", "abbreviation": "CC BY-ND 3.0"}), - ("http://creativecommons.org/licenses/by-nc/3.0", + ("http://creativecommons.org/licenses/by-nc/3.0/", {"name": "Creative Commons Attribution-NonCommercial Unported 3.0", "abbreviation": "CC BY-NC 3.0"}), - ("http://creativecommons.org/licenses/by-nc-sa/3.0", + ("http://creativecommons.org/licenses/by-nc-sa/3.0/", {"name": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported", "abbreviation": "CC BY-NC-SA 3.0"}), - ("http://creativecommons.org/licenses/by-nc-nd/3.0", + ("http://creativecommons.org/licenses/by-nc-nd/3.0/", {"name": "Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported", "abbreviation": "CC BY-NC-ND 3.0"}), ("http://creativecommons.org/publicdomain/zero/1.0/", -- cgit v1.2.3 From 02ede85826e0cede55a3ae23b16508bf606cbb45 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 2 Jan 2012 13:07:16 +0100 Subject: Create a fully functional get_comments for SQL Using proper sqlalchemy syntax instead of the emulated mongo one. --- mediagoblin/db/sql/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 507efe62..d5573a56 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -109,6 +109,13 @@ class MediaEntry(Base, MediaEntryMixin): # attachment_files # fail_error + def get_comments(self, ascending=False): + order_col = MediaComment.created + if not ascending: + order_col = desc(order_col) + return MediaComment.query.filter_by( + media_entry=self.id).order_by(order_col) + class MediaFile(Base): __tablename__ = "mediafiles" -- cgit v1.2.3 From c47a03b909ecd97cab5b144d0cab007b62b92a90 Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 4 Jan 2012 22:13:19 +0100 Subject: Proper url_to_{prev,next} for SQL Uses complete sqlalchemy syntax now. --- mediagoblin/db/sql/models.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index d5573a56..57444c2c 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -23,6 +23,7 @@ from sqlalchemy import ( UniqueConstraint) from sqlalchemy.orm import relationship from sqlalchemy.orm.collections import attribute_mapped_collection +from sqlalchemy.sql.expression import desc from sqlalchemy.ext.associationproxy import association_proxy from mediagoblin.db.sql.extratypes import PathTupleWithSlashes @@ -116,6 +117,26 @@ class MediaEntry(Base, MediaEntryMixin): return MediaComment.query.filter_by( media_entry=self.id).order_by(order_col) + def url_to_prev(self, urlgen): + """get the next 'newer' entry by this user""" + media = MediaEntry.query.filter( + (MediaEntry.uploader == self.uploader) + & (MediaEntry.state == 'processed') + & (MediaEntry.id > self.id)).order_by(MediaEntry.id).first() + + if media is not None: + return media.url_for_self(urlgen) + + def url_to_next(self, urlgen): + """get the next 'older' entry by this user""" + media = MediaEntry.query.filter( + (MediaEntry.uploader == self.uploader) + & (MediaEntry.state == 'processed') + & (MediaEntry.id < self.id)).order_by(desc(MediaEntry.id)).first() + + if media is not None: + return media.url_for_self(urlgen) + class MediaFile(Base): __tablename__ = "mediafiles" -- cgit v1.2.3 From c5ba5b0456a711d157e317f220e9c739226e7f50 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 01:54:37 +0100 Subject: Installed leaflet in extlib --- extlib/leaflet/CHANGELOG.md | 88 ++++ extlib/leaflet/LICENSE | 22 + extlib/leaflet/README.md | 10 + extlib/leaflet/debug/control/map-control.html | 29 ++ extlib/leaflet/debug/css/mobile.css | 6 + extlib/leaflet/debug/css/screen.css | 5 + extlib/leaflet/debug/geojson/geojson-sample.js | 50 +++ extlib/leaflet/debug/geojson/geojson.html | 56 +++ extlib/leaflet/debug/leaflet-include.js | 100 +++++ extlib/leaflet/debug/map/canvas.html | 46 ++ extlib/leaflet/debug/map/map-mobile.html | 42 ++ extlib/leaflet/debug/map/map.html | 56 +++ extlib/leaflet/debug/map/wms-marble.html | 30 ++ extlib/leaflet/debug/map/wms.html | 37 ++ extlib/leaflet/debug/vector/route.js | 1 + extlib/leaflet/debug/vector/vector-mobile.html | 38 ++ extlib/leaflet/debug/vector/vector.html | 38 ++ extlib/leaflet/spec/runner.html | 82 ++++ extlib/leaflet/spec/suites/LeafletSpec.js | 15 + extlib/leaflet/spec/suites/SpecHelper.js | 5 + extlib/leaflet/spec/suites/core/ClassSpec.js | 120 ++++++ extlib/leaflet/spec/suites/core/EventsSpec.js | 110 +++++ extlib/leaflet/spec/suites/core/UtilSpec.js | 63 +++ extlib/leaflet/spec/suites/dom/DomEventSpec.js | 102 +++++ extlib/leaflet/spec/suites/dom/DomUtilSpec.js | 29 ++ extlib/leaflet/spec/suites/geo/LatLngBoundsSpec.js | 1 + extlib/leaflet/spec/suites/geo/LatLngSpec.js | 70 ++++ extlib/leaflet/spec/suites/geo/ProjectionSpec.js | 42 ++ extlib/leaflet/spec/suites/geometry/BoundsSpec.js | 43 ++ extlib/leaflet/spec/suites/geometry/PointSpec.js | 45 ++ .../spec/suites/geometry/TransformationSpec.js | 19 + extlib/leaflet/spec/suites/layer/TileLayerSpec.js | 1 + extlib/leaflet/spec/suites/map/MapSpec.js | 1 + extlib/leaflet/src/Leaflet.js | 35 ++ extlib/leaflet/src/control/Control.Attribution.js | 55 +++ extlib/leaflet/src/control/Control.Zoom.js | 36 ++ extlib/leaflet/src/control/Control.js | 9 + extlib/leaflet/src/core/Browser.js | 23 + extlib/leaflet/src/core/Class.js | 66 +++ extlib/leaflet/src/core/Events.js | 58 +++ extlib/leaflet/src/core/Util.js | 96 +++++ extlib/leaflet/src/dom/DomEvent.DoubleTap.js | 41 ++ extlib/leaflet/src/dom/DomEvent.js | 132 ++++++ extlib/leaflet/src/dom/DomUtil.js | 124 ++++++ extlib/leaflet/src/dom/Draggable.js | 129 ++++++ .../src/dom/transition/Transition.Native.js | 89 ++++ .../leaflet/src/dom/transition/Transition.Timer.js | 124 ++++++ extlib/leaflet/src/dom/transition/Transition.js | 28 ++ extlib/leaflet/src/geo/LatLng.js | 35 ++ extlib/leaflet/src/geo/LatLngBounds.js | 62 +++ extlib/leaflet/src/geo/crs/CRS.EPSG3395.js | 13 + extlib/leaflet/src/geo/crs/CRS.EPSG3857.js | 17 + extlib/leaflet/src/geo/crs/CRS.EPSG4326.js | 7 + extlib/leaflet/src/geo/crs/CRS.js | 17 + .../src/geo/projection/Projection.LonLat.js | 10 + .../src/geo/projection/Projection.Mercator.js | 49 +++ .../geo/projection/Projection.SphericalMercator.js | 23 + extlib/leaflet/src/geo/projection/Projection.js | 5 + extlib/leaflet/src/geometry/Bounds.js | 48 +++ extlib/leaflet/src/geometry/LineUtil.js | 159 +++++++ extlib/leaflet/src/geometry/Point.js | 66 +++ extlib/leaflet/src/geometry/PolyUtil.js | 55 +++ extlib/leaflet/src/geometry/Transformation.js | 31 ++ extlib/leaflet/src/handler/DoubleClickZoom.js | 21 + extlib/leaflet/src/handler/Handler.js | 13 + extlib/leaflet/src/handler/MapDrag.js | 44 ++ extlib/leaflet/src/handler/MarkerDrag.js | 54 +++ extlib/leaflet/src/handler/ScrollWheelZoom.js | 50 +++ extlib/leaflet/src/handler/ShiftDragZoom.js | 79 ++++ extlib/leaflet/src/handler/TouchZoom.js | 87 ++++ extlib/leaflet/src/layer/FeatureGroup.js | 40 ++ extlib/leaflet/src/layer/GeoJSON.js | 106 +++++ extlib/leaflet/src/layer/ImageOverlay.js | 58 +++ extlib/leaflet/src/layer/LayerGroup.js | 58 +++ extlib/leaflet/src/layer/Popup.js | 165 ++++++++ extlib/leaflet/src/layer/marker/Icon.js | 56 +++ extlib/leaflet/src/layer/marker/Marker.Popup.js | 28 ++ extlib/leaflet/src/layer/marker/Marker.js | 123 ++++++ extlib/leaflet/src/layer/tile/TileLayer.Canvas.js | 41 ++ extlib/leaflet/src/layer/tile/TileLayer.WMS.js | 47 +++ extlib/leaflet/src/layer/tile/TileLayer.js | 262 ++++++++++++ extlib/leaflet/src/layer/vector/Circle.js | 51 +++ extlib/leaflet/src/layer/vector/CircleMarker.js | 25 ++ extlib/leaflet/src/layer/vector/MultiPoly.js | 27 ++ extlib/leaflet/src/layer/vector/Path.Popup.js | 24 ++ extlib/leaflet/src/layer/vector/Path.VML.js | 91 ++++ extlib/leaflet/src/layer/vector/Path.js | 207 +++++++++ extlib/leaflet/src/layer/vector/Polygon.js | 58 +++ extlib/leaflet/src/layer/vector/Polyline.js | 112 +++++ extlib/leaflet/src/map/Map.js | 464 +++++++++++++++++++++ extlib/leaflet/src/map/ext/Map.Control.js | 50 +++ extlib/leaflet/src/map/ext/Map.Geolocation.js | 69 +++ extlib/leaflet/src/map/ext/Map.PanAnimation.js | 62 +++ extlib/leaflet/src/map/ext/Map.Popup.js | 15 + extlib/leaflet/src/map/ext/Map.ZoomAnimation.js | 124 ++++++ mediagoblin/static/extlib/leaflet | 1 + 96 files changed, 5756 insertions(+) create mode 100644 extlib/leaflet/CHANGELOG.md create mode 100644 extlib/leaflet/LICENSE create mode 100644 extlib/leaflet/README.md create mode 100644 extlib/leaflet/debug/control/map-control.html create mode 100644 extlib/leaflet/debug/css/mobile.css create mode 100644 extlib/leaflet/debug/css/screen.css create mode 100644 extlib/leaflet/debug/geojson/geojson-sample.js create mode 100644 extlib/leaflet/debug/geojson/geojson.html create mode 100644 extlib/leaflet/debug/leaflet-include.js create mode 100644 extlib/leaflet/debug/map/canvas.html create mode 100644 extlib/leaflet/debug/map/map-mobile.html create mode 100644 extlib/leaflet/debug/map/map.html create mode 100644 extlib/leaflet/debug/map/wms-marble.html create mode 100644 extlib/leaflet/debug/map/wms.html create mode 100644 extlib/leaflet/debug/vector/route.js create mode 100644 extlib/leaflet/debug/vector/vector-mobile.html create mode 100644 extlib/leaflet/debug/vector/vector.html create mode 100644 extlib/leaflet/spec/runner.html create mode 100644 extlib/leaflet/spec/suites/LeafletSpec.js create mode 100644 extlib/leaflet/spec/suites/SpecHelper.js create mode 100644 extlib/leaflet/spec/suites/core/ClassSpec.js create mode 100644 extlib/leaflet/spec/suites/core/EventsSpec.js create mode 100644 extlib/leaflet/spec/suites/core/UtilSpec.js create mode 100644 extlib/leaflet/spec/suites/dom/DomEventSpec.js create mode 100644 extlib/leaflet/spec/suites/dom/DomUtilSpec.js create mode 100644 extlib/leaflet/spec/suites/geo/LatLngBoundsSpec.js create mode 100644 extlib/leaflet/spec/suites/geo/LatLngSpec.js create mode 100644 extlib/leaflet/spec/suites/geo/ProjectionSpec.js create mode 100644 extlib/leaflet/spec/suites/geometry/BoundsSpec.js create mode 100644 extlib/leaflet/spec/suites/geometry/PointSpec.js create mode 100644 extlib/leaflet/spec/suites/geometry/TransformationSpec.js create mode 100644 extlib/leaflet/spec/suites/layer/TileLayerSpec.js create mode 100644 extlib/leaflet/spec/suites/map/MapSpec.js create mode 100644 extlib/leaflet/src/Leaflet.js create mode 100644 extlib/leaflet/src/control/Control.Attribution.js create mode 100644 extlib/leaflet/src/control/Control.Zoom.js create mode 100644 extlib/leaflet/src/control/Control.js create mode 100644 extlib/leaflet/src/core/Browser.js create mode 100644 extlib/leaflet/src/core/Class.js create mode 100644 extlib/leaflet/src/core/Events.js create mode 100644 extlib/leaflet/src/core/Util.js create mode 100644 extlib/leaflet/src/dom/DomEvent.DoubleTap.js create mode 100644 extlib/leaflet/src/dom/DomEvent.js create mode 100644 extlib/leaflet/src/dom/DomUtil.js create mode 100644 extlib/leaflet/src/dom/Draggable.js create mode 100644 extlib/leaflet/src/dom/transition/Transition.Native.js create mode 100644 extlib/leaflet/src/dom/transition/Transition.Timer.js create mode 100644 extlib/leaflet/src/dom/transition/Transition.js create mode 100644 extlib/leaflet/src/geo/LatLng.js create mode 100644 extlib/leaflet/src/geo/LatLngBounds.js create mode 100644 extlib/leaflet/src/geo/crs/CRS.EPSG3395.js create mode 100644 extlib/leaflet/src/geo/crs/CRS.EPSG3857.js create mode 100644 extlib/leaflet/src/geo/crs/CRS.EPSG4326.js create mode 100644 extlib/leaflet/src/geo/crs/CRS.js create mode 100644 extlib/leaflet/src/geo/projection/Projection.LonLat.js create mode 100644 extlib/leaflet/src/geo/projection/Projection.Mercator.js create mode 100644 extlib/leaflet/src/geo/projection/Projection.SphericalMercator.js create mode 100644 extlib/leaflet/src/geo/projection/Projection.js create mode 100644 extlib/leaflet/src/geometry/Bounds.js create mode 100644 extlib/leaflet/src/geometry/LineUtil.js create mode 100644 extlib/leaflet/src/geometry/Point.js create mode 100644 extlib/leaflet/src/geometry/PolyUtil.js create mode 100644 extlib/leaflet/src/geometry/Transformation.js create mode 100644 extlib/leaflet/src/handler/DoubleClickZoom.js create mode 100644 extlib/leaflet/src/handler/Handler.js create mode 100644 extlib/leaflet/src/handler/MapDrag.js create mode 100644 extlib/leaflet/src/handler/MarkerDrag.js create mode 100644 extlib/leaflet/src/handler/ScrollWheelZoom.js create mode 100644 extlib/leaflet/src/handler/ShiftDragZoom.js create mode 100644 extlib/leaflet/src/handler/TouchZoom.js create mode 100644 extlib/leaflet/src/layer/FeatureGroup.js create mode 100644 extlib/leaflet/src/layer/GeoJSON.js create mode 100644 extlib/leaflet/src/layer/ImageOverlay.js create mode 100644 extlib/leaflet/src/layer/LayerGroup.js create mode 100644 extlib/leaflet/src/layer/Popup.js create mode 100644 extlib/leaflet/src/layer/marker/Icon.js create mode 100644 extlib/leaflet/src/layer/marker/Marker.Popup.js create mode 100644 extlib/leaflet/src/layer/marker/Marker.js create mode 100644 extlib/leaflet/src/layer/tile/TileLayer.Canvas.js create mode 100644 extlib/leaflet/src/layer/tile/TileLayer.WMS.js create mode 100644 extlib/leaflet/src/layer/tile/TileLayer.js create mode 100644 extlib/leaflet/src/layer/vector/Circle.js create mode 100644 extlib/leaflet/src/layer/vector/CircleMarker.js create mode 100644 extlib/leaflet/src/layer/vector/MultiPoly.js create mode 100644 extlib/leaflet/src/layer/vector/Path.Popup.js create mode 100644 extlib/leaflet/src/layer/vector/Path.VML.js create mode 100644 extlib/leaflet/src/layer/vector/Path.js create mode 100644 extlib/leaflet/src/layer/vector/Polygon.js create mode 100644 extlib/leaflet/src/layer/vector/Polyline.js create mode 100644 extlib/leaflet/src/map/Map.js create mode 100644 extlib/leaflet/src/map/ext/Map.Control.js create mode 100644 extlib/leaflet/src/map/ext/Map.Geolocation.js create mode 100644 extlib/leaflet/src/map/ext/Map.PanAnimation.js create mode 100644 extlib/leaflet/src/map/ext/Map.Popup.js create mode 100644 extlib/leaflet/src/map/ext/Map.ZoomAnimation.js create mode 120000 mediagoblin/static/extlib/leaflet diff --git a/extlib/leaflet/CHANGELOG.md b/extlib/leaflet/CHANGELOG.md new file mode 100644 index 00000000..49ebfe24 --- /dev/null +++ b/extlib/leaflet/CHANGELOG.md @@ -0,0 +1,88 @@ +Leaflet Changelog +================= + +## 0.3 (master) + +## 0.2.1 (2011-06-18) + + * Fixed regression that caused error in `TileLayer.Canvas` + +## 0.2 (2011-06-17) + +### Major features + + * Added **WMS** support (`TileLayer.WMS` layer). + * Added different **projections** support, having `EPSG:3857`, `EPSG:4326` and `EPSG:3395` out of the box (through `crs` option in `Map`). Thanks to [@Miroff](https://github.com/Miroff) & [@Komzpa](https://github.com/Komzpa) for great advice and explanation regarding this. + * Added **GeoJSON** layer support. + +### Improvements + +#### Usability improvements + + * Improved panning performance in Chrome and FF considerably with the help of `requestAnimationFrame`. [#130](https://github.com/CloudMade/Leaflet/issues/130) + * Improved click responsiveness in mobile WebKit (now it happens without delay). [#26](https://github.com/CloudMade/Leaflet/issues/26) + * Added tap tolerance (so click happens even if you moved your finger slighly when tapping). + * Improved geolocation error handling: better error messages, explicit timeout, set world view on locateAndSetView failure. [#61](https://github.com/CloudMade/Leaflet/issues/61) + +#### API improvements + + * Added **MultiPolyline** and **MultiPolygon** layers. [#77](https://github.com/CloudMade/Leaflet/issues/77) + * Added **LayerGroup** and **FeatureGroup** layers for grouping other layers. + * Added **TileLayer.Canvas** for easy creation of canvas-based tile layers. + * Changed `Circle` to be zoom-dependent (with radius in meters); circle of a permanent size is now called `CircleMarker`. + * Added `mouseover` and `mouseout` events to map, markers and paths; added map `mousemove` event. + * Added `setLatLngs`, `spliceLatLngs`, `addLatLng`, `getLatLngs` methods to polylines and polygons. + * Added `setLatLng` and `setRadius` methods to `Circle` and `CircleMarker`. + * Improved `LatLngBounds contains` method to accept `LatLng` in addition to `LatLngBounds`, the same for `Bounds contains` and `Point` + * Improved `LatLngBounds` & `Bounds` to allow their instantiation without arguments (by [@snc](https://github.com/snc)). + * Added TMS tile numbering support through `TileLayer` `scheme: 'tms'` option (by [@tmcw](https://github.com/tmcw)). + * Added `TileLayer` `noWrap` option to disable wrapping `x` tile coordinate (by [@jasondavies](https://github.com/jasondavies)). + * Added `opacity` option and `setOpacity` method to `TileLayer`. + * Added `setLatLng` and `setIcon` methods to `Marker`. + * Added `title` option to `Marker`. + * Added `maxZoom` argument to `map.locateAndSetView` method. + * Added ability to pass Geolocation options to map `locate` and `locateAndSetView` methods (by [@JasonSanford](https://github.com/JasonSanford)). + * Improved `Popup` to accept HTML elements in addition to strings as its content. + +#### Development workflow improvements + + * Added `Makefile` for building `leaflet.js` on non-Windows machines (by [@tmcw](https://github.com/tmcw)). + * Improved `debug/leaflet-include.js` script to allow using it outside of `debug` folder (by [@antonj](https://github.com/antonj)). + * Improved `L` definition to be compatible with CommonJS. [#122](https://github.com/CloudMade/Leaflet/issues/122) + +### Bug fixes + +#### General bugfixes + + * Fixed a bug where zooming is broken if the map contains a polygon and you zoom to an area where it's not visible. [#47](https://github.com/CloudMade/Leaflet/issues/47) + * Fixed a bug where closed polylines would not appear on the map. + * Fixed a bug where marker that was added, removed and then added again would not appear on the map. [#66](https://github.com/CloudMade/Leaflet/issues/66) + * Fixed a bug where tile layer that was added, removed and then added again would not appear on the map. + * Fixed a bug where some tiles would not load when panning across the date line. [#97](https://github.com/CloudMade/Leaflet/issues/97) + * Fixed a bug where map div with `position: absolute` is reset to `relative`. [#100](https://github.com/CloudMade/Leaflet/issues/100) + * Fixed a bug that caused an error when trying to add a marker without shadow in its icon. + * Fixed a bug where popup content would not update on `setContent` call. [#94](https://github.com/CloudMade/Leaflet/issues/94) + * Fixed a bug where double click zoom wouldn't work if popup is opened on map click + * Fixed a bug with click propagation on popup close button. [#99](https://github.com/CloudMade/Leaflet/issues/99) + * Fixed inability to remove ImageOverlay layer. + +#### Browser bugfixes + + * Fixed a bug where paths would not appear in IE8. + * Fixed a bug where there were occasional slowdowns before zoom animation in WebKit. [#123](https://github.com/CloudMade/Leaflet/issues/123) + * Fixed incorrect zoom animation & popup styling in Opera 11.11. + * Fixed popup fade animation in Firefox and Opera. + * Fixed a bug where map isn't displayed in Firefox when there's an `img { max-width: 100% }` rule. + +#### Mobile browsers bugfixes + + * Fixed a bug that prevented panning on some Android 2.1 (and possibly older) devices. [#84](https://github.com/CloudMade/Leaflet/issues/84) + * Disabled zoom animation on Android by default because it's buggy on some devices (will be enabled back when it's stable enough). [#32](https://github.com/CloudMade/Leaflet/issues/32) + * Fixed a bug where map would occasionally break while multi-touch-zooming on iOS. [#32](https://github.com/CloudMade/Leaflet/issues/32) + * Fixed a bug that prevented panning/clicking on Android 3 tablets. [#121](https://github.com/CloudMade/Leaflet/issues/121) + * Fixed a bug that prevented panning/clicking on Opera Mobile. [#138](https://github.com/CloudMade/Leaflet/issues/138) + * Fixed potentional memory leak on WebKit when removing tiles, thanks to [@Scalar4eg](https://github.com/Scalar4eg). [#107](https://github.com/CloudMade/Leaflet/issues/107) + +## 0.1 (2011-05-13) + + * Initial Leaflet release. diff --git a/extlib/leaflet/LICENSE b/extlib/leaflet/LICENSE new file mode 100644 index 00000000..883dc212 --- /dev/null +++ b/extlib/leaflet/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/extlib/leaflet/README.md b/extlib/leaflet/README.md new file mode 100644 index 00000000..b6caae96 --- /dev/null +++ b/extlib/leaflet/README.md @@ -0,0 +1,10 @@ +Leaflet + +Leaflet is a modern, lightweight BSD-licensed JavaScript library for making tile-based interactive maps for both desktop and mobile web browsers, developed by [CloudMade](http://cloudmade.com) to form the core of its next generation JavaScript API. + +It is built from the ground up to work efficiently and smoothly on both platforms, utilizing cutting-edge technologies included in HTML5. Its top priorities are usability, performance and small size, [A-grade](http://developer.yahoo.com/yui/articles/gbs/) browser support, flexibility and easy to use API. The OOP-based code of the library is designed to be modular, extensible and very easy to understand. + +Check out the website for more information: [leaflet.cloudmade.com](http://leaflet.cloudmade.com) + +## Contributing to Leaflet +Let's make the best open-source library for maps that can possibly exist! Please send your pull requests to [Vladimir Agafonkin](http://github.com/mourner) (Leaflet maintainer) - we'll be happy to accept your contributions! [List of Leaflet contributors](http://github.com/CloudMade/Leaflet/contributors) \ No newline at end of file diff --git a/extlib/leaflet/debug/control/map-control.html b/extlib/leaflet/debug/control/map-control.html new file mode 100644 index 00000000..8d52bc98 --- /dev/null +++ b/extlib/leaflet/debug/control/map-control.html @@ -0,0 +1,29 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/css/mobile.css b/extlib/leaflet/debug/css/mobile.css new file mode 100644 index 00000000..d8f46f32 --- /dev/null +++ b/extlib/leaflet/debug/css/mobile.css @@ -0,0 +1,6 @@ +html, body, #map { + margin: 0; + padding: 0; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/extlib/leaflet/debug/css/screen.css b/extlib/leaflet/debug/css/screen.css new file mode 100644 index 00000000..f9886987 --- /dev/null +++ b/extlib/leaflet/debug/css/screen.css @@ -0,0 +1,5 @@ +#map { + width: 800px; + height: 600px; + border: 1px solid #ccc; + } \ No newline at end of file diff --git a/extlib/leaflet/debug/geojson/geojson-sample.js b/extlib/leaflet/debug/geojson/geojson-sample.js new file mode 100644 index 00000000..24ecf050 --- /dev/null +++ b/extlib/leaflet/debug/geojson/geojson-sample.js @@ -0,0 +1,50 @@ +var geojsonSample = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [102.0, 0.5] + }, + "properties": { + "prop0": "value0", + "color": "blue" + } + }, + + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]] + }, + "properties": { + "color": "red", + "prop1": 0.0 + } + }, + + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]] + }, + "properties": { + "color": "green", + "prop1": { + "this": "that" + } + } + }, + + { + "type": "Feature", + "geometry": { + "type": "MultiPolygon", + "coordinates": [[[[100.0, 1.5], [100.5, 1.5], [100.5, 2.0], [100.0, 2.0], [100.0, 1.5]]], [[[100.5, 2.0], [100.5, 2.5], [101.0, 2.5], [101.0, 2.0], [100.5, 2.0]]]] + } + } + ] +}; \ No newline at end of file diff --git a/extlib/leaflet/debug/geojson/geojson.html b/extlib/leaflet/debug/geojson/geojson.html new file mode 100644 index 00000000..319e7c13 --- /dev/null +++ b/extlib/leaflet/debug/geojson/geojson.html @@ -0,0 +1,56 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/leaflet-include.js b/extlib/leaflet/debug/leaflet-include.js new file mode 100644 index 00000000..9ae8f458 --- /dev/null +++ b/extlib/leaflet/debug/leaflet-include.js @@ -0,0 +1,100 @@ +(function() { + //TODO replace script list with the one from ../buid/deps.js + var scripts = [ + 'Leaflet.js', + + 'core/Util.js', + 'core/Class.js', + 'core/Events.js', + 'core/Browser.js', + + 'geometry/Point.js', + 'geometry/Bounds.js', + 'geometry/Transformation.js', + 'geometry/LineUtil.js', + 'geometry/PolyUtil.js', + + 'dom/DomEvent.js', + 'dom/DomEvent.DoubleTap.js', + 'dom/DomUtil.js', + 'dom/Draggable.js', + + 'dom/transition/Transition.js', + 'dom/transition/Transition.Native.js', + 'dom/transition/Transition.Timer.js', + + 'geo/LatLng.js', + 'geo/LatLngBounds.js', + + 'geo/projection/Projection.js', + 'geo/projection/Projection.SphericalMercator.js', + 'geo/projection/Projection.LonLat.js', + 'geo/projection/Projection.Mercator.js', + + 'geo/crs/CRS.js', + 'geo/crs/CRS.EPSG3857.js', + 'geo/crs/CRS.EPSG4326.js', + 'geo/crs/CRS.EPSG3395.js', + + 'layer/LayerGroup.js', + 'layer/FeatureGroup.js', + + 'layer/tile/TileLayer.js', + 'layer/tile/TileLayer.WMS.js', + 'layer/tile/TileLayer.Canvas.js', + 'layer/ImageOverlay.js', + 'layer/Popup.js', + + 'layer/marker/Icon.js', + 'layer/marker/Marker.js', + 'layer/marker/Marker.Popup.js', + + 'layer/vector/Path.js', + 'layer/vector/Path.VML.js', + 'layer/vector/Path.Popup.js', + 'layer/vector/Polyline.js', + 'layer/vector/Polygon.js', + 'layer/vector/MultiPoly.js', + 'layer/vector/Circle.js', + 'layer/vector/CircleMarker.js', + + 'layer/GeoJSON.js', + + 'handler/Handler.js', + 'handler/MapDrag.js', + 'handler/TouchZoom.js', + 'handler/DoubleClickZoom.js', + 'handler/ScrollWheelZoom.js', + 'handler/ShiftDragZoom.js', + 'handler/MarkerDrag.js', + + 'control/Control.js', + 'control/Control.Zoom.js', + 'control/Control.Attribution.js', + + 'map/Map.js', + 'map/ext/Map.Geolocation.js', + 'map/ext/Map.Popup.js', + 'map/ext/Map.PanAnimation.js', + 'map/ext/Map.ZoomAnimation.js', + 'map/ext/Map.Control.js' + ]; + + function getSrcUrl() { + var scripts = document.getElementsByTagName('script'); + for (var i = 0; i < scripts.length; i++) { + var src = scripts[i].src; + if (src) { + var res = src.match(/^(.*)leaflet-include\.js$/); + if (res) { + return res[1] + '../src/'; + } + } + } + } + + var path = getSrcUrl(); + for (var i = 0; i < scripts.length; i++) { + document.writeln(""); + } +})(); \ No newline at end of file diff --git a/extlib/leaflet/debug/map/canvas.html b/extlib/leaflet/debug/map/canvas.html new file mode 100644 index 00000000..233035f1 --- /dev/null +++ b/extlib/leaflet/debug/map/canvas.html @@ -0,0 +1,46 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/map/map-mobile.html b/extlib/leaflet/debug/map/map-mobile.html new file mode 100644 index 00000000..27d12ed9 --- /dev/null +++ b/extlib/leaflet/debug/map/map-mobile.html @@ -0,0 +1,42 @@ + + + + Leaflet debug page + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/map/map.html b/extlib/leaflet/debug/map/map.html new file mode 100644 index 00000000..88bdd5b0 --- /dev/null +++ b/extlib/leaflet/debug/map/map.html @@ -0,0 +1,56 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/map/wms-marble.html b/extlib/leaflet/debug/map/wms-marble.html new file mode 100644 index 00000000..fd5443ab --- /dev/null +++ b/extlib/leaflet/debug/map/wms-marble.html @@ -0,0 +1,30 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/map/wms.html b/extlib/leaflet/debug/map/wms.html new file mode 100644 index 00000000..08694726 --- /dev/null +++ b/extlib/leaflet/debug/map/wms.html @@ -0,0 +1,37 @@ + + + + Leaflet debug page + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/vector/route.js b/extlib/leaflet/debug/vector/route.js new file mode 100644 index 00000000..fa847e31 --- /dev/null +++ b/extlib/leaflet/debug/vector/route.js @@ -0,0 +1 @@ +var route = [[51.452339,-0.26291],[51.452011,-0.26479],[51.451839,-0.26624],[51.45187,-0.26706],[51.451881,-0.26733],[51.452049,-0.26734],[51.453098,-0.26734],[51.453838,-0.26717],[51.454849,-0.267],[51.45575,-0.26704],[51.45631,-0.26723],[51.456402,-0.26729],[51.456669,-0.26745],[51.45689,-0.26755],[51.457001,-0.26758],[51.45797,-0.26776],[51.458359,-0.26786],[51.459019,-0.26783],[51.459629,-0.26785],[51.459888,-0.26809],[51.460178,-0.26845],[51.46077,-0.26841],[51.461102,-0.26838],[51.461479,-0.2685],[51.46159,-0.26848],[51.462479,-0.26776],[51.462921,-0.26766],[51.463291,-0.26754],[51.463558,-0.26736],[51.46373,-0.26728],[51.464291,-0.26676],[51.464432,-0.26675],[51.464722,-0.26671],[51.464821,-0.2657],[51.46484,-0.2655],[51.464851,-0.26504],[51.46489,-0.26456],[51.464951,-0.26397],[51.464981,-0.26357],[51.46497,-0.26344],[51.465031,-0.26294],[51.46508,-0.26224],[51.465111,-0.26179],[51.46513,-0.26157],[51.465149,-0.261],[51.465149,-0.26077],[51.465149,-0.26051],[51.465149,-0.26011],[51.46513,-0.25982],[51.46513,-0.25955],[51.46513,-0.25929],[51.465111,-0.25872],[51.46513,-0.2583],[51.46513,-0.25771],[51.465141,-0.25753],[51.46516,-0.25675],[51.46516,-0.25658],[51.46516,-0.25647],[51.465179,-0.25574],[51.465191,-0.25525],[51.465199,-0.25486],[51.46521,-0.25455],[51.46521,-0.25413],[51.46524,-0.25293],[51.465229,-0.25186],[51.465191,-0.25085],[51.46513,-0.25001],[51.46508,-0.24926],[51.465069,-0.24862],[51.465111,-0.24775],[51.465149,-0.2472],[51.465172,-0.24675],[51.46524,-0.24571],[51.465279,-0.24482],[51.465321,-0.24423],[51.465229,-0.24372],[51.465149,-0.24266],[51.465118,-0.24208],[51.465069,-0.24147],[51.464939,-0.24028],[51.464821,-0.2395],[51.46476,-0.2389],[51.464729,-0.23852],[51.464642,-0.23755],[51.464569,-0.23693],[51.464481,-0.2365],[51.464371,-0.23557],[51.464211,-0.23437],[51.46418,-0.23421],[51.464001,-0.23334],[51.463959,-0.23316],[51.463829,-0.23253],[51.463779,-0.23235],[51.463699,-0.23189],[51.463661,-0.2317],[51.463589,-0.23136],[51.463539,-0.23106],[51.463402,-0.23025],[51.463341,-0.2299],[51.463249,-0.22924],[51.463139,-0.22838],[51.46312,-0.22823],[51.463001,-0.22726],[51.462959,-0.22698],[51.462891,-0.22645],[51.462769,-0.22551],[51.462761,-0.22516],[51.462681,-0.22436],[51.46262,-0.224],[51.462521,-0.22297],[51.462421,-0.22247],[51.462181,-0.22183],[51.462009,-0.22149],[51.461731,-0.22074],[51.461399,-0.2196],[51.461361,-0.21948],[51.46122,-0.21878],[51.461109,-0.21824],[51.460979,-0.2175],[51.460789,-0.21715],[51.46069,-0.21685],[51.460522,-0.21596],[51.4604,-0.21533],[51.460361,-0.21511],[51.460251,-0.21458],[51.46022,-0.2144],[51.460159,-0.21411],[51.460121,-0.21389],[51.46011,-0.2138],[51.459961,-0.21308],[51.459942,-0.21294],[51.459702,-0.21186],[51.459702,-0.21184],[51.45948,-0.21112],[51.459259,-0.21038],[51.459011,-0.20963],[51.45892,-0.2094],[51.458809,-0.2091],[51.458759,-0.20898],[51.45858,-0.20853],[51.458328,-0.20795],[51.458179,-0.2076],[51.458141,-0.20751],[51.458099,-0.20743],[51.457981,-0.2072],[51.45771,-0.20668],[51.4575,-0.20638],[51.457321,-0.20614],[51.45718,-0.20596],[51.457088,-0.20584],[51.456921,-0.20558],[51.456829,-0.20541],[51.456772,-0.20522],[51.45676,-0.20518],[51.456749,-0.20509],[51.45673,-0.20469],[51.456718,-0.20466],[51.456699,-0.20425],[51.456692,-0.20391],[51.456692,-0.20371],[51.456661,-0.20284],[51.456661,-0.20272],[51.456661,-0.20254],[51.456669,-0.20231],[51.456692,-0.20178],[51.456699,-0.20148],[51.45673,-0.20116],[51.45676,-0.20077],[51.45686,-0.19978],[51.45697,-0.19857],[51.457001,-0.19826],[51.457039,-0.19806],[51.45705,-0.19793],[51.457142,-0.19781],[51.457211,-0.19776],[51.45742,-0.19785],[51.45763,-0.19794],[51.45776,-0.19795],[51.457829,-0.19791],[51.45789,-0.19784],[51.458,-0.19751],[51.458172,-0.19697],[51.458271,-0.19654],[51.458439,-0.19585],[51.458599,-0.19507],[51.45863,-0.1949],[51.458729,-0.19437],[51.458809,-0.19394],[51.45892,-0.19318],[51.45892,-0.1926],[51.458839,-0.19206],[51.458858,-0.19189],[51.45887,-0.1917],[51.459049,-0.19117],[51.45916,-0.19078],[51.459148,-0.19065],[51.45908,-0.19055],[51.458679,-0.19041],[51.458511,-0.19034],[51.458271,-0.19026],[51.457939,-0.19013],[51.457329,-0.1899],[51.457199,-0.18985],[51.456829,-0.18972],[51.457069,-0.18858],[51.457142,-0.18824],[51.457211,-0.18785],[51.45731,-0.18732],[51.457581,-0.1857],[51.457649,-0.18525],[51.457878,-0.18476],[51.45797,-0.18457],[51.45829,-0.18387],[51.45866,-0.18305],[51.458771,-0.18276],[51.458801,-0.18269],[51.4589,-0.18243],[51.458981,-0.18222],[51.45911,-0.1819],[51.459229,-0.1815],[51.459358,-0.18094],[51.459431,-0.18064],[51.45956,-0.18014],[51.459518,-0.18],[51.459469,-0.17984],[51.45882,-0.1796],[51.458431,-0.17945],[51.458351,-0.17935],[51.458279,-0.17924],[51.458309,-0.17861],[51.458401,-0.17714],[51.458511,-0.17525],[51.45853,-0.17515],[51.45858,-0.17493],[51.458912,-0.17401],[51.459,-0.17374],[51.459179,-0.1732],[51.45929,-0.17292],[51.459461,-0.17245],[51.459579,-0.1721],[51.459919,-0.17123],[51.460232,-0.17037],[51.4604,-0.16967],[51.46048,-0.16947],[51.460579,-0.16882],[51.460751,-0.16781],[51.460838,-0.16703],[51.460781,-0.16653],[51.460819,-0.16599],[51.460831,-0.1658],[51.460869,-0.16534],[51.46088,-0.16485],[51.460899,-0.16431],[51.460979,-0.16321],[51.460999,-0.16296],[51.461021,-0.16268],[51.461021,-0.1625],[51.46104,-0.16213],[51.46106,-0.16186],[51.461151,-0.16126],[51.46122,-0.1602],[51.4613,-0.15897],[51.461319,-0.15819],[51.461281,-0.15716],[51.4613,-0.15642],[51.460049,-0.15658],[51.45993,-0.15658],[51.459759,-0.15659],[51.45969,-0.15658],[51.458931,-0.15604],[51.458172,-0.15538],[51.457878,-0.1551],[51.45742,-0.15465],[51.456821,-0.15379],[51.455681,-0.15134],[51.455528,-0.15098],[51.45475,-0.14926],[51.453999,-0.14742],[51.45401,-0.14732],[51.454159,-0.14628],[51.453369,-0.14419],[51.452862,-0.14297],[51.452332,-0.14222],[51.451832,-0.14213],[51.45174,-0.14214],[51.451328,-0.14212],[51.451099,-0.14197],[51.451012,-0.14191],[51.450729,-0.14134],[51.450691,-0.14118],[51.450489,-0.1404],[51.449871,-0.13813],[51.449799,-0.13787],[51.449539,-0.13695],[51.449261,-0.13612],[51.44915,-0.13577],[51.448811,-0.13476],[51.448502,-0.13383],[51.448391,-0.13351],[51.44833,-0.13332],[51.44812,-0.13277],[51.447861,-0.13189],[51.447609,-0.13092],[51.447552,-0.13067],[51.44735,-0.12992],[51.44717,-0.12935],[51.447071,-0.12885],[51.446991,-0.12862],[51.446972,-0.12857],[51.44685,-0.1282],[51.445992,-0.12606],[51.44511,-0.12436],[51.44492,-0.12368],[51.44487,-0.12353],[51.444752,-0.12276],[51.444721,-0.12266],[51.444641,-0.12243],[51.44453,-0.12213],[51.444389,-0.12187],[51.44434,-0.12167],[51.444118,-0.12058],[51.444012,-0.12013],[51.44371,-0.11895],[51.443531,-0.1182],[51.443489,-0.11803],[51.443451,-0.11786],[51.443371,-0.11758],[51.4431,-0.11661],[51.44276,-0.1158],[51.44212,-0.11491],[51.441689,-0.11427],[51.44138,-0.11364],[51.441151,-0.11289],[51.441101,-0.11274],[51.441059,-0.11257],[51.440651,-0.11082],[51.440578,-0.11025],[51.440392,-0.10871],[51.441078,-0.10854],[51.441441,-0.10829],[51.44109,-0.10701],[51.44101,-0.10662],[51.440941,-0.10626],[51.440929,-0.10578],[51.440891,-0.1052],[51.440762,-0.10446],[51.44051,-0.10355],[51.440441,-0.10333],[51.440189,-0.10274],[51.43964,-0.10179],[51.439461,-0.10091],[51.439339,-0.10016],[51.43935,-0.10003],[51.439339,-0.09909],[51.4394,-0.09832],[51.439548,-0.0979],[51.43969,-0.09752],[51.43985,-0.09727],[51.440189,-0.09671],[51.44043,-0.09609],[51.44046,-0.09599],[51.44072,-0.09489],[51.440948,-0.09397],[51.441071,-0.09291],[51.441101,-0.09183],[51.441109,-0.09137],[51.441109,-0.091],[51.441101,-0.09],[51.44104,-0.0892],[51.440861,-0.08854],[51.440891,-0.08813],[51.440979,-0.08768],[51.44173,-0.08473],[51.44183,-0.08436],[51.441891,-0.08413],[51.44191,-0.08401],[51.44199,-0.08292],[51.442089,-0.08137],[51.4422,-0.08036],[51.442242,-0.08006],[51.44228,-0.07963],[51.44231,-0.07934],[51.442451,-0.07843],[51.442551,-0.07765],[51.442669,-0.07675],[51.442982,-0.07507],[51.443298,-0.07406],[51.443489,-0.07357],[51.443562,-0.07321],[51.443569,-0.0728],[51.443489,-0.07209],[51.443359,-0.07099],[51.443119,-0.0694],[51.4431,-0.06915],[51.443089,-0.06894],[51.443138,-0.06811],[51.44318,-0.06783],[51.443199,-0.06772],[51.443291,-0.06757],[51.443069,-0.06722],[51.442532,-0.06649],[51.442421,-0.06637],[51.4422,-0.06613],[51.442059,-0.06597],[51.44186,-0.06575],[51.44178,-0.06567],[51.441761,-0.06555],[51.441269,-0.06498],[51.44112,-0.06465],[51.44104,-0.06435],[51.441021,-0.06425],[51.440948,-0.06408],[51.440609,-0.06253],[51.440601,-0.0622],[51.440559,-0.06188],[51.440552,-0.06152],[51.44054,-0.0609],[51.440529,-0.06047],[51.44051,-0.06015],[51.44051,-0.05982],[51.44054,-0.05915],[51.44054,-0.05889],[51.440552,-0.0586],[51.440552,-0.0584],[51.440472,-0.05796],[51.440361,-0.05765],[51.440239,-0.05739],[51.440109,-0.05707],[51.43969,-0.05579],[51.43924,-0.05458],[51.43911,-0.05418],[51.439049,-0.054],[51.439289,-0.05379],[51.439751,-0.0538],[51.440102,-0.05379],[51.440201,-0.05371],[51.440239,-0.05359],[51.440269,-0.05332],[51.4403,-0.05295],[51.440281,-0.05266],[51.440231,-0.05243],[51.440022,-0.05139],[51.43998,-0.05115],[51.440071,-0.0507],[51.440479,-0.04968],[51.440762,-0.04884],[51.44138,-0.04734],[51.442162,-0.04733],[51.442181,-0.04733],[51.442268,-0.04725],[51.442329,-0.04588],[51.442329,-0.04563],[51.44228,-0.04412],[51.442242,-0.04251],[51.44215,-0.04132],[51.44202,-0.03995],[51.442051,-0.03951],[51.442089,-0.03879],[51.442211,-0.03746],[51.442299,-0.03678],[51.442329,-0.03654],[51.442341,-0.03618],[51.442341,-0.03586],[51.442322,-0.03489],[51.442291,-0.03441],[51.442081,-0.03347],[51.441929,-0.03274],[51.441898,-0.03239],[51.441959,-0.03208],[51.442131,-0.03124],[51.442322,-0.03081],[51.442692,-0.02992],[51.4431,-0.02868],[51.443138,-0.028],[51.443169,-0.0276],[51.44323,-0.02698],[51.443352,-0.02683],[51.443741,-0.02636],[51.443851,-0.02623],[51.443932,-0.02613],[51.444221,-0.02538],[51.44455,-0.02409],[51.444618,-0.02361],[51.444691,-0.02308],[51.44479,-0.02226],[51.444801,-0.02197],[51.444809,-0.02115],[51.44487,-0.02082],[51.444939,-0.02056],[51.445019,-0.02034],[51.445122,-0.02013],[51.445229,-0.01994],[51.445431,-0.01983],[51.445969,-0.01957],[51.446129,-0.01946],[51.446072,-0.01873],[51.44595,-0.01764],[51.4459,-0.01725],[51.445709,-0.01584],[51.445511,-0.0145],[51.445339,-0.01315],[51.445068,-0.01105],[51.445068,-0.00916],[51.445068,-0.00897],[51.445099,-0.00713],[51.44511,-0.00561],[51.445099,-0.00474],[51.44508,-0.00345],[51.445122,-0.00221],[51.44516,-0.00109],[51.445171,0.00011],[51.44519,0.00135],[51.445202,0.00247],[51.445221,0.00356],[51.445278,0.00442],[51.445301,0.00467],[51.445389,0.00518],[51.44556,0.00565],[51.44558,0.00603],[51.44556,0.00663],[51.445572,0.00772],[51.445641,0.00859],[51.445679,0.00959],[51.445721,0.01089],[51.445801,0.0115],[51.445889,0.0127],[51.446159,0.01386],[51.446381,0.01466],[51.446609,0.0156],[51.447708,0.02026],[51.44775,0.02043],[51.448189,0.02234],[51.44825,0.02255],[51.448292,0.0227],[51.448441,0.0232],[51.448669,0.02399],[51.448879,0.02476],[51.44902,0.02536],[51.449089,0.02561],[51.44978,0.02794],[51.450119,0.02896],[51.450191,0.02912],[51.450249,0.02914],[51.450279,0.02917],[51.450298,0.0292],[51.450329,0.02924],[51.450352,0.02933],[51.450359,0.02943],[51.45034,0.02953],[51.450279,0.02964],[51.45023,0.02969],[51.450161,0.0297],[51.4501,0.02967],[51.450039,0.02965],[51.44997,0.02965],[51.44978,0.02972],[51.4492,0.02993],[51.44857,0.03013],[51.448021,0.03033],[51.44772,0.03043],[51.44696,0.03077],[51.446739,0.03084],[51.446419,0.03088],[51.44614,0.0309],[51.44577,0.03095],[51.445438,0.03104],[51.445148,0.03122],[51.444939,0.03145],[51.444721,0.03171],[51.444561,0.03193],[51.444401,0.03219],[51.444241,0.0325],[51.443958,0.03315],[51.443501,0.03425],[51.4431,0.03519],[51.442791,0.03597],[51.442471,0.03678],[51.44228,0.03729],[51.442131,0.0378],[51.441811,0.03879],[51.441368,0.04027],[51.441231,0.04084],[51.44101,0.04174],[51.440479,0.04412],[51.43972,0.04768],[51.439651,0.04802],[51.4394,0.04924],[51.439369,0.04944],[51.439178,0.05038],[51.43911,0.05061],[51.438999,0.05081],[51.438789,0.05132],[51.438568,0.05182],[51.438358,0.05242],[51.438179,0.05313],[51.43795,0.05417],[51.437191,0.05753],[51.436932,0.05848],[51.436871,0.05864],[51.43679,0.05888],[51.436581,0.0594],[51.435188,0.0627],[51.434921,0.0634],[51.43483,0.06364],[51.434711,0.06398],[51.43462,0.06424],[51.434502,0.06462],[51.43433,0.06534],[51.43401,0.06693],[51.43359,0.06872],[51.433361,0.0698],[51.43288,0.07194],[51.432598,0.07332],[51.432369,0.07429],[51.43206,0.07563],[51.431351,0.07868],[51.431042,0.07999],[51.430489,0.08221],[51.430351,0.08261],[51.430119,0.08312],[51.429951,0.08344],[51.429798,0.08367],[51.429409,0.08413],[51.42889,0.08458],[51.427738,0.08559],[51.426731,0.08656],[51.4259,0.08747],[51.424511,0.08901],[51.422531,0.09173],[51.421539,0.09321],[51.420368,0.09517],[51.418839,0.09795],[51.417141,0.10123],[51.416222,0.10311],[51.415829,0.10403],[51.415371,0.10513],[51.415119,0.10581],[51.41444,0.10769],[51.414009,0.10905],[51.413521,0.11098],[51.41264,0.11505],[51.412041,0.11826],[51.41124,0.12231],[51.410992,0.12349],[51.410671,0.12522],[51.410599,0.12554],[51.41003,0.12827],[51.409771,0.12976],[51.409649,0.13078],[51.409561,0.13171],[51.409512,0.13284],[51.4095,0.13436],[51.409489,0.13994],[51.409489,0.1408],[51.4095,0.14117],[51.409489,0.1419],[51.40947,0.14288],[51.409389,0.14418],[51.40921,0.14569],[51.409069,0.14648],[51.408932,0.14716],[51.408749,0.14788],[51.40852,0.14863],[51.408131,0.14982],[51.407532,0.15119],[51.40696,0.15228],[51.40654,0.15293],[51.406269,0.15334],[51.405628,0.15413],[51.4049,0.15499],[51.404308,0.15556],[51.404129,0.15573],[51.403271,0.15645],[51.402302,0.15709],[51.401112,0.15767],[51.399971,0.15804],[51.399109,0.15828],[51.398079,0.15855],[51.397049,0.15889],[51.396179,0.15931],[51.39547,0.1598],[51.39452,0.16056],[51.393681,0.1614],[51.392921,0.16234],[51.392551,0.16289],[51.39212,0.16354],[51.391571,0.16447],[51.39085,0.166],[51.390228,0.1678],[51.38979,0.16935],[51.389469,0.17106],[51.389259,0.1728],[51.389172,0.17438],[51.38916,0.17585],[51.389221,0.17702],[51.389542,0.18034],[51.38969,0.18225],[51.38974,0.18407],[51.38974,0.18552],[51.389679,0.18714],[51.38942,0.18934],[51.389172,0.19115],[51.38876,0.19339],[51.388161,0.196],[51.38747,0.19845],[51.38702,0.19998],[51.38678,0.20088],[51.38625,0.20298],[51.385509,0.20598],[51.38522,0.20735],[51.385052,0.20821],[51.38467,0.21019],[51.38448,0.21191],[51.384418,0.21259],[51.384392,0.21318],[51.38435,0.21409],[51.3843,0.21612],[51.384171,0.22142],[51.384029,0.22337],[51.383831,0.22515],[51.38345,0.22739],[51.383411,0.22763],[51.383362,0.22786],[51.382919,0.22983],[51.382351,0.23176],[51.38184,0.23328],[51.381142,0.23508],[51.380901,0.23562],[51.38076,0.23596],[51.38039,0.23683],[51.37867,0.24056],[51.377449,0.24298],[51.37598,0.2457],[51.375271,0.24696],[51.373531,0.24988],[51.37122,0.25339],[51.3703,0.2548],[51.36866,0.25733],[51.366501,0.26056],[51.365349,0.26232],[51.364361,0.26381],[51.3634,0.26522],[51.362431,0.26644],[51.361179,0.26788],[51.360851,0.26818],[51.360149,0.26885],[51.359001,0.26981],[51.357712,0.27082],[51.355461,0.27233],[51.3531,0.27363],[51.351528,0.27437],[51.349098,0.27529],[51.347988,0.27563],[51.346981,0.27589],[51.34605,0.27605],[51.3451,0.27615],[51.344181,0.27614],[51.343079,0.27607],[51.340969,0.27571],[51.340099,0.27544],[51.33886,0.27496],[51.336941,0.27424],[51.336651,0.27417],[51.335949,0.274],[51.334801,0.27373],[51.33308,0.27351],[51.33073,0.27348],[51.329079,0.27365],[51.327808,0.27388],[51.326462,0.2743],[51.32526,0.27495],[51.323929,0.27599],[51.322701,0.27727],[51.321671,0.27865],[51.32098,0.27987],[51.32074,0.28029],[51.319931,0.28203],[51.319359,0.28364],[51.318668,0.28581],[51.318241,0.28741],[51.317829,0.28888],[51.31641,0.29444],[51.315529,0.29828],[51.315029,0.30069],[51.314289,0.30436],[51.313911,0.30597],[51.31348,0.30744],[51.312672,0.30974],[51.311611,0.31285],[51.311081,0.31464],[51.31041,0.31727],[51.309399,0.32178],[51.308849,0.32467],[51.308479,0.32698],[51.308041,0.32987],[51.307991,0.33014],[51.307961,0.33033],[51.30772,0.33232],[51.307419,0.3351],[51.30714,0.33829],[51.306919,0.34202],[51.306789,0.34573],[51.30677,0.34766],[51.30682,0.35044],[51.306919,0.35324],[51.307178,0.35651],[51.307468,0.35934],[51.30772,0.36124],[51.308189,0.36418],[51.308651,0.36814],[51.308708,0.36896],[51.30883,0.37218],[51.30891,0.3746],[51.30888,0.37754],[51.30901,0.38345],[51.309071,0.38842],[51.309261,0.39099],[51.309601,0.39395],[51.309959,0.39628],[51.31065,0.40007],[51.310909,0.40133],[51.311081,0.40247],[51.311211,0.40348],[51.311432,0.40537],[51.311531,0.4067],[51.3116,0.40831],[51.311611,0.40987],[51.311581,0.41178],[51.311569,0.41225],[51.311539,0.41272],[51.311481,0.41354],[51.311359,0.41489],[51.311192,0.41651],[51.310768,0.41924],[51.310379,0.42111],[51.310101,0.42242],[51.309231,0.42526],[51.308262,0.42798],[51.30727,0.43082],[51.306931,0.43183],[51.30674,0.43252],[51.306149,0.4349],[51.305901,0.43603],[51.305679,0.43715],[51.305038,0.44058],[51.30397,0.44616],[51.303379,0.44947],[51.303249,0.45038],[51.303162,0.45112],[51.30302,0.45268],[51.302769,0.45542],[51.302471,0.45849],[51.30238,0.45939],[51.302231,0.46031],[51.30196,0.46153],[51.30164,0.46285],[51.300961,0.4654],[51.300701,0.46637],[51.300461,0.46734],[51.300289,0.46822],[51.300121,0.46922],[51.300011,0.47011],[51.299931,0.47089],[51.299831,0.47189],[51.29977,0.47257],[51.29966,0.47387],[51.299591,0.47437],[51.299549,0.47468],[51.299541,0.47477],[51.29948,0.47513],[51.299438,0.47536],[51.299339,0.47598],[51.29911,0.47691],[51.298889,0.47756],[51.298691,0.47816],[51.298359,0.47894],[51.298241,0.47919],[51.297661,0.48044],[51.296921,0.48235],[51.296581,0.48351],[51.296398,0.48429],[51.29623,0.48525],[51.29612,0.48602],[51.29599,0.48772],[51.295959,0.49028],[51.295971,0.49123],[51.296001,0.49224],[51.29607,0.4932],[51.296188,0.4943],[51.29636,0.49533],[51.296558,0.49635],[51.29673,0.49698],[51.297211,0.49875],[51.297371,0.49922],[51.297459,0.49954],[51.297871,0.50098],[51.29808,0.50212],[51.298248,0.50355],[51.298351,0.50497],[51.298569,0.50858],[51.29879,0.51282],[51.298901,0.51441],[51.298969,0.51558],[51.29903,0.51657],[51.29908,0.51737],[51.29911,0.51794],[51.29911,0.51862],[51.299091,0.51915],[51.299,0.51987],[51.298908,0.52049],[51.298809,0.52116],[51.29863,0.52195],[51.298359,0.52297],[51.298168,0.52345],[51.297852,0.52421],[51.297489,0.52491],[51.29665,0.52623],[51.29557,0.52804],[51.29483,0.52931],[51.29427,0.53038],[51.292782,0.53339],[51.292221,0.53459],[51.291859,0.53532],[51.291599,0.53592],[51.291191,0.53707],[51.291019,0.53768],[51.290722,0.53911],[51.29047,0.54019],[51.290291,0.54093],[51.290131,0.54148],[51.28989,0.54226],[51.28923,0.544],[51.288582,0.54589],[51.288429,0.54636],[51.28828,0.54689],[51.288181,0.54746],[51.28804,0.54834],[51.287949,0.54936],[51.28791,0.55003],[51.287922,0.55088],[51.287971,0.55186],[51.288029,0.55306],[51.2882,0.55569],[51.28828,0.55696],[51.2883,0.55782],[51.288212,0.56001],[51.288101,0.56193],[51.28796,0.56383],[51.287762,0.56577],[51.287579,0.56706],[51.287361,0.56836],[51.286812,0.57094],[51.28624,0.57306],[51.285789,0.57454],[51.285332,0.57591],[51.284599,0.57786],[51.284061,0.57915],[51.283489,0.58035],[51.282799,0.58177],[51.28257,0.58224],[51.282299,0.58279],[51.280529,0.58595],[51.278931,0.58872],[51.277351,0.5914],[51.276951,0.59208],[51.275421,0.59477],[51.273571,0.59799],[51.271709,0.60145],[51.270592,0.60341],[51.270481,0.6036],[51.269989,0.60445],[51.269489,0.60531],[51.26915,0.60589],[51.268242,0.60747],[51.266701,0.60995],[51.26535,0.61188],[51.264179,0.61357],[51.263302,0.61501],[51.262489,0.6163],[51.261459,0.61795],[51.261311,0.61822],[51.261169,0.6185],[51.261051,0.61878],[51.260929,0.61903],[51.26062,0.61976],[51.260448,0.62018],[51.260201,0.6208],[51.259079,0.62382],[51.258289,0.62644],[51.25795,0.62747],[51.257641,0.62829],[51.256618,0.63055],[51.25634,0.63115],[51.256031,0.63176],[51.255371,0.63291],[51.255032,0.63346],[51.254688,0.63397],[51.252941,0.63631],[51.25243,0.63704],[51.252289,0.63724],[51.251289,0.63867],[51.250961,0.63918],[51.250599,0.63978],[51.249569,0.64159],[51.249271,0.64217],[51.24876,0.64322],[51.248112,0.64466],[51.24781,0.64535],[51.247509,0.64616],[51.247162,0.64707],[51.246861,0.64794],[51.246681,0.64849],[51.246471,0.64916],[51.246281,0.64979],[51.245949,0.65084],[51.245899,0.65104],[51.245171,0.65347],[51.244541,0.65575],[51.24361,0.65901],[51.242668,0.66237],[51.241711,0.66557],[51.241371,0.66662],[51.24102,0.66764],[51.240028,0.6704],[51.239609,0.67148],[51.23914,0.6726],[51.237942,0.67524],[51.237469,0.67616],[51.237041,0.67698],[51.236649,0.67772],[51.23645,0.6781],[51.23595,0.67909],[51.23518,0.68037],[51.234089,0.68227],[51.23365,0.68299],[51.233101,0.68384],[51.232632,0.68449],[51.232208,0.68509],[51.23159,0.68585],[51.231098,0.68638],[51.230659,0.68688],[51.229839,0.6878],[51.229019,0.6888],[51.228279,0.68988],[51.22797,0.69037],[51.227661,0.69092],[51.227211,0.6918],[51.2267,0.69285],[51.226509,0.69331],[51.226261,0.69388],[51.225819,0.69502],[51.225578,0.69575],[51.225281,0.69674],[51.22506,0.69754],[51.224869,0.69836],[51.224701,0.69918],[51.224548,0.69999],[51.224419,0.70091],[51.224339,0.70158],[51.224232,0.70277],[51.22414,0.70386],[51.22414,0.70392],[51.223942,0.70706],[51.223801,0.70842],[51.223709,0.70911],[51.223591,0.70976],[51.223358,0.71097],[51.223049,0.71225],[51.222851,0.71295],[51.22263,0.71364],[51.22224,0.71477],[51.221802,0.71586],[51.221561,0.71644],[51.221291,0.71697],[51.220409,0.71862],[51.220058,0.71922],[51.21965,0.71985],[51.21843,0.72149],[51.2178,0.72229],[51.217461,0.72274],[51.217072,0.72331],[51.21653,0.72418],[51.216202,0.72477],[51.215851,0.72538],[51.215481,0.72616],[51.215069,0.72716],[51.21442,0.72904],[51.21418,0.72975],[51.213928,0.73048],[51.21331,0.73252],[51.212719,0.7343],[51.212502,0.73491],[51.212261,0.73557],[51.21175,0.73686],[51.210781,0.73941],[51.210411,0.74033],[51.210091,0.74111],[51.208961,0.74368],[51.207371,0.7471],[51.205879,0.7505],[51.20435,0.75444],[51.20369,0.7563],[51.2029,0.75831],[51.202068,0.76009],[51.201199,0.76191],[51.199879,0.76458],[51.198879,0.76694],[51.198349,0.76836],[51.196941,0.77223],[51.195881,0.77579],[51.19482,0.77989],[51.19363,0.78381],[51.193481,0.78425],[51.192371,0.78747],[51.19109,0.79133],[51.190819,0.79238],[51.190521,0.79363],[51.190319,0.79462],[51.190182,0.79558],[51.18988,0.79784],[51.189522,0.80175],[51.189091,0.80706],[51.188862,0.8117],[51.188721,0.81612],[51.188599,0.82169],[51.18837,0.8241],[51.188251,0.82496],[51.188099,0.82587],[51.187962,0.82665],[51.187752,0.82763],[51.187569,0.82836],[51.187119,0.82975],[51.186378,0.83164],[51.185749,0.83293],[51.18531,0.83368],[51.184811,0.83448],[51.184299,0.83517],[51.183121,0.83649],[51.182381,0.83722],[51.18198,0.83761],[51.181862,0.83773],[51.179722,0.83981],[51.177509,0.84225],[51.17527,0.84496],[51.17326,0.84778],[51.171341,0.85072],[51.169498,0.85395],[51.167709,0.85684],[51.167049,0.85787],[51.166241,0.8591],[51.16478,0.86123],[51.163509,0.86324],[51.16193,0.86581],[51.1614,0.8668],[51.161079,0.86742],[51.160549,0.8685],[51.160221,0.86923],[51.15966,0.87046],[51.15884,0.87253],[51.157841,0.87482],[51.156559,0.87788],[51.15509,0.88152],[51.1548,0.88219],[51.15337,0.88568],[51.151508,0.89005],[51.15062,0.89223],[51.150249,0.89302],[51.150169,0.8932],[51.149899,0.8938],[51.149632,0.89439],[51.149109,0.89545],[51.148479,0.8966],[51.147461,0.89819],[51.146549,0.89942],[51.14473,0.90196],[51.142151,0.90519],[51.141788,0.90564],[51.140621,0.90699],[51.139591,0.90816],[51.138611,0.90931],[51.13802,0.91008],[51.137371,0.91099],[51.13644,0.91254],[51.135948,0.91346],[51.135071,0.91531],[51.13448,0.91676],[51.133438,0.91969],[51.13208,0.92321],[51.13131,0.92488],[51.13047,0.92637],[51.12999,0.92714],[51.129501,0.92789],[51.12772,0.93053],[51.127171,0.93141],[51.126259,0.93304],[51.125408,0.9346],[51.12484,0.93569],[51.123291,0.93894],[51.122822,0.93991],[51.121529,0.94233],[51.12104,0.94323],[51.119839,0.9451],[51.117802,0.94831],[51.11721,0.94936],[51.11676,0.95022],[51.116459,0.95082],[51.116219,0.95133],[51.115978,0.95189],[51.115761,0.95245],[51.11544,0.9533],[51.114738,0.95539],[51.113811,0.95882],[51.11272,0.96273],[51.111561,0.96647],[51.110279,0.97016],[51.108822,0.97406],[51.10833,0.97522],[51.107491,0.97725],[51.107121,0.97813],[51.106419,0.97979],[51.105999,0.98086],[51.105621,0.98185],[51.105209,0.98297],[51.104858,0.98403],[51.10453,0.98504],[51.10405,0.9866],[51.103519,0.98858],[51.103161,0.98998],[51.102631,0.99251],[51.10183,0.99697],[51.101261,1.00094],[51.100498,1.00727],[51.100441,1.00801],[51.100101,1.01554],[51.099789,1.02085],[51.09943,1.02433],[51.09914,1.02641],[51.098629,1.02937],[51.09795,1.03334],[51.097301,1.03712],[51.096981,1.03903],[51.096691,1.04113],[51.096191,1.04478],[51.09565,1.04961],[51.09523,1.05352],[51.095001,1.05578],[51.094818,1.05718],[51.094551,1.05899],[51.094002,1.0625],[51.093811,1.06352],[51.093479,1.06512],[51.09296,1.06772],[51.09272,1.06914],[51.092541,1.07024],[51.092381,1.07156],[51.09222,1.07294],[51.092091,1.07427],[51.091991,1.07574],[51.091911,1.07683],[51.09185,1.07825],[51.091801,1.08103],[51.09182,1.08295],[51.091881,1.08497],[51.091999,1.08669],[51.09206,1.08743],[51.092178,1.0886],[51.092339,1.09011],[51.092628,1.09246],[51.09293,1.09531],[51.093651,1.09994],[51.093788,1.10123],[51.093811,1.10192],[51.093849,1.10356],[51.0937,1.10681],[51.093472,1.10861],[51.09317,1.1104],[51.092239,1.11382],[51.091209,1.11814],[51.090988,1.12],[51.090889,1.12149],[51.090839,1.12251],[51.090839,1.12344],[51.090988,1.1267],[51.091251,1.12838],[51.091549,1.12994],[51.09219,1.13217],[51.09248,1.13289],[51.092812,1.13363],[51.093449,1.13509],[51.09383,1.13608],[51.09417,1.13718],[51.094791,1.14033],[51.09528,1.14437],[51.095539,1.14675],[51.09565,1.14905],[51.095638,1.15199],[51.0956,1.1539],[51.09557,1.15553],[51.0956,1.15691],[51.09565,1.15785],[51.095711,1.15863],[51.095791,1.15935],[51.095909,1.16004],[51.096081,1.16075],[51.096378,1.16185],[51.096771,1.16293],[51.097149,1.16373],[51.097439,1.16425],[51.09853,1.16572],[51.099621,1.16672],[51.099831,1.16689],[51.10281,1.16969],[51.104382,1.17116],[51.105709,1.17244],[51.106781,1.17389],[51.107849,1.17564],[51.108719,1.17739],[51.109619,1.17987],[51.110512,1.18248],[51.111488,1.18548],[51.112228,1.18863],[51.112499,1.19082],[51.112549,1.19196],[51.112549,1.19278],[51.112518,1.19351],[51.112469,1.19398],[51.11235,1.19533],[51.112228,1.19671],[51.112171,1.19839],[51.11219,1.19926],[51.112209,1.20014],[51.112331,1.20197],[51.112438,1.20275],[51.112541,1.20346],[51.112839,1.20577],[51.11301,1.20811],[51.113022,1.21006],[51.11293,1.2119],[51.11264,1.21474],[51.112301,1.21747],[51.111851,1.22028],[51.111382,1.22301],[51.110882,1.22546],[51.110329,1.22787],[51.10997,1.22901],[51.10955,1.23013],[51.108589,1.23208],[51.106739,1.23498],[51.105942,1.23623],[51.10466,1.23946],[51.104389,1.24029],[51.10429,1.24069],[51.104172,1.24137],[51.10397,1.24288],[51.103889,1.24393],[51.103859,1.24491],[51.10387,1.24596],[51.103958,1.24726],[51.10405,1.24807],[51.104221,1.24973],[51.104488,1.25164],[51.104809,1.25353],[51.10564,1.2573],[51.107071,1.26226],[51.107208,1.26301],[51.107529,1.26477],[51.107689,1.26757],[51.107849,1.27028],[51.108292,1.27241],[51.109692,1.27641],[51.11018,1.27878],[51.110298,1.28074],[51.110031,1.285],[51.110329,1.28792],[51.11063,1.28913],[51.111111,1.29063],[51.112011,1.29313],[51.11293,1.29586],[51.11335,1.29733],[51.113689,1.29877],[51.114029,1.30058],[51.114239,1.30197],[51.114311,1.3025],[51.11441,1.30284],[51.114471,1.30292],[51.11454,1.30295],[51.114601,1.30302],[51.114639,1.30313],[51.114651,1.30328],[51.114639,1.30338],[51.11459,1.30349],[51.114552,1.30354],[51.114559,1.30386],[51.114571,1.30415],[51.114658,1.30462],[51.114731,1.30493],[51.11491,1.30535],[51.11507,1.30566],[51.11525,1.30597],[51.115429,1.3062],[51.115829,1.30659],[51.11618,1.30687],[51.116539,1.30705],[51.11694,1.30718],[51.1171,1.3072],[51.117249,1.30716],[51.117298,1.30712],[51.11739,1.30709],[51.11747,1.30711],[51.11755,1.3072],[51.11771,1.30735],[51.117859,1.30746],[51.118038,1.30755],[51.118301,1.30769],[51.11861,1.30787],[51.118938,1.30809],[51.119362,1.30841],[51.119888,1.30906],[51.11993,1.30902],[51.11998,1.30901],[51.12001,1.30901],[51.12006,1.30904],[51.120098,1.30911],[51.120121,1.30918],[51.120121,1.30924],[51.120609,1.3098],[51.12125,1.31049],[51.122311,1.3116],[51.122829,1.31228],[51.123299,1.31321],[51.12336,1.31319],[51.12344,1.31321],[51.123489,1.31326],[51.123531,1.31334],[51.12355,1.31343],[51.12355,1.31351],[51.123531,1.3136],[51.123501,1.31366],[51.12384,1.31478],[51.123871,1.31488],[51.12392,1.31503],[51.1241,1.31553],[51.12455,1.3167],[51.125172,1.31831],[51.125408,1.31906],[51.125462,1.3194],[51.125481,1.31952],[51.1255,1.3205],[51.12537,1.3222],[51.12534,1.32278],[51.125351,1.32315],[51.12537,1.32341],[51.125389,1.32368],[51.1255,1.3245],[51.12595,1.32607],[51.126171,1.32679],[51.126251,1.32687],[51.126301,1.32687],[51.12635,1.32691],[51.126381,1.32697],[51.1264,1.32701],[51.126411,1.32709],[51.126411,1.32714],[51.12661,1.3272],[51.12674,1.32733],[51.127281,1.32823],[51.127659,1.32897],[51.12793,1.3295],[51.128151,1.33004],[51.128342,1.33049],[51.128391,1.33063],[51.128429,1.33076],[51.128479,1.331],[51.128502,1.33119],[51.128632,1.33167],[51.128719,1.33201],[51.12878,1.33245],[51.128799,1.3326],[51.12886,1.33275],[51.129009,1.33327],[51.12907,1.33347],[51.12907,1.33365],[51.12907,1.33392],[51.129421,1.33511],[51.12965,1.33549],[51.129799,1.33605],[51.12986,1.33621],[51.129921,1.33647],[51.12994,1.33681],[51.1301,1.33749],[51.130089,1.33783],[51.129978,1.33815],[51.129921,1.33843],[51.12991,1.33859],[51.12989,1.33884],[51.12989,1.33906],[51.129921,1.33965],[51.130001,1.34022],[51.130131,1.34103],[51.130161,1.34122],[51.13018,1.3414],[51.130169,1.34149],[51.13015,1.34158],[51.130112,1.34162],[51.130058,1.34167],[51.12999,1.34169],[51.129921,1.34164],[51.129879,1.34158],[51.129848,1.34154],[51.12981,1.34135],[51.12981,1.34135],[51.129761,1.34097],[51.1297,1.3406],[51.129681,1.34054],[51.129601,1.34023],[51.129601,1.3402],[51.129551,1.33999],[51.129539,1.3399],[51.12952,1.33983],[51.129509,1.33976],[51.12949,1.33967],[51.129478,1.33961],[51.129459,1.33953],[51.12944,1.33945],[51.129349,1.33897],[51.129341,1.3389],[51.129292,1.33865],[51.12928,1.33857],[51.129269,1.33852],[51.12925,1.33846],[51.1292,1.3382],[51.12899,1.33747],[51.128502,1.33599],[51.127621,1.33327],[51.127369,1.33316],[51.126629,1.33378],[51.126621,1.33374],[51.126621,1.33364],[51.12664,1.33357],[51.12669,1.33347],[51.124249,1.33631],[51.12339,1.33681],[51.122921,1.33723],[51.122219,1.33852],[51.121521,1.34088],[51.1213,1.34214],[51.120991,1.34396],[51.121029,1.34623],[51.12122,1.34811],[51.121658,1.3505],[51.122429,1.35514],[51.122669,1.35707],[51.12252,1.35925],[51.117809,1.37432],[51.113098,1.38939],[51.108391,1.40446],[51.10368,1.41953],[51.098961,1.4346],[51.09425,1.44967],[51.089539,1.46474],[51.084831,1.47981],[51.080109,1.49488],[51.068069,1.51962],[51.053921,1.56329],[51.04071,1.59852],[51.025211,1.63092],[51.001999,1.66988],[50.982979,1.702],[50.971821,1.73021],[50.965912,1.75008],[50.965778,1.7616],[50.967621,1.78272],[50.970249,1.81447],[50.9734,1.83058],[50.971569,1.84148],[50.970322,1.84528],[50.96946,1.84855],[50.968941,1.85085],[50.967468,1.851],[50.9664,1.85395],[50.965809,1.85499],[50.965721,1.85539],[50.965389,1.85658],[50.965279,1.857],[50.965061,1.85736],[50.964859,1.85768],[50.964828,1.85799],[50.964859,1.85852],[50.96513,1.86018],[50.965439,1.86224],[50.96553,1.86291],[50.965591,1.86335],[50.965679,1.86408],[50.965759,1.86463],[50.965801,1.86492],[50.96571,1.86559],[50.966,1.86722],[50.966209,1.86859],[50.9664,1.86985],[50.966579,1.87094],[50.966721,1.87124],[50.966881,1.87146],[50.967152,1.87174],[50.967251,1.87199],[50.967319,1.87213],[50.967339,1.8723],[50.967319,1.87242],[50.967258,1.87253],[50.967171,1.87264],[50.967049,1.87269],[50.966961,1.87267],[50.9669,1.87264],[50.966782,1.87256],[50.966679,1.87258],[50.966621,1.87266],[50.966579,1.87277],[50.966572,1.87295],[50.966591,1.87306],[50.966709,1.87319],[50.966831,1.87318],[50.9669,1.87312],[50.966942,1.87316],[50.967289,1.87339],[50.9678,1.87385],[50.968369,1.87442],[50.968632,1.87467],[50.968922,1.87501],[50.968971,1.87539],[50.969151,1.87581],[50.96944,1.87606],[50.969521,1.87685],[50.969688,1.87737],[50.97023,1.87846],[50.970631,1.88081],[50.971611,1.88645],[50.97216,1.88977],[50.972839,1.89413],[50.973099,1.89619],[50.973129,1.89712],[50.97298,1.89819],[50.972778,1.8989],[50.972679,1.89918],[50.972198,1.90005],[50.971581,1.90064],[50.97086,1.90113],[50.970188,1.9014],[50.969372,1.90176],[50.96859,1.90212],[50.967812,1.90248],[50.964081,1.90407],[50.961891,1.9049],[50.96096,1.9052],[50.959148,1.90522],[50.95834,1.90519],[50.95726,1.90522],[50.956211,1.90542],[50.955238,1.90564],[50.9543,1.90587],[50.95359,1.90598],[50.95314,1.90604],[50.951931,1.90612],[50.950241,1.90554],[50.948601,1.90488],[50.94746,1.90462],[50.946918,1.90463],[50.946239,1.90463],[50.94558,1.90469],[50.94376,1.90518],[50.941341,1.90606],[50.93996,1.90648],[50.938591,1.90685],[50.938332,1.90688],[50.93803,1.90684],[50.937759,1.90675],[50.93718,1.90661],[50.936871,1.90664],[50.936359,1.90679],[50.936211,1.90684],[50.935741,1.907],[50.93536,1.90711],[50.93515,1.90722],[50.93494,1.90754],[50.934849,1.90806],[50.93491,1.90848],[50.935089,1.90874],[50.935341,1.909],[50.93557,1.90922],[50.935749,1.90945],[50.935871,1.90982],[50.935982,1.91027],[50.9361,1.91173],[50.93652,1.91885],[50.936661,1.92109],[50.93705,1.9273],[50.937328,1.93228],[50.93745,1.93517],[50.937481,1.93688],[50.937592,1.94222],[50.93758,1.94278],[50.937469,1.94724],[50.937031,1.954],[50.936668,1.95871],[50.936298,1.96403],[50.936111,1.96788],[50.936081,1.96839],[50.936081,1.96851],[50.93605,1.96892],[50.935841,1.97239],[50.935669,1.97436],[50.935249,1.97886],[50.934761,1.98359],[50.93433,1.98798],[50.933788,1.99334],[50.933262,1.99872],[50.93314,1.99992],[50.93272,2.00394],[50.932549,2.00585],[50.932232,2.00935],[50.931931,2.01479],[50.931839,2.0177],[50.931839,2.02036],[50.931911,2.0256],[50.932259,2.03095],[50.932838,2.0366],[50.93351,2.04213],[50.93404,2.04668],[50.934681,2.0518],[50.934731,2.05231],[50.93486,2.05341],[50.935459,2.05849],[50.93618,2.06459],[50.936821,2.06931],[50.937,2.07046],[50.93721,2.07157],[50.938049,2.07576],[50.939331,2.08131],[50.940979,2.08698],[50.943771,2.09651],[50.944969,2.10024],[50.945171,2.10083],[50.945358,2.10132],[50.94603,2.103],[50.947449,2.10617],[50.948669,2.10898],[50.94949,2.11112],[50.95013,2.11311],[50.950569,2.11476],[50.95084,2.11595],[50.951061,2.11703],[50.951229,2.11799],[50.95134,2.11879],[50.95142,2.11946],[50.951481,2.12005],[50.951561,2.12091],[50.951611,2.12154],[50.95163,2.12226],[50.95166,2.12399],[50.95163,2.12719],[50.95166,2.12849],[50.951679,2.12922],[50.95174,2.12994],[50.951801,2.13068],[50.952049,2.13256],[50.95219,2.13337],[50.952339,2.13407],[50.95245,2.13468],[50.952751,2.13587],[50.95314,2.13722],[50.95356,2.1384],[50.955509,2.14382],[50.95594,2.14511],[50.956402,2.14664],[50.956619,2.14741],[50.957272,2.15017],[50.957581,2.15165],[50.95792,2.15362],[50.958241,2.1558],[50.958389,2.15706],[50.958488,2.15826],[50.958569,2.15916],[50.958691,2.16131],[50.958729,2.16278],[50.958759,2.16826],[50.958771,2.17093],[50.958771,2.1724],[50.958778,2.17312],[50.958771,2.17719],[50.958809,2.18107],[50.958809,2.18387],[50.958832,2.18546],[50.95887,2.18725],[50.958931,2.1886],[50.959,2.18962],[50.959042,2.19044],[50.959202,2.1941],[50.95929,2.19583],[50.959358,2.19713],[50.959431,2.19857],[50.95977,2.2044],[50.959888,2.20581],[50.959999,2.20656],[50.960129,2.20742],[50.9603,2.2083],[50.960491,2.20918],[50.96106,2.21099],[50.961369,2.21185],[50.96188,2.21307],[50.962372,2.2141],[50.963051,2.2153],[50.9636,2.21608],[50.964081,2.21676],[50.964951,2.21779],[50.966351,2.21906],[50.967548,2.21984],[50.968819,2.2204],[50.969082,2.22051],[50.96999,2.22091],[50.971722,2.22168],[50.973011,2.22223],[50.975269,2.22326],[50.977989,2.22447],[50.979801,2.22537],[50.981491,2.22651],[50.98312,2.22801],[50.98465,2.22979],[50.985142,2.23047],[50.98571,2.23135],[50.98613,2.23207],[50.987309,2.23417],[50.98785,2.23533],[50.988258,2.23622],[50.988621,2.2371],[50.988838,2.23776],[50.988979,2.23815],[50.98951,2.23991],[50.98983,2.24111],[50.990131,2.24249],[50.990311,2.24335],[50.990471,2.24433],[50.990582,2.2451],[50.990631,2.24546],[50.990749,2.24652],[50.990849,2.24767],[50.991001,2.24997],[50.991089,2.25132],[50.991219,2.25285],[50.991371,2.25542],[50.991428,2.25736],[50.99139,2.25824],[50.99131,2.25904],[50.991131,2.26062],[50.990978,2.26203],[50.990929,2.2628],[50.990929,2.26349],[50.990959,2.26412],[50.991089,2.26534],[50.991329,2.26651],[50.991539,2.26752],[50.99189,2.26896],[50.992081,2.26975],[50.992519,2.27123],[50.99271,2.27176],[50.992908,2.27231],[50.993698,2.27429],[50.993881,2.27475],[50.994141,2.27543],[50.994438,2.27647],[50.994991,2.27878],[50.9953,2.2799],[50.99596,2.28193],[50.99688,2.28418],[50.997162,2.2849],[50.997421,2.28563],[50.998192,2.2878],[50.99921,2.29085],[50.999458,2.29158],[51.000069,2.29328],[51.00098,2.29593],[51.002178,2.29964],[51.002411,2.30036],[51.002861,2.30196],[51.003071,2.3028],[51.003368,2.30435],[51.003601,2.30583],[51.004189,2.3101],[51.00425,2.31055],[51.00428,2.31072],[51.004551,2.31257],[51.00457,2.31275],[51.004662,2.3134],[51.005409,2.31722],[51.006069,2.31984],[51.00629,2.32056],[51.007221,2.32332],[51.00766,2.32452],[51.008259,2.32605],[51.008968,2.32791],[51.00951,2.32936],[51.00988,2.33063],[51.01022,2.3319],[51.010448,2.3329],[51.01078,2.33461],[51.01096,2.33604],[51.011009,2.33643],[51.011589,2.34118],[51.01228,2.34741],[51.012379,2.34865],[51.012421,2.34995],[51.012428,2.35025],[51.01247,2.35212],[51.012482,2.35917],[51.01247,2.36228],[51.01247,2.36496],[51.012508,2.36668],[51.012539,2.36733],[51.012569,2.36826],[51.01263,2.36958],[51.012718,2.37139],[51.01276,2.37266],[51.01281,2.37337],[51.012859,2.37427],[51.012989,2.37692],[51.013031,2.37775],[51.0131,2.37894],[51.013119,2.37918],[51.013168,2.37968],[51.013229,2.38015],[51.01339,2.38113],[51.01387,2.38398],[51.013981,2.38455],[51.014462,2.38727],[51.015091,2.39079],[51.01532,2.39201],[51.015518,2.39305],[51.01577,2.39428],[51.016029,2.39543],[51.016209,2.39619],[51.016369,2.39682],[51.01656,2.39753],[51.017361,2.40001],[51.01757,2.40063],[51.018608,2.40362],[51.018929,2.40452],[51.020679,2.40955],[51.02113,2.41077],[51.02158,2.41194],[51.022331,2.41373],[51.02293,2.41513],[51.02372,2.41692],[51.024632,2.41896],[51.026299,2.42273],[51.02718,2.42467],[51.028221,2.42699],[51.030571,2.43217],[51.031361,2.43401],[51.033642,2.43905],[51.035229,2.44255],[51.036591,2.44564],[51.03743,2.4476],[51.037861,2.44877],[51.03817,2.44976],[51.03846,2.45073],[51.038769,2.45191],[51.039108,2.45333],[51.039459,2.45497],[51.040298,2.45914],[51.04211,2.46828],[51.042839,2.47194],[51.043209,2.47404],[51.043419,2.47535],[51.043671,2.47711],[51.043831,2.47876],[51.04398,2.48044],[51.044079,2.4824],[51.04414,2.48386],[51.04417,2.48536],[51.04414,2.48689],[51.044071,2.48871],[51.044022,2.48969],[51.043941,2.49072],[51.043228,2.49809],[51.042229,2.50844],[51.042099,2.51063],[51.042042,2.51265],[51.04208,2.51446],[51.04216,2.51609],[51.042301,2.5175],[51.042431,2.51842],[51.042789,2.52042],[51.043201,2.52211],[51.043598,2.52368],[51.044231,2.52565],[51.04472,2.5272],[51.044941,2.52797],[51.045132,2.52855],[51.04546,2.52966],[51.04578,2.53064],[51.045891,2.53098],[51.046169,2.5318],[51.04644,2.5325],[51.046551,2.5328],[51.047539,2.53531],[51.048191,2.53675],[51.048828,2.53811],[51.051281,2.54349],[51.052811,2.54681],[51.053501,2.5486],[51.054089,2.5503],[51.054699,2.55229],[51.055302,2.55448],[51.055779,2.55651],[51.056301,2.55905],[51.056591,2.56043],[51.057049,2.56247],[51.057251,2.5634],[51.058319,2.56843],[51.058601,2.56969],[51.05888,2.57087],[51.059212,2.57214],[51.05962,2.57351],[51.060001,2.57471],[51.060371,2.57579],[51.060902,2.57714],[51.061588,2.57888],[51.062038,2.58001],[51.063679,2.58404],[51.064041,2.58492],[51.0644,2.58588],[51.064911,2.58728],[51.065319,2.58853],[51.065651,2.58961],[51.066101,2.59122],[51.066479,2.59272],[51.06683,2.59427],[51.067131,2.59571],[51.06741,2.59735],[51.06752,2.59797],[51.067711,2.59921],[51.06786,2.6003],[51.068031,2.60169],[51.068169,2.60318],[51.06831,2.60502],[51.06839,2.60678],[51.068409,2.6073],[51.068439,2.60869],[51.068439,2.6096],[51.068409,2.61156],[51.068352,2.61305],[51.068291,2.61409],[51.068241,2.61486],[51.068169,2.61588],[51.06805,2.61712],[51.067928,2.61827],[51.067799,2.61933],[51.067631,2.62045],[51.06739,2.62205],[51.067131,2.62364],[51.066879,2.62531],[51.066589,2.62707],[51.066341,2.62856],[51.06609,2.63003],[51.065769,2.63167],[51.065529,2.63282],[51.065239,2.63404],[51.064911,2.63527],[51.064499,2.63671],[51.064251,2.63747],[51.064041,2.63811],[51.063499,2.63943],[51.06292,2.64086],[51.06221,2.64252],[51.061131,2.64454],[51.06012,2.64638],[51.059299,2.64799],[51.05862,2.6494],[51.058022,2.65077],[51.057529,2.6522],[51.05703,2.65394],[51.056808,2.65493],[51.056419,2.65689],[51.05621,2.65862],[51.056099,2.65998],[51.056091,2.66042],[51.056019,2.66226],[51.056011,2.66247],[51.05621,2.66523],[51.056252,2.66562],[51.05637,2.66661],[51.056469,2.66746],[51.05687,2.67003],[51.057079,2.67121],[51.057301,2.67227],[51.057659,2.67373],[51.058041,2.67517],[51.0583,2.676],[51.058529,2.67676],[51.059441,2.67934],[51.059929,2.68044],[51.060501,2.68175],[51.061081,2.68296],[51.061581,2.68396],[51.062191,2.68504],[51.06329,2.68672],[51.066238,2.69064],[51.069191,2.6946],[51.06953,2.69505],[51.07011,2.69584],[51.071651,2.69795],[51.072418,2.69904],[51.072762,2.69952],[51.07328,2.70028],[51.073631,2.70076],[51.075062,2.70318],[51.075989,2.70478],[51.076469,2.7056],[51.07737,2.70742],[51.078041,2.70881],[51.080669,2.71368],[51.082119,2.71651],[51.08403,2.72024],[51.08596,2.72395],[51.08749,2.72654],[51.08762,2.72676],[51.088009,2.72735],[51.08828,2.72776],[51.089901,2.72983],[51.090542,2.73054],[51.092491,2.73254],[51.097069,2.73603],[51.100849,2.7394],[51.10141,2.73993],[51.102261,2.74083],[51.104359,2.74302],[51.10585,2.74498],[51.106361,2.74564],[51.10854,2.7486],[51.109261,2.74981],[51.11198,2.75436],[51.11467,2.76005],[51.114891,2.76061],[51.115601,2.7626],[51.115761,2.76306],[51.116161,2.76409],[51.116589,2.76529],[51.117771,2.76841],[51.12117,2.77827],[51.12418,2.78692],[51.124359,2.78746],[51.124859,2.78887],[51.12764,2.7969],[51.127831,2.79746],[51.12862,2.79973],[51.129101,2.80112],[51.129269,2.80159],[51.132858,2.81214],[51.133221,2.81331],[51.133461,2.8141],[51.133888,2.81561],[51.134201,2.81676],[51.134811,2.8192],[51.135349,2.82163],[51.13567,2.82325],[51.135899,2.82449],[51.136089,2.82548],[51.136349,2.82713],[51.1371,2.83239],[51.13726,2.83359],[51.137409,2.83465],[51.138371,2.8417],[51.139099,2.84658],[51.140308,2.85454],[51.141491,2.86184],[51.14164,2.86276],[51.1422,2.86733],[51.142479,2.86962],[51.14296,2.87444],[51.144299,2.8852],[51.145679,2.89336],[51.146931,2.89956],[51.147221,2.90083],[51.147518,2.90218],[51.149181,2.9089],[51.150909,2.91532],[51.15292,2.92111],[51.153099,2.92162],[51.15398,2.92417],[51.154831,2.92664],[51.157249,2.93277],[51.158779,2.9367],[51.161579,2.94386],[51.162491,2.94619],[51.163288,2.94829],[51.16412,2.95068],[51.16468,2.95227],[51.16494,2.95305],[51.165619,2.95527],[51.166962,2.96013],[51.16769,2.96342],[51.168159,2.96567],[51.16877,2.96918],[51.16906,2.97102],[51.169399,2.97327],[51.171879,2.99036],[51.17207,2.99165],[51.172211,2.99269],[51.172989,2.99807],[51.17305,2.99851],[51.17329,3.00016],[51.173649,3.00226],[51.17411,3.0044],[51.17445,3.0058],[51.174931,3.00759],[51.175331,3.00901],[51.17564,3.00987],[51.17952,3.01954],[51.179989,3.02066],[51.18058,3.02217],[51.18092,3.02299],[51.18111,3.02352],[51.181301,3.02409],[51.18166,3.02515],[51.182072,3.02648],[51.182388,3.02762],[51.18367,3.03306],[51.185581,3.04182],[51.189091,3.05743],[51.18932,3.0583],[51.18961,3.05942],[51.190521,3.06289],[51.191109,3.06485],[51.19252,3.06975],[51.19273,3.07071],[51.192909,3.07177],[51.193031,3.0727],[51.19313,3.07392],[51.193161,3.07501],[51.19313,3.07626],[51.193081,3.07739],[51.193001,3.07852],[51.19286,3.07972],[51.192612,3.08154],[51.191601,3.0869],[51.191349,3.08837],[51.189911,3.09536],[51.189129,3.0984],[51.1884,3.10066],[51.18821,3.10126],[51.186199,3.10705],[51.184799,3.11107],[51.18198,3.11918],[51.18063,3.1231],[51.177151,3.13324],[51.172661,3.14639],[51.170872,3.15257],[51.17012,3.15582],[51.168468,3.16401],[51.166939,3.17116],[51.163761,3.18813],[51.163589,3.18902],[51.163559,3.18919],[51.162868,3.19267],[51.162819,3.19292],[51.162769,3.19321],[51.16209,3.19636],[51.161621,3.19818],[51.16148,3.19868],[51.16127,3.19942],[51.160938,3.20048],[51.160412,3.20206],[51.160301,3.20234],[51.159901,3.20339],[51.159859,3.2035],[51.159431,3.20455],[51.158451,3.20644],[51.1577,3.20792],[51.15741,3.2085],[51.157162,3.209],[51.156761,3.20971],[51.155579,3.21174],[51.1549,3.21289],[51.153931,3.2146],[51.15324,3.21591],[51.15237,3.2175],[51.152191,3.21782],[51.15126,3.21969],[51.151169,3.21993],[51.15036,3.22156],[51.14901,3.22481],[51.14785,3.22818],[51.146881,3.23154],[51.146709,3.23211],[51.14645,3.23302],[51.144199,3.24088],[51.141628,3.25038],[51.141071,3.25233],[51.14082,3.25322],[51.140671,3.25373],[51.13924,3.25883],[51.136539,3.26866],[51.13134,3.28713],[51.128139,3.29863],[51.123081,3.3166],[51.12204,3.32055],[51.120621,3.32559],[51.118851,3.33186],[51.115269,3.34479],[51.112011,3.35628],[51.111431,3.35809],[51.110771,3.35983],[51.104359,3.37599],[51.1012,3.38387],[51.099739,3.38761],[51.095131,3.39893],[51.094082,3.40177],[51.09256,3.40559],[51.09137,3.40854],[51.089691,3.41275],[51.087132,3.41912],[51.085651,3.42274],[51.084728,3.42507],[51.083801,3.42739],[51.082878,3.42956],[51.081799,3.43221],[51.077339,3.4436],[51.076519,3.44591],[51.07608,3.44729],[51.075981,3.44763],[51.07539,3.44979],[51.07523,3.45041],[51.074879,3.4518],[51.074501,3.45334],[51.07251,3.46253],[51.07196,3.46512],[51.066978,3.48751],[51.06411,3.50061],[51.06105,3.51623],[51.05904,3.5268],[51.058491,3.52974],[51.05685,3.53852],[51.052608,3.55965],[51.05125,3.56586],[51.050892,3.56749],[51.050529,3.56911],[51.050449,3.56951],[51.048389,3.5789],[51.043869,3.59986],[51.03994,3.61792],[51.03949,3.61953],[51.03775,3.62573],[51.034882,3.63601],[51.03474,3.63647],[51.0336,3.64051],[51.033539,3.6407],[51.032398,3.64472],[51.031979,3.64616],[51.030102,3.65281],[51.024891,3.67076],[51.02475,3.67125],[51.023972,3.67402],[51.023472,3.67574],[51.022491,3.67923],[51.022339,3.67977],[51.021801,3.68161],[51.021339,3.68336],[51.02124,3.68376],[51.020981,3.68476],[51.020741,3.68568],[51.020451,3.68685],[51.019531,3.69031],[51.019001,3.69241],[51.018669,3.69363],[51.017109,3.70012],[51.014702,3.71009],[51.014622,3.71042],[51.014179,3.71226],[51.012611,3.71878],[51.01199,3.72128],[51.011631,3.72217],[51.011311,3.72284],[51.010921,3.72339],[51.010578,3.72382],[51.010239,3.72423],[51.009869,3.72483],[51.00975,3.72508],[51.00951,3.72588],[51.00948,3.72621],[51.009491,3.72647],[51.009541,3.72679],[51.009609,3.72702],[51.00983,3.72759],[51.01009,3.72808],[51.010429,3.72839],[51.01075,3.7285],[51.010948,3.72849],[51.01115,3.7284],[51.01136,3.72827],[51.011532,3.72811],[51.011829,3.72787],[51.012039,3.72778],[51.012211,3.72778],[51.012581,3.72798],[51.01424,3.72894],[51.014629,3.72916],[51.014919,3.72937],[51.01688,3.73074],[51.018459,3.73179],[51.020302,3.73307],[51.021832,3.73444],[51.02388,3.7366],[51.025539,3.73839],[51.026699,3.74038],[51.026909,3.74077],[51.028519,3.74369],[51.028671,3.744],[51.028851,3.74435],[51.02964,3.74592],[51.031132,3.74879],[51.03175,3.74997],[51.033428,3.75321],[51.03426,3.75482],[51.03434,3.755],[51.034649,3.75563],[51.03513,3.75661],[51.03561,3.75785],[51.035999,3.75894],[51.036079,3.75915],[51.036282,3.75982],[51.03661,3.76089],[51.037029,3.76254],[51.037769,3.76571],[51.039028,3.771],[51.040112,3.77556],[51.040489,3.77719],[51.04076,3.77847],[51.042011,3.7838],[51.043049,3.78806],[51.043869,3.79144],[51.044189,3.7928],[51.044739,3.79514],[51.044922,3.79591],[51.046181,3.80122],[51.047771,3.80846],[51.04842,3.81174],[51.051239,3.82769],[51.052109,3.8319],[51.053669,3.83831],[51.055191,3.84386],[51.061069,3.8642],[51.064442,3.87572],[51.06472,3.87678],[51.066898,3.88445],[51.06712,3.88559],[51.06768,3.88811],[51.067719,3.88837],[51.068501,3.89206],[51.06926,3.89805],[51.06974,3.90363],[51.070461,3.91495],[51.070679,3.91877],[51.07111,3.92565],[51.073029,3.95806],[51.07357,3.96646],[51.07431,3.97915],[51.075008,3.98714],[51.0751,3.98797],[51.075199,3.98883],[51.07579,3.99259],[51.07642,3.99564],[51.077061,3.99842],[51.0779,4.00133],[51.07872,4.00399],[51.079762,4.00683],[51.0811,4.01003],[51.08247,4.01287],[51.083832,4.0154],[51.084141,4.01594],[51.084549,4.01667],[51.086521,4.02014],[51.087921,4.02232],[51.08857,4.02339],[51.089588,4.02513],[51.09214,4.02944],[51.094528,4.03348],[51.095089,4.03443],[51.095211,4.03463],[51.100471,4.04349],[51.103989,4.049],[51.1068,4.05277],[51.11087,4.05734],[51.11171,4.05818],[51.112061,4.05854],[51.114491,4.06102],[51.116741,4.06331],[51.119381,4.0661],[51.120918,4.06809],[51.122429,4.07029],[51.123482,4.07216],[51.12402,4.07318],[51.124882,4.07494],[51.125778,4.07704],[51.126629,4.07964],[51.1269,4.08055],[51.127289,4.08194],[51.127541,4.08293],[51.12801,4.08511],[51.128479,4.08777],[51.128948,4.09103],[51.129021,4.09139],[51.13044,4.10455],[51.131821,4.1169],[51.132099,4.1194],[51.132549,4.12348],[51.13287,4.12635],[51.13327,4.12978],[51.133492,4.1312],[51.133839,4.13343],[51.134129,4.13519],[51.13456,4.13755],[51.13567,4.14353],[51.13641,4.14755],[51.137051,4.15104],[51.137211,4.15195],[51.13842,4.15828],[51.13921,4.16272],[51.1399,4.16663],[51.140591,4.17049],[51.141171,4.17362],[51.141891,4.17733],[51.142601,4.181],[51.142792,4.1819],[51.14307,4.18315],[51.143871,4.18615],[51.144581,4.18849],[51.145512,4.1912],[51.146679,4.19441],[51.147179,4.19574],[51.148769,4.20004],[51.149929,4.2034],[51.151112,4.20707],[51.152241,4.21068],[51.15329,4.21422],[51.154541,4.21836],[51.15575,4.22231],[51.157169,4.22699],[51.15839,4.23061],[51.159031,4.23227],[51.15947,4.23338],[51.160358,4.23531],[51.16151,4.23769],[51.16222,4.23907],[51.163422,4.24145],[51.16465,4.24383],[51.166279,4.24703],[51.166729,4.24793],[51.16856,4.25151],[51.170139,4.25456],[51.171581,4.25746],[51.172611,4.25952],[51.173389,4.26121],[51.174561,4.26389],[51.175739,4.26696],[51.176899,4.26997],[51.17799,4.27286],[51.1791,4.27582],[51.180599,4.2799],[51.181931,4.2834],[51.182461,4.28477],[51.183208,4.28673],[51.184212,4.28934],[51.18536,4.29224],[51.18586,4.29331],[51.18729,4.29642],[51.188278,4.29836],[51.18964,4.30093],[51.191269,4.30374],[51.192951,4.30655],[51.19482,4.30962],[51.19622,4.31194],[51.19809,4.3151],[51.200298,4.31877],[51.20142,4.32063],[51.201969,4.32153],[51.202431,4.32237],[51.202721,4.32293],[51.203899,4.32522],[51.204651,4.32687],[51.205391,4.32855],[51.206261,4.33073],[51.208328,4.33607],[51.208649,4.33695],[51.210098,4.34071],[51.211281,4.34388],[51.21146,4.34438],[51.211811,4.3453],[51.21233,4.34667],[51.212791,4.348],[51.213051,4.34876],[51.21312,4.34901],[51.213211,4.34932],[51.21349,4.35058],[51.21365,4.3516],[51.213749,4.35238],[51.21384,4.35324],[51.21389,4.35429],[51.213909,4.35537],[51.21386,4.35653],[51.21368,4.35807],[51.21347,4.35916],[51.213249,4.36017],[51.212978,4.36114],[51.21265,4.3621],[51.212238,4.36311],[51.211731,4.36418],[51.21101,4.36534],[51.210381,4.3662],[51.208759,4.36794],[51.208309,4.36843],[51.20274,4.37432],[51.20155,4.3756],[51.20089,4.37635],[51.2006,4.37673],[51.200272,4.37721],[51.19981,4.37797],[51.199322,4.37899],[51.199009,4.37978],[51.19873,4.38062],[51.198471,4.38164],[51.198238,4.38273],[51.19799,4.38423],[51.197701,4.38573],[51.19759,4.38626],[51.197311,4.38756],[51.19706,4.3886],[51.19685,4.38936],[51.19664,4.39006],[51.196251,4.39129],[51.195099,4.39424],[51.194302,4.39627],[51.193001,4.39983],[51.192059,4.40279],[51.191349,4.40556],[51.190941,4.40767],[51.190632,4.40985],[51.190472,4.41161],[51.19038,4.41322],[51.19035,4.41513],[51.19038,4.41674],[51.190498,4.4188],[51.190659,4.42035],[51.190891,4.42221],[51.191311,4.42416],[51.191719,4.42575],[51.192131,4.42716],[51.192619,4.42862],[51.193001,4.42966],[51.193321,4.43038],[51.193649,4.43107],[51.19397,4.43165],[51.194241,4.4321],[51.194618,4.43266],[51.194981,4.43311],[51.195259,4.43343],[51.19561,4.43381],[51.19595,4.43416],[51.196289,4.43445],[51.196659,4.43472],[51.197411,4.43528],[51.198662,4.43609],[51.201191,4.43746],[51.202412,4.43821],[51.203381,4.43891],[51.20462,4.43994],[51.206181,4.44129],[51.206921,4.44199],[51.207901,4.44294],[51.20924,4.44419],[51.210659,4.44546],[51.21167,4.44639],[51.21254,4.44721],[51.213921,4.44847],[51.214569,4.44921],[51.21471,4.4494],[51.214809,4.44956],[51.214951,4.4498],[51.215069,4.45005],[51.215179,4.45031],[51.215279,4.45061],[51.21553,4.45146],[51.215752,4.45216],[51.215969,4.45301],[51.216179,4.45406],[51.21629,4.45504],[51.21624,4.4558],[51.216091,4.45644],[51.21587,4.45707],[51.215561,4.4577],[51.21513,4.45828],[51.214211,4.45917],[51.214001,4.45936],[51.213348,4.45995],[51.212799,4.46049],[51.212372,4.46099],[51.21188,4.46168],[51.211639,4.46209],[51.211399,4.4626],[51.21117,4.46318],[51.210999,4.46376],[51.21085,4.46433],[51.21072,4.46503],[51.21064,4.46571],[51.21059,4.46636],[51.21059,4.46705],[51.21064,4.46793],[51.21069,4.46847],[51.210751,4.4691],[51.210831,4.4697],[51.210949,4.47055],[51.211071,4.47136],[51.211208,4.47228],[51.21133,4.47315],[51.211391,4.47381],[51.21143,4.47447],[51.211441,4.47509],[51.211418,4.4757],[51.211369,4.4763],[51.211288,4.47694],[51.211151,4.47781],[51.21104,4.47848],[51.210621,4.48085],[51.210522,4.48162],[51.210468,4.48231],[51.210442,4.48312],[51.210449,4.48395],[51.210522,4.485],[51.21067,4.48653],[51.2108,4.4878],[51.211021,4.49018],[51.211121,4.49141],[51.211189,4.49236],[51.211281,4.49391],[51.211311,4.49473],[51.211399,4.49656],[51.211411,4.49859],[51.21143,4.49937],[51.211521,4.50276],[51.211601,4.50624],[51.211712,4.51037],[51.211819,4.51426],[51.211979,4.51977],[51.212101,4.52414],[51.212139,4.52645],[51.212139,4.5272],[51.212139,4.52783],[51.212101,4.52956],[51.212009,4.53141],[51.211868,4.53313],[51.21167,4.53514],[51.211361,4.53743],[51.211048,4.5392],[51.210789,4.54045],[51.210499,4.54188],[51.210258,4.54291],[51.20974,4.54486],[51.20895,4.54791],[51.207958,4.55163],[51.207031,4.55523],[51.206242,4.55827],[51.205238,4.56186],[51.204288,4.56546],[51.203209,4.5695],[51.202259,4.57309],[51.201279,4.57603],[51.200741,4.57732],[51.200111,4.57852],[51.199451,4.57959],[51.198872,4.58057],[51.19838,4.58161],[51.19804,4.58262],[51.1978,4.5836],[51.197651,4.58463],[51.197559,4.58614],[51.197651,4.5877],[51.197849,4.58903],[51.198071,4.58982],[51.19841,4.59072],[51.198761,4.59151],[51.199219,4.59231],[51.19952,4.59268],[51.199821,4.59306],[51.2006,4.59405],[51.201351,4.59523],[51.202019,4.59651],[51.202499,4.5977],[51.20274,4.59835],[51.203411,4.60025],[51.2048,4.60414],[51.205589,4.60638],[51.20805,4.61359],[51.20908,4.61659],[51.209782,4.61862],[51.2118,4.62442],[51.211979,4.62497],[51.21299,4.62775],[51.21402,4.63045],[51.215729,4.63444],[51.217651,4.63834],[51.220181,4.64284],[51.22282,4.64712],[51.231232,4.66047],[51.233978,4.66484],[51.236111,4.66835],[51.237961,4.67215],[51.238979,4.67465],[51.239761,4.67689],[51.240608,4.67974],[51.241291,4.68251],[51.241741,4.68479],[51.24213,4.68706],[51.242741,4.6915],[51.243031,4.69416],[51.243351,4.69842],[51.243519,4.70165],[51.24366,4.70643],[51.243729,4.71221],[51.24371,4.71458],[51.243629,4.72741],[51.24353,4.74118],[51.243649,4.75037],[51.243801,4.7541],[51.244019,4.75768],[51.244381,4.76209],[51.24469,4.765],[51.245781,4.77292],[51.24646,4.77688],[51.24728,4.78085],[51.248569,4.7859],[51.250038,4.79077],[51.250561,4.79228],[51.252048,4.79611],[51.254349,4.80124],[51.25631,4.80483],[51.257271,4.80658],[51.259121,4.80975],[51.260399,4.81183],[51.266781,4.82263],[51.279442,4.84386],[51.282082,4.84837],[51.284592,4.85299],[51.285591,4.85501],[51.286049,4.85596],[51.287418,4.85902],[51.288658,4.862],[51.28981,4.86514],[51.290352,4.86664],[51.291531,4.87026],[51.29224,4.87277],[51.292912,4.87527],[51.29356,4.87801],[51.29409,4.88039],[51.294601,4.88287],[51.295071,4.88551],[51.29549,4.88814],[51.29586,4.89084],[51.29615,4.89339],[51.29641,4.89605],[51.296761,4.90148],[51.29689,4.90434],[51.297009,4.90816],[51.297138,4.91369],[51.29726,4.91806],[51.297291,4.91929],[51.297428,4.92479],[51.297451,4.92556],[51.29755,4.92814],[51.29763,4.93275],[51.29784,4.94177],[51.297951,4.94568],[51.298038,4.94993],[51.298092,4.95214],[51.298229,4.95715],[51.298328,4.96224],[51.298389,4.96824],[51.298351,4.97133],[51.298229,4.97483],[51.298038,4.97831],[51.297821,4.98128],[51.297489,4.98522],[51.297081,4.9888],[51.296631,4.99216],[51.295898,4.9968],[51.29517,5.00171],[51.294781,5.00454],[51.294411,5.00746],[51.294209,5.00934],[51.29406,5.01122],[51.293911,5.01361],[51.293781,5.01604],[51.29372,5.01984],[51.293751,5.02273],[51.293812,5.02471],[51.293911,5.02694],[51.294369,5.03214],[51.29475,5.03562],[51.29538,5.04046],[51.296322,5.04725],[51.296661,5.05005],[51.296989,5.05315],[51.29726,5.05621],[51.297401,5.05818],[51.297489,5.06011],[51.297539,5.0623],[51.29755,5.06443],[51.297489,5.06721],[51.29734,5.07002],[51.297009,5.07402],[51.296612,5.07796],[51.295879,5.08397],[51.29549,5.08691],[51.295132,5.09009],[51.294731,5.09394],[51.29464,5.09467],[51.294441,5.09768],[51.294319,5.10016],[51.29425,5.10457],[51.294312,5.10802],[51.294498,5.11234],[51.294731,5.11532],[51.29509,5.11857],[51.295509,5.12156],[51.29599,5.12459],[51.296761,5.12847],[51.298199,5.13422],[51.300072,5.14081],[51.300591,5.14276],[51.301399,5.1459],[51.301991,5.14842],[51.30265,5.15159],[51.303249,5.15458],[51.303871,5.15814],[51.30452,5.16165],[51.305229,5.16517],[51.30595,5.16817],[51.306999,5.17226],[51.30851,5.17732],[51.310181,5.18249],[51.31218,5.18855],[51.312382,5.1892],[51.314838,5.19669],[51.318821,5.20905],[51.32016,5.21303],[51.320591,5.21436],[51.321072,5.21581],[51.321671,5.21766],[51.322681,5.22073],[51.323341,5.22275],[51.324051,5.22488],[51.32439,5.22589],[51.325031,5.22768],[51.325691,5.2294],[51.326279,5.23089],[51.327061,5.23264],[51.327991,5.23451],[51.32906,5.23651],[51.33009,5.23831],[51.331451,5.24065],[51.337521,5.25108],[51.344028,5.26264],[51.349178,5.27182],[51.351452,5.27587],[51.352482,5.27774],[51.353378,5.27947],[51.353821,5.28036],[51.35434,5.28142],[51.35508,5.28302],[51.355801,5.28465],[51.356491,5.28625],[51.36055,5.29579],[51.360729,5.29619],[51.363239,5.30209],[51.36348,5.30268],[51.364941,5.30605],[51.365059,5.30632],[51.36898,5.31556],[51.370361,5.31878],[51.37159,5.32166],[51.374432,5.32837],[51.375191,5.33016],[51.376862,5.33405],[51.382038,5.34624],[51.38332,5.34934],[51.384441,5.35214],[51.385429,5.35471],[51.387878,5.3613],[51.388371,5.36264],[51.389221,5.36492],[51.390381,5.36807],[51.39267,5.37428],[51.393459,5.37644],[51.39439,5.379],[51.394581,5.37961],[51.394798,5.3803],[51.394989,5.38097],[51.395168,5.38164],[51.395432,5.38274],[51.39555,5.38332],[51.395679,5.38394],[51.395851,5.38488],[51.395931,5.38535],[51.396049,5.38617],[51.396118,5.38674],[51.396259,5.38787],[51.396339,5.38878],[51.39642,5.38967],[51.39653,5.39132],[51.396641,5.393],[51.39674,5.39426],[51.396851,5.39539],[51.396912,5.39591],[51.397099,5.39728],[51.397221,5.39805],[51.397369,5.39886],[51.397449,5.39924],[51.397629,5.40014],[51.39777,5.40073],[51.397919,5.40135],[51.398209,5.40239],[51.40057,5.41075],[51.400631,5.41097],[51.402519,5.41765],[51.40287,5.41891],[51.403229,5.42027],[51.403629,5.422],[51.403839,5.42325],[51.403992,5.42403],[51.404099,5.42481],[51.40416,5.4252],[51.404202,5.42569],[51.404209,5.42611],[51.404221,5.42679],[51.404221,5.42789],[51.404209,5.42864],[51.404202,5.42919],[51.40419,5.42974],[51.404209,5.4303],[51.404209,5.43096],[51.404228,5.43145],[51.404259,5.43249],[51.404289,5.43305],[51.40435,5.43362],[51.404461,5.43508],[51.40453,5.43605],[51.404621,5.43689],[51.40485,5.43825],[51.404949,5.43928],[51.405041,5.44026],[51.405121,5.44118],[51.405201,5.44248],[51.405251,5.44356],[51.405369,5.44983],[51.405399,5.45333],[51.405449,5.45596],[51.405491,5.4582],[51.405571,5.46179],[51.40559,5.46252],[51.405609,5.4658],[51.405609,5.46911],[51.405521,5.47301],[51.40551,5.47352],[51.405399,5.47652],[51.40538,5.47713],[51.40527,5.48024],[51.405239,5.48126],[51.404968,5.48955],[51.404942,5.49025],[51.404911,5.49086],[51.404839,5.49202],[51.404781,5.49246],[51.404701,5.49293],[51.40461,5.49339],[51.40453,5.49377],[51.404469,5.4942],[51.404419,5.49469],[51.404388,5.495],[51.404388,5.49536],[51.404388,5.49565],[51.40443,5.49614],[51.404449,5.49643],[51.40448,5.4969],[51.404541,5.49732],[51.404621,5.49771],[51.404709,5.49809],[51.4048,5.49852],[51.404861,5.49884],[51.4049,5.49925],[51.404919,5.49962],[51.40493,5.49999],[51.404919,5.50091],[51.404919,5.50125],[51.4049,5.50403],[51.4049,5.50435],[51.40493,5.51077],[51.40493,5.51908],[51.404911,5.53358],[51.4049,5.53708],[51.4049,5.54587],[51.404911,5.54781],[51.404961,5.54935],[51.405041,5.5509],[51.40517,5.55247],[51.405239,5.55322],[51.40538,5.55445],[51.405571,5.55591],[51.405788,5.55737],[51.40588,5.55797],[51.40617,5.55947],[51.40646,5.56091],[51.40659,5.56148],[51.40731,5.56419],[51.407681,5.56548],[51.408421,5.56768],[51.408791,5.56875],[51.408951,5.56924],[51.41061,5.57402],[51.411709,5.57722],[51.413349,5.582],[51.416458,5.5911],[51.41695,5.59265],[51.417591,5.59477],[51.417992,5.59638],[51.418369,5.59811],[51.41872,5.59991],[51.418949,5.60137],[51.419189,5.60318],[51.419449,5.60551],[51.420132,5.61227],[51.421539,5.62703],[51.421829,5.63011],[51.42268,5.63891],[51.423019,5.64245],[51.423439,5.64695],[51.423569,5.64864],[51.423649,5.6499],[51.423691,5.6508],[51.423698,5.65328],[51.423672,5.65704],[51.423641,5.6593],[51.42358,5.66349],[51.4235,5.66887],[51.423439,5.67272],[51.423409,5.676],[51.423359,5.67842],[51.423241,5.68237],[51.423222,5.68285],[51.42308,5.68647],[51.422939,5.6889],[51.422791,5.69085],[51.422359,5.69652],[51.422218,5.69818],[51.42205,5.70026],[51.421551,5.7066],[51.4212,5.7111],[51.42083,5.7156],[51.42057,5.71879],[51.420441,5.72116],[51.420319,5.723],[51.42025,5.72475],[51.420109,5.72959],[51.42012,5.73225],[51.42017,5.73484],[51.420212,5.73755],[51.420219,5.73999],[51.42017,5.74142],[51.42009,5.74328],[51.419949,5.74522],[51.419701,5.74773],[51.419529,5.74925],[51.419449,5.74987],[51.419128,5.75225],[51.418869,5.75407],[51.41861,5.75592],[51.418388,5.75762],[51.418079,5.75985],[51.41795,5.76072],[51.417461,5.76412],[51.417301,5.76526],[51.41711,5.76661],[51.41692,5.76774],[51.416599,5.76945],[51.41618,5.77184],[51.41555,5.77506],[51.415131,5.77699],[51.41449,5.7797],[51.414021,5.78159],[51.41349,5.7837],[51.412601,5.7868],[51.411781,5.78951],[51.410831,5.79252],[51.4072,5.80385],[51.407001,5.80447],[51.40556,5.80905],[51.404072,5.81369],[51.403431,5.81581],[51.402599,5.81868],[51.401981,5.82092],[51.3988,5.83371],[51.397251,5.83991],[51.396141,5.84441],[51.39502,5.8489],[51.393501,5.85508],[51.39146,5.86325],[51.39127,5.864],[51.390388,5.86731],[51.389561,5.87036],[51.387989,5.87586],[51.3848,5.88699],[51.382519,5.89479],[51.380829,5.90075],[51.380119,5.90336],[51.37936,5.90683],[51.37886,5.90941],[51.378521,5.91146],[51.378189,5.91406],[51.377979,5.9158],[51.377789,5.91788],[51.377682,5.91923],[51.377468,5.92297],[51.377441,5.92369],[51.377411,5.92498],[51.377399,5.92758],[51.377499,5.93505],[51.377659,5.94228],[51.377918,5.95907],[51.37801,5.96417],[51.378029,5.96599],[51.37801,5.96775],[51.377918,5.97046],[51.377781,5.97305],[51.377548,5.97627],[51.377331,5.98114],[51.37735,5.9839],[51.37735,5.98477],[51.37759,5.99092],[51.37812,5.99769],[51.37854,6.00253],[51.378769,6.00521],[51.378971,6.00723],[51.37949,6.01193],[51.380131,6.01689],[51.380531,6.01951],[51.381161,6.02336],[51.381538,6.02554],[51.38237,6.02959],[51.382751,6.03147],[51.383732,6.03571],[51.387409,6.05021],[51.389172,6.05713],[51.393082,6.07238],[51.393429,6.07391],[51.393791,6.0758],[51.393978,6.077],[51.394131,6.07807],[51.394249,6.07917],[51.394329,6.0803],[51.394421,6.08177],[51.394451,6.08392],[51.394199,6.09123],[51.394039,6.09627],[51.393539,6.10898],[51.393478,6.1104],[51.39336,6.11481],[51.39333,6.11742],[51.393471,6.1237],[51.393688,6.12859],[51.394279,6.13838],[51.39436,6.13939],[51.394451,6.14064],[51.394501,6.14145],[51.39518,6.15196],[51.39534,6.15451],[51.395611,6.15861],[51.395901,6.16434],[51.39592,6.16507],[51.39595,6.16609],[51.395969,6.1688],[51.395931,6.17027],[51.395851,6.17172],[51.395809,6.17254],[51.395741,6.17316],[51.39547,6.17562],[51.39521,6.17761],[51.39481,6.17986],[51.394588,6.18087],[51.39426,6.18234],[51.393848,6.18393],[51.393051,6.18666],[51.391201,6.19293],[51.389439,6.19895],[51.387581,6.20492],[51.387119,6.20635],[51.386139,6.20954],[51.384048,6.21632],[51.382431,6.22147],[51.382191,6.2223],[51.38166,6.22413],[51.381069,6.2267],[51.380482,6.23024],[51.380211,6.23265],[51.380039,6.23456],[51.379971,6.23568],[51.379929,6.23745],[51.379971,6.23919],[51.38002,6.24017],[51.380169,6.24235],[51.380199,6.24288],[51.380268,6.24355],[51.380409,6.24457],[51.38081,6.24762],[51.381229,6.24972],[51.381771,6.25191],[51.381851,6.25218],[51.3825,6.25446],[51.382992,6.25592],[51.384571,6.25981],[51.38628,6.26362],[51.38763,6.26717],[51.387741,6.26748],[51.388821,6.27117],[51.388981,6.27186],[51.389351,6.27366],[51.389759,6.27584],[51.38987,6.27655],[51.389969,6.27729],[51.390339,6.28112],[51.390339,6.28241],[51.390339,6.28301],[51.39035,6.28613],[51.390091,6.29202],[51.389912,6.29597],[51.38982,6.29785],[51.389729,6.30039],[51.389488,6.30467],[51.389172,6.31284],[51.388729,6.32214],[51.38855,6.329],[51.388599,6.33371],[51.388821,6.33742],[51.38884,6.33765],[51.38884,6.33775],[51.389149,6.34048],[51.389622,6.34365],[51.39024,6.3467],[51.390331,6.34707],[51.390652,6.34839],[51.391491,6.35144],[51.392441,6.35452],[51.393871,6.3589],[51.394058,6.35941],[51.394421,6.3605],[51.394821,6.36159],[51.39584,6.36458],[51.39621,6.36582],[51.39698,6.36793],[51.399311,6.3749],[51.400372,6.37825],[51.400539,6.37881],[51.401581,6.38237],[51.403149,6.38824],[51.403801,6.39103],[51.404282,6.39306],[51.404369,6.39346],[51.40443,6.39371],[51.40451,6.39412],[51.405708,6.40013],[51.406979,6.40767],[51.40802,6.41569],[51.40815,6.41689],[51.40823,6.41773],[51.408329,6.41866],[51.40844,6.41988],[51.408619,6.42204],[51.408718,6.42343],[51.408958,6.42648],[51.409351,6.43376],[51.410229,6.44922],[51.410912,6.46069],[51.411388,6.46954],[51.41164,6.47208],[51.411819,6.47329],[51.41193,6.47387],[51.412102,6.47472],[51.412529,6.47644],[51.41304,6.47806],[51.413429,6.47915],[51.41362,6.47958],[51.41433,6.48118],[51.416302,6.4848],[51.418781,6.48943],[51.419121,6.4901],[51.419258,6.49035],[51.419521,6.49084],[51.419819,6.49143],[51.420101,6.49197],[51.42136,6.49432],[51.423061,6.49833],[51.42363,6.49987],[51.42461,6.50291],[51.425228,6.50535],[51.426071,6.50966],[51.426102,6.50984],[51.426151,6.51011],[51.426491,6.51252],[51.426498,6.51262],[51.42659,6.51358],[51.426762,6.51535],[51.427052,6.52207],[51.427231,6.53069],[51.427238,6.53088],[51.427368,6.53329],[51.427521,6.53609],[51.42799,6.54291],[51.42828,6.54714],[51.428631,6.55212],[51.428928,6.55589],[51.429508,6.56421],[51.43005,6.56866],[51.43092,6.57325],[51.431541,6.57603],[51.432091,6.57825],[51.432789,6.58093],[51.433418,6.58378],[51.434471,6.58956],[51.435162,6.59419],[51.435532,6.59735],[51.435841,6.60087],[51.435982,6.60295],[51.436031,6.60391],[51.436089,6.60506],[51.436169,6.60728],[51.436211,6.60933],[51.43623,6.61085],[51.436218,6.61229],[51.436211,6.61338],[51.43618,6.61485],[51.436161,6.61573],[51.436119,6.61677],[51.436001,6.61847],[51.435909,6.62006],[51.43589,6.62054],[51.435791,6.62232],[51.435719,6.6238],[51.435619,6.6272],[51.435631,6.63186],[51.435719,6.63537],[51.435928,6.63872],[51.436218,6.64277],[51.43652,6.64744],[51.43663,6.64967],[51.43671,6.65219],[51.436729,6.65546],[51.43679,6.65711],[51.43697,6.66175],[51.437,6.66234],[51.437019,6.66297],[51.437279,6.67126],[51.437321,6.67279],[51.437359,6.67531],[51.43742,6.68066],[51.437401,6.68155],[51.43737,6.68277],[51.437271,6.68504],[51.437111,6.68668],[51.43681,6.6887],[51.43618,6.69207],[51.435699,6.69477],[51.435581,6.69569],[51.435509,6.69632],[51.43541,6.69751],[51.435349,6.69886],[51.435329,6.70035],[51.435379,6.70175],[51.435509,6.70337],[51.435692,6.70467],[51.436069,6.7069],[51.43811,6.71953],[51.438358,6.72115],[51.438541,6.7228],[51.438629,6.72482],[51.438511,6.72655],[51.438271,6.72848],[51.437729,6.73069],[51.436901,6.7328],[51.436451,6.73392],[51.436169,6.73462],[51.43568,6.73624],[51.435421,6.73745],[51.435291,6.73821],[51.435051,6.73985],[51.43491,6.74152],[51.43486,6.74321],[51.434849,6.74462],[51.434929,6.74645],[51.435169,6.74879],[51.435349,6.7499],[51.435471,6.75059],[51.43568,6.75184],[51.43605,6.75345],[51.436588,6.75525],[51.437061,6.75633],[51.43734,6.75687],[51.438301,6.7584],[51.439831,6.76023],[51.44173,6.76266],[51.44257,6.76421],[51.443211,6.76552],[51.443981,6.76754],[51.444592,6.7697],[51.445171,6.77222],[51.44598,6.77676],[51.44632,6.77867],[51.446621,6.78057],[51.447021,6.78296],[51.447361,6.78519],[51.44762,6.78704],[51.4478,6.78876],[51.44783,6.79036],[51.4478,6.79163],[51.447601,6.79349],[51.447311,6.79505],[51.44696,6.79636],[51.446671,6.79732],[51.44632,6.79822],[51.446072,6.79865],[51.445259,6.80026],[51.444401,6.80188],[51.44429,6.80213],[51.443951,6.80283],[51.443432,6.80394],[51.44305,6.80456],[51.44294,6.80471],[51.442791,6.80487],[51.44265,6.80495],[51.442459,6.80499],[51.442329,6.80496],[51.442181,6.80488],[51.442081,6.80479],[51.44194,6.80458],[51.44186,6.8043],[51.441811,6.8041],[51.441792,6.8038],[51.441792,6.80368],[51.441811,6.80346],[51.441879,6.80322],[51.441959,6.80295],[51.442089,6.80256],[51.442211,6.80226],[51.442429,6.80195],[51.442871,6.80134],[51.44342,6.8007],[51.444061,6.80015],[51.444431,6.79987],[51.444641,6.79971],[51.444809,6.7996],[51.44566,6.79921],[51.446529,6.799],[51.447182,6.79889],[51.447929,6.79884],[51.449249,6.79886],[51.450062,6.79895],[51.451248,6.7991],[51.45211,6.79927],[51.45311,6.79947],[51.454029,6.79984],[51.454899,6.80039],[51.45573,6.80101],[51.45639,6.80168],[51.456959,6.80235],[51.457588,6.80329],[51.458141,6.80427],[51.45866,6.80531],[51.459122,6.80651],[51.459789,6.80861],[51.460159,6.8097],[51.460659,6.81081],[51.46172,6.81251],[51.461948,6.81283],[51.462391,6.81341],[51.462681,6.81371],[51.463501,6.81453],[51.46389,6.81483],[51.464821,6.81552],[51.465771,6.8159],[51.466869,6.81625],[51.468349,6.81658],[51.470051,6.81669],[51.471851,6.8165],[51.473011,6.81621],[51.47398,6.81587],[51.474541,6.8157],[51.47541,6.81537],[51.47633,6.81497],[51.477489,6.81446],[51.478821,6.81388],[51.47916,6.81377],[51.480099,6.81351],[51.48127,6.81332],[51.48185,6.8133],[51.483139,6.81333],[51.483341,6.81342],[51.483582,6.81349],[51.484051,6.8136],[51.484409,6.8137],[51.4851,6.814],[51.4855,6.81421],[51.485771,6.8144],[51.486031,6.8146],[51.486149,6.81473],[51.48632,6.81496],[51.486488,6.81527],[51.48661,6.81557],[51.48674,6.81603],[51.486801,6.81641],[51.48682,6.81667],[51.486832,6.81699],[51.486809,6.81731],[51.486252,6.82101],[51.486198,6.82155],[51.486191,6.82224],[51.48613,6.82305],[51.486099,6.82352],[51.486069,6.82462],[51.486118,6.82628],[51.48629,6.82779],[51.48674,6.83007],[51.4874,6.83218],[51.488831,6.836],[51.489079,6.83642],[51.48975,6.83737],[51.490349,6.83822],[51.490829,6.83886],[51.49268,6.84133],[51.492962,6.84171],[51.493629,6.84264],[51.49432,6.84385],[51.4949,6.84507],[51.495281,6.84597],[51.49572,6.84735],[51.496052,6.8486],[51.496349,6.85008],[51.496571,6.85205],[51.496651,6.85463],[51.49654,6.85815],[51.496441,6.86022],[51.496342,6.86164],[51.49622,6.8647],[51.496101,6.86872],[51.496132,6.87109],[51.496342,6.88355],[51.496422,6.88532],[51.496639,6.8891],[51.496681,6.88994],[51.496769,6.89124],[51.49688,6.89292],[51.49704,6.89456],[51.49754,6.90146],[51.49781,6.91115],[51.49823,6.9167],[51.498699,6.92018],[51.499279,6.92279],[51.49995,6.9251],[51.500381,6.92628],[51.502979,6.93204],[51.503391,6.93294],[51.50415,6.93473],[51.50428,6.93505],[51.504478,6.93559],[51.50473,6.93621],[51.505058,6.93707],[51.50531,6.93774],[51.50568,6.93884],[51.505909,6.93961],[51.506149,6.94042],[51.50634,6.94113],[51.506481,6.94171],[51.50668,6.94259],[51.506882,6.94349],[51.507061,6.94441],[51.507309,6.94577],[51.507511,6.94717],[51.507629,6.94811],[51.507679,6.9483],[51.507751,6.94906],[51.507851,6.95002],[51.507919,6.95101],[51.50798,6.95199],[51.508011,6.95296],[51.508049,6.95394],[51.508049,6.95491],[51.50803,6.95637],[51.508011,6.95741],[51.507969,6.95846],[51.5079,6.95952],[51.507809,6.96061],[51.50771,6.96166],[51.50761,6.96267],[51.507511,6.96364],[51.507401,6.96457],[51.507301,6.96548],[51.50721,6.96642],[51.507099,6.96736],[51.507011,6.96826],[51.506908,6.96914],[51.506802,6.97007],[51.506618,6.97107],[51.506481,6.97167],[51.506088,6.97303],[51.50581,6.97399],[51.50378,6.97994],[51.50354,6.9808],[51.503361,6.98158],[51.50322,6.98288],[51.503109,6.98417],[51.503059,6.98502],[51.503059,6.98587],[51.503132,6.98712],[51.503201,6.98794],[51.50338,6.98916],[51.503559,6.98996],[51.50386,6.99122],[51.50407,6.99203],[51.504471,6.99341],[51.504799,6.99441],[51.505051,6.99517],[51.50531,6.99594],[51.505661,6.99694],[51.505951,6.99787],[51.50618,6.99864],[51.50639,6.99936],[51.506611,7.0001],[51.50679,7.00076],[51.50692,7.00141],[51.50713,7.00247],[51.507252,7.0032],[51.507309,7.00377],[51.507389,7.00478],[51.507469,7.00601],[51.507511,7.00706],[51.507568,7.00815],[51.507622,7.0094],[51.50771,7.01091],[51.507778,7.01189],[51.5079,7.01303],[51.50798,7.01356],[51.50808,7.01418],[51.50853,7.01628],[51.508598,7.01657],[51.50882,7.01736],[51.508911,7.01776],[51.508991,7.01802],[51.509449,7.01924],[51.509651,7.01977],[51.51001,7.02061],[51.510441,7.0216],[51.51067,7.02212],[51.510971,7.02282],[51.511318,7.02362],[51.511749,7.02466],[51.51218,7.02575],[51.512489,7.02662],[51.51302,7.02839],[51.51318,7.02901],[51.513241,7.02923],[51.513378,7.02978],[51.5135,7.03033],[51.51379,7.03182],[51.51405,7.03356],[51.514198,7.03489],[51.514351,7.03674],[51.51437,7.03743],[51.514381,7.03811],[51.5144,7.03938],[51.51442,7.04053],[51.514431,7.04131],[51.514469,7.04353],[51.514469,7.04414],[51.514488,7.04472],[51.514542,7.04728],[51.51458,7.04906],[51.514709,7.0513],[51.514931,7.05337],[51.515228,7.05491],[51.51569,7.05666],[51.51609,7.0581],[51.51664,7.05958],[51.51804,7.06284],[51.519421,7.06611],[51.51976,7.06685],[51.520069,7.0676],[51.520451,7.06844],[51.521461,7.07034],[51.522091,7.07128],[51.522469,7.07174],[51.522919,7.07226],[51.523548,7.07292],[51.523918,7.07324],[51.524281,7.07349],[51.52504,7.07395],[51.525612,7.07422],[51.526218,7.0745],[51.52739,7.07508],[51.528431,7.07578],[51.529202,7.07652],[51.529968,7.07744],[51.530621,7.07847],[51.531349,7.07998],[51.531639,7.08085],[51.53178,7.08126],[51.532188,7.08277],[51.532478,7.08456],[51.532539,7.08514],[51.532681,7.0868],[51.532902,7.08914],[51.533161,7.09096],[51.533421,7.09249],[51.533749,7.09376],[51.534119,7.09503],[51.534389,7.09584],[51.534439,7.09597],[51.534561,7.09629],[51.53529,7.09819],[51.535419,7.09858],[51.535782,7.09977],[51.536011,7.10056],[51.536228,7.10172],[51.536419,7.10277],[51.536591,7.10419],[51.53746,7.11268],[51.537781,7.11582],[51.537899,7.117],[51.53796,7.11818],[51.537991,7.11909],[51.537979,7.12019],[51.53783,7.12271],[51.53772,7.12502],[51.537651,7.12646],[51.537651,7.12701],[51.53764,7.1282],[51.53764,7.12896],[51.537651,7.12917],[51.53764,7.12952],[51.53801,7.135],[51.538422,7.1388],[51.538589,7.1399],[51.538929,7.14149],[51.53949,7.14344],[51.540791,7.14728],[51.540798,7.14734],[51.541142,7.14849],[51.541241,7.14885],[51.541569,7.15025],[51.54187,7.15221],[51.542019,7.15344],[51.54203,7.15516],[51.541931,7.15783],[51.541889,7.15901],[51.541821,7.16064],[51.541889,7.16227],[51.541931,7.16295],[51.54224,7.16765],[51.542301,7.16893],[51.542358,7.17118],[51.542389,7.17196],[51.5424,7.17221],[51.54258,7.17451],[51.54261,7.17482],[51.54285,7.17645],[51.542992,7.17739],[51.543129,7.17809],[51.543251,7.17887],[51.543362,7.17973],[51.543541,7.18114],[51.54364,7.18225],[51.54372,7.18371],[51.54377,7.18551],[51.543739,7.18735],[51.543751,7.18831],[51.543739,7.1901],[51.54377,7.19114],[51.54377,7.19203],[51.5438,7.19345],[51.5439,7.19547],[51.54401,7.197],[51.54406,7.19781],[51.544159,7.19858],[51.544319,7.19959],[51.544491,7.20032],[51.544949,7.20227],[51.545071,7.20274],[51.545212,7.20327],[51.5453,7.20364],[51.545719,7.20504],[51.547321,7.20951],[51.548038,7.2115],[51.54821,7.21198],[51.548439,7.2125],[51.549198,7.21465],[51.5495,7.21541],[51.555611,7.23041],[51.555901,7.23109],[51.55603,7.23137],[51.556141,7.23164],[51.556469,7.23245],[51.556751,7.2331],[51.557121,7.2339],[51.557549,7.23481],[51.557961,7.23604],[51.55835,7.23732],[51.558632,7.23866],[51.55888,7.24011],[51.559021,7.24148],[51.559101,7.2429],[51.559132,7.24386],[51.55899,7.24571],[51.558868,7.24714],[51.558651,7.24856],[51.5583,7.25041],[51.55806,7.25159],[51.557812,7.25266],[51.557541,7.25399],[51.55732,7.25532],[51.557159,7.25671],[51.55706,7.25809],[51.556992,7.25947],[51.557011,7.26144],[51.55706,7.26255],[51.557159,7.26354],[51.55751,7.26621],[51.557701,7.26752],[51.557861,7.26839],[51.557949,7.26905],[51.558071,7.26972],[51.55827,7.27111],[51.558392,7.27207],[51.558529,7.27356],[51.558609,7.27506],[51.55862,7.27656],[51.55859,7.27804],[51.558529,7.27895],[51.558529,7.27951],[51.558418,7.28097],[51.558361,7.28194],[51.558289,7.28291],[51.558239,7.28386],[51.558189,7.28481],[51.558159,7.28624],[51.558189,7.28766],[51.55827,7.28906],[51.558411,7.29047],[51.558571,7.29187],[51.558601,7.29208],[51.55867,7.29261],[51.55883,7.29417],[51.558949,7.29507],[51.559071,7.29598],[51.559189,7.29688],[51.559299,7.29778],[51.559422,7.29868],[51.559528,7.29958],[51.559639,7.30045],[51.559731,7.30127],[51.55983,7.30207],[51.559929,7.30283],[51.560032,7.30362],[51.56012,7.30442],[51.560211,7.3052],[51.56031,7.30583],[51.560349,7.30618],[51.560471,7.30717],[51.560551,7.30793],[51.560669,7.30902],[51.56078,7.30999],[51.56105,7.31307],[51.561241,7.3154],[51.56147,7.31788],[51.561569,7.31974],[51.561611,7.32072],[51.56171,7.32205],[51.561779,7.32318],[51.56184,7.32389],[51.562012,7.32659],[51.562149,7.33011],[51.56229,7.3331],[51.562389,7.33599],[51.562469,7.33965],[51.562519,7.34197],[51.562519,7.34284],[51.562519,7.34333],[51.562531,7.34573],[51.562469,7.3485],[51.562328,7.35043],[51.562069,7.35259],[51.562031,7.35289],[51.561779,7.35495],[51.561531,7.35659],[51.561291,7.35808],[51.561291,7.35811],[51.561199,7.35845],[51.561008,7.35929],[51.560909,7.3595],[51.56078,7.35966],[51.560692,7.35974],[51.560589,7.35978],[51.56049,7.35978],[51.560291,7.3597],[51.5602,7.3596],[51.56007,7.35931],[51.560032,7.35916],[51.560032,7.35899],[51.560059,7.35869],[51.560101,7.35858],[51.560181,7.35841],[51.560299,7.35828],[51.560379,7.35823],[51.560551,7.3582],[51.561131,7.35833],[51.561661,7.35851],[51.561779,7.35856],[51.561939,7.35859],[51.562241,7.3587],[51.562809,7.35894],[51.563351,7.35919],[51.563709,7.35935],[51.564259,7.35961],[51.564602,7.35978],[51.564892,7.35988],[51.56517,7.35999],[51.565578,7.36019],[51.566071,7.36044],[51.56638,7.3606],[51.566589,7.36071],[51.566719,7.36077],[51.56686,7.36084],[51.566952,7.36086],[51.567051,7.36085],[51.56723,7.36094],[51.567402,7.36103],[51.567589,7.36112],[51.568249,7.36145],[51.568581,7.36161],[51.568901,7.36176],[51.569561,7.36207],[51.569901,7.36223],[51.570229,7.36237],[51.571281,7.36284],[51.571812,7.36307],[51.572319,7.36329],[51.57275,7.36346],[51.573139,7.36362],[51.573471,7.36376],[51.573818,7.3639],[51.574638,7.36421],[51.575439,7.36451],[51.576359,7.36484],[51.576591,7.36492],[51.576988,7.36506],[51.5774,7.36519],[51.57777,7.36532],[51.578259,7.36548],[51.579189,7.36578],[51.579529,7.36596],[51.579689,7.36601],[51.580959,7.36641],[51.581139,7.36647],[51.582199,7.36688],[51.58263,7.36702],[51.58305,7.36722],[51.58326,7.36734],[51.583469,7.36749],[51.583649,7.36767],[51.583839,7.36786],[51.58403,7.36812],[51.58419,7.36836],[51.584339,7.36861],[51.58448,7.36891],[51.584629,7.36921],[51.58482,7.36963],[51.584969,7.36999],[51.585041,7.37021],[51.585091,7.37044],[51.585121,7.37069],[51.585152,7.37097],[51.585159,7.37122],[51.585159,7.37148],[51.585121,7.37199],[51.584991,7.37375],[51.584991,7.374],[51.584671,7.37836],[51.584621,7.37916],[51.58432,7.38337],[51.584221,7.3848],[51.584122,7.38621],[51.584019,7.38768],[51.583721,7.39179],[51.583691,7.39218],[51.583611,7.39328],[51.583569,7.39381],[51.583542,7.39437],[51.583488,7.39536],[51.58345,7.39625],[51.583389,7.39708],[51.58334,7.39788],[51.58329,7.3991],[51.583279,7.40034],[51.58329,7.40065],[51.583309,7.40171],[51.583382,7.40315],[51.583439,7.4039],[51.5835,7.40464],[51.583519,7.40483],[51.583591,7.40521],[51.583672,7.40557],[51.583721,7.40612],[51.58382,7.40704],[51.58392,7.40807],[51.58403,7.40904],[51.584202,7.41055],[51.58432,7.41158],[51.584431,7.41267],[51.584499,7.41334],[51.584549,7.41403],[51.584579,7.4145],[51.58461,7.4151],[51.584641,7.4157],[51.58466,7.41627],[51.584671,7.41685],[51.584671,7.41771],[51.584648,7.41847],[51.584629,7.41912],[51.584599,7.41974],[51.584549,7.42059],[51.584492,7.42138],[51.584431,7.42199],[51.584351,7.42266],[51.584221,7.42369],[51.58408,7.42462],[51.583832,7.42597],[51.583691,7.42671],[51.58353,7.42746],[51.58337,7.4282],[51.58321,7.42895],[51.582531,7.43192],[51.58099,7.43861],[51.577789,7.45246],[51.576969,7.45601],[51.57658,7.45769],[51.576351,7.4587],[51.57613,7.45966],[51.575909,7.46067],[51.57571,7.46165],[51.57552,7.46265],[51.575329,7.4637],[51.57518,7.46471],[51.575039,7.46575],[51.574928,7.4668],[51.574829,7.46786],[51.57476,7.46891],[51.574718,7.47],[51.574692,7.47104],[51.57468,7.47212],[51.574699,7.47319],[51.574749,7.47434],[51.57481,7.47533],[51.57489,7.4764],[51.57494,7.47691],[51.574989,7.47742],[51.575119,7.47844],[51.57523,7.47924],[51.57539,7.48021],[51.57555,7.48119],[51.57576,7.48235],[51.57608,7.48387],[51.576271,7.48479],[51.576309,7.485],[51.576771,7.48709],[51.577591,7.49089],[51.578011,7.49299],[51.578152,7.49385],[51.57827,7.4947],[51.5784,7.49571],[51.57851,7.49673],[51.57859,7.49762],[51.578651,7.49843],[51.578701,7.49912],[51.578739,7.4999],[51.578751,7.50038],[51.57877,7.50084],[51.578781,7.50189],[51.578781,7.50282],[51.578758,7.50375],[51.578739,7.5045],[51.578701,7.5054],[51.57869,7.50576],[51.578621,7.50705],[51.57859,7.50803],[51.578571,7.50862],[51.578529,7.50941],[51.578499,7.51038],[51.57848,7.5108],[51.57843,7.51217],[51.578381,7.51321],[51.578339,7.51423],[51.5783,7.51529],[51.578281,7.51577],[51.578259,7.51615],[51.578209,7.51752],[51.578171,7.51851],[51.578129,7.5196],[51.578091,7.5207],[51.578091,7.5218],[51.57811,7.52288],[51.578152,7.52394],[51.578201,7.52478],[51.57827,7.52559],[51.578331,7.52628],[51.578369,7.5266],[51.57843,7.52711],[51.578499,7.52769],[51.57864,7.52868],[51.57877,7.5294],[51.578899,7.53008],[51.578991,7.53053],[51.579079,7.53098],[51.579281,7.53187],[51.579441,7.53249],[51.579609,7.53312],[51.57983,7.53392],[51.58007,7.53472],[51.58046,7.53605],[51.580769,7.53709],[51.58123,7.53863],[51.581451,7.53938],[51.581871,7.54081],[51.582241,7.54203],[51.583309,7.54564],[51.58363,7.54673],[51.584259,7.54883],[51.584648,7.55012],[51.584831,7.55076],[51.585011,7.5514],[51.585159,7.55197],[51.585289,7.55252],[51.585411,7.55302],[51.585529,7.55354],[51.585651,7.55411],[51.58577,7.55468],[51.585869,7.55518],[51.58596,7.55569],[51.58606,7.5563],[51.586159,7.55691],[51.5863,7.55789],[51.586411,7.55872],[51.586491,7.55944],[51.586571,7.56016],[51.586861,7.56301],[51.58717,7.56606],[51.587811,7.57225],[51.588902,7.58372],[51.58952,7.5933],[51.59026,7.6039],[51.590408,7.60583],[51.590462,7.60636],[51.590549,7.60696],[51.59111,7.61037],[51.59132,7.61134],[51.591709,7.61331],[51.59182,7.614],[51.592159,7.61592],[51.592571,7.61796],[51.592892,7.61959],[51.59317,7.62098],[51.593712,7.62371],[51.594002,7.62533],[51.594719,7.62911],[51.59486,7.62982],[51.59499,7.63051],[51.597221,7.64195],[51.59819,7.64671],[51.598789,7.6504],[51.59893,7.65125],[51.599091,7.65217],[51.599911,7.65679],[51.60001,7.65743],[51.60043,7.65993],[51.600689,7.66178],[51.600769,7.66243],[51.60088,7.66422],[51.60091,7.66476],[51.60096,7.66599],[51.600948,7.66965],[51.60091,7.67532],[51.600891,7.67944],[51.600899,7.68501],[51.600891,7.6879],[51.60088,7.69047],[51.600891,7.69413],[51.600861,7.69814],[51.600868,7.70294],[51.600868,7.70605],[51.600941,7.70745],[51.60104,7.7089],[51.601219,7.71043],[51.601521,7.71234],[51.601768,7.71369],[51.60215,7.71536],[51.602661,7.71758],[51.603401,7.72063],[51.605679,7.73041],[51.606239,7.73281],[51.60643,7.73365],[51.607349,7.73746],[51.607731,7.73907],[51.60902,7.74463],[51.609558,7.74701],[51.609879,7.74839],[51.610779,7.75216],[51.61095,7.75295],[51.61179,7.75657],[51.612148,7.75829],[51.61359,7.7652],[51.613682,7.76564],[51.614151,7.76791],[51.6143,7.76865],[51.615742,7.77577],[51.616322,7.77862],[51.617611,7.78492],[51.618111,7.78763],[51.618752,7.79107],[51.619671,7.79649],[51.62072,7.8026],[51.621819,7.80895],[51.62244,7.81259],[51.623089,7.81769],[51.623421,7.82074],[51.6236,7.82378],[51.624069,7.83272],[51.624149,7.83382],[51.624611,7.84164],[51.624901,7.8468],[51.62495,7.84767],[51.625149,7.85185],[51.625198,7.85266],[51.625301,7.85381],[51.62553,7.85567],[51.625759,7.8571],[51.62603,7.85854],[51.626621,7.86089],[51.626999,7.86221],[51.627499,7.8637],[51.628529,7.86656],[51.63028,7.87145],[51.632408,7.87746],[51.63369,7.88111],[51.634609,7.88375],[51.635479,7.88627],[51.636829,7.89005],[51.638069,7.89329],[51.63982,7.89801],[51.643669,7.90798],[51.64444,7.90994],[51.64513,7.91146],[51.645748,7.91261],[51.646309,7.91357],[51.647079,7.91479],[51.64782,7.91587],[51.649281,7.91756],[51.650162,7.9185],[51.652962,7.92068],[51.65921,7.92535],[51.66478,7.92948],[51.666481,7.93092],[51.667461,7.93197],[51.668388,7.93306],[51.669121,7.93402],[51.669701,7.93487],[51.670361,7.93596],[51.67128,7.93766],[51.67181,7.9387],[51.672089,7.93925],[51.675251,7.94549],[51.675961,7.9468],[51.676571,7.94784],[51.677509,7.94919],[51.67844,7.9504],[51.679081,7.95118],[51.68021,7.95252],[51.681889,7.95451],[51.68465,7.9577],[51.68486,7.95795],[51.688831,7.96253],[51.68943,7.96323],[51.691681,7.96587],[51.694801,7.96948],[51.694969,7.96969],[51.696449,7.97137],[51.698071,7.97327],[51.699009,7.97433],[51.69981,7.97509],[51.700691,7.97584],[51.70166,7.97653],[51.70285,7.97724],[51.703911,7.97781],[51.704929,7.97819],[51.706108,7.97849],[51.70723,7.97867],[51.709469,7.97887],[51.712429,7.97905],[51.72028,7.97964],[51.72121,7.97971],[51.721931,7.9798],[51.722488,7.97991],[51.723068,7.98007],[51.724079,7.98043],[51.725029,7.98082],[51.725941,7.98132],[51.72683,7.98186],[51.730968,7.98433],[51.735161,7.98683],[51.73597,7.98732],[51.757,7.99996],[51.75713,8.00004],[51.761951,8.00292],[51.76778,8.00644],[51.76865,8.00706],[51.769272,8.00759],[51.769791,8.00808],[51.77037,8.00867],[51.771149,8.00953],[51.771778,8.01032],[51.772381,8.01117],[51.772739,8.01171],[51.773022,8.01213],[51.77364,8.01325],[51.774139,8.01421],[51.7747,8.01539],[51.77486,8.01581],[51.775139,8.01646],[51.775558,8.01758],[51.77586,8.01844],[51.77607,8.01915],[51.776249,8.01978],[51.776482,8.0207],[51.777779,8.02621],[51.779148,8.03231],[51.77919,8.0325],[51.77935,8.03314],[51.78109,8.04068],[51.78199,8.04458],[51.782379,8.04621],[51.782761,8.04768],[51.783119,8.0489],[51.78363,8.0505],[51.785709,8.05654],[51.7859,8.05711],[51.788849,8.0656],[51.790531,8.07057],[51.790661,8.07092],[51.79266,8.07673],[51.79438,8.08179],[51.796059,8.08666],[51.79829,8.09329],[51.798752,8.09476],[51.7994,8.09704],[51.800251,8.10029],[51.801769,8.10654],[51.802818,8.11106],[51.803341,8.11329],[51.803589,8.11438],[51.804901,8.12144],[51.806179,8.12817],[51.806469,8.1297],[51.806881,8.13148],[51.807301,8.133],[51.807522,8.13369],[51.80777,8.13451],[51.8083,8.13594],[51.80957,8.13884],[51.81089,8.14193],[51.81139,8.1432],[51.81179,8.14429],[51.812328,8.14601],[51.812851,8.14795],[51.813831,8.15192],[51.815701,8.15951],[51.819611,8.17346],[51.821659,8.18062],[51.823521,8.1873],[51.824162,8.1898],[51.824612,8.19176],[51.825001,8.19363],[51.825298,8.19525],[51.825661,8.19734],[51.826599,8.20373],[51.828011,8.21375],[51.828949,8.22073],[51.8321,8.2427],[51.833431,8.25189],[51.834709,8.26084],[51.83506,8.26298],[51.835461,8.26496],[51.836048,8.26736],[51.837231,8.27094],[51.840221,8.27917],[51.842819,8.28644],[51.843109,8.28733],[51.843418,8.28839],[51.844082,8.29078],[51.84436,8.29183],[51.8452,8.29493],[51.84552,8.29616],[51.84684,8.30111],[51.847271,8.30268],[51.848518,8.30731],[51.849789,8.31204],[51.850498,8.31436],[51.85062,8.31468],[51.851238,8.31633],[51.851891,8.31787],[51.853531,8.32144],[51.854641,8.32379],[51.855209,8.32498],[51.85619,8.32714],[51.857101,8.32945],[51.857349,8.33024],[51.857601,8.33111],[51.85788,8.33211],[51.85804,8.33269],[51.858318,8.33384],[51.85857,8.33501],[51.85894,8.33723],[51.859798,8.34333],[51.860321,8.34674],[51.860401,8.34727],[51.861069,8.35194],[51.86124,8.35297],[51.86142,8.35408],[51.861752,8.35569],[51.862141,8.35716],[51.862942,8.36004],[51.86388,8.36343],[51.86396,8.36376],[51.864109,8.36425],[51.865002,8.36734],[51.866741,8.37381],[51.867729,8.37732],[51.868149,8.37884],[51.868641,8.38072],[51.869041,8.38247],[51.86937,8.38443],[51.869659,8.38654],[51.871109,8.39815],[51.871651,8.40257],[51.871948,8.40499],[51.872162,8.40643],[51.872631,8.40925],[51.872952,8.41071],[51.873329,8.41213],[51.873749,8.4135],[51.874168,8.41477],[51.874729,8.41609],[51.875431,8.41777],[51.879452,8.42606],[51.88131,8.4298],[51.88176,8.43074],[51.88216,8.43158],[51.882431,8.43212],[51.88261,8.43246],[51.883171,8.43365],[51.88406,8.43552],[51.88525,8.438],[51.886379,8.44002],[51.887032,8.44107],[51.888119,8.4428],[51.889061,8.44421],[51.889858,8.44547],[51.890759,8.44697],[51.891472,8.44826],[51.89222,8.44966],[51.892891,8.45104],[51.893501,8.45238],[51.894169,8.45389],[51.894829,8.45555],[51.89537,8.45697],[51.895889,8.45831],[51.896221,8.45935],[51.896488,8.46014],[51.89698,8.4617],[51.897369,8.46326],[51.897789,8.46489],[51.89819,8.46655],[51.89856,8.46816],[51.898918,8.47006],[51.899799,8.47499],[51.900379,8.47826],[51.901348,8.48375],[51.90192,8.48683],[51.902241,8.48842],[51.903591,8.49471],[51.903889,8.49611],[51.903938,8.49633],[51.90406,8.49683],[51.90443,8.49858],[51.90485,8.50032],[51.90535,8.50198],[51.905899,8.50358],[51.90662,8.50537],[51.907452,8.50714],[51.90823,8.50857],[51.909039,8.50989],[51.909969,8.5112],[51.911041,8.51252],[51.912109,8.5137],[51.913021,8.51467],[51.91333,8.51497],[51.91526,8.51712],[51.916302,8.51825],[51.91737,8.51944],[51.918381,8.5205],[51.91951,8.52178],[51.92281,8.52542],[51.924339,8.52709],[51.92609,8.52888],[51.926949,8.5297],[51.927811,8.53037],[51.92894,8.53128],[51.92989,8.53191],[51.931068,8.53263],[51.93187,8.53305],[51.93512,8.53467],[51.935982,8.53512],[51.93679,8.53563],[51.937489,8.53612],[51.93824,8.5367],[51.93858,8.53698],[51.93906,8.53741],[51.939301,8.53765],[51.939751,8.53815],[51.940151,8.5386],[51.940842,8.53947],[51.941341,8.54009],[51.942139,8.54127],[51.94286,8.54242],[51.94323,8.54305],[51.943459,8.5435],[51.943748,8.54411],[51.944279,8.54521],[51.944771,8.54638],[51.945148,8.54732],[51.945351,8.54789],[51.94632,8.55056],[51.94648,8.55101],[51.946869,8.55216],[51.94733,8.55343],[51.94743,8.55374],[51.950321,8.56168],[51.95089,8.56321],[51.951962,8.56566],[51.95256,8.56682],[51.953461,8.56841],[51.954559,8.57018],[51.954639,8.5703],[51.955059,8.57101],[51.95639,8.57315],[51.957119,8.57434],[51.95779,8.57562],[51.958481,8.57689],[51.959141,8.57828],[51.959751,8.57966],[51.960361,8.58111],[51.96093,8.58259],[51.961929,8.58578],[51.962639,8.58817],[51.964272,8.59382],[51.96476,8.59554],[51.965649,8.59864],[51.966709,8.60208],[51.96719,8.60341],[51.967461,8.60407],[51.969151,8.60787],[51.970402,8.61055],[51.970772,8.6113],[51.971081,8.61183],[51.97139,8.61236],[51.971828,8.6129],[51.972309,8.61345],[51.97282,8.61393],[51.973431,8.61437],[51.973961,8.61469],[51.974499,8.61493],[51.975441,8.61518],[51.97644,8.61538],[51.977409,8.61549],[51.978371,8.61561],[51.979061,8.6157],[51.979389,8.61575],[51.980129,8.61587],[51.980331,8.61591],[51.98135,8.61604],[51.982288,8.61597],[51.98317,8.61576],[51.9841,8.61553],[51.984982,8.6153],[51.985439,8.6152],[51.985882,8.61516],[51.98682,8.6152],[51.98735,8.61529],[51.987831,8.61541],[51.988739,8.61577],[51.9897,8.61619],[51.98988,8.61626],[51.99004,8.61632],[51.9907,8.6166],[51.99086,8.61666],[51.99165,8.61701],[51.992439,8.61736],[51.992611,8.61745],[51.993599,8.61787],[51.994911,8.61845],[51.995369,8.61865],[51.9958,8.61883],[51.997459,8.61953],[51.997799,8.61967],[51.99855,8.61999],[51.999088,8.62024],[51.999481,8.6204],[51.999889,8.62059],[52.00095,8.62121],[52.00148,8.62154],[52.002121,8.62197],[52.002831,8.62255],[52.003342,8.623],[52.003979,8.62353],[52.004601,8.62405],[52.005199,8.62456],[52.00592,8.62518],[52.006649,8.62579],[52.006809,8.62593],[52.007721,8.62671],[52.00893,8.62773],[52.010181,8.62879],[52.011429,8.62977],[52.012291,8.63042],[52.01255,8.63061],[52.013939,8.63147],[52.014462,8.63181],[52.0159,8.63256],[52.01722,8.63319],[52.01857,8.63373],[52.019871,8.63422],[52.021141,8.63468],[52.02203,8.63501],[52.022339,8.63513],[52.023869,8.63568],[52.024651,8.63597],[52.024811,8.63603],[52.025478,8.63629],[52.027969,8.6372],[52.02935,8.63771],[52.030788,8.63828],[52.031471,8.63861],[52.032108,8.63895],[52.032879,8.63944],[52.032982,8.63951],[52.03352,8.63991],[52.034409,8.64064],[52.03516,8.64128],[52.035961,8.64212],[52.036591,8.64282],[52.037182,8.64357],[52.03833,8.64516],[52.039349,8.64674],[52.04047,8.64829],[52.041012,8.64892],[52.041649,8.64968],[52.042881,8.6509],[52.04414,8.65191],[52.04549,8.65281],[52.04697,8.65372],[52.047981,8.65432],[52.048161,8.65444],[52.04858,8.65471],[52.050201,8.65569],[52.052029,8.65683],[52.053902,8.65782],[52.055759,8.65866],[52.056389,8.65888],[52.05896,8.65966],[52.06068,8.66016],[52.063389,8.66092],[52.0644,8.66127],[52.06546,8.66172],[52.06646,8.66223],[52.06741,8.66276],[52.06839,8.6634],[52.06934,8.66409],[52.070309,8.66492],[52.07122,8.66574],[52.072128,8.66665],[52.073071,8.66769],[52.073898,8.6687],[52.074791,8.66986],[52.075588,8.67106],[52.076389,8.67232],[52.07716,8.67369],[52.077351,8.67404],[52.077431,8.67419],[52.077881,8.67505],[52.07856,8.67651],[52.07914,8.67787],[52.079689,8.67926],[52.080231,8.68064],[52.080742,8.68195],[52.081032,8.68267],[52.081261,8.68324],[52.081749,8.68446],[52.082199,8.68568],[52.08271,8.68697],[52.083191,8.68823],[52.083801,8.68973],[52.084461,8.69108],[52.085018,8.69204],[52.08551,8.69285],[52.085701,8.69313],[52.086071,8.69366],[52.086941,8.69476],[52.087109,8.69495],[52.088348,8.69625],[52.08963,8.69755],[52.08987,8.69779],[52.091042,8.69914],[52.091331,8.69947],[52.091862,8.70014],[52.092861,8.70151],[52.093109,8.70187],[52.093811,8.70295],[52.094212,8.70363],[52.094769,8.70458],[52.095451,8.70579],[52.09568,8.70625],[52.09721,8.70946],[52.097439,8.70994],[52.099529,8.71434],[52.101131,8.71777],[52.101261,8.71805],[52.101479,8.71853],[52.102081,8.7198],[52.102921,8.72151],[52.103481,8.72259],[52.10397,8.72343],[52.104481,8.72428],[52.104969,8.72507],[52.105549,8.72595],[52.108551,8.73051],[52.10973,8.73234],[52.110168,8.73303],[52.110771,8.7339],[52.111389,8.73469],[52.111851,8.73522],[52.112289,8.73566],[52.11285,8.73615],[52.11338,8.73657],[52.11377,8.73683],[52.114021,8.73698],[52.11462,8.73728],[52.115231,8.73755],[52.115681,8.73768],[52.116249,8.73781],[52.116859,8.73788],[52.117432,8.7379],[52.118141,8.73783],[52.118759,8.7377],[52.119438,8.73752],[52.120628,8.73726],[52.124889,8.73636],[52.12582,8.73621],[52.126659,8.73614],[52.127281,8.73615],[52.12785,8.73619],[52.128529,8.73633],[52.12936,8.73659],[52.129959,8.73687],[52.130539,8.73717],[52.131649,8.73792],[52.132839,8.739],[52.133789,8.74002],[52.13435,8.74077],[52.13456,8.74107],[52.135368,8.74246],[52.135929,8.74357],[52.136349,8.74463],[52.136742,8.74578],[52.137001,8.74657],[52.13744,8.74827],[52.137718,8.74973],[52.138359,8.75359],[52.13842,8.75398],[52.13879,8.75656],[52.13903,8.75876],[52.139229,8.76081],[52.139389,8.76305],[52.139408,8.76347],[52.13969,8.76717],[52.139919,8.76944],[52.140049,8.77036],[52.14016,8.77109],[52.14027,8.77176],[52.140659,8.77359],[52.1409,8.77464],[52.141029,8.77515],[52.1413,8.77632],[52.14188,8.77859],[52.141918,8.77874],[52.142818,8.7822],[52.143681,8.78554],[52.14452,8.78879],[52.14492,8.79018],[52.145649,8.79237],[52.146839,8.79541],[52.147991,8.7985],[52.148628,8.80016],[52.149361,8.80197],[52.14946,8.80217],[52.149792,8.80289],[52.150139,8.80355],[52.150181,8.80361],[52.150688,8.8044],[52.151588,8.80559],[52.152279,8.80629],[52.15361,8.80748],[52.155849,8.80938],[52.157341,8.81068],[52.15818,8.81133],[52.158909,8.81174],[52.159672,8.81207],[52.160351,8.81231],[52.164749,8.8136],[52.164989,8.81368],[52.16539,8.81381],[52.168892,8.8148],[52.170528,8.81523],[52.171021,8.81539],[52.17152,8.81563],[52.172192,8.816],[52.173,8.81661],[52.178951,8.82136],[52.179169,8.82156],[52.181911,8.82381],[52.18261,8.82431],[52.183281,8.82466],[52.18404,8.82497],[52.184589,8.82513],[52.18552,8.82528],[52.18766,8.82536],[52.18837,8.82545],[52.18885,8.8255],[52.189201,8.82555],[52.189449,8.82561],[52.190498,8.82589],[52.191158,8.82615],[52.191971,8.82656],[52.192581,8.8269],[52.193588,8.82747],[52.195042,8.82846],[52.195419,8.82872],[52.198071,8.83052],[52.198551,8.83085],[52.19976,8.83166],[52.200359,8.83217],[52.201069,8.83284],[52.20174,8.83362],[52.202339,8.83453],[52.202961,8.83556],[52.203571,8.83691],[52.204048,8.83833],[52.20438,8.83961],[52.204609,8.8406],[52.20483,8.84169],[52.20512,8.84355],[52.205269,8.84427],[52.20536,8.84474],[52.205509,8.84547],[52.205669,8.84615],[52.205929,8.84722],[52.20607,8.84783],[52.206478,8.84943],[52.206982,8.85093],[52.2075,8.8524],[52.208408,8.85498],[52.208771,8.85602],[52.209572,8.85826],[52.209862,8.85908],[52.21014,8.85993],[52.210258,8.86032],[52.210461,8.86108],[52.210659,8.86194],[52.210812,8.86277],[52.21093,8.86365],[52.210999,8.8642],[52.211048,8.86475],[52.211102,8.86559],[52.211151,8.86791],[52.21125,8.87073],[52.21125,8.87193],[52.211231,8.87273],[52.211189,8.87377],[52.211128,8.87522],[52.210911,8.88039],[52.210892,8.88137],[52.210911,8.88202],[52.21101,8.88493],[52.211239,8.89031],[52.211189,8.89171],[52.211079,8.89306],[52.210781,8.89507],[52.210609,8.8961],[52.210159,8.89882],[52.209759,8.90154],[52.209518,8.90427],[52.209461,8.90684],[52.209499,8.91353],[52.209549,8.91769],[52.209549,8.9181],[52.20956,8.92176],[52.20961,8.92312],[52.209671,8.92455],[52.209728,8.92545],[52.20982,8.92636],[52.209881,8.92682],[52.210041,8.92827],[52.210369,8.93009],[52.21067,8.93149],[52.2113,8.93413],[52.211449,8.93478],[52.211849,8.93633],[52.212269,8.9384],[52.212502,8.9396],[52.212711,8.94083],[52.212879,8.94212],[52.213051,8.94348],[52.21323,8.94536],[52.213539,8.94827],[52.21368,8.94928],[52.213951,8.9507],[52.214329,8.95231],[52.214691,8.95385],[52.21526,8.95603],[52.215549,8.95712],[52.21579,8.95823],[52.216141,8.96002],[52.21645,8.96171],[52.21664,8.96307],[52.21677,8.96447],[52.216881,8.96608],[52.21693,8.96771],[52.21693,8.96872],[52.21693,8.96993],[52.216831,8.97907],[52.216808,8.98151],[52.216759,8.9851],[52.21674,8.98697],[52.216728,8.98927],[52.21674,8.98993],[52.216789,8.99054],[52.21682,8.9912],[52.2169,8.99186],[52.21706,8.99292],[52.21714,8.99333],[52.217258,8.994],[52.2174,8.99456],[52.2178,8.99593],[52.21825,8.9975],[52.218712,8.99906],[52.218948,9.00004],[52.21912,9.00089],[52.219189,9.00138],[52.219311,9.00233],[52.21941,9.00328],[52.219521,9.00466],[52.219589,9.00562],[52.219669,9.00663],[52.21978,9.00785],[52.219929,9.00907],[52.2201,9.01008],[52.220291,9.01108],[52.220409,9.01157],[52.220791,9.01314],[52.221321,9.01521],[52.22142,9.01562],[52.221661,9.01673],[52.22184,9.01791],[52.22197,9.01901],[52.22205,9.02011],[52.222061,9.02136],[52.222,9.02263],[52.221901,9.02388],[52.221291,9.03157],[52.221218,9.0324],[52.22113,9.03318],[52.22102,9.03388],[52.220772,9.03518],[52.220249,9.03779],[52.220051,9.03881],[52.218788,9.04554],[52.218609,9.04663],[52.218441,9.04758],[52.218288,9.04868],[52.21817,9.04986],[52.218128,9.05084],[52.218151,9.0517],[52.218262,9.05309],[52.218342,9.05377],[52.218441,9.05453],[52.218689,9.056],[52.218891,9.05675],[52.2192,9.05781],[52.219662,9.05924],[52.22028,9.06112],[52.220879,9.06312],[52.221062,9.0639],[52.22123,9.0648],[52.221329,9.06549],[52.221409,9.06617],[52.221458,9.0669],[52.2215,9.06774],[52.2215,9.06863],[52.22147,9.06938],[52.221409,9.07029],[52.221149,9.07354],[52.22068,9.07999],[52.22049,9.08252],[52.220291,9.08523],[52.2202,9.08661],[52.22015,9.08735],[52.220131,9.08799],[52.2201,9.08931],[52.220139,9.09049],[52.220242,9.09183],[52.22039,9.09328],[52.22102,9.09803],[52.221352,9.10071],[52.221519,9.10211],[52.221649,9.10343],[52.221699,9.10437],[52.22171,9.10532],[52.221729,9.10629],[52.221691,9.1071],[52.221649,9.10781],[52.22155,9.10848],[52.221439,9.10903],[52.22131,9.10977],[52.22086,9.11192],[52.220482,9.11371],[52.22023,9.11495],[52.22002,9.11628],[52.21994,9.11706],[52.219879,9.11793],[52.21983,9.11944],[52.21991,9.12097],[52.219971,9.12181],[52.22007,9.12263],[52.22028,9.12413],[52.22049,9.12557],[52.220619,9.12718],[52.22065,9.12849],[52.220619,9.12928],[52.220581,9.13004],[52.22047,9.13138],[52.220119,9.13498],[52.21981,9.13805],[52.21973,9.13917],[52.219669,9.14079],[52.219551,9.14517],[52.219551,9.1457],[52.219479,9.14736],[52.219379,9.14908],[52.21817,9.15879],[52.218029,9.15981],[52.21785,9.16074],[52.217449,9.16232],[52.21669,9.16492],[52.216209,9.16663],[52.216,9.16779],[52.215839,9.16909],[52.215771,9.17014],[52.215752,9.17206],[52.215698,9.17478],[52.21563,9.17699],[52.215611,9.17739],[52.21545,9.18024],[52.215431,9.18139],[52.215511,9.18293],[52.215641,9.18409],[52.215759,9.1848],[52.2159,9.18562],[52.216171,9.18673],[52.216579,9.1883],[52.217991,9.19375],[52.218449,9.19555],[52.219471,9.19907],[52.21983,9.20038],[52.220951,9.20474],[52.221272,9.20601],[52.22147,9.20691],[52.221619,9.20768],[52.221802,9.20891],[52.221901,9.20997],[52.221958,9.21096],[52.22197,9.21188],[52.22187,9.21513],[52.22184,9.21685],[52.221901,9.21811],[52.22197,9.21912],[52.222031,9.21982],[52.222252,9.22108],[52.222549,9.22248],[52.222809,9.22344],[52.223091,9.22428],[52.223412,9.22504],[52.223789,9.2259],[52.224602,9.22741],[52.225891,9.22959],[52.22863,9.23392],[52.228882,9.23433],[52.23019,9.23661],[52.230541,9.23736],[52.230862,9.23816],[52.231152,9.23898],[52.231621,9.24076],[52.232052,9.24308],[52.232349,9.2454],[52.232571,9.24712],[52.23275,9.24839],[52.232841,9.24905],[52.23315,9.25142],[52.233521,9.25422],[52.233898,9.2571],[52.234241,9.25995],[52.234612,9.26276],[52.234951,9.26555],[52.235222,9.26732],[52.23531,9.26785],[52.235649,9.26968],[52.236031,9.27126],[52.236721,9.27361],[52.237251,9.27518],[52.23777,9.2765],[52.23822,9.27756],[52.23859,9.27833],[52.239071,9.27929],[52.23954,9.2801],[52.240299,9.28136],[52.241081,9.2825],[52.24173,9.2833],[52.24263,9.28436],[52.24453,9.28641],[52.24649,9.28847],[52.247452,9.28956],[52.24828,9.29058],[52.248501,9.29089],[52.249249,9.29197],[52.249989,9.29312],[52.250622,9.29429],[52.25116,9.2954],[52.254822,9.30336],[52.256031,9.30584],[52.256618,9.30694],[52.257198,9.3079],[52.25774,9.30869],[52.258369,9.30952],[52.259209,9.31058],[52.26017,9.31164],[52.261101,9.31259],[52.26149,9.31296],[52.26339,9.31468],[52.26498,9.31612],[52.26535,9.31651],[52.26646,9.31788],[52.267059,9.31869],[52.267681,9.31962],[52.268299,9.32062],[52.268822,9.32155],[52.269459,9.32285],[52.273449,9.33127],[52.274132,9.33276],[52.274872,9.3343],[52.275391,9.33547],[52.278141,9.34138],[52.278709,9.34251],[52.279369,9.34372],[52.280022,9.34479],[52.28017,9.34507],[52.28112,9.34654],[52.28614,9.3543],[52.287659,9.35666],[52.288509,9.35787],[52.289421,9.35901],[52.289719,9.35935],[52.291088,9.36072],[52.292488,9.36198],[52.292671,9.36213],[52.302601,9.37094],[52.319118,9.38574],[52.321159,9.38775],[52.322319,9.38908],[52.32336,9.39044],[52.324322,9.39183],[52.325069,9.39299],[52.32523,9.39327],[52.325859,9.39436],[52.326618,9.39575],[52.327579,9.39764],[52.328411,9.39929],[52.32859,9.39964],[52.329109,9.4006],[52.329769,9.40172],[52.330891,9.40352],[52.332241,9.40555],[52.333649,9.4077],[52.333889,9.40806],[52.33432,9.40873],[52.335529,9.41062],[52.335838,9.41112],[52.336159,9.41163],[52.337959,9.41435],[52.338539,9.41519],[52.339409,9.41632],[52.340111,9.41712],[52.34082,9.41784],[52.34166,9.4186],[52.342659,9.41942],[52.343609,9.42004],[52.344292,9.42046],[52.347092,9.42214],[52.34774,9.42256],[52.348728,9.4233],[52.349461,9.42388],[52.350231,9.42454],[52.351101,9.42534],[52.353039,9.42715],[52.357361,9.43114],[52.35881,9.43264],[52.359692,9.43366],[52.367809,9.44407],[52.369389,9.4463],[52.37072,9.44836],[52.370861,9.44859],[52.37278,9.45184],[52.37532,9.45624],[52.377548,9.4601],[52.38052,9.46524],[52.38113,9.46629],[52.381649,9.46712],[52.382561,9.46848],[52.383499,9.4698],[52.388901,9.4772],[52.39045,9.47932],[52.396099,9.48702],[52.39711,9.48859],[52.398029,9.49015],[52.401131,9.49559],[52.406521,9.50506],[52.407982,9.50763],[52.409161,9.50972],[52.410191,9.51151],[52.41164,9.51406],[52.413311,9.51703],[52.41428,9.51884],[52.415138,9.52054],[52.41576,9.52185],[52.416382,9.52326],[52.416969,9.52472],[52.417488,9.52615],[52.41803,9.52775],[52.41877,9.53015],[52.419331,9.53233],[52.419689,9.53391],[52.419991,9.53553],[52.420319,9.53729],[52.42057,9.53902],[52.42078,9.54093],[52.420971,9.54285],[52.421131,9.54533],[52.42131,9.54945],[52.421459,9.55652],[52.421551,9.55856],[52.42165,9.56019],[52.421909,9.56349],[52.422329,9.56859],[52.42276,9.57334],[52.42281,9.57401],[52.423309,9.58008],[52.423458,9.58243],[52.423489,9.58307],[52.423561,9.58555],[52.423592,9.5876],[52.42358,9.58984],[52.423519,9.59303],[52.423229,9.59739],[52.421131,9.61986],[52.42091,9.62265],[52.420811,9.62446],[52.420792,9.62634],[52.420811,9.62772],[52.420872,9.6294],[52.421051,9.63173],[52.421242,9.63346],[52.421619,9.63605],[52.422058,9.6385],[52.424,9.64852],[52.42527,9.6551],[52.42683,9.66314],[52.427429,9.66629],[52.4282,9.67028],[52.428421,9.67169],[52.428612,9.67311],[52.428921,9.67626],[52.429321,9.68156],[52.429611,9.68496],[52.430241,9.69297],[52.430389,9.69674],[52.43042,9.69946],[52.430401,9.70035],[52.430248,9.70318],[52.43,9.70612],[52.42923,9.71208],[52.429001,9.71376],[52.42823,9.72024],[52.427898,9.72294],[52.427872,9.72335],[52.427551,9.72654],[52.427441,9.72852],[52.427441,9.72884],[52.427391,9.73166],[52.427391,9.73378],[52.42738,9.74271],[52.42725,9.74974],[52.427189,9.75209],[52.427189,9.75226],[52.427071,9.75852],[52.427059,9.75878],[52.426979,9.76416],[52.426979,9.76718],[52.42709,9.7718],[52.427219,9.77332],[52.427471,9.77608],[52.42757,9.77697],[52.42802,9.78012],[52.42849,9.78298],[52.42894,9.78534],[52.4296,9.78852],[52.43013,9.7913],[52.430309,9.79236],[52.43084,9.79586],[52.431061,9.79878],[52.43108,9.80093],[52.43108,9.80136],[52.431061,9.80156],[52.431011,9.80331],[52.430851,9.80506],[52.43058,9.80699],[52.429859,9.81081],[52.42926,9.81314],[52.427879,9.81772],[52.42767,9.81826],[52.427589,9.81848],[52.42622,9.82272],[52.42561,9.82427],[52.425179,9.8253],[52.4244,9.82718],[52.42313,9.82991],[52.421791,9.83242],[52.421059,9.83371],[52.420341,9.83493],[52.419991,9.83549],[52.41695,9.84032],[52.41547,9.84266],[52.414028,9.84502],[52.41272,9.84724],[52.412521,9.84753],[52.412201,9.84809],[52.411758,9.84889],[52.410969,9.85049],[52.40963,9.8534],[52.40897,9.85474],[52.4067,9.85982],[52.406231,9.8608],[52.404419,9.8647],[52.402882,9.86814],[52.4021,9.87012],[52.40136,9.87221],[52.40065,9.87454],[52.40015,9.87635],[52.399601,9.87873],[52.39933,9.88],[52.399101,9.8813],[52.398849,9.88279],[52.39864,9.88436],[52.398048,9.88966],[52.39793,9.89076],[52.397449,9.89538],[52.39716,9.89822],[52.396938,9.90041],[52.39613,9.90822],[52.39547,9.91468],[52.39489,9.91989],[52.394291,9.92539],[52.392899,9.93625],[52.392502,9.93943],[52.391991,9.94348],[52.391129,9.95032],[52.390652,9.95501],[52.390388,9.95814],[52.389771,9.96834],[52.38966,9.97063],[52.38961,9.97158],[52.389488,9.97431],[52.38945,9.97521],[52.389271,9.97919],[52.389179,9.98179],[52.388851,9.98807],[52.388741,9.98972],[52.38866,9.99068],[52.38855,9.99183],[52.388371,9.99334],[52.38826,9.9942],[52.388031,9.99557],[52.38776,9.99715],[52.387428,9.99872],[52.38665,10.00213],[52.386589,10.00236],[52.384411,10.01166],[52.384232,10.01243],[52.383591,10.01513],[52.38287,10.01818],[52.38216,10.02108],[52.381931,10.02194],[52.380798,10.02608],[52.37854,10.03394],[52.37793,10.03613],[52.375851,10.0434],[52.36834,10.06986],[52.367668,10.07246],[52.367241,10.07433],[52.366859,10.07654],[52.366489,10.079],[52.366112,10.08264],[52.364349,10.10102],[52.363918,10.10537],[52.363731,10.10793],[52.363621,10.11056],[52.363522,10.11825],[52.363491,10.12034],[52.363461,10.12095],[52.3634,10.12439],[52.36322,10.12821],[52.362869,10.13312],[52.362389,10.13806],[52.361851,10.14326],[52.361752,10.14428],[52.36092,10.15225],[52.36026,10.15861],[52.3587,10.17429],[52.358459,10.17639],[52.35775,10.18056],[52.357601,10.18136],[52.35696,10.18402],[52.356331,10.18616],[52.355492,10.18883],[52.35437,10.19165],[52.34618,10.20908],[52.342449,10.21785],[52.341831,10.21931],[52.340672,10.22211],[52.340179,10.22335],[52.33963,10.2249],[52.339489,10.22534],[52.33881,10.22759],[52.33831,10.2295],[52.337898,10.23125],[52.33733,10.23424],[52.336891,10.23742],[52.336781,10.23822],[52.33654,10.24093],[52.336449,10.2429],[52.336418,10.24385],[52.336399,10.24622],[52.33654,10.25446],[52.33659,10.25766],[52.336559,10.2601],[52.33646,10.2636],[52.336189,10.26843],[52.335072,10.28774],[52.334919,10.29107],[52.334919,10.29154],[52.335011,10.29579],[52.33514,10.29783],[52.33543,10.30059],[52.33551,10.30138],[52.338169,10.32413],[52.339352,10.33431],[52.339642,10.33706],[52.339771,10.33882],[52.339809,10.33951],[52.339931,10.3423],[52.339939,10.34619],[52.339771,10.35151],[52.339378,10.36378],[52.339321,10.36578],[52.339298,10.36685],[52.339039,10.3733],[52.33876,10.37846],[52.338699,10.37918],[52.33749,10.39397],[52.33744,10.39459],[52.337231,10.39709],[52.337078,10.39883],[52.33704,10.39933],[52.33699,10.39991],[52.336658,10.40373],[52.336601,10.40446],[52.335541,10.41656],[52.33511,10.41984],[52.33482,10.42191],[52.33448,10.42399],[52.33408,10.42626],[52.333401,10.43028],[52.331501,10.44129],[52.330391,10.44793],[52.32967,10.4525],[52.32896,10.45634],[52.326759,10.46555],[52.32547,10.47095],[52.324322,10.4756],[52.321678,10.48679],[52.320992,10.48957],[52.320641,10.49099],[52.316238,10.50933],[52.315941,10.51061],[52.314949,10.51487],[52.314602,10.51663],[52.314301,10.51826],[52.31406,10.51997],[52.313622,10.52316],[52.31337,10.52554],[52.313339,10.5259],[52.313229,10.52723],[52.31316,10.52956],[52.313171,10.53276],[52.31321,10.53498],[52.313221,10.53566],[52.313061,10.55503],[52.313049,10.55618],[52.31303,10.55924],[52.31303,10.56007],[52.313,10.56157],[52.312969,10.5638],[52.31292,10.56636],[52.312801,10.57008],[52.312691,10.57225],[52.31237,10.57724],[52.312019,10.58152],[52.310211,10.60278],[52.310032,10.60504],[52.309978,10.60568],[52.309872,10.60751],[52.30978,10.60984],[52.3097,10.61282],[52.309689,10.61409],[52.3097,10.61489],[52.309761,10.61923],[52.309769,10.62277],[52.309761,10.62736],[52.30975,10.62812],[52.30975,10.62927],[52.3097,10.63306],[52.309689,10.63377],[52.309689,10.63433],[52.309471,10.65566],[52.30938,10.66094],[52.308651,10.68318],[52.308578,10.6847],[52.308189,10.6965],[52.30817,10.69703],[52.30814,10.6977],[52.307961,10.70307],[52.307949,10.70368],[52.307869,10.70846],[52.30788,10.7108],[52.307961,10.71448],[52.307968,10.71477],[52.30806,10.71921],[52.30817,10.7233],[52.3083,10.72591],[52.308521,10.72918],[52.309261,10.736],[52.31052,10.74826],[52.31287,10.76876],[52.313519,10.77534],[52.313702,10.77924],[52.313702,10.7817],[52.313629,10.78393],[52.312489,10.79746],[52.312439,10.79808],[52.312309,10.79964],[52.311661,10.80753],[52.31155,10.80886],[52.311489,10.80955],[52.311218,10.81283],[52.310982,10.81575],[52.310928,10.81642],[52.310619,10.82023],[52.310299,10.82408],[52.31007,10.82577],[52.309681,10.82813],[52.30938,10.82972],[52.308922,10.83178],[52.308781,10.8324],[52.308571,10.83322],[52.307831,10.83578],[52.30703,10.83832],[52.306911,10.83871],[52.30648,10.84012],[52.30463,10.84596],[52.29977,10.86152],[52.299469,10.8625],[52.29797,10.86634],[52.29623,10.87042],[52.29607,10.8708],[52.290569,10.88392],[52.290298,10.88454],[52.289761,10.88581],[52.287991,10.89006],[52.286442,10.89384],[52.28561,10.89616],[52.284981,10.89818],[52.28405,10.90174],[52.283741,10.90314],[52.283581,10.90391],[52.283199,10.90601],[52.283039,10.90711],[52.282848,10.90841],[52.2827,10.9098],[52.28249,10.91186],[52.282211,10.91447],[52.28194,10.91689],[52.281818,10.91823],[52.281689,10.91955],[52.281521,10.92115],[52.281342,10.92276],[52.281239,10.92347],[52.281101,10.92451],[52.280941,10.92543],[52.28067,10.92687],[52.280579,10.92729],[52.280411,10.92808],[52.280281,10.92867],[52.27998,10.92985],[52.279621,10.93119],[52.278999,10.93321],[52.278809,10.93376],[52.27845,10.93479],[52.27808,10.93571],[52.277599,10.93683],[52.274021,10.94491],[52.272881,10.94751],[52.272579,10.94815],[52.272388,10.94866],[52.271629,10.95055],[52.271149,10.95184],[52.270691,10.9532],[52.270409,10.95412],[52.269989,10.9559],[52.269711,10.95711],[52.269402,10.95878],[52.269051,10.96101],[52.26873,10.96379],[52.268589,10.96511],[52.268459,10.96648],[52.26825,10.96781],[52.268051,10.96897],[52.267792,10.97028],[52.26746,10.97173],[52.267109,10.97311],[52.266541,10.97495],[52.2659,10.97686],[52.26535,10.97857],[52.264729,10.98044],[52.264431,10.98125],[52.264069,10.98226],[52.263611,10.98342],[52.26334,10.98406],[52.26302,10.9848],[52.26265,10.98559],[52.262428,10.98599],[52.261951,10.98683],[52.261559,10.98751],[52.260738,10.98882],[52.26009,10.98974],[52.25935,10.99068],[52.258259,10.99194],[52.258091,10.99214],[52.25774,10.99256],[52.25737,10.99298],[52.256519,10.99397],[52.25563,10.99497],[52.254391,10.99625],[52.25322,10.99741],[52.25264,10.99793],[52.25235,10.99823],[52.251209,10.99934],[52.250229,11.00027],[52.250031,11.00046],[52.24955,11.00092],[52.247181,11.0032],[52.246609,11.00382],[52.246151,11.00434],[52.245621,11.00498],[52.24514,11.0056],[52.244751,11.00613],[52.244381,11.00663],[52.24419,11.0069],[52.243999,11.00721],[52.24379,11.00755],[52.24321,11.00858],[52.242661,11.00965],[52.242088,11.01079],[52.241951,11.01111],[52.24165,11.01174],[52.240669,11.01376],[52.24049,11.01413],[52.24007,11.01488],[52.239738,11.01546],[52.23951,11.01586],[52.239281,11.01623],[52.238449,11.01743],[52.237862,11.01826],[52.237492,11.01872],[52.23708,11.01926],[52.236061,11.02047],[52.235901,11.02068],[52.235519,11.02112],[52.23484,11.02197],[52.23436,11.02264],[52.233879,11.0233],[52.232819,11.02502],[52.23238,11.02578],[52.232151,11.02621],[52.2318,11.02692],[52.231319,11.02796],[52.23064,11.02948],[52.22974,11.03148],[52.226608,11.03863],[52.224251,11.04442],[52.222542,11.04881],[52.22213,11.04988],[52.221722,11.0509],[52.21994,11.05556],[52.219559,11.05661],[52.219021,11.05819],[52.218639,11.05949],[52.218262,11.06097],[52.217609,11.06406],[52.217312,11.06595],[52.21701,11.06904],[52.216759,11.07434],[52.216389,11.08081],[52.21616,11.08396],[52.21582,11.08679],[52.215549,11.08848],[52.215321,11.08966],[52.215,11.091],[52.21471,11.09206],[52.21439,11.09308],[52.214119,11.09393],[52.213581,11.09541],[52.213032,11.097],[52.212528,11.09842],[52.2122,11.09948],[52.211971,11.10029],[52.211639,11.10148],[52.21032,11.10647],[52.209942,11.10794],[52.209572,11.10945],[52.209259,11.11086],[52.209019,11.11196],[52.208809,11.11301],[52.20853,11.11437],[52.20821,11.11676],[52.208031,11.11851],[52.20726,11.1314],[52.207218,11.13201],[52.20718,11.1333],[52.20715,11.13446],[52.207142,11.13474],[52.207142,11.13663],[52.20723,11.13807],[52.207298,11.1391],[52.208012,11.14741],[52.20826,11.1505],[52.208382,11.15266],[52.208431,11.15428],[52.208389,11.15683],[52.20826,11.15952],[52.20808,11.16168],[52.207748,11.16434],[52.207439,11.16667],[52.207272,11.16756],[52.204609,11.17897],[52.204288,11.18041],[52.20369,11.18307],[52.20295,11.18697],[52.202518,11.19054],[52.202309,11.19309],[52.201889,11.20136],[52.201839,11.20206],[52.200691,11.22617],[52.200531,11.23064],[52.20031,11.23465],[52.20018,11.23625],[52.19997,11.23853],[52.199551,11.24218],[52.199379,11.24359],[52.198601,11.24932],[52.198441,11.2506],[52.196831,11.26289],[52.196758,11.26343],[52.19664,11.26425],[52.19611,11.2682],[52.195919,11.26956],[52.195831,11.27021],[52.192509,11.29526],[52.192451,11.29572],[52.191921,11.2998],[52.191681,11.30193],[52.191631,11.30242],[52.19038,11.31644],[52.188,11.34272],[52.18729,11.35063],[52.18716,11.35227],[52.187069,11.35391],[52.187012,11.35556],[52.186981,11.35735],[52.186951,11.35924],[52.186958,11.36334],[52.187,11.36713],[52.18713,11.38555],[52.18718,11.38968],[52.18718,11.38998],[52.187191,11.39058],[52.187191,11.39091],[52.18721,11.39275],[52.18779,11.41141],[52.187809,11.41185],[52.187962,11.41739],[52.18808,11.42094],[52.188099,11.42154],[52.18819,11.425],[52.18829,11.42803],[52.188339,11.43127],[52.18832,11.43313],[52.18821,11.43495],[52.188049,11.43668],[52.187771,11.43853],[52.18734,11.44089],[52.186981,11.44246],[52.186001,11.44599],[52.185928,11.44622],[52.185829,11.44653],[52.183041,11.45638],[52.181412,11.46197],[52.17691,11.47781],[52.176159,11.4802],[52.175781,11.48138],[52.175251,11.48278],[52.174389,11.48491],[52.173431,11.48724],[52.17202,11.49069],[52.168011,11.50037],[52.16666,11.50414],[52.166458,11.50475],[52.16629,11.50537],[52.16589,11.50676],[52.165611,11.50802],[52.165359,11.50931],[52.165161,11.51038],[52.16502,11.51134],[52.164791,11.51371],[52.1647,11.51587],[52.16468,11.5163],[52.16465,11.51743],[52.164669,11.5184],[52.164742,11.51996],[52.16489,11.52163],[52.165058,11.52326],[52.165119,11.52365],[52.165421,11.52569],[52.166439,11.53267],[52.166611,11.53392],[52.167339,11.53867],[52.167439,11.53937],[52.169441,11.55281],[52.16991,11.55575],[52.170231,11.55711],[52.170559,11.55839],[52.171291,11.56133],[52.17382,11.57087],[52.175751,11.57812],[52.178219,11.58746],[52.182308,11.603],[52.183929,11.60919],[52.185032,11.61315],[52.185822,11.61628],[52.186619,11.61919],[52.187531,11.62238],[52.188011,11.62375],[52.18858,11.62524],[52.18866,11.62546],[52.18959,11.62733],[52.190868,11.62959],[52.192478,11.63237],[52.199959,11.6454],[52.200359,11.64613],[52.20084,11.64695],[52.201038,11.64729],[52.20842,11.66016],[52.208679,11.66065],[52.209332,11.66179],[52.21109,11.66484],[52.21154,11.66565],[52.211788,11.66607],[52.213799,11.66959],[52.215851,11.67339],[52.216461,11.67478],[52.217049,11.67633],[52.217369,11.67731],[52.217579,11.67796],[52.217838,11.67877],[52.218311,11.68052],[52.21854,11.68151],[52.21909,11.6844],[52.219452,11.68751],[52.219749,11.69092],[52.220051,11.69427],[52.221161,11.70682],[52.22168,11.71211],[52.222061,11.71632],[52.223511,11.73166],[52.223629,11.73272],[52.223759,11.73362],[52.225361,11.74258],[52.22699,11.75169],[52.22805,11.75741],[52.228409,11.75924],[52.228741,11.76117],[52.229019,11.76374],[52.229149,11.76571],[52.229179,11.76778],[52.22897,11.77192],[52.227791,11.7904],[52.22768,11.79214],[52.2276,11.79329],[52.227291,11.79804],[52.226688,11.80733],[52.22665,11.80793],[52.226009,11.81791],[52.225689,11.82334],[52.225529,11.82563],[52.22541,11.82819],[52.22543,11.83002],[52.225471,11.83125],[52.225559,11.83267],[52.225651,11.83379],[52.227291,11.84773],[52.232201,11.88916],[52.23251,11.89181],[52.232639,11.89276],[52.232731,11.89358],[52.233051,11.89658],[52.23336,11.89995],[52.233601,11.90274],[52.233768,11.90531],[52.233879,11.90798],[52.234348,11.92429],[52.234779,11.94053],[52.235249,11.95714],[52.235409,11.96376],[52.2356,11.97119],[52.235748,11.97729],[52.23579,11.97894],[52.235771,11.98051],[52.235699,11.98249],[52.235432,11.98812],[52.235081,11.99699],[52.234341,12.01401],[52.233761,12.02773],[52.233421,12.03474],[52.233101,12.04213],[52.232632,12.05301],[52.232609,12.0542],[52.23262,12.05541],[52.23267,12.05675],[52.232841,12.0587],[52.23296,12.06002],[52.233101,12.06113],[52.233459,12.06384],[52.233681,12.06548],[52.233768,12.0661],[52.24308,12.13948],[52.2439,12.14593],[52.249649,12.19065],[52.252121,12.21038],[52.25235,12.21264],[52.252441,12.2143],[52.252491,12.21691],[52.252319,12.2199],[52.249069,12.25665],[52.248631,12.26174],[52.24828,12.2661],[52.24699,12.28226],[52.24678,12.28543],[52.246658,12.2885],[52.24675,12.29159],[52.246891,12.29349],[52.247169,12.29568],[52.24765,12.29831],[52.24847,12.30145],[52.248791,12.30246],[52.249241,12.30368],[52.2495,12.30437],[52.249821,12.30523],[52.253349,12.31351],[52.253639,12.31419],[52.26292,12.33628],[52.263882,12.33891],[52.264481,12.34107],[52.26495,12.34305],[52.265339,12.34523],[52.267719,12.36252],[52.277241,12.4319],[52.27755,12.43401],[52.278061,12.43658],[52.278561,12.43851],[52.279259,12.4407],[52.2799,12.44244],[52.280529,12.44386],[52.281189,12.44522],[52.281849,12.4464],[52.28727,12.45523],[52.289341,12.45825],[52.290829,12.46031],[52.292488,12.46235],[52.295609,12.46595],[52.299759,12.47067],[52.304459,12.47609],[52.30703,12.47905],[52.30975,12.48217],[52.312519,12.48525],[52.314991,12.48782],[52.318409,12.49088],[52.323139,12.49511],[52.326832,12.49837],[52.33028,12.50148],[52.333721,12.50458],[52.335201,12.50586],[52.335838,12.50645],[52.336571,12.50723],[52.337528,12.5084],[52.33836,12.50953],[52.339062,12.51066],[52.340118,12.51264],[52.340401,12.51326],[52.340809,12.51413],[52.341591,12.51603],[52.342892,12.51968],[52.344269,12.52359],[52.347919,12.53389],[52.348782,12.53666],[52.349419,12.53922],[52.349751,12.54055],[52.349819,12.5409],[52.350552,12.54517],[52.35088,12.54797],[52.351059,12.55027],[52.351181,12.55295],[52.351189,12.55519],[52.351158,12.55847],[52.35107,12.56422],[52.350922,12.57661],[52.350681,12.59304],[52.350632,12.59599],[52.35059,12.59717],[52.350498,12.5986],[52.35041,12.59981],[52.350182,12.60171],[52.349911,12.60367],[52.349659,12.60507],[52.34938,12.60644],[52.348999,12.60803],[52.348122,12.61133],[52.344818,12.62296],[52.34457,12.62384],[52.344391,12.62446],[52.34346,12.62779],[52.342911,12.62973],[52.34272,12.63038],[52.33942,12.64209],[52.339191,12.64297],[52.338009,12.64715],[52.33754,12.64889],[52.33662,12.65224],[52.33625,12.6537],[52.335899,12.65536],[52.33567,12.65673],[52.335419,12.65854],[52.3353,12.65974],[52.335209,12.66093],[52.335152,12.66218],[52.335121,12.66309],[52.335129,12.66403],[52.335171,12.6655],[52.33527,12.66721],[52.335411,12.66883],[52.336739,12.68137],[52.336811,12.68207],[52.33744,12.68802],[52.337521,12.68873],[52.338161,12.69472],[52.33852,12.6982],[52.338631,12.69936],[52.338799,12.70087],[52.339081,12.70356],[52.339729,12.70973],[52.339951,12.71174],[52.340092,12.71322],[52.34016,12.7143],[52.34021,12.71555],[52.340221,12.71697],[52.340179,12.71834],[52.340111,12.71968],[52.34005,12.72069],[52.34,12.72143],[52.339859,12.72375],[52.33979,12.72533],[52.339771,12.72611],[52.339729,12.72804],[52.339642,12.73175],[52.339588,12.73409],[52.339611,12.73499],[52.339661,12.73628],[52.339729,12.73744],[52.340691,12.75166],[52.341099,12.7577],[52.341141,12.75848],[52.341209,12.75966],[52.34127,12.76134],[52.341259,12.76291],[52.341171,12.76464],[52.341049,12.76608],[52.340149,12.7758],[52.339111,12.78689],[52.338871,12.78991],[52.338409,12.79716],[52.338299,12.79892],[52.338009,12.80411],[52.33791,12.80584],[52.33783,12.80681],[52.337711,12.80768],[52.337509,12.80871],[52.33728,12.8097],[52.33696,12.8107],[52.33646,12.81194],[52.336109,12.81268],[52.33569,12.81338],[52.33519,12.81405],[52.33503,12.81426],[52.334839,12.81447],[52.334141,12.81513],[52.333599,12.81561],[52.332981,12.81612],[52.332359,12.81673],[52.331921,12.81723],[52.331402,12.81794],[52.330929,12.81869],[52.330479,12.81961],[52.33017,12.8204],[52.32988,12.82124],[52.328949,12.82439],[52.327759,12.82837],[52.324871,12.83843],[52.322739,12.84587],[52.320759,12.85271],[52.320202,12.85459],[52.319859,12.85564],[52.31958,12.85649],[52.31926,12.85738],[52.318802,12.85852],[52.318409,12.85941],[52.317501,12.8613],[52.31609,12.86413],[52.313278,12.86984],[52.31123,12.874],[52.31044,12.87558],[52.310322,12.87582],[52.309509,12.87753],[52.306961,12.8826],[52.305679,12.88513],[52.298168,12.90026],[52.297329,12.90199],[52.29649,12.90364],[52.295471,12.90573],[52.292488,12.9117],[52.291592,12.91353],[52.291409,12.91394],[52.291069,12.91483],[52.29092,12.9154],[52.290779,12.91593],[52.29063,12.91674],[52.29052,12.91769],[52.290482,12.91831],[52.290451,12.91879],[52.290451,12.91924],[52.290482,12.91992],[52.290581,12.92099],[52.290749,12.92183],[52.29097,12.92274],[52.291271,12.92371],[52.291809,12.92508],[52.29211,12.92599],[52.292511,12.92743],[52.292961,12.92949],[52.298199,12.95228],[52.299309,12.95707],[52.301849,12.96836],[52.30249,12.97116],[52.302849,12.97277],[52.30302,12.97345],[52.303169,12.9741],[52.303341,12.97503],[52.303471,12.97595],[52.303539,12.97658],[52.3036,12.97733],[52.303638,12.97817],[52.303379,13.00804],[52.303349,13.00964],[52.303322,13.01115],[52.303261,13.01224],[52.303169,13.01321],[52.30304,13.01414],[52.302879,13.01503],[52.30267,13.01593],[52.30154,13.01991],[52.30014,13.02485],[52.299999,13.02532],[52.299839,13.02589],[52.29945,13.0273],[52.299179,13.02828],[52.298981,13.029],[52.298851,13.02948],[52.298691,13.03007],[52.298599,13.03051],[52.298489,13.031],[52.298409,13.0315],[52.298351,13.03191],[52.298302,13.03235],[52.29826,13.03275],[52.298229,13.03316],[52.298222,13.03357],[52.29821,13.03402],[52.29821,13.03448],[52.29821,13.03477],[52.298229,13.03535],[52.298248,13.03579],[52.298309,13.03639],[52.29837,13.03689],[52.29847,13.0375],[52.29858,13.03805],[52.298691,13.0386],[52.298889,13.0393],[52.299019,13.03977],[52.29924,13.04038],[52.30006,13.04263],[52.300331,13.04338],[52.30048,13.04386],[52.300621,13.04441],[52.300739,13.04491],[52.300819,13.04535],[52.300911,13.04586],[52.30098,13.04634],[52.301041,13.04686],[52.30109,13.04735],[52.301121,13.04784],[52.30114,13.04834],[52.30114,13.04896],[52.300999,13.05311],[52.300701,13.06163],[52.300671,13.06223],[52.300499,13.06709],[52.300159,13.07772],[52.30011,13.07952],[52.300049,13.08123],[52.30003,13.08219],[52.30006,13.08293],[52.300091,13.08362],[52.300129,13.08421],[52.300179,13.08472],[52.300228,13.0852],[52.300331,13.08582],[52.300541,13.08696],[52.30196,13.09434],[52.302139,13.09526],[52.302261,13.09585],[52.302559,13.09734],[52.30267,13.09799],[52.30275,13.09857],[52.30283,13.09933],[52.30286,13.09979],[52.302898,13.10039],[52.302921,13.10091],[52.302929,13.10139],[52.302921,13.10196],[52.302879,13.10399],[52.302631,13.11285],[52.30257,13.11635],[52.30254,13.11712],[52.302391,13.12387],[52.302311,13.12553],[52.301029,13.14169],[52.300968,13.14249],[52.30085,13.14398],[52.300831,13.14447],[52.300812,13.14488],[52.300812,13.14539],[52.3008,13.14592],[52.30085,13.15346],[52.300819,13.15558],[52.3008,13.15612],[52.300781,13.15662],[52.300739,13.15714],[52.300209,13.16418],[52.299351,13.17524],[52.298931,13.18064],[52.29892,13.18097],[52.298908,13.18142],[52.298908,13.1821],[52.29892,13.18257],[52.298931,13.18301],[52.298962,13.18349],[52.299,13.18391],[52.299042,13.18431],[52.299091,13.18475],[52.299149,13.18519],[52.299221,13.18569],[52.299301,13.18608],[52.29937,13.18646],[52.299431,13.18678],[52.299561,13.18732],[52.30003,13.18925],[52.30019,13.18995],[52.30151,13.1953],[52.301579,13.19566],[52.30167,13.19612],[52.301731,13.19652],[52.3018,13.19693],[52.301849,13.1973],[52.301899,13.19773],[52.301929,13.19806],[52.30196,13.19841],[52.301979,13.19887],[52.30201,13.19935],[52.302021,13.19977],[52.302021,13.20011],[52.30201,13.20053],[52.30201,13.20089],[52.301998,13.20135],[52.301891,13.20437],[52.301739,13.20819],[52.30159,13.21251],[52.30143,13.21658],[52.301399,13.21761],[52.30101,13.22814],[52.300629,13.23876],[52.300362,13.24577],[52.300339,13.24618],[52.300331,13.24667],[52.30032,13.24713],[52.30032,13.24761],[52.30032,13.24802],[52.300331,13.24849],[52.30035,13.24896],[52.300369,13.24944],[52.300419,13.24996],[52.300461,13.25048],[52.300529,13.25102],[52.300598,13.25154],[52.300701,13.25207],[52.300812,13.25259],[52.300919,13.25312],[52.301041,13.2536],[52.30117,13.25409],[52.301331,13.25467],[52.302052,13.25682],[52.303631,13.26149],[52.306171,13.26909],[52.306549,13.27018],[52.307129,13.27192],[52.307289,13.27238],[52.30743,13.27285],[52.307571,13.27335],[52.307701,13.27383],[52.307819,13.2743],[52.307941,13.27481],[52.308048,13.27532],[52.30814,13.27581],[52.308239,13.27632],[52.308319,13.2768],[52.308392,13.27732],[52.308449,13.27784],[52.30851,13.27835],[52.308559,13.27889],[52.30859,13.27942],[52.308601,13.27994],[52.308609,13.28048],[52.30862,13.281],[52.308601,13.28153],[52.308571,13.28206],[52.308552,13.28255],[52.308498,13.28311],[52.30801,13.28764],[52.30764,13.2907],[52.307468,13.2923],[52.30743,13.29283],[52.307388,13.29332],[52.307369,13.29385],[52.30735,13.29491],[52.307259,13.2995],[52.307259,13.29988],[52.30722,13.30167],[52.307178,13.30244],[52.306789,13.30749],[52.30616,13.31553],[52.30563,13.32229],[52.305561,13.32336],[52.305519,13.32442],[52.3055,13.32547],[52.3055,13.32656],[52.305531,13.3276],[52.30558,13.32869],[52.30566,13.32976],[52.305771,13.33087],[52.305901,13.33203],[52.305969,13.33278],[52.306438,13.33712],[52.30653,13.33803],[52.307461,13.3466],[52.307571,13.34768],[52.307659,13.34873],[52.307709,13.34979],[52.307739,13.35073],[52.307751,13.35086],[52.307758,13.35191],[52.30769,13.36154],[52.30769,13.36237],[52.30761,13.37333],[52.30759,13.37434],[52.307549,13.37523],[52.307499,13.37612],[52.30743,13.37713],[52.306961,13.38394],[52.3069,13.38485],[52.306709,13.38766],[52.306549,13.38997],[52.30653,13.39038],[52.306259,13.39469],[52.30616,13.39737],[52.30603,13.40509],[52.305882,13.4151],[52.305882,13.41575],[52.305851,13.41721],[52.30584,13.41831],[52.305801,13.42242],[52.305828,13.42609],[52.305851,13.42757],[52.305931,13.43275],[52.30603,13.43915],[52.30608,13.44054],[52.306141,13.44131],[52.30616,13.4416],[52.306229,13.44238],[52.30629,13.4429],[52.306641,13.44551],[52.306839,13.4466],[52.307899,13.45187],[52.308128,13.45298],[52.30838,13.45421],[52.308769,13.45611],[52.30912,13.45786],[52.309681,13.46055],[52.309719,13.46078],[52.310341,13.4639],[52.310459,13.4645],[52.311951,13.47177],[52.312611,13.47496],[52.312679,13.47535],[52.314789,13.48567],[52.315231,13.48783],[52.316971,13.49645],[52.317291,13.49799],[52.317951,13.50123],[52.3186,13.50442],[52.31881,13.50564],[52.318932,13.50642],[52.319031,13.50718],[52.319141,13.50822],[52.31921,13.50916],[52.31926,13.51001],[52.319302,13.51074],[52.319309,13.51155],[52.319321,13.51231],[52.319309,13.51293],[52.31929,13.51368],[52.319229,13.51505],[52.318851,13.52142],[52.318569,13.52585],[52.318359,13.52936],[52.31831,13.53107],[52.318279,13.53268],[52.31834,13.53601],[52.318371,13.53704],[52.318588,13.54471],[52.318771,13.55087],[52.31889,13.55457],[52.31889,13.55478],[52.318951,13.55658],[52.31897,13.55785],[52.319111,13.56125],[52.319141,13.56241],[52.319351,13.56982],[52.319481,13.57375],[52.319611,13.57905],[52.319679,13.58139],[52.319679,13.58179],[52.319672,13.58228],[52.319649,13.58274],[52.31963,13.58324],[52.319592,13.58371],[52.31953,13.58429],[52.319469,13.58477],[52.319401,13.5853],[52.319302,13.58579],[52.319199,13.5863],[52.319111,13.58674],[52.318981,13.58716],[52.318878,13.58758],[52.318771,13.588],[52.3186,13.58854],[52.318409,13.58908],[52.314541,13.59834],[52.313011,13.60187],[52.312778,13.60244],[52.31237,13.60355],[52.312092,13.60442],[52.311699,13.60583],[52.311562,13.60662],[52.31144,13.60741],[52.31134,13.60828],[52.311218,13.60965],[52.311131,13.61102],[52.310959,13.61394],[52.310749,13.61685],[52.310581,13.61942],[52.31041,13.62219],[52.310219,13.62503],[52.310089,13.62699],[52.31007,13.6275],[52.31007,13.62845],[52.31007,13.62939],[52.310169,13.63121],[52.310249,13.63253],[52.31028,13.63349],[52.310299,13.63427],[52.31039,13.63698],[52.31065,13.64389],[52.310699,13.64603],[52.310829,13.64817],[52.31089,13.64904],[52.311039,13.65133],[52.311359,13.65437],[52.311451,13.65497],[52.311939,13.65849],[52.312649,13.66256],[52.312679,13.6627],[52.312778,13.66331],[52.31284,13.66363],[52.313709,13.66821],[52.31422,13.67078],[52.316711,13.68074],[52.318481,13.68853],[52.32093,13.69869],[52.323811,13.71061],[52.324039,13.71157],[52.324181,13.71243],[52.324329,13.71357],[52.324421,13.7144],[52.324478,13.71538],[52.324501,13.7164],[52.32439,13.72013],[52.32423,13.72539],[52.324211,13.72651],[52.324032,13.73115],[52.323959,13.73364],[52.323719,13.73806],[52.323471,13.74205],[52.32333,13.74668],[52.32317,13.75164],[52.323151,13.75306],[52.323158,13.7541],[52.3232,13.75505],[52.323231,13.75592],[52.323261,13.7567],[52.32328,13.75751],[52.32328,13.75826],[52.323261,13.75934],[52.323231,13.76009],[52.32309,13.76171],[52.323009,13.76277],[52.32291,13.76362],[52.322769,13.76464],[52.322479,13.76632],[52.321991,13.76899],[52.321259,13.77266],[52.320969,13.7741],[52.319851,13.77939],[52.31921,13.78262],[52.318939,13.78396],[52.318501,13.78613],[52.317551,13.79078],[52.317509,13.79102],[52.317341,13.79181],[52.317108,13.7929],[52.31657,13.79519],[52.315449,13.79977],[52.315079,13.80129],[52.313332,13.80844],[52.31131,13.81651],[52.310841,13.81912],[52.310638,13.82042],[52.31049,13.8217],[52.310379,13.82292],[52.310299,13.8241],[52.310242,13.82523],[52.310211,13.82659],[52.310211,13.82763],[52.31028,13.82919],[52.31039,13.83102],[52.310612,13.83456],[52.310829,13.83808],[52.311031,13.84117],[52.312199,13.85973],[52.312481,13.86492],[52.31292,13.8716],[52.313129,13.87394],[52.3134,13.87599],[52.31377,13.87848],[52.315659,13.8905],[52.316002,13.89283],[52.316109,13.89382],[52.316139,13.89395],[52.316231,13.89513],[52.316341,13.89711],[52.31636,13.89782],[52.316368,13.89843],[52.316368,13.89941],[52.316368,13.89974],[52.316319,13.9008],[52.316299,13.90126],[52.31628,13.90146],[52.316231,13.90217],[52.3162,13.90265],[52.31612,13.9035],[52.316051,13.90423],[52.315929,13.90506],[52.315769,13.90622],[52.31554,13.90753],[52.315449,13.90808],[52.31525,13.90935],[52.314678,13.91243],[52.313839,13.91717],[52.313591,13.91856],[52.313251,13.9206],[52.313,13.92272],[52.312859,13.92457],[52.312672,13.92828],[52.312469,13.93198],[52.31221,13.93685],[52.31189,13.94362],[52.311821,13.94501],[52.311699,13.94711],[52.3116,13.94925],[52.311531,13.95186],[52.311501,13.95388],[52.31152,13.95569],[52.31155,13.95647],[52.31155,13.95723],[52.31155,13.95759],[52.3116,13.95848],[52.311649,13.95939],[52.31171,13.96051],[52.31189,13.9633],[52.311958,13.96403],[52.312031,13.96476],[52.312111,13.96553],[52.312309,13.9676],[52.312679,13.97042],[52.313519,13.97695],[52.31419,13.98221],[52.315079,13.98901],[52.31559,13.99114],[52.316631,13.99535],[52.320641,14.01003],[52.321388,14.01278],[52.32254,14.01699],[52.327091,14.03302],[52.327888,14.03549],[52.32877,14.03817],[52.329361,14.03994],[52.329639,14.04085],[52.329868,14.04185],[52.330509,14.0449],[52.331181,14.04833],[52.332371,14.05431],[52.333389,14.0594],[52.33419,14.0635],[52.334278,14.06416],[52.334389,14.06499],[52.33445,14.06608],[52.33448,14.06779],[52.334492,14.06882],[52.334499,14.06961],[52.33453,14.0718],[52.33461,14.07611],[52.334621,14.07673],[52.334629,14.07948],[52.334641,14.0799],[52.33469,14.08319],[52.334709,14.08396],[52.33493,14.09404],[52.335129,14.10164],[52.335171,14.10379],[52.3353,14.10977],[52.33532,14.11047],[52.335442,14.1153],[52.335579,14.12059],[52.335781,14.12908],[52.335941,14.13594],[52.336109,14.14278],[52.336159,14.14419],[52.336269,14.14563],[52.336399,14.14698],[52.33659,14.14847],[52.336849,14.15005],[52.33704,14.15106],[52.337559,14.15323],[52.33905,14.15899],[52.33989,14.16224],[52.340832,14.16591],[52.342758,14.17332],[52.343319,14.17564],[52.343731,14.17809],[52.34388,14.18072],[52.343811,14.18341],[52.34338,14.18688],[52.342838,14.18988],[52.341709,14.19427],[52.340618,14.19713],[52.338531,14.20352],[52.337429,14.20914],[52.337021,14.2144],[52.336578,14.22596],[52.335991,14.24164],[52.33585,14.24464],[52.335499,14.24766],[52.334919,14.2509],[52.334171,14.25369],[52.333778,14.25489],[52.333649,14.25527],[52.332611,14.25821],[52.330059,14.2653],[52.328659,14.26944],[52.328289,14.27081],[52.32753,14.27394],[52.327179,14.27573],[52.326401,14.27954],[52.325371,14.28448],[52.324718,14.2877],[52.324291,14.29105],[52.32399,14.29796],[52.323471,14.31189],[52.32296,14.32586],[52.322208,14.34336],[52.322159,14.3474],[52.322029,14.35058],[52.321739,14.359],[52.321239,14.37253],[52.32095,14.37974],[52.320938,14.38024],[52.320881,14.38183],[52.32056,14.39143],[52.32029,14.39804],[52.32019,14.40253],[52.320221,14.41164],[52.32032,14.42128],[52.3204,14.43098],[52.320591,14.44889],[52.32069,14.45717],[52.320679,14.46126],[52.320641,14.46375],[52.320591,14.46598],[52.32053,14.46934],[52.320431,14.47422],[52.320419,14.475],[52.320358,14.47841],[52.32019,14.48646],[52.320011,14.49741],[52.31992,14.50324],[52.319832,14.50629],[52.319721,14.50929],[52.319519,14.51284],[52.319302,14.51651],[52.319069,14.51992],[52.318989,14.5207],[52.31889,14.52167],[52.318729,14.52265],[52.318451,14.52381],[52.318111,14.52488],[52.317699,14.52601],[52.316898,14.52836],[52.316601,14.52915],[52.316311,14.52992],[52.31617,14.53036],[52.315948,14.53115],[52.315681,14.53209],[52.315552,14.53266],[52.315231,14.53412],[52.314899,14.53588],[52.31472,14.53705],[52.314548,14.53846],[52.314442,14.53961],[52.31435,14.54102],[52.314289,14.54354],[52.31432,14.54571],[52.314381,14.54728],[52.314388,14.54786],[52.31451,14.55143],[52.314579,14.55382],[52.31461,14.55563],[52.314621,14.55709],[52.31459,14.56008],[52.314548,14.56303],[52.314499,14.56659],[52.314579,14.56822],[52.314789,14.57063],[52.314919,14.57244],[52.315189,14.57603],[52.31538,14.57823],[52.31575,14.582],[52.316051,14.5845],[52.316212,14.58597],[52.316299,14.58661],[52.316368,14.58724],[52.316441,14.58844],[52.316521,14.58954],[52.316681,14.59023],[52.316879,14.59181],[52.31699,14.59264],[52.31889,14.59981],[52.320629,14.60601],[52.322411,14.61267],[52.323078,14.6152],[52.32394,14.61827],[52.32452,14.62057],[52.324692,14.62123],[52.325001,14.62245],[52.325611,14.62534],[52.32589,14.6274],[52.326092,14.6291],[52.326199,14.63064],[52.326248,14.63312],[52.32616,14.63536],[52.325989,14.63746],[52.325851,14.63898],[52.325691,14.64077],[52.325489,14.64297],[52.325272,14.64536],[52.324631,14.65187],[52.324131,14.65751],[52.323959,14.66148],[52.32394,14.66456],[52.324268,14.66852],[52.324959,14.67386],[52.325951,14.68193],[52.32679,14.68798],[52.32782,14.69577],[52.328308,14.69948],[52.3284,14.69984],[52.3288,14.70276],[52.32935,14.70716],[52.329762,14.71018],[52.33012,14.71311],[52.33057,14.71611],[52.330719,14.71743],[52.33099,14.71987],[52.331348,14.72298],[52.331509,14.72419],[52.332329,14.73033],[52.33297,14.7351],[52.333672,14.73998],[52.334278,14.74597],[52.334839,14.74961],[52.335121,14.75285],[52.33532,14.75599],[52.335251,14.76015],[52.335251,14.76259],[52.335251,14.76802],[52.335281,14.77738],[52.335312,14.78783],[52.335312,14.79524],[52.335312,14.8001],[52.335121,14.80287],[52.33474,14.80595],[52.334,14.80992],[52.3326,14.81719],[52.331188,14.82469],[52.33181,14.82495],[52.332211,14.82512],[52.336479,14.82671],[52.33667,14.82695],[52.3367,14.82708],[52.336899,14.82746],[52.337959,14.83174],[52.33971,14.84149],[52.339722,14.8423],[52.339249,14.84258],[52.337952,14.84265],[52.33688,14.84286],[52.33585,14.8435],[52.334579,14.84484],[52.332611,14.84689],[52.33099,14.84875],[52.329708,14.84906],[52.329891,14.85048],[52.32983,14.85069],[52.329731,14.85084],[52.329269,14.85094],[52.32988,14.85503],[52.331451,14.8649],[52.332531,14.87174],[52.333229,14.87593],[52.333488,14.87793],[52.333511,14.87955],[52.333382,14.88108],[52.33308,14.8827],[52.33213,14.88645],[52.329849,14.89468],[52.327461,14.90341],[52.32626,14.90796],[52.325859,14.90951],[52.324551,14.91448],[52.323891,14.91709],[52.32333,14.92519],[52.322842,14.93262],[52.32272,14.93431],[52.32272,14.93545],[52.322701,14.93746],[52.322601,14.94129],[52.322571,14.94231],[52.322529,14.94388],[52.322491,14.94485],[52.3223,14.94668],[52.322048,14.94901],[52.322102,14.95146],[52.32214,14.95324],[52.323261,14.96119],[52.323551,14.96432],[52.32428,14.96949],[52.324532,14.97133],[52.325459,14.97816],[52.325851,14.98161],[52.326069,14.98478],[52.326172,14.9859],[52.326431,14.99044],[52.32671,14.9952],[52.327068,15.00165],[52.327141,15.00297],[52.32748,15.00926],[52.327492,15.01057],[52.3274,15.01196],[52.327202,15.0133],[52.326889,15.01427],[52.32626,15.01541],[52.326038,15.01612],[52.325581,15.01866],[52.325211,15.01991],[52.323639,15.02362],[52.321442,15.02881],[52.319618,15.03303],[52.31826,15.03632],[52.317959,15.03744],[52.317749,15.03856],[52.317539,15.03964],[52.317451,15.04015],[52.317299,15.04102],[52.3172,15.04158],[52.31712,15.04197],[52.31575,15.05026],[52.314671,15.05675],[52.31459,15.05757],[52.314362,15.0613],[52.314308,15.06239],[52.314129,15.06768],[52.314129,15.06804],[52.314018,15.07221],[52.314011,15.07287],[52.314011,15.07321],[52.31406,15.07634],[52.31406,15.07645],[52.31403,15.07699],[52.313969,15.07741],[52.313759,15.07815],[52.31358,15.07869],[52.313381,15.07915],[52.313061,15.07986],[52.31271,15.08079],[52.312401,15.08214],[52.312351,15.08315],[52.312359,15.0838],[52.3125,15.0857],[52.312778,15.08879],[52.313099,15.09145],[52.313129,15.09244],[52.313122,15.09307],[52.312889,15.09459],[52.312592,15.09667],[52.31163,15.10237],[52.311291,15.10456],[52.311131,15.10562],[52.3102,15.11167],[52.309429,15.1158],[52.309212,15.11783],[52.307449,15.12917],[52.305851,15.13853],[52.305531,15.14046],[52.305679,15.1434],[52.30682,15.15571],[52.307621,15.16481],[52.30814,15.16976],[52.308449,15.17354],[52.308491,15.17476],[52.30835,15.17634],[52.307598,15.18076],[52.30743,15.18192],[52.30706,15.18441],[52.306221,15.19006],[52.305679,15.19367],[52.305141,15.19727],[52.304531,15.20115],[52.304321,15.20249],[52.30415,15.20363],[52.304161,15.20518],[52.304138,15.2125],[52.304081,15.21744],[52.30415,15.22173],[52.304062,15.22459],[52.30323,15.22903],[52.302021,15.23598],[52.300991,15.24142],[52.300159,15.24576],[52.299431,15.24963],[52.299141,15.25119],[52.298908,15.25245],[52.298779,15.25318],[52.297981,15.25758],[52.296871,15.26387],[52.296539,15.26546],[52.296162,15.26735],[52.29599,15.26859],[52.296009,15.27042],[52.296291,15.27157],[52.296638,15.27262],[52.297279,15.27445],[52.29789,15.27607],[52.29921,15.27976],[52.299759,15.28133],[52.300079,15.28318],[52.300201,15.28427],[52.300282,15.28585],[52.30032,15.28881],[52.30032,15.29367],[52.300098,15.30026],[52.29995,15.30136],[52.29969,15.30273],[52.29908,15.30553],[52.296902,15.31165],[52.29541,15.31585],[52.293541,15.32154],[52.29134,15.32788],[52.290749,15.32981],[52.290359,15.33222],[52.290199,15.33807],[52.28923,15.34195],[52.286598,15.34702],[52.282909,15.35303],[52.28138,15.35526],[52.28064,15.35622],[52.279541,15.35927],[52.278992,15.36026],[52.278389,15.36093],[52.277431,15.36179],[52.276669,15.36254],[52.276081,15.36362],[52.274551,15.36875],[52.272739,15.37466],[52.2714,15.37907],[52.270931,15.38053],[52.270679,15.38137],[52.269402,15.38597],[52.268921,15.38743],[52.26889,15.38753],[52.268349,15.38872],[52.267929,15.38954],[52.266949,15.39075],[52.265129,15.39281],[52.263699,15.39487],[52.262249,15.39781],[52.26144,15.39949],[52.260139,15.4022],[52.258701,15.40485],[52.257919,15.40721],[52.257301,15.41013],[52.257069,15.41427],[52.25671,15.41949],[52.256142,15.42734],[52.255051,15.44218],[52.254669,15.44881],[52.253799,15.45979],[52.253811,15.46035],[52.253769,15.4612],[52.25412,15.46642],[52.254219,15.46799],[52.254169,15.469],[52.254028,15.47212],[52.25436,15.47424],[52.254292,15.47588],[52.25423,15.47617],[52.253578,15.47933],[52.25301,15.48252],[52.25317,15.4857],[52.253681,15.488],[52.255531,15.49359],[52.256592,15.49689],[52.25745,15.49939],[52.258282,15.50201],[52.25943,15.50561],[52.259819,15.50713],[52.260269,15.51073],[52.26046,15.51246],[52.26078,15.51575],[52.26115,15.5193],[52.261292,15.52025],[52.261452,15.52155],[52.262089,15.5273],[52.262291,15.52977],[52.262249,15.53163],[52.26223,15.53312],[52.26202,15.5332],[52.261929,15.53345],[52.261971,15.53376],[52.26215,15.53395],[52.261848,15.5347],[52.260761,15.53751],[52.260719,15.53759],[52.260151,15.53888],[52.256161,15.5487],[52.255932,15.54923],[52.255569,15.5501],[52.252998,15.55644],[52.252178,15.55843],[52.251789,15.56074],[52.2519,15.56195],[52.25211,15.56461],[52.253609,15.57056],[52.2556,15.57819],[52.256821,15.58265],[52.256802,15.5835],[52.257481,15.5857],[52.25787,15.58713],[52.25988,15.59026],[52.26302,15.5945],[52.266281,15.5992],[52.268742,15.60275],[52.271172,15.6061],[52.272129,15.60787],[52.272579,15.60917],[52.273281,15.61221],[52.274811,15.61984],[52.275711,15.62407],[52.277569,15.63269],[52.278252,15.63792],[52.27877,15.64118],[52.279442,15.64462],[52.280972,15.64746],[52.283218,15.64905],[52.285912,15.65071],[52.287239,15.65119],[52.289459,15.6513],[52.293442,15.6511],[52.295109,15.65142],[52.297279,15.65219],[52.299271,15.65359],[52.30196,15.65767],[52.303341,15.65965],[52.305401,15.66148],[52.308849,15.66356],[52.31028,15.66424],[52.311329,15.66496],[52.312618,15.66619],[52.31633,15.66969],[52.31855,15.67166],[52.319462,15.67272],[52.320271,15.67374],[52.320709,15.67491],[52.321201,15.67633],[52.32132,15.67753],[52.321419,15.67846],[52.321331,15.68024],[52.32106,15.68229],[52.32103,15.68387],[52.321301,15.68584],[52.321831,15.68795],[52.322472,15.69054],[52.322781,15.69181],[52.32394,15.69626],[52.3269,15.70543],[52.32933,15.71288],[52.33041,15.71597],[52.33242,15.72132],[52.332859,15.72245],[52.332901,15.72256],[52.332939,15.72267],[52.333858,15.72466],[52.33744,15.73182],[52.33881,15.73474],[52.33939,15.73652],[52.339828,15.73898],[52.341141,15.74844],[52.341801,15.75126],[52.342041,15.75225],[52.342319,15.75323],[52.342739,15.75468],[52.34322,15.75633],[52.34446,15.76096],[52.344971,15.76281],[52.345161,15.7647],[52.34523,15.76731],[52.344761,15.77811],[52.344379,15.78276],[52.34428,15.78559],[52.344429,15.78784],[52.344711,15.78962],[52.3451,15.79201],[52.345829,15.7957],[52.346882,15.7995],[52.347641,15.8022],[52.3503,15.81156],[52.3531,15.82158],[52.353291,15.82229],[52.353619,15.82347],[52.356079,15.83324],[52.35796,15.84103],[52.358109,15.84228],[52.35828,15.84537],[52.358429,15.84972],[52.35873,15.85273],[52.358829,15.85334],[52.358891,15.85361],[52.359669,15.85557],[52.36055,15.85676],[52.36179,15.85789],[52.36377,15.8595],[52.36541,15.86088],[52.366211,15.86172],[52.36718,15.86298],[52.36763,15.86378],[52.36797,15.86447],[52.368431,15.86563],[52.368519,15.86592],[52.36887,15.86689],[52.370312,15.87259],[52.37077,15.87381],[52.37096,15.87428],[52.37191,15.87661],[52.372532,15.87872],[52.372829,15.88037],[52.37294,15.88168],[52.372929,15.88325],[52.372398,15.88678],[52.37236,15.88699],[52.371841,15.89046],[52.371609,15.89246],[52.371269,15.89542],[52.371078,15.89704],[52.371719,15.903],[52.37233,15.9084],[52.372551,15.90929],[52.373058,15.91025],[52.373959,15.91201],[52.37439,15.9134],[52.37508,15.91632],[52.375851,15.91963],[52.376381,15.92256],[52.377209,15.92803],[52.37722,15.92961],[52.376469,15.93341],[52.37648,15.93775],[52.3764,15.93848],[52.375511,15.94449],[52.375252,15.94754],[52.375278,15.94982],[52.375629,15.95385],[52.375751,15.95709],[52.375839,15.95888],[52.375851,15.9591],[52.375912,15.96079],[52.37608,15.96312],[52.37645,15.96516],[52.377838,15.97023],[52.379761,15.97643],[52.379902,15.97828],[52.37991,15.97955],[52.379452,15.98388],[52.380009,15.99173],[52.380421,15.99552],[52.380459,15.99832],[52.38055,16.001459],[52.380169,16.00466],[52.379589,16.007641],[52.378349,16.01523],[52.376911,16.02301],[52.376369,16.02775],[52.376301,16.02907],[52.376301,16.03022],[52.376331,16.032221],[52.376431,16.035379],[52.376789,16.04607],[52.377239,16.057249],[52.377392,16.06572],[52.377522,16.07852],[52.37772,16.09374],[52.37756,16.09358],[52.377369,16.093679],[52.377289,16.09392],[52.3773,16.09408],[52.375912,16.09433],[52.374691,16.094549],[52.3713,16.09503],[52.37112,16.09507],[52.366039,16.096029],[52.36264,16.096661],[52.36253,16.097219],[52.362289,16.09865],[52.36216,16.099291],[52.361931,16.099661],[52.36129,16.09997],[52.360569,16.100269],[52.360031,16.10107],[52.359779,16.102039],[52.359699,16.10269],[52.3596,16.103861],[52.359631,16.104851],[52.36039,16.10857],[52.36195,16.117229],[52.362999,16.123461],[52.36385,16.130489],[52.364521,16.136801],[52.365608,16.147249],[52.367062,16.161501],[52.367298,16.16527],[52.36742,16.168301],[52.367451,16.172119],[52.367611,16.185591],[52.36763,16.187149],[52.367821,16.19273],[52.368038,16.19655],[52.368622,16.20146],[52.36945,16.20701],[52.372471,16.222179],[52.375481,16.238211],[52.375839,16.24123],[52.376221,16.244749],[52.376629,16.249599],[52.37714,16.26313],[52.37738,16.270679],[52.377781,16.279659],[52.37822,16.288481],[52.379379,16.309139],[52.380039,16.32155],[52.38118,16.34289],[52.381981,16.356291],[52.38266,16.36916],[52.38324,16.37723],[52.383869,16.383631],[52.38559,16.396589],[52.38728,16.408449],[52.388142,16.41563],[52.388851,16.42271],[52.389351,16.428341],[52.38969,16.434139],[52.39006,16.44529],[52.390018,16.448879],[52.389881,16.453251],[52.389729,16.45645],[52.3895,16.459141],[52.38924,16.46138],[52.388569,16.46607],[52.387341,16.47382],[52.38707,16.47554],[52.386841,16.477989],[52.386749,16.479481],[52.3867,16.48031],[52.386551,16.483351],[52.386478,16.486731],[52.38657,16.491039],[52.386761,16.494961],[52.387081,16.49999],[52.387459,16.50783],[52.387501,16.511551],[52.387451,16.514919],[52.387249,16.520399],[52.3867,16.52607],[52.38604,16.531031],[52.385269,16.5352],[52.384708,16.53763],[52.383999,16.540649],[52.38084,16.55183],[52.37812,16.56093],[52.3773,16.563681],[52.376591,16.56605],[52.373539,16.575661],[52.370152,16.584909],[52.3647,16.59923],[52.360741,16.60952],[52.357101,16.61961],[52.35582,16.62454],[52.355042,16.628139],[52.353432,16.638],[52.35215,16.64694],[52.350979,16.654249],[52.35059,16.656679],[52.349979,16.660419],[52.349369,16.664169],[52.34903,16.66687],[52.348579,16.67141],[52.348389,16.67975],[52.34893,16.691719],[52.349468,16.70499],[52.349819,16.713869],[52.349899,16.715731],[52.35001,16.718731],[52.350319,16.726601],[52.350422,16.729759],[52.350491,16.73181],[52.350491,16.73185],[52.350491,16.731979],[52.350491,16.736811],[52.350491,16.74202],[52.350479,16.75079],[52.350521,16.761419],[52.350479,16.77059],[52.35043,16.778931],[52.35046,16.795071],[52.35033,16.81012],[52.3503,16.826269],[52.350319,16.83869],[52.35041,16.841261],[52.350609,16.84532],[52.350651,16.846121],[52.35088,16.849079],[52.35112,16.85165],[52.35257,16.863581],[52.354179,16.876539],[52.3545,16.879709],[52.354691,16.88483],[52.354698,16.88644],[52.354641,16.888269],[52.354519,16.89225],[52.354389,16.89537],[52.354179,16.897949],[52.35379,16.901699],[52.353741,16.90243],[52.353352,16.90744],[52.35313,16.91028],[52.35281,16.914261],[52.352631,16.916651],[52.352428,16.91897],[52.3521,16.923109],[52.350979,16.937201],[52.349918,16.94964],[52.3494,16.956039],[52.348999,16.961029],[52.348652,16.9655],[52.348,16.973419],[52.347019,16.98617],[52.346531,16.99177],[52.345741,17.0009],[52.345322,17.004881],[52.345009,17.007601],[52.344269,17.01376],[52.34333,17.0207],[52.342529,17.0254],[52.34095,17.034031],[52.337791,17.049919],[52.334721,17.0646],[52.331821,17.078711],[52.329639,17.087839],[52.32906,17.090099],[52.32856,17.09207],[52.327869,17.094801],[52.326542,17.099489],[52.324188,17.107441],[52.32201,17.114479],[52.318722,17.12499],[52.31752,17.12882],[52.31514,17.136431],[52.312561,17.144501],[52.311531,17.1478],[52.311031,17.14967],[52.310692,17.150949],[52.310612,17.1513],[52.310101,17.15361],[52.309872,17.15439],[52.309158,17.157721],[52.308281,17.163059],[52.307789,17.166821],[52.307411,17.170919],[52.307159,17.17539],[52.307072,17.179951],[52.307159,17.18524],[52.30761,17.190941],[52.307919,17.19392],[52.30904,17.201851],[52.309639,17.20735],[52.310059,17.212879],[52.310219,17.223009],[52.310131,17.24172],[52.310131,17.25379],[52.310059,17.265499],[52.310009,17.2722],[52.31004,17.278469],[52.310001,17.296169],[52.309929,17.305731],[52.309929,17.32172],[52.309841,17.34235],[52.309818,17.35442],[52.30991,17.357189],[52.310108,17.362419],[52.311218,17.376181],[52.311531,17.37855],[52.312019,17.38233],[52.312881,17.38825],[52.314861,17.399639],[52.317001,17.41197],[52.317711,17.417191],[52.318211,17.421301],[52.318691,17.42766],[52.31892,17.4317],[52.319038,17.436029],[52.31905,17.440769],[52.318821,17.454201],[52.31863,17.468769],[52.318409,17.48267],[52.31818,17.49605],[52.317921,17.50906],[52.317699,17.51322],[52.316971,17.521919],[52.316311,17.526711],[52.31567,17.530861],[52.315208,17.53367],[52.31498,17.53483],[52.314461,17.53759],[52.31406,17.539631],[52.313801,17.540899],[52.31295,17.54521],[52.312279,17.548889],[52.31216,17.549549],[52.311619,17.55254],[52.31144,17.553499],[52.310799,17.55788],[52.31052,17.56024],[52.3102,17.563971],[52.30999,17.56748],[52.30975,17.57126],[52.30954,17.574511],[52.30933,17.57836],[52.309101,17.58201],[52.30883,17.58531],[52.308441,17.588831],[52.307899,17.592569],[52.30722,17.596371],[52.306309,17.600479],[52.305389,17.6045],[52.304482,17.60854],[52.303532,17.612631],[52.302601,17.61665],[52.301689,17.620621],[52.300812,17.624559],[52.299938,17.628269],[52.299042,17.63216],[52.298119,17.6362],[52.297241,17.639971],[52.29636,17.64382],[52.295509,17.64756],[52.294621,17.65148],[52.293709,17.65538],[52.29277,17.659121],[52.29174,17.662821],[52.290619,17.666571],[52.289539,17.66995],[52.288361,17.673321],[52.287079,17.67683],[52.285419,17.68096],[52.284302,17.683741],[52.282619,17.687811],[52.281368,17.690929],[52.279861,17.694639],[52.27853,17.697969],[52.27705,17.70166],[52.275711,17.70507],[52.274361,17.70862],[52.272991,17.712521],[52.271801,17.716221],[52.270828,17.719391],[52.26992,17.72262],[52.269112,17.72566],[52.268009,17.73033],[52.267029,17.73484],[52.266171,17.739389],[52.26545,17.74361],[52.264851,17.74773],[52.264339,17.75156],[52.26395,17.755159],[52.263531,17.75952],[52.2631,17.764071],[52.262661,17.76853],[52.262291,17.77253],[52.261848,17.776291],[52.261261,17.780161],[52.260521,17.78458],[52.259731,17.78904],[52.25893,17.7936],[52.258129,17.79822],[52.25724,17.80298],[52.256351,17.80759],[52.25547,17.81222],[52.254551,17.81682],[52.25354,17.82229],[52.25312,17.824261],[52.252941,17.82514],[52.25259,17.82683],[52.252419,17.827629],[52.251381,17.83252],[52.2509,17.83478],[52.249779,17.83993],[52.248749,17.84458],[52.247639,17.84947],[52.246498,17.85438],[52.245319,17.8594],[52.24419,17.86404],[52.24305,17.868641],[52.24176,17.8738],[52.240639,17.87789],[52.239029,17.88295],[52.23682,17.889059],[52.235039,17.894119],[52.23349,17.898911],[52.23222,17.903549],[52.23119,17.90774],[52.23016,17.91255],[52.229259,17.91707],[52.228359,17.921789],[52.22744,17.92672],[52.226559,17.931179],[52.225601,17.935749],[52.224491,17.940611],[52.223751,17.943661],[52.22287,17.946989],[52.222279,17.949011],[52.221851,17.95014],[52.221439,17.951441],[52.221069,17.953329],[52.22031,17.956221],[52.218899,17.96109],[52.2174,17.966471],[52.216011,17.97163],[52.21492,17.97599],[52.21381,17.980471],[52.212631,17.98546],[52.21167,17.98987],[52.210781,17.99387],[52.20961,17.99971],[52.20866,18.004471],[52.20779,18.008881],[52.206749,18.013941],[52.20602,18.017241],[52.205151,18.02088],[52.204651,18.02261],[52.204361,18.023609],[52.203629,18.026171],[52.20158,18.032551],[52.199871,18.03726],[52.198181,18.04203],[52.196732,18.046591],[52.19548,18.051359],[52.19442,18.056259],[52.19352,18.06118],[52.19257,18.06632],[52.19146,18.07118],[52.190239,18.075649],[52.18866,18.080429],[52.187099,18.085381],[52.18586,18.09009],[52.1847,18.094481],[52.183529,18.099291],[52.182571,18.10388],[52.181751,18.108379],[52.180939,18.11359],[52.180149,18.11895],[52.17931,18.124451],[52.178391,18.12904],[52.177391,18.133511],[52.176289,18.13798],[52.175289,18.142071],[52.174252,18.146379],[52.173119,18.15097],[52.172169,18.15522],[52.171021,18.160151],[52.17004,18.164909],[52.169079,18.1696],[52.168129,18.17441],[52.16724,18.179291],[52.166359,18.18424],[52.165501,18.18927],[52.164799,18.193991],[52.164261,18.19729],[52.163601,18.201611],[52.163479,18.202221],[52.163288,18.203501],[52.162941,18.205879],[52.162628,18.20842],[52.162441,18.210489],[52.162209,18.212669],[52.162029,18.21505],[52.161758,18.218439],[52.161381,18.223881],[52.161018,18.229349],[52.160629,18.234871],[52.160221,18.24069],[52.15979,18.24567],[52.15921,18.250759],[52.158298,18.256281],[52.157089,18.26198],[52.15686,18.262859],[52.156521,18.264111],[52.156021,18.26605],[52.155621,18.26754],[52.155529,18.267851],[52.153629,18.273861],[52.151821,18.279779],[52.151131,18.28227],[52.150261,18.28594],[52.149189,18.29163],[52.14827,18.299],[52.147739,18.303749],[52.147419,18.307131],[52.146671,18.31233],[52.145721,18.31716],[52.14344,18.32645],[52.1422,18.33209],[52.141201,18.3377],[52.14061,18.342541],[52.140171,18.348499],[52.14003,18.353571],[52.140141,18.359501],[52.140388,18.36388],[52.14098,18.369869],[52.141541,18.37516],[52.141998,18.381081],[52.142281,18.386061],[52.142429,18.390619],[52.142551,18.39543],[52.142719,18.40027],[52.14312,18.40498],[52.143608,18.409361],[52.144421,18.414459],[52.145329,18.419029],[52.1464,18.42411],[52.14727,18.42831],[52.148239,18.432989],[52.14922,18.437771],[52.15012,18.4422],[52.150902,18.446541],[52.151581,18.450729],[52.1521,18.4548],[52.152512,18.46007],[52.152641,18.46566],[52.152561,18.470949],[52.152241,18.476339],[52.15163,18.48201],[52.150822,18.487101],[52.149769,18.492439],[52.148651,18.497259],[52.147419,18.502279],[52.1464,18.50639],[52.145149,18.511869],[52.144218,18.516371],[52.14336,18.521139],[52.142601,18.526649],[52.14204,18.531811],[52.14164,18.5376],[52.141411,18.54336],[52.141399,18.54904],[52.141472,18.55442],[52.141609,18.55991],[52.141731,18.565041],[52.141842,18.569691],[52.141979,18.57476],[52.142101,18.57938],[52.14212,18.584629],[52.14204,18.589439],[52.141811,18.594589],[52.141441,18.59964],[52.141029,18.603769],[52.140869,18.60504],[52.140541,18.607731],[52.140091,18.610941],[52.140011,18.61146],[52.139519,18.614491],[52.138969,18.617519],[52.13818,18.62149],[52.13723,18.62561],[52.135731,18.631559],[52.135681,18.63175],[52.134151,18.63732],[52.13364,18.63928],[52.13271,18.64283],[52.13187,18.6465],[52.13039,18.654449],[52.129341,18.660379],[52.128231,18.66544],[52.127201,18.669399],[52.12553,18.674879],[52.123859,18.680531],[52.12262,18.685539],[52.121559,18.691231],[52.121071,18.694349],[52.120071,18.702909],[52.1194,18.708441],[52.118649,18.71439],[52.118198,18.71767],[52.1171,18.723419],[52.116119,18.727289],[52.115021,18.731091],[52.114159,18.733749],[52.112358,18.73856],[52.110241,18.74337],[52.10701,18.74958],[52.104431,18.75449],[52.102268,18.75923],[52.1003,18.76413],[52.09827,18.769489],[52.096371,18.7742],[52.09589,18.775391],[52.094379,18.77862],[52.093109,18.781071],[52.091259,18.78434],[52.089241,18.7875],[52.08601,18.791849],[52.082939,18.79541],[52.080631,18.79825],[52.077099,18.80315],[52.07399,18.80831],[52.072338,18.811621],[52.071739,18.81282],[52.070518,18.81525],[52.0704,18.8155],[52.068199,18.82025],[52.06596,18.82456],[52.063099,18.82938],[52.0588,18.835791],[52.055489,18.840611],[52.052441,18.845091],[52.049061,18.850071],[52.045551,18.85527],[52.042881,18.859631],[52.04081,18.8634],[52.03949,18.8661],[52.038158,18.86907],[52.03714,18.8715],[52.035439,18.8759],[52.034222,18.879629],[52.033932,18.880529],[52.0327,18.88485],[52.031189,18.89113],[52.029381,18.899929],[52.02813,18.906179],[52.026958,18.911909],[52.025688,18.916809],[52.024479,18.92082],[52.02261,18.926399],[52.019821,18.93458],[52.017609,18.941151],[52.015862,18.94672],[52.014771,18.950951],[52.013149,18.95867],[52.011902,18.96446],[52.01046,18.969851],[52.008881,18.974689],[52.006538,18.98114],[52.00449,18.987221],[52.003071,18.991859],[52.001549,18.997669],[52.00045,19.002541],[51.999458,19.00773],[51.998039,19.01741],[51.99765,19.02055],[51.997459,19.02207],[51.99728,19.02351],[51.996399,19.0298],[51.995399,19.035801],[51.995022,19.03763],[51.994659,19.039221],[51.994148,19.04134],[51.99337,19.04438],[51.992531,19.047159],[51.991379,19.050579],[51.989731,19.054779],[51.98848,19.05761],[51.987129,19.0604],[51.985611,19.06324],[51.984531,19.06517],[51.97858,19.075291],[51.975769,19.08061],[51.973869,19.08461],[51.971889,19.08955],[51.970181,19.0944],[51.96793,19.10198],[51.966339,19.10762],[51.964859,19.112471],[51.96376,19.11552],[51.96101,19.12225],[51.95937,19.12607],[51.957458,19.13121],[51.95565,19.137289],[51.954498,19.142019],[51.952572,19.151661],[51.951248,19.15736],[51.94973,19.162621],[51.946812,19.171141],[51.94466,19.177509],[51.94305,19.183149],[51.941799,19.188761],[51.94101,19.193199],[51.940472,19.19698],[51.939911,19.20273],[51.93969,19.20854],[51.93964,19.214411],[51.93972,19.222719],[51.93969,19.22901],[51.93951,19.23262],[51.939289,19.235571],[51.93895,19.239189],[51.938301,19.244301],[51.937191,19.25193],[51.93644,19.25717],[51.935619,19.262699],[51.935001,19.266729],[51.934132,19.271299],[51.932522,19.278561],[51.931179,19.284679],[51.930161,19.289539],[51.92918,19.29582],[51.928619,19.301411],[51.928188,19.309851],[51.92783,19.31459],[51.927368,19.31875],[51.92696,19.321699],[51.92617,19.32612],[51.925098,19.33124],[51.924011,19.336901],[51.92337,19.34087],[51.922699,19.345881],[51.922249,19.349649],[51.922031,19.351789],[51.922001,19.35211],[51.921799,19.354139],[51.9217,19.35556],[51.921539,19.35808],[51.921391,19.360901],[51.921329,19.36195],[51.9212,19.36455],[51.921082,19.37055],[51.921101,19.375401],[51.921139,19.383471],[51.921082,19.38681],[51.920979,19.390619],[51.92075,19.393961],[51.920269,19.39966],[51.91922,19.40678],[51.918449,19.4112],[51.917461,19.41625],[51.91684,19.41865],[51.916069,19.42169],[51.912361,19.432541],[51.910278,19.43788],[51.90992,19.438749],[51.909222,19.44047],[51.90802,19.44343],[51.905972,19.44853],[51.90398,19.45363],[51.902161,19.45896],[51.901321,19.46212],[51.90086,19.464001],[51.900398,19.46608],[51.899971,19.46797],[51.89933,19.4711],[51.898151,19.47998],[51.89793,19.483231],[51.897812,19.48616],[51.89777,19.49305],[51.898151,19.51585],[51.898129,19.516371],[51.898041,19.5182],[51.897861,19.522011],[51.896622,19.536489],[51.889702,19.57382],[51.888969,19.57979],[51.88868,19.58357],[51.888618,19.585079],[51.888519,19.58819],[51.88858,19.591181],[51.888599,19.591881],[51.888729,19.594959],[51.888889,19.598301],[51.889099,19.601311],[51.88942,19.60549],[51.889549,19.60721],[51.88998,19.612881],[51.890079,19.614189],[51.890732,19.623899],[51.89077,19.62446],[51.891209,19.626949],[51.891251,19.627399],[51.891319,19.627939],[51.891418,19.62862],[51.891602,19.62936],[51.89183,19.630011],[51.89201,19.63035],[51.892159,19.63055],[51.892429,19.63093],[51.892792,19.63135],[51.893051,19.631559],[51.893471,19.6318],[51.89389,19.631929],[51.894218,19.631941],[51.894482,19.63191],[51.894711,19.63187],[51.894878,19.631781],[51.895161,19.631651],[51.89534,19.631531],[51.89547,19.631451],[51.895649,19.6313],[51.896198,19.630911],[51.89645,19.63073],[51.896679,19.63059],[51.896992,19.630381],[51.89743,19.630079],[51.898602,19.629339],[51.899212,19.628929],[51.900139,19.628349],[51.901081,19.62775],[51.90221,19.627171],[51.904461,19.62602],[51.90659,19.625019],[51.90855,19.624161],[51.910789,19.62328],[51.911888,19.62302],[51.912621,19.62285],[51.912819,19.62285],[51.913059,19.623051],[51.914322,19.625601],[51.914452,19.62591],[51.914661,19.626341],[51.9161,19.628691],[51.925201,19.644131],[51.925949,19.64506],[51.92897,19.647631],[51.93063,19.64908],[51.931019,19.649509],[51.931149,19.6497],[51.932259,19.652],[51.932751,19.65308],[51.943272,19.676041],[51.94331,19.676121],[51.94688,19.68264],[51.949989,19.68832],[51.95681,19.700911],[51.958549,19.704069],[51.9589,19.70484],[51.959049,19.705549],[51.95969,19.71069],[51.960819,19.723619],[51.96109,19.726681],[51.961231,19.728161],[51.961239,19.728291],[51.961361,19.7293],[51.961571,19.7299],[51.961811,19.7304],[51.962719,19.731529],[51.96312,19.732019],[51.963539,19.73242],[51.964809,19.733271],[51.965191,19.733509],[51.965439,19.73369],[51.965641,19.7339],[51.96574,19.73403],[51.9664,19.735121],[51.970589,19.742229],[51.973179,19.74663],[51.979118,19.75663],[51.993279,19.7805],[51.99371,19.781219],[52.001862,19.79495],[52.002369,19.79583],[52.0056,19.80126],[52.005829,19.8018],[52.006008,19.802219],[52.006229,19.802891],[52.006248,19.802971],[52.006939,19.8053],[52.00761,19.8076],[52.008629,19.811211],[52.008709,19.811489],[52.008808,19.811819],[52.0089,19.812111],[52.00927,19.81325],[52.009628,19.81402],[52.01593,19.82633],[52.023281,19.84086],[52.02507,19.84432],[52.026192,19.846519],[52.039162,19.87204],[52.039261,19.87224],[52.040749,19.87517],[52.041199,19.87606],[52.041538,19.87673],[52.042561,19.878771],[52.042839,19.87924],[52.044312,19.88221],[52.048222,19.88994],[52.04845,19.890381],[52.048969,19.89139],[52.04916,19.891769],[52.049259,19.89193],[52.04937,19.89213],[52.049419,19.892179],[52.04969,19.89249],[52.050049,19.892771],[52.050961,19.893471],[52.05225,19.89448],[52.05455,19.89625],[52.05455,19.896259],[52.059502,19.900061],[52.060539,19.90085],[52.06316,19.90287],[52.068199,19.90674],[52.068508,19.906981],[52.069099,19.907419],[52.07645,19.91301],[52.076649,19.91317],[52.0769,19.91337],[52.076969,19.913429],[52.077579,19.9139],[52.07782,19.91408],[52.07843,19.91453],[52.079029,19.91498],[52.080231,19.915899],[52.08263,19.917749],[52.083,19.91802],[52.08308,19.918079],[52.084671,19.919279],[52.08535,19.9198],[52.085579,19.919941],[52.085819,19.920059],[52.08609,19.920179],[52.086391,19.92024],[52.086731,19.920271],[52.087021,19.920231],[52.087231,19.920231],[52.087421,19.920259],[52.087471,19.920349],[52.087521,19.920389],[52.087582,19.920401],[52.08765,19.92037],[52.087688,19.920309],[52.08773,19.920231],[52.08786,19.92013],[52.088089,19.920059],[52.088181,19.92005],[52.09103,19.91968],[52.091709,19.91959],[52.092682,19.91946],[52.094219,19.919241],[52.095741,19.919029],[52.096741,19.9189],[52.09774,19.91877],[52.09972,19.918501],[52.10078,19.91835],[52.101028,19.91835],[52.101631,19.918409],[52.10215,19.91857],[52.1026,19.918779],[52.10284,19.91894],[52.103149,19.919161],[52.103401,19.91938],[52.103729,19.919701],[52.10397,19.919991],[52.104198,19.92029],[52.10445,19.920679],[52.104691,19.921129],[52.104961,19.92174],[52.105209,19.92234],[52.105961,19.924509],[52.106411,19.92577],[52.107052,19.92757],[52.107109,19.927719],[52.107231,19.928011],[52.107349,19.928221],[52.10754,19.928579],[52.107731,19.92885],[52.107929,19.929119],[52.108089,19.929279],[52.108452,19.929609],[52.10873,19.929819],[52.109039,19.929991],[52.109371,19.93012],[52.109699,19.930189],[52.111229,19.93025],[52.111641,19.930269],[52.11277,19.930321],[52.112801,19.930321],[52.114609,19.930401],[52.116451,19.93051],[52.116501,19.930519],[52.117069,19.93054],[52.11721,19.930559],[52.117699,19.930639],[52.117962,19.93071],[52.118198,19.93082],[52.118259,19.930849],[52.118629,19.931061],[52.1189,19.93124],[52.119511,19.93181],[52.119598,19.93195],[52.11964,19.93211],[52.119652,19.93228],[52.11964,19.932501],[52.11948,19.93355],[52.1194,19.934561],[52.11937,19.934799],[52.119209,19.9359],[52.11879,19.938721],[52.11866,19.939581],[52.118591,19.94043],[52.118462,19.943199],[52.11832,19.94618],[52.118279,19.947439],[52.118191,19.94982],[52.118069,19.952339],[52.118,19.95396],[52.117882,19.95689],[52.11755,19.96439],[52.117512,19.965401],[52.117512,19.96545],[52.117512,19.9655],[52.117458,19.966459],[52.11742,19.967331],[52.117371,19.968451],[52.117241,19.971201],[52.11721,19.97176],[52.11705,19.974291],[52.11705,19.974951],[52.117062,19.97537],[52.117069,19.97596],[52.11718,19.976419],[52.118179,19.980631],[52.12101,19.99221],[52.12315,20.00086],[52.124432,20.006109],[52.125622,20.010969],[52.125771,20.0116],[52.128719,20.02354],[52.13121,20.03376],[52.137619,20.05954],[52.137859,20.06052],[52.140442,20.07085],[52.14724,20.097931],[52.14912,20.105459],[52.150661,20.111549],[52.151909,20.11652],[52.15295,20.120399],[52.153191,20.12104],[52.153542,20.121799],[52.154518,20.12351],[52.155048,20.12418],[52.15556,20.12472],[52.156071,20.125191],[52.163651,20.130739],[52.16431,20.131229],[52.169559,20.13509],[52.17205,20.136921],[52.18475,20.14629],[52.185478,20.146959],[52.18557,20.147079],[52.186081,20.147791],[52.190811,20.155861],[52.195271,20.163349],[52.199051,20.169781],[52.20237,20.17544],[52.203159,20.176781],[52.21146,20.19092],[52.215248,20.197371],[52.217178,20.20079],[52.2178,20.20186],[52.218819,20.203791],[52.21891,20.204121],[52.218868,20.20435],[52.218529,20.2052],[52.21241,20.216709],[52.21188,20.21773],[52.211472,20.218559],[52.211281,20.21888],[52.210812,20.2201],[52.210548,20.22089],[52.210312,20.221519],[52.20911,20.22497],[52.20903,20.22521],[52.207981,20.228109],[52.206749,20.23156],[52.20615,20.23431],[52.206039,20.235769],[52.20602,20.237249],[52.206169,20.23875],[52.206409,20.240061],[52.20697,20.2428],[52.207569,20.24559],[52.207909,20.246861],[52.20834,20.248211],[52.20892,20.249411],[52.209549,20.250441],[52.20974,20.250799],[52.209721,20.250919],[52.20974,20.25104],[52.209789,20.251129],[52.209862,20.251181],[52.20993,20.251181],[52.209969,20.25116],[52.21006,20.2512],[52.210258,20.25141],[52.210758,20.251921],[52.210999,20.252069],[52.212631,20.253281],[52.214298,20.254391],[52.223068,20.26042],[52.22393,20.26133],[52.224411,20.26195],[52.224731,20.26248],[52.225361,20.2637],[52.22538,20.263929],[52.225479,20.264299],[52.225689,20.26482],[52.226009,20.265989],[52.226021,20.26605],[52.226261,20.267429],[52.226398,20.267891],[52.226471,20.26993],[52.226421,20.270821],[52.225651,20.27956],[52.22266,20.312559],[52.220852,20.33256],[52.220421,20.33741],[52.220032,20.34166],[52.219318,20.349609],[52.218319,20.36063],[52.217331,20.371441],[52.21656,20.37977],[52.215939,20.38644],[52.21373,20.41028],[52.2132,20.416161],[52.21209,20.42832],[52.211891,20.430229],[52.2117,20.432301],[52.209419,20.45714],[52.208721,20.46471],[52.206589,20.488091],[52.205059,20.50466],[52.20435,20.512369],[52.204269,20.51329],[52.202881,20.52837],[52.201641,20.54178],[52.201469,20.54582],[52.20039,20.571939],[52.199059,20.60359],[52.19899,20.60586],[52.19899,20.605989],[52.198978,20.60627],[52.198841,20.60903],[52.198799,20.610081],[52.198711,20.612419],[52.198582,20.61577],[52.198528,20.616989],[52.198528,20.61718],[52.198502,20.6178],[52.199001,20.61994],[52.19936,20.62149],[52.19968,20.62286],[52.199902,20.62373],[52.199982,20.62405],[52.200249,20.62512],[52.20163,20.6308],[52.20644,20.650591],[52.207199,20.653879],[52.207699,20.656031],[52.207859,20.656719],[52.208321,20.659109],[52.208889,20.66353],[52.208988,20.66445],[52.21006,20.673531],[52.2113,20.68404],[52.21133,20.684271],[52.211842,20.688919],[52.212139,20.691401],[52.21273,20.69622],[52.212811,20.701071],[52.2118,20.74048],[52.21143,20.75633],[52.211239,20.7649],[52.211151,20.76845],[52.211121,20.769911],[52.21088,20.778219],[52.210678,20.78578],[52.210579,20.788231],[52.21056,20.788971],[52.21051,20.791401],[52.210468,20.793091],[52.210419,20.794769],[52.210381,20.79623],[52.210331,20.797279],[52.210232,20.801121],[52.21014,20.804319],[52.210041,20.80776],[52.209999,20.809271],[52.209999,20.80971],[52.21003,20.81019],[52.210091,20.81061],[52.210178,20.81123],[52.211182,20.817699],[52.21244,20.82584],[52.212551,20.826891],[52.2131,20.83094],[52.213821,20.835529],[52.214272,20.83843],[52.214321,20.838869],[52.214359,20.839069],[52.214451,20.83972],[52.214741,20.841749],[52.21489,20.843809],[52.21524,20.84981],[52.215832,20.859699],[52.215839,20.85993],[52.2159,20.861],[52.215961,20.861971],[52.216,20.8626],[52.216141,20.86487],[52.216148,20.86503],[52.21632,20.86783],[52.216351,20.86927],[52.21637,20.871429],[52.216381,20.873899],[52.216389,20.874929],[52.216381,20.877769],[52.216381,20.880011],[52.21637,20.88043],[52.216381,20.885969],[52.216389,20.8887],[52.216381,20.89061],[52.216358,20.89253],[52.21637,20.89607],[52.216389,20.896629],[52.216431,20.89715],[52.21648,20.89769],[52.216572,20.89847],[52.21677,20.90044],[52.216808,20.90089],[52.216869,20.90147],[52.21693,20.90193],[52.217159,20.904011],[52.217209,20.90428],[52.217579,20.906019],[52.218021,20.90799],[52.218342,20.90933],[52.218399,20.90958],[52.218559,20.910271],[52.219501,20.914419],[52.219879,20.91584],[52.219921,20.91605],[52.219971,20.91625],[52.220039,20.91663],[52.220539,20.91868],[52.221008,20.92062],[52.221161,20.921289],[52.22171,20.92355],[52.221939,20.92453],[52.22208,20.925131],[52.2225,20.926991],[52.222778,20.9282],[52.22319,20.929831],[52.22324,20.930031],[52.223289,20.93021],[52.223671,20.93152],[52.223881,20.93219],[52.224041,20.932739],[52.224998,20.93623],[52.22514,20.93675],[52.225189,20.93696],[52.22562,20.93853],[52.225719,20.939369],[52.225761,20.939659],[52.225788,20.940701],[52.225868,20.941589],[52.22588,20.94166],[52.225929,20.94198],[52.226311,20.94463],[52.226921,20.948071],[52.22739,20.951281],[52.227451,20.95166],[52.227482,20.95199],[52.227638,20.95425],[52.22773,20.95582],[52.22773,20.956141],[52.227692,20.956659],[52.227692,20.95694],[52.227539,20.95694],[52.226009,20.95731],[52.225349,20.957581],[52.2243,20.957781],[52.22422,20.957821],[52.22353,20.957991],[52.22324,20.95809],[52.22245,20.95833],[52.222252,20.95842],[52.222012,20.95859],[52.22086,20.95952],[52.220581,20.95965],[52.22002,20.95978],[52.21814,20.959909],[52.217659,20.95998],[52.216461,20.9606],[52.216331,20.96073],[52.21619,20.96109],[52.216179,20.961399],[52.216221,20.96166],[52.216572,20.962601],[52.21703,20.963711],[52.21759,20.96524],[52.219391,20.970369],[52.219479,20.97084],[52.219479,20.971251],[52.219471,20.971371],[52.21946,20.97147],[52.218948,20.972969],[52.218861,20.973249],[52.21875,20.973551],[52.217621,20.976971],[52.217541,20.977221],[52.217461,20.977461],[52.2164,20.980619],[52.216301,20.980909],[52.21624,20.98107],[52.216228,20.9811],[52.216179,20.981239],[52.21611,20.981449],[52.216042,20.981649],[52.215981,20.981911],[52.215961,20.982149],[52.215969,20.98246],[52.215981,20.982679],[52.216042,20.983801],[52.216061,20.9842],[52.216091,20.98497],[52.216221,20.987],[52.216228,20.98728],[52.216221,20.987591],[52.216209,20.98782],[52.21619,20.98806],[52.216179,20.98838],[52.216179,20.98884],[52.216259,20.989929],[52.21627,20.990259],[52.21632,20.99095],[52.216511,20.99444],[52.216801,20.999901],[52.21682,21.000429],[52.217121,21.004539],[52.21719,21.00563],[52.21727,21.00716],[52.217281,21.00845],[52.217209,21.01022],[52.217159,21.01169],[52.216999,21.01438],[52.216999,21.0149],[52.21703,21.015421],[52.217079,21.01594],[52.217171,21.01647],[52.217449,21.0177],[52.21759,21.01844],[52.21767,21.018801],[52.217861,21.019581],[52.21793,21.01984],[52.218399,21.021761],[52.219059,21.024469],[52.219372,21.02578],[52.219742,21.027309],[52.21994,21.0282],[52.220669,21.03112],[52.221458,21.034109],[52.222229,21.037251],[52.22266,21.03857],[52.223,21.03944],[52.223148,21.039841],[52.223301,21.040211],[52.223511,21.040739],[52.223701,21.04143],[52.223789,21.04184],[52.22403,21.0431],[52.22443,21.045059],[52.225712,21.05121],[52.22612,21.053249],[52.226509,21.055201],[52.22686,21.056789],[52.2271,21.057699],[52.228149,21.061621],[52.228378,21.06255],[52.228901,21.06455],[52.229111,21.065319],[52.229401,21.0665],[52.229889,21.06831],[52.23035,21.07052],[52.230652,21.07151],[52.230831,21.07196],[52.23233,21.074381],[52.233021,21.07556],[52.235081,21.078911],[52.235271,21.079479],[52.235401,21.0802],[52.23547,21.080629],[52.235531,21.081091],[52.235661,21.08217],[52.235889,21.08399],[52.236061,21.08552],[52.236099,21.08663],[52.236099,21.08683],[52.236038,21.087641],[52.235958,21.088421],[52.235771,21.089439],[52.2351,21.093491],[52.234951,21.09482],[52.234871,21.095501],[52.23468,21.097151],[52.234661,21.09741],[52.234631,21.097679],[52.23444,21.099489],[52.23436,21.10021],[52.2342,21.101629],[52.233971,21.10355],[52.23386,21.10463],[52.233768,21.10532],[52.233459,21.10816],[52.233349,21.109051],[52.233059,21.111691],[52.232899,21.113239],[52.232861,21.11352],[52.232681,21.115021],[52.232571,21.116529],[52.232521,21.118191],[52.232521,21.11837],[52.23251,21.118799],[52.232571,21.12027],[52.23259,21.121389],[52.232601,21.12254],[52.23262,21.12421],[52.232639,21.125429],[52.232639,21.126711],[52.232658,21.12788],[52.232651,21.12854],[52.232639,21.129089],[52.232559,21.12974],[52.23243,21.130461],[52.23225,21.131069],[52.23201,21.13171],[52.231602,21.13269],[52.230782,21.134729],[52.23003,21.136499],[52.22971,21.137251],[52.22934,21.138109],[52.22908,21.138691],[52.228691,21.13958],[52.2286,21.139799],[52.228352,21.140369],[52.228039,21.14101],[52.22784,21.14147],[52.227188,21.142929],[52.226871,21.143669],[52.226669,21.14419],[52.226551,21.144661],[52.22644,21.145149],[52.226372,21.14566],[52.226341,21.146231],[52.22628,21.148359],[52.22628,21.14887],[52.226231,21.14978],[52.226181,21.15131],[52.226158,21.152491],[52.22612,21.15346],[52.226101,21.153851],[52.226059,21.15535],[52.225922,21.158939],[52.225891,21.15937],[52.225819,21.161421],[52.225689,21.165609],[52.22551,21.17029],[52.225189,21.17864],[52.224819,21.18928],[52.224529,21.196859],[52.224491,21.198009],[52.22427,21.20554],[52.224072,21.21101],[52.223911,21.21578],[52.223782,21.219891],[52.22369,21.22279],[52.223679,21.22303],[52.223671,21.223289],[52.223629,21.22451],[52.223469,21.229271],[52.223381,21.230721],[52.223301,21.23295],[52.223259,21.23402],[52.22324,21.235041],[52.223179,21.23679],[52.22316,21.237249],[52.223049,21.23951],[52.22303,21.240021],[52.22295,21.243151],[52.222832,21.24703],[52.22274,21.24946],[52.22271,21.24983],[52.222691,21.249929],[52.222679,21.25062],[52.222511,21.255859],[52.222351,21.26104],[52.222309,21.26218],[52.22221,21.26466],[52.222179,21.26539],[52.222149,21.266211],[52.22208,21.267851],[52.22205,21.26918],[52.222038,21.26963],[52.222031,21.26977],[52.222,21.27087],[52.221771,21.277281],[52.2215,21.284731],[52.221481,21.28517],[52.221371,21.287571],[52.221321,21.288719],[52.22113,21.2906],[52.220459,21.293631],[52.219471,21.298019],[52.218601,21.301941],[52.21851,21.302389],[52.21767,21.306379],[52.216961,21.30962],[52.216648,21.311029],[52.215851,21.314739],[52.215611,21.315929],[52.215149,21.3183],[52.213772,21.32457],[52.21249,21.33049],[52.21233,21.331261],[52.211109,21.337],[52.210251,21.34096],[52.209511,21.34437],[52.207809,21.35216],[52.206211,21.35932],[52.20467,21.366529],[52.203072,21.374001],[52.202629,21.377239],[52.202209,21.380011],[52.202202,21.380091],[52.201889,21.38555],[52.201691,21.389219],[52.201439,21.3937],[52.201118,21.401541],[52.200611,21.410839],[52.200291,21.41663],[52.200119,21.42065],[52.199989,21.42417],[52.19978,21.427259],[52.199459,21.43342],[52.19923,21.43766],[52.199169,21.439381],[52.1992,21.44058],[52.1992,21.44236],[52.19923,21.443769],[52.199299,21.446381],[52.199429,21.44973],[52.199451,21.450439],[52.19952,21.452971],[52.19965,21.45809],[52.199871,21.46624],[52.20023,21.475121],[52.20052,21.484421],[52.20063,21.48831],[52.200581,21.490219],[52.200359,21.492001],[52.19994,21.49367],[52.198551,21.49864],[52.19664,21.505899],[52.194981,21.51228],[52.193371,21.51828],[52.192188,21.522989],[52.19175,21.52454],[52.190979,21.527349],[52.190819,21.527321],[52.190689,21.52746],[52.19062,21.527731],[52.19067,21.527941],[52.1908,21.528099],[52.190659,21.52861],[52.190048,21.530781],[52.18895,21.534809],[52.188709,21.53578],[52.188171,21.537849],[52.187778,21.539431],[52.18734,21.540939],[52.187061,21.54196],[52.18692,21.54249],[52.186329,21.544649],[52.18631,21.54475],[52.185612,21.54744],[52.185341,21.54867],[52.18454,21.55163],[52.184219,21.55286],[52.18388,21.55415],[52.183281,21.556311],[52.182911,21.55773],[52.182652,21.55871],[52.18248,21.55938],[52.181751,21.56234],[52.181149,21.564791],[52.18074,21.566441],[52.180698,21.56658],[52.180592,21.566999],[52.18029,21.568159],[52.179909,21.5697],[52.179588,21.571011],[52.179539,21.571159],[52.179329,21.57198],[52.179031,21.57312],[52.17873,21.574301],[52.178398,21.575541],[52.178059,21.57678],[52.178082,21.577339],[52.178169,21.580919],[52.178242,21.58276],[52.178291,21.58411],[52.178299,21.58423],[52.178421,21.589001],[52.178619,21.59437],[52.178791,21.59881],[52.17915,21.609301],[52.17923,21.611561],[52.179581,21.62187],[52.17976,21.626841],[52.18013,21.629681],[52.180229,21.630461],[52.182049,21.644159],[52.183769,21.64847],[52.184509,21.65386],[52.188019,21.68083],[52.192032,21.710409],[52.192532,21.723101],[52.195358,21.743959],[52.20295,21.80003],[52.203152,21.80052],[52.20396,21.802349],[52.206169,21.80718],[52.206692,21.808411],[52.208061,21.81164],[52.208801,21.813181],[52.209278,21.81419],[52.209461,21.81456],[52.210251,21.816771],[52.2104,21.81769],[52.210442,21.820499],[52.210419,21.82181],[52.210251,21.832239],[52.209831,21.861191],[52.209389,21.886351],[52.20929,21.89757],[52.208271,21.907749],[52.20443,21.94763],[52.203869,21.953699],[52.20055,21.98842],[52.197842,22.01725],[52.196651,22.0296],[52.196602,22.0301],[52.195881,22.03702],[52.19558,22.04031],[52.195709,22.042641],[52.197639,22.05447],[52.197762,22.055639],[52.197701,22.05674],[52.197571,22.057659],[52.196949,22.06188],[52.196949,22.061899],[52.19656,22.06428],[52.195641,22.069839],[52.19046,22.100559],[52.18803,22.11499],[52.187031,22.12093],[52.186642,22.123289],[52.184971,22.13299],[52.183868,22.140181],[52.18354,22.14233],[52.18045,22.16251],[52.18042,22.16272],[52.179218,22.170521],[52.178082,22.17807],[52.177551,22.18157],[52.17654,22.188499],[52.176029,22.191971],[52.175301,22.19693],[52.1745,22.202379],[52.173512,22.20912],[52.173241,22.21105],[52.172321,22.217211],[52.172031,22.21862],[52.171841,22.219561],[52.171371,22.221001],[52.171101,22.221569],[52.1707,22.2222],[52.170269,22.222759],[52.169971,22.223061],[52.169651,22.22337],[52.168919,22.223761],[52.16806,22.22397],[52.157452,22.223801],[52.149818,22.223669],[52.149181,22.223841],[52.148411,22.22414],[52.14703,22.225031],[52.145828,22.22603],[52.145191,22.226721],[52.14463,22.22753],[52.14407,22.228821],[52.143768,22.22994],[52.143559,22.23114],[52.143471,22.232981],[52.14365,22.236931],[52.14365,22.24024],[52.14352,22.242979],[52.143341,22.245081],[52.1427,22.24972],[52.14188,22.254181],[52.14146,22.256161],[52.141121,22.25769],[52.1409,22.25869],[52.14072,22.259331],[52.140381,22.26058],[52.13974,22.26259],[52.138321,22.266199],[52.137569,22.26819],[52.137032,22.26984],[52.136089,22.273109],[52.13562,22.275169],[52.13472,22.28014],[52.1339,22.284821],[52.133598,22.28676],[52.132912,22.29147],[52.13261,22.29401],[52.132191,22.29804],[52.131882,22.302031],[52.13163,22.307911],[52.13158,22.309839],[52.13158,22.315981],[52.131672,22.318979],[52.131882,22.323021],[52.132011,22.325979],[52.132011,22.327101],[52.131931,22.328251],[52.131882,22.328659],[52.131802,22.329201],[52.131672,22.32984],[52.131241,22.331301],[52.130268,22.33366],[52.1297,22.335079],[52.128479,22.338051],[52.1273,22.34091],[52.12524,22.34581],[52.124432,22.34767],[52.122318,22.35253],[52.122181,22.352859],[52.120171,22.35787],[52.11734,22.364731],[52.114368,22.371731],[52.112019,22.377439],[52.108501,22.385799],[52.105831,22.3922],[52.103809,22.39706],[52.102531,22.400141],[52.09618,22.415409],[52.0909,22.42794],[52.090092,22.43022],[52.08979,22.432711],[52.089741,22.43593],[52.089531,22.43782],[52.08934,22.4384],[52.08786,22.44297],[52.086208,22.45097],[52.08498,22.457041],[52.08387,22.46246],[52.083172,22.466141],[52.08202,22.476231],[52.081631,22.479191],[52.08065,22.482149],[52.0779,22.48863],[52.076649,22.49193],[52.074421,22.5],[52.072891,22.505619],[52.071678,22.51009],[52.06942,22.51827],[52.069012,22.51996],[52.06884,22.5236],[52.068878,22.526569],[52.068501,22.5291],[52.066872,22.534929],[52.06464,22.5427],[52.06356,22.54652],[52.063011,22.550079],[52.062531,22.55407],[52.061378,22.563471],[52.059921,22.57184],[52.059441,22.574579],[52.057259,22.58708],[52.057041,22.589569],[52.056999,22.591801],[52.057301,22.59729],[52.057678,22.608959],[52.05785,22.614059],[52.057991,22.618019],[52.058109,22.622311],[52.05743,22.62789],[52.055672,22.63789],[52.053139,22.652349],[52.050991,22.664709],[52.050049,22.67042],[52.049622,22.67214],[52.048592,22.67454],[52.045151,22.68055],[52.039101,22.691231],[52.03442,22.699511],[52.029881,22.707371],[52.02383,22.71763],[52.019051,22.72547],[52.015331,22.73226],[52.007431,22.74612],[52.0047,22.75083],[52.00449,22.75119],[52.004169,22.75172],[52.003368,22.753139],[52.002972,22.75382],[52.00243,22.75474],[52.001228,22.756901],[52.00069,22.75861],[52.000469,22.759689],[52.000408,22.76021],[52.000332,22.76083],[52.000301,22.763399],[52.00029,22.764009],[52.00029,22.76417],[52.00029,22.76475],[52.000259,22.766911],[52.000271,22.767811],[52.00029,22.7693],[52.000271,22.77309],[52.000092,22.78389],[51.999699,22.81146],[51.999771,22.813219],[51.999809,22.813709],[51.999969,22.814501],[52.000389,22.815821],[52.001049,22.817221],[52.002491,22.819941],[52.019131,22.850771],[52.02018,22.85272],[52.026829,22.86499],[52.027561,22.86714],[52.027748,22.86878],[52.02803,22.87328],[52.02816,22.876579],[52.028591,22.880751],[52.034531,22.91885],[52.036671,22.9328],[52.038502,22.94478],[52.038651,22.94701],[52.03661,22.99505],[52.034679,23.03936],[52.034382,23.04616],[52.033852,23.060539],[52.033821,23.06105],[52.033779,23.061331],[52.033741,23.06406],[52.033779,23.06502],[52.033932,23.066481],[52.03397,23.06702],[52.034039,23.06745],[52.03413,23.068199],[52.034382,23.069441],[52.034851,23.07103],[52.035332,23.072411],[52.035728,23.073481],[52.035858,23.07374],[52.035912,23.07374],[52.037621,23.077749],[52.038502,23.07987],[52.042339,23.08906],[52.045219,23.09586],[52.047531,23.10133],[52.049171,23.10528],[52.049759,23.107201],[52.05061,23.10993],[52.05101,23.11146],[52.05143,23.1134],[52.051769,23.115351],[52.052139,23.118019],[52.05233,23.120081],[52.052441,23.12163],[52.05254,23.1243],[52.05249,23.126431],[52.05241,23.128111],[52.05225,23.13044],[52.052052,23.132139],[52.051689,23.134399],[52.05138,23.136129],[52.051079,23.137541],[52.05014,23.14085],[52.049431,23.14304],[52.046921,23.149401],[52.046329,23.150881],[52.046249,23.151091],[52.041649,23.16205],[52.04108,23.16349],[52.040989,23.163771],[52.040878,23.16407],[52.040722,23.16494],[52.040668,23.165991],[52.040699,23.166901],[52.040852,23.16884],[52.04092,23.17067],[52.040909,23.170799],[52.040352,23.17984],[52.040001,23.184799],[52.039848,23.18705],[52.03894,23.19945],[52.038151,23.211281],[52.037041,23.226919],[52.036201,23.23984],[52.035629,23.247259],[52.035198,23.254669],[52.034111,23.268709],[52.034019,23.270809],[52.0341,23.278021],[52.034279,23.285179],[52.03437,23.289591],[52.034679,23.30765],[52.03487,23.319969],[52.03503,23.33103],[52.035431,23.352261],[52.035568,23.36269],[52.035751,23.37554],[52.036121,23.39966],[52.03648,23.423731],[52.03669,23.44198],[52.037102,23.471069],[52.056198,23.47821],[52.057281,23.479031],[52.062019,23.48612],[52.06966,23.497549],[52.07505,23.50531],[52.074341,23.506451],[52.074478,23.507071],[52.075321,23.508471],[52.076199,23.51207],[52.077019,23.517269],[52.078541,23.523121],[52.079208,23.52372],[52.080021,23.527479],[52.080372,23.52845],[52.080971,23.52993],[52.08247,23.531771],[52.097488,23.550831],[52.100391,23.55324],[52.115749,23.565399],[52.116249,23.565861],[52.116879,23.566429],[52.119869,23.56897],[52.12009,23.569189],[52.121159,23.570431],[52.1236,23.573311],[52.123859,23.57374],[52.124371,23.57469],[52.124889,23.57572],[52.125641,23.577629],[52.12632,23.580099],[52.128811,23.59057],[52.135269,23.61853],[52.136452,23.62384],[52.137909,23.62999],[52.139091,23.63512],[52.140079,23.63932],[52.143768,23.6551],[52.148842,23.67742],[52.150139,23.68292],[52.15052,23.68453],[52.15115,23.687281],[52.151402,23.68865],[52.151531,23.68964],[52.151569,23.69029],[52.151539,23.6905],[52.151482,23.69071],[52.151371,23.69096],[52.151291,23.69117],[52.151199,23.691401],[52.15115,23.69166],[52.15118,23.69203],[52.15126,23.69227],[52.151371,23.69243],[52.15147,23.69253],[52.151539,23.69256],[52.151619,23.692869],[52.151661,23.69306],[52.151661,23.693319],[52.151409,23.69803],[52.15023,23.716619],[52.149399,23.72999],[52.149052,23.73517],[52.148842,23.736971],[52.148689,23.73807],[52.14843,23.739651],[52.147911,23.741989],[52.14674,23.74641],[52.145618,23.750441],[52.14502,23.75275],[52.143379,23.758739],[52.140732,23.768591],[52.13792,23.778919],[52.134338,23.792219],[52.133091,23.796761],[52.13205,23.80051],[52.131889,23.80109],[52.131039,23.803761],[52.13002,23.807489],[52.12822,23.81422],[52.127369,23.81785],[52.125999,23.823071],[52.125622,23.824289],[52.125111,23.82625],[52.124451,23.82873],[52.123501,23.83223],[52.122688,23.83518],[52.119701,23.846319],[52.119282,23.84778],[52.11903,23.84841],[52.118832,23.848749],[52.11869,23.84897],[52.118542,23.84914],[52.117519,23.849951],[52.115879,23.85117],[52.1157,23.85137],[52.11554,23.85165],[52.115459,23.85203],[52.11549,23.852341],[52.11557,23.852631],[52.115791,23.85289],[52.116161,23.85309],[52.11647,23.85318],[52.116699,23.85335],[52.116909,23.853609],[52.11705,23.85391],[52.117249,23.85433],[52.117489,23.85548],[52.118221,23.859249],[52.119019,23.863449],[52.120411,23.870689],[52.122372,23.880699],[52.123039,23.88419],[52.12328,23.88542],[52.123749,23.887831],[52.124321,23.89076],[52.124779,23.893221],[52.125229,23.895611],[52.125561,23.897301],[52.126678,23.902849],[52.127029,23.904711],[52.128262,23.91103],[52.129269,23.91626],[52.132622,23.933611],[52.13448,23.94289],[52.136089,23.951241],[52.136509,23.953409],[52.142052,23.98245],[52.146332,24.00466],[52.150719,24.02721],[52.15287,24.038589],[52.153019,24.03994],[52.153469,24.04154],[52.156288,24.056391],[52.156681,24.058439],[52.161079,24.08123],[52.162399,24.089331],[52.174301,24.15033],[52.17466,24.152189],[52.174889,24.153469],[52.175442,24.15617],[52.18956,24.230101],[52.196079,24.264339],[52.199089,24.28031],[52.19923,24.281],[52.19944,24.282619],[52.199551,24.28367],[52.199581,24.284281],[52.199612,24.284599],[52.19965,24.28643],[52.199619,24.288059],[52.19957,24.28903],[52.199471,24.290131],[52.19928,24.291771],[52.199009,24.293159],[52.198792,24.29434],[52.198509,24.29549],[52.197891,24.297371],[52.197289,24.29891],[52.196892,24.29986],[52.196411,24.300791],[52.195591,24.302271],[52.188881,24.313999],[52.183769,24.323021],[52.183262,24.324051],[52.182659,24.32563],[52.181591,24.328341],[52.181141,24.32947],[52.179619,24.33334],[52.178951,24.33515],[52.178391,24.337999],[52.178268,24.339239],[52.17823,24.340731],[52.17831,24.34374],[52.179089,24.34906],[52.183552,24.378071],[52.183861,24.38007],[52.18441,24.38382],[52.18655,24.39747],[52.186989,24.399099],[52.187328,24.400299],[52.187931,24.40176],[52.18853,24.40288],[52.189732,24.40468],[52.20063,24.41729],[52.20261,24.4191],[52.204411,24.42038],[52.206039,24.42116],[52.211021,24.422621],[52.212681,24.42293],[52.214001,24.42318],[52.215591,24.42333],[52.217979,24.423161],[52.2192,24.42297],[52.22105,24.422831],[52.222321,24.42293],[52.22385,24.423321],[52.225868,24.42404],[52.228271,24.425619],[52.230419,24.427509],[52.231529,24.428801],[52.232738,24.430429],[52.233681,24.43189],[52.235142,24.434719],[52.23634,24.437719],[52.241661,24.452061],[52.242008,24.453091],[52.253422,24.4839],[52.26458,24.51351],[52.268871,24.525961],[52.269901,24.529051],[52.271702,24.53377],[52.28355,24.560369],[52.285519,24.564409],[52.287491,24.567841],[52.292042,24.574789],[52.306461,24.59617],[52.30748,24.59763],[52.30904,24.599939],[52.319759,24.616079],[52.32431,24.622601],[52.330669,24.632299],[52.33255,24.635481],[52.335209,24.64028],[52.337109,24.64397],[52.342079,24.654699],[52.343632,24.65839],[52.345772,24.66363],[52.349812,24.673929],[52.350559,24.676041],[52.35154,24.67881],[52.353062,24.68375],[52.354408,24.688789],[52.357021,24.69972],[52.35873,24.707319],[52.362679,24.72423],[52.363628,24.72757],[52.364658,24.730659],[52.367229,24.736759],[52.368778,24.739759],[52.373501,24.74791],[52.38131,24.761391],[52.383621,24.765249],[52.388451,24.773621],[52.38855,24.77379],[52.39101,24.77809],[52.393539,24.78227],[52.3965,24.78685],[52.41954,24.822229],[52.422569,24.827021],[52.424461,24.830351],[52.426479,24.834499],[52.427849,24.83754],[52.429131,24.840481],[52.430511,24.84441],[52.4314,24.8477],[52.441212,24.883829],[52.44294,24.88942],[52.443958,24.89241],[52.445389,24.896049],[52.44688,24.89949],[52.448021,24.90184],[52.449162,24.904119],[52.451,24.907551],[52.453011,24.910851],[52.455921,24.9151],[52.461411,24.922119],[52.467789,24.93049],[52.470421,24.934071],[52.473919,24.93903],[52.476212,24.942381],[52.479328,24.947491],[52.482948,24.95442],[52.48391,24.956329],[52.48698,24.96279],[52.48798,24.964991],[52.48925,24.967751],[52.490189,24.96986],[52.492401,24.97484],[52.492649,24.975401],[52.49403,24.978621],[52.49469,24.980169],[52.496922,24.98489],[52.498718,24.988501],[52.519588,25.0278],[52.520592,25.02973],[52.521301,25.031099],[52.52507,25.03837],[52.527649,25.04274],[52.52961,25.0455],[52.53075,25.046949],[52.53273,25.04933],[52.534431,25.051411],[52.5364,25.053301],[52.539749,25.056129],[52.541809,25.05759],[52.545658,25.059971],[52.547218,25.06094],[52.54744,25.061069],[52.549191,25.062229],[52.55151,25.064199],[52.551819,25.064489],[52.553219,25.06583],[52.553829,25.066351],[52.555779,25.068609],[52.558262,25.0716],[52.560169,25.07407],[52.561642,25.076389],[52.563782,25.07999],[52.56601,25.084459],[52.567131,25.08695],[52.568508,25.090639],[52.572731,25.10277],[52.57513,25.109541],[52.57803,25.11776],[52.579449,25.12146],[52.580349,25.1236],[52.582748,25.128571],[52.585499,25.1339],[52.587391,25.13707],[52.603531,25.16132],[52.60696,25.16728],[52.619831,25.19175],[52.62933,25.20981],[52.638729,25.2279],[52.642921,25.235781],[52.646118,25.24214],[52.648548,25.247339],[52.650021,25.250879],[52.65147,25.254431],[52.655708,25.26573],[52.657131,25.26956],[52.663799,25.28743],[52.670471,25.305389],[52.67519,25.317829],[52.676392,25.32058],[52.677589,25.323071],[52.678539,25.324949],[52.685322,25.33684],[52.686031,25.338091],[52.686932,25.33967],[52.690979,25.34693],[52.694809,25.35368],[52.696079,25.356079],[52.69733,25.35858],[52.698761,25.36157],[52.6996,25.363581],[52.701019,25.366541],[52.701279,25.3671],[52.705292,25.375839],[52.7066,25.37879],[52.70787,25.38176],[52.708672,25.383801],[52.709251,25.385441],[52.709419,25.38592],[52.709709,25.38682],[52.710079,25.388],[52.711231,25.392071],[52.716991,25.4137],[52.7183,25.418739],[52.720131,25.42551],[52.721111,25.428499],[52.739941,25.479],[52.741951,25.48362],[52.744061,25.487761],[52.746841,25.49316],[52.751289,25.501659],[52.755569,25.509899],[52.759911,25.518129],[52.764179,25.526369],[52.766369,25.530569],[52.768459,25.534611],[52.771091,25.53908],[52.77211,25.540621],[52.774021,25.54327],[52.775429,25.545059],[52.776859,25.546721],[52.779099,25.549101],[52.782619,25.552271],[52.783932,25.5534],[52.792992,25.56155],[52.80965,25.57682],[52.814861,25.581841],[52.819981,25.586889],[52.82056,25.58742],[52.823421,25.59034],[52.82497,25.59215],[52.82642,25.59403],[52.827709,25.59584],[52.829689,25.59893],[52.831699,25.6026],[52.848228,25.63558],[52.84856,25.636141],[52.851398,25.64073],[52.85294,25.64296],[52.854359,25.64463],[52.85601,25.64657],[52.856602,25.647209],[52.85952,25.65036],[52.862049,25.652399],[52.86385,25.65369],[52.87775,25.66201],[52.87981,25.66321],[52.909302,25.680429],[52.915451,25.684071],[52.91869,25.686131],[52.92049,25.68742],[52.922901,25.68939],[52.924961,25.69128],[52.942982,25.70956],[52.96899,25.73591],[52.97192,25.73875],[52.972931,25.73988],[52.974899,25.741449],[52.977322,25.743719],[52.979759,25.74596],[52.99173,25.756599],[52.995258,25.760201],[53.016541,25.78355],[53.019798,25.787149],[53.022121,25.7899],[53.023918,25.792471],[53.025719,25.795219],[53.027699,25.798651],[53.0289,25.80097],[53.03817,25.820801],[53.04126,25.827749],[53.04269,25.8312],[53.046341,25.83993],[53.048012,25.843889],[53.050179,25.84898],[53.05201,25.85334],[53.052311,25.85404],[53.05312,25.85597],[53.053879,25.857531],[53.05418,25.85813],[53.05508,25.85981],[53.055511,25.86055],[53.055969,25.861361],[53.057049,25.86311],[53.05798,25.8645],[53.058998,25.865959],[53.062111,25.870159],[53.065109,25.8743],[53.066399,25.87586],[53.067471,25.877171],[53.068508,25.878229],[53.07008,25.87978],[53.071529,25.88101],[53.072281,25.88184],[53.073898,25.88307],[53.075279,25.88385],[53.077129,25.88483],[53.079182,25.88578],[53.080479,25.8862],[53.083389,25.88695],[53.085979,25.8874],[53.087601,25.88747],[53.089241,25.8874],[53.09404,25.886721],[53.0961,25.886629],[53.096451,25.886629],[53.09988,25.88706],[53.102112,25.887569],[53.103748,25.88818],[53.105808,25.88912],[53.108028,25.89032],[53.112411,25.89315],[53.115761,25.895639],[53.119362,25.898821],[53.121681,25.90131],[53.123829,25.903879],[53.126228,25.907141],[53.132069,25.916241],[53.13332,25.918301],[53.13414,25.91993],[53.134918,25.92161],[53.135571,25.92318],[53.1362,25.92485],[53.13686,25.926741],[53.137531,25.92907],[53.13768,25.929621],[53.138199,25.93149],[53.143181,25.94968],[53.14468,25.955219],[53.145969,25.959669],[53.147171,25.96319],[53.148121,25.96542],[53.149151,25.967569],[53.150089,25.96937],[53.151649,25.971849],[53.15337,25.974279],[53.155159,25.97641],[53.157219,25.97847],[53.15992,25.981119],[53.1605,25.98172],[53.161949,25.983271],[53.162571,25.983999],[53.163448,25.985069],[53.16431,25.986231],[53.164928,25.98716],[53.165539,25.988171],[53.166439,25.989811],[53.167469,25.99184],[53.168159,25.993349],[53.169361,25.996111],[53.170769,25.99935],[53.172871,26.004181],[53.17337,26.005409],[53.17395,26.006849],[53.17477,26.00901],[53.175369,26.010719],[53.176022,26.012739],[53.177299,26.01713],[53.178398,26.020969],[53.17889,26.022751],[53.17992,26.02721],[53.18042,26.03027],[53.180641,26.031981],[53.180962,26.03536],[53.18111,26.03808],[53.18124,26.04175],[53.181339,26.044069],[53.181412,26.045179],[53.181511,26.04649],[53.181641,26.047819],[53.181862,26.049601],[53.182152,26.0516],[53.18261,26.05405],[53.183041,26.056061],[53.183689,26.05863],[53.184799,26.06218],[53.185841,26.06506],[53.186329,26.06621],[53.18679,26.067221],[53.18766,26.06904],[53.190399,26.073931],[53.191769,26.076349],[53.19278,26.078159],[53.193851,26.08016],[53.194691,26.08189],[53.195339,26.08326],[53.199032,26.09133],[53.202541,26.098961],[53.205929,26.106091],[53.20739,26.10952],[53.208809,26.113569],[53.2094,26.115471],[53.210152,26.118019],[53.21088,26.120831],[53.211411,26.12294],[53.214512,26.135269],[53.21537,26.138359],[53.216911,26.14283],[53.218201,26.146351],[53.220181,26.150721],[53.221458,26.15321],[53.222752,26.155701],[53.225071,26.159559],[53.231251,26.16943],[53.233479,26.17347],[53.235538,26.177759],[53.238289,26.184879],[53.25219,26.22514],[53.252789,26.2272],[53.254162,26.231581],[53.256481,26.24033],[53.265919,26.283159],[53.266911,26.28706],[53.26712,26.28784],[53.267841,26.290371],[53.268761,26.293369],[53.26973,26.29624],[53.270748,26.29887],[53.271671,26.301069],[53.27219,26.302299],[53.284641,26.32745],[53.286011,26.33037],[53.287338,26.33342],[53.289612,26.33955],[53.298111,26.368389],[53.2994,26.37191],[53.300369,26.374399],[53.301029,26.37586],[53.303261,26.380489],[53.304722,26.38315],[53.306862,26.386669],[53.32317,26.41036],[53.327122,26.41663],[53.333561,26.42787],[53.34557,26.44907],[53.353561,26.46315],[53.36377,26.481091],[53.38026,26.5079],[53.382992,26.512329],[53.384769,26.51553],[53.385658,26.51713],[53.388828,26.52306],[53.403172,26.549919],[53.410461,26.5634],[53.41235,26.56649],[53.413979,26.56889],[53.416801,26.57254],[53.419128,26.575069],[53.421341,26.57732],[53.42445,26.57979],[53.444881,26.594299],[53.445061,26.594469],[53.448471,26.597139],[53.450371,26.598591],[53.454659,26.60228],[53.47768,26.625601],[53.478031,26.62594],[53.478981,26.626881],[53.485222,26.633181],[53.488049,26.63652],[53.489861,26.63876],[53.492352,26.642191],[53.494888,26.646099],[53.508911,26.67008],[53.509418,26.67103],[53.511311,26.674629],[53.512939,26.678129],[53.514229,26.68124],[53.515598,26.68502],[53.51675,26.68894],[53.52256,26.710939],[53.525829,26.724689],[53.52702,26.72982],[53.528221,26.73597],[53.52869,26.738371],[53.529221,26.74115],[53.529961,26.745029],[53.530151,26.745899],[53.532902,26.76289],[53.533401,26.76598],[53.535519,26.779091],[53.536121,26.78458],[53.536461,26.789391],[53.53664,26.79497],[53.53664,26.7978],[53.536251,26.805441],[53.53595,26.80879],[53.535339,26.813669],[53.534401,26.819],[53.534229,26.819771],[53.530708,26.83737],[53.530209,26.83996],[53.52985,26.8426],[53.52951,26.84527],[53.529251,26.849039],[53.529171,26.852131],[53.529289,26.856291],[53.529591,26.86054],[53.530048,26.86355],[53.530369,26.86561],[53.53059,26.86692],[53.531738,26.872299],[53.536381,26.8929],[53.538391,26.90213],[53.543839,26.9268],[53.551048,26.95891],[53.551739,26.961479],[53.552341,26.963369],[53.55397,26.96689],[53.556889,26.9729],[53.569759,26.99976],[53.584961,27.03109],[53.588219,27.037609],[53.58942,27.03907],[53.590111,27.039761],[53.59095,27.040529],[53.592159,27.04105],[53.595341,27.04215],[53.595509,27.04221],[53.598179,27.043249],[53.60865,27.047779],[53.61459,27.050211],[53.619888,27.05237],[53.625561,27.05632],[53.642429,27.06823],[53.649181,27.073],[53.650631,27.074301],[53.651821,27.07575],[53.652611,27.076799],[53.654018,27.0788],[53.655418,27.08147],[53.656712,27.08456],[53.65757,27.087391],[53.65834,27.090401],[53.659031,27.095289],[53.659199,27.097521],[53.65937,27.11211],[53.659458,27.11709],[53.65971,27.12756],[53.660141,27.132629],[53.661091,27.137951],[53.661598,27.14044],[53.663151,27.14567],[53.666531,27.155149],[53.674389,27.17734],[53.675251,27.1798],[53.675869,27.182501],[53.676491,27.18531],[53.67712,27.189251],[53.677551,27.19454],[53.67757,27.19717],[53.677399,27.20146],[53.676708,27.20841],[53.676109,27.216311],[53.675758,27.223089],[53.675591,27.230471],[53.675758,27.243179],[53.676022,27.247549],[53.676449,27.25416],[53.676971,27.26008],[53.678001,27.267981],[53.679451,27.277531],[53.685551,27.31776],[53.686409,27.32394],[53.688721,27.340521],[53.691151,27.358589],[53.691441,27.36087],[53.694908,27.38806],[53.697571,27.409691],[53.698601,27.415951],[53.699711,27.42239],[53.701248,27.42951],[53.702412,27.434111],[53.703892,27.439819],[53.709179,27.45775],[53.709728,27.459539],[53.710258,27.461411],[53.723,27.503969],[53.723629,27.506109],[53.72496,27.51058],[53.72691,27.517099],[53.727348,27.51852],[53.72789,27.520281],[53.729149,27.52442],[53.729729,27.526529],[53.730129,27.528099],[53.73082,27.53133],[53.731548,27.534981],[53.73214,27.53829],[53.732651,27.54188],[53.733139,27.54612],[53.734119,27.55578],[53.736309,27.57708],[53.73687,27.58239],[53.737789,27.5914],[53.738548,27.59878],[53.739639,27.609711],[53.740021,27.61257],[53.740139,27.613449],[53.740749,27.61706],[53.741371,27.620041],[53.742371,27.62392],[53.743832,27.628731],[53.745338,27.632971],[53.746071,27.634689],[53.746868,27.6364],[53.747452,27.637609],[53.748058,27.63879],[53.749298,27.641029],[53.751671,27.64571],[53.752972,27.64875],[53.754261,27.65201],[53.75613,27.657351],[53.75626,27.657721],[53.756908,27.659731],[53.757381,27.6609],[53.7579,27.66235],[53.75832,27.663469],[53.759029,27.665319],[53.759819,27.66711],[53.7607,27.669029],[53.76162,27.67108],[53.762192,27.67214],[53.762901,27.673441],[53.78426,27.712919],[53.786491,27.71736],[53.78846,27.721979],[53.790089,27.726471],[53.79097,27.72916],[53.791382,27.73045],[53.79229,27.733801],[53.793221,27.73777],[53.793499,27.73922],[53.793591,27.739651],[53.793678,27.740191],[53.797211,27.759199],[53.797871,27.76277],[53.79966,27.77269],[53.799881,27.773951],[53.80064,27.778521],[53.802368,27.786659],[53.803139,27.78932],[53.804249,27.793011],[53.80431,27.79318],[53.804878,27.794809],[53.805222,27.795771],[53.80621,27.798479],[53.807301,27.801189],[53.807899,27.80257],[53.80859,27.80405],[53.809689,27.806351],[53.811291,27.80949],[53.813919,27.81415],[53.814121,27.81451],[53.81707,27.81988],[53.81773,27.82114],[53.825401,27.835051],[53.829479,27.842819],[53.833488,27.85062],[53.84153,27.866261],[53.84193,27.86705],[53.843239,27.86961],[53.843891,27.87084],[53.84454,27.872101],[53.845829,27.87459],[53.848412,27.879601],[53.849861,27.882389],[53.85133,27.885229],[53.854252,27.89086],[53.8601,27.902121],[53.861439,27.90472],[53.861599,27.90501],[53.861832,27.90547],[53.863529,27.90876],[53.867081,27.915569],[53.868511,27.91836],[53.86998,27.92103],[53.871288,27.923189],[53.87262,27.925261],[53.874321,27.92758],[53.87606,27.929779],[53.87867,27.93269],[53.878841,27.93284],[53.879501,27.933479],[53.88142,27.93531],[53.88348,27.936951],[53.885021,27.938061],[53.88905,27.94046],[53.891708,27.941771],[53.900379,27.94578],[53.90905,27.949909],[53.92561,27.957621],[53.929649,27.95952],[53.93251,27.960819],[53.935322,27.962351],[53.9361,27.96287],[53.93803,27.96422],[53.939861,27.96578],[53.943039,27.96896],[53.945961,27.972651],[53.946449,27.9734],[53.948139,27.976049],[53.948669,27.97698],[53.949188,27.97789],[53.949478,27.978399],[53.951279,27.98192],[53.952648,27.98527],[53.954319,27.98984],[53.955662,27.99394],[53.963131,28.020201],[53.967251,28.03454],[53.97094,28.047319],[53.973339,28.05479],[53.979519,28.07144],[53.98209,28.078051],[53.98476,28.08552],[53.986301,28.09041],[53.9869,28.09239],[53.98888,28.09968],[53.989651,28.103109],[53.992908,28.116159],[53.995659,28.12775],[53.99601,28.129181],[53.997028,28.13341],[53.998138,28.137791],[54.000198,28.144911],[54.001411,28.148689],[54.003471,28.154779],[54.005531,28.16062],[54.007931,28.167139],[54.009392,28.17161],[54.01128,28.17779],[54.011459,28.178431],[54.012642,28.18281],[54.013149,28.18469],[54.01342,28.18568],[54.014881,28.19212],[54.015739,28.19615],[54.01757,28.206301],[54.01849,28.21307],[54.019348,28.22019],[54.020149,28.22949],[54.020199,28.23004],[54.02026,28.230841],[54.025688,28.30113],[54.02647,28.30962],[54.026981,28.313141],[54.02906,28.32885],[54.03334,28.357349],[54.033852,28.36507],[54.035309,28.373911],[54.035309,28.374081],[54.037109,28.38241],[54.039768,28.39279],[54.041309,28.398251],[54.045609,28.413481],[54.04776,28.420601],[54.049469,28.425579],[54.050381,28.427641],[54.052132,28.431589],[54.054089,28.435329],[54.058441,28.443689],[54.062519,28.4515],[54.06673,28.458969],[54.068951,28.46274],[54.07069,28.465349],[54.07119,28.466089],[54.075909,28.47262],[54.08123,28.47879],[54.083618,28.481319],[54.090328,28.488411],[54.119419,28.518909],[54.120449,28.519991],[54.123631,28.523769],[54.132729,28.535789],[54.137619,28.54188],[54.141651,28.546431],[54.14526,28.550119],[54.148689,28.553471],[54.153591,28.55793],[54.157619,28.56119],[54.166599,28.56822],[54.172371,28.572741],[54.174809,28.574551],[54.177021,28.576191],[54.179588,28.5781],[54.183971,28.581619],[54.18663,28.58419],[54.194271,28.59235],[54.194778,28.592859],[54.207661,28.60651],[54.209042,28.60816],[54.211609,28.611231],[54.213921,28.614321],[54.217701,28.61964],[54.225941,28.632429],[54.237782,28.650801],[54.239159,28.652691],[54.242161,28.65612],[54.245602,28.65913],[54.24791,28.660931],[54.250912,28.662531],[54.251759,28.662979],[54.257092,28.665819],[54.258808,28.666759],[54.25959,28.66728],[54.260441,28.668051],[54.261471,28.669081],[54.262852,28.670799],[54.264141,28.672859],[54.265079,28.67457],[54.266201,28.677059],[54.266911,28.679251],[54.267231,28.680241],[54.268341,28.685101],[54.269032,28.688141],[54.26947,28.691031],[54.269539,28.691481],[54.269588,28.691971],[54.270061,28.69663],[54.270061,28.7071],[54.270111,28.708799],[54.27026,28.710541],[54.270401,28.711769],[54.270569,28.712681],[54.270908,28.71414],[54.271351,28.715691],[54.27232,28.718201],[54.272541,28.718781],[54.282761,28.738779],[54.28997,28.752939],[54.291,28.755939],[54.291599,28.758169],[54.291859,28.761259],[54.291931,28.763109],[54.29155,28.77039],[54.29108,28.780661],[54.29015,28.800529],[54.289959,28.804581],[54.289879,28.806379],[54.289688,28.810459],[54.289631,28.811729],[54.28904,28.8241],[54.288971,28.826241],[54.288971,28.82822],[54.289219,28.83215],[54.290699,28.85079],[54.291061,28.86319],[54.291309,28.87359],[54.29155,28.876591],[54.292801,28.884689],[54.295979,28.904261],[54.297779,28.916269],[54.29821,28.919451],[54.29855,28.923229],[54.300251,28.947069],[54.30027,28.948721],[54.300468,28.950411],[54.301041,28.95756],[54.301842,28.969],[54.301991,28.97043],[54.30262,28.97678],[54.30302,28.979361],[54.30756,29.00271],[54.308418,29.007339],[54.30928,29.01326],[54.31057,29.022791],[54.3116,29.029831],[54.31271,29.036091],[54.31366,29.04081],[54.31572,29.04871],[54.318378,29.056259],[54.331249,29.092911],[54.334259,29.099689],[54.3358,29.10261],[54.336319,29.10347],[54.339409,29.10836],[54.345329,29.11635],[54.347988,29.120119],[54.349541,29.12261],[54.35194,29.127251],[54.35434,29.13282],[54.355801,29.1366],[54.362148,29.155661],[54.362839,29.15814],[54.364391,29.16415],[54.364811,29.166031],[54.36499,29.167061],[54.36573,29.171209],[54.366531,29.17643],[54.370911,29.20389],[54.371681,29.209299],[54.3722,29.21393],[54.37244,29.217501],[54.372532,29.220209],[54.37252,29.22753],[54.371471,29.281111],[54.371391,29.285179],[54.371319,29.28879],[54.37125,29.291611],[54.37133,29.29336],[54.371422,29.295219],[54.37159,29.297819],[54.371891,29.300289],[54.37254,29.304399],[54.37331,29.30826],[54.374168,29.3111],[54.374729,29.312901],[54.375938,29.316811],[54.377258,29.321051],[54.377522,29.32234],[54.378811,29.3274],[54.379921,29.332979],[54.380428,29.336161],[54.380871,29.338989],[54.384121,29.36319],[54.38438,29.36491],[54.385578,29.37075],[54.39082,29.39521],[54.395538,29.417101],[54.396999,29.42594],[54.397598,29.42997],[54.400002,29.45031],[54.400139,29.4513],[54.401031,29.457689],[54.401981,29.46336],[54.403011,29.46817],[54.406269,29.48439],[54.40765,29.49065],[54.408932,29.49555],[54.409962,29.49881],[54.412708,29.506189],[54.419231,29.52121],[54.419899,29.523069],[54.421791,29.52866],[54.42292,29.532749],[54.424809,29.541121],[54.4291,29.5606],[54.430389,29.56739],[54.431252,29.57262],[54.43219,29.579491],[54.433311,29.588181],[54.433491,29.589689],[54.434528,29.596939],[54.435322,29.60264],[54.435619,29.60507],[54.436909,29.61408],[54.43708,29.615191],[54.437241,29.616381],[54.437531,29.618191],[54.438141,29.621481],[54.43848,29.623091],[54.43895,29.62516],[54.439571,29.627609],[54.439899,29.62882],[54.4403,29.63028],[54.44136,29.63376],[54.442451,29.63719],[54.444641,29.644039],[54.447151,29.652069],[54.447788,29.654169],[54.448349,29.655951],[54.449291,29.65892],[54.450218,29.66189],[54.451248,29.665831],[54.456188,29.687019],[54.45718,29.69128],[54.457722,29.693911],[54.458038,29.695749],[54.458679,29.69985],[54.45927,29.704639],[54.459541,29.70756],[54.460072,29.71306],[54.460258,29.715099],[54.461971,29.735531],[54.462318,29.738621],[54.46262,29.74155],[54.463428,29.746429],[54.46386,29.74917],[54.464981,29.754169],[54.46627,29.759899],[54.474419,29.79578],[54.47678,29.806629],[54.477001,29.807631],[54.477772,29.81303],[54.478512,29.819361],[54.479141,29.824711],[54.479389,29.829189],[54.479401,29.832861],[54.479401,29.835779],[54.479221,29.838869],[54.47897,29.84136],[54.478539,29.84436],[54.4776,29.84943],[54.476601,29.85458],[54.47485,29.86367],[54.474331,29.86685],[54.47393,29.870871],[54.47348,29.876631],[54.473301,29.882641],[54.473301,29.88702],[54.473549,29.892269],[54.473911,29.89637],[54.474331,29.90015],[54.475101,29.905821],[54.47588,29.911261],[54.476009,29.91217],[54.476131,29.912979],[54.477509,29.921949],[54.481918,29.952721],[54.482849,29.95892],[54.484451,29.969681],[54.485748,29.978769],[54.491371,30.01828],[54.492378,30.02508],[54.492661,30.02648],[54.493229,30.02866],[54.4939,30.03088],[54.498699,30.047119],[54.49884,30.047621],[54.49926,30.049259],[54.499592,30.051069],[54.49976,30.052429],[54.500011,30.055189],[54.500301,30.060289],[54.501331,30.07649],[54.501949,30.08609],[54.50198,30.087179],[54.502239,30.089689],[54.502361,30.090799],[54.50425,30.10475],[54.504608,30.107281],[54.506271,30.11908],[54.50687,30.12211],[54.50737,30.12393],[54.507919,30.125839],[54.508739,30.128019],[54.51511,30.1404],[54.518089,30.14632],[54.52309,30.15601],[54.538921,30.187611],[54.542049,30.193951],[54.542679,30.195641],[54.543171,30.19755],[54.543339,30.19824],[54.543598,30.19936],[54.546089,30.2173],[54.54718,30.225519],[54.547581,30.228439],[54.547989,30.23138],[54.548382,30.23432],[54.549858,30.244499],[54.553299,30.269739],[54.553471,30.27051],[54.55373,30.271799],[54.554161,30.273689],[54.55484,30.27557],[54.555531,30.277031],[54.56171,30.28862],[54.56274,30.29068],[54.563511,30.29283],[54.564201,30.29463],[54.570549,30.314199],[54.57132,30.31609],[54.572262,30.31806],[54.575699,30.32493],[54.576469,30.32621],[54.577251,30.32733],[54.590641,30.34347],[54.5914,30.344391],[54.59483,30.34856],[54.599911,30.35471],[54.600761,30.355829],[54.60162,30.357109],[54.602482,30.35874],[54.603939,30.36286],[54.6096,30.379601],[54.618641,30.405649],[54.619301,30.407579],[54.619732,30.40913],[54.620029,30.41082],[54.620369,30.41293],[54.62162,30.424231],[54.62302,30.435459],[54.623508,30.438999],[54.623852,30.44174],[54.624538,30.446289],[54.62994,30.48938],[54.632351,30.508261],[54.635349,30.53229],[54.638962,30.56225],[54.641529,30.583191],[54.642479,30.591089],[54.64325,30.59547],[54.652691,30.63521],[54.656288,30.650311],[54.65913,30.66264],[54.669769,30.70816],[54.672771,30.720779],[54.675861,30.738199],[54.683159,30.780769],[54.683159,30.78112],[54.68359,30.785839],[54.685989,30.830641],[54.686119,30.8328],[54.68737,30.854071],[54.689079,30.883511],[54.689362,30.889811],[54.68943,30.891411],[54.689861,30.926941],[54.68993,30.93252],[54.690369,30.968229],[54.690708,30.981791],[54.690842,30.992599],[54.69091,30.99811],[54.690929,30.999861],[54.69099,31.000401],[54.69099,31.000641],[54.690948,31.00079],[54.690971,31.001591],[54.691109,31.014879],[54.69112,31.0201],[54.689701,31.05283],[54.689949,31.06406],[54.69099,31.07468],[54.70348,31.20154],[54.709801,31.244169],[54.710098,31.24548],[54.72105,31.283421],[54.722359,31.28828],[54.72567,31.30747],[54.729439,31.33021],[54.730431,31.336189],[54.735111,31.35618],[54.738861,31.372881],[54.742531,31.41223],[54.744179,31.42782],[54.749039,31.478109],[54.74955,31.48155],[54.751961,31.488119],[54.771992,31.53681],[54.786671,31.57107],[54.791,31.578859],[54.792702,31.58213],[54.794479,31.58531],[54.795181,31.58655],[54.79652,31.589029],[54.802349,31.599859],[54.80621,31.60693],[54.80685,31.60828],[54.807449,31.610001],[54.80798,31.612209],[54.810699,31.62418],[54.81295,31.63438],[54.81358,31.63641],[54.814232,31.63796],[54.81496,31.639339],[54.815788,31.640591],[54.83802,31.663321],[54.841209,31.666731],[54.842098,31.66818],[54.842949,31.67001],[54.843651,31.6724],[54.84396,31.67371],[54.844181,31.675091],[54.844349,31.677031],[54.84444,31.679331],[54.84465,31.68441],[54.846569,31.740999],[54.849239,31.8048],[54.850559,31.838461],[54.850788,31.844669],[54.851139,31.852501],[54.851139,31.854111],[54.8512,31.85553],[54.851311,31.857031],[54.85144,31.85841],[54.85149,31.85882],[54.851688,31.860241],[54.852032,31.861959],[54.859341,31.893641],[54.859699,31.89522],[54.860031,31.896851],[54.860298,31.89867],[54.860409,31.900021],[54.860729,31.907431],[54.863209,31.965019],[54.863461,31.97064],[54.86396,31.97884],[54.864151,31.98205],[54.865582,32.003571],[54.865761,32.00528],[54.86586,32.00592],[54.86607,32.007],[54.86644,32.00843],[54.870831,32.024979],[54.87233,32.030609],[54.878571,32.05394],[54.882,32.067009],[54.882839,32.070171],[54.883598,32.073101],[54.883839,32.074139],[54.88406,32.075291],[54.884701,32.07951],[54.88501,32.081261],[54.889851,32.10043],[54.89156,32.105839],[54.893639,32.111629],[54.894569,32.113979],[54.895279,32.115372],[54.896961,32.11755],[54.89856,32.11887],[54.908989,32.124649],[54.91114,32.12619],[54.912048,32.127312],[54.914181,32.130299],[54.92564,32.14669],[54.92709,32.14933],[54.93465,32.165771],[54.941029,32.179642],[54.942371,32.18211],[54.951599,32.195801],[54.955898,32.20388],[54.957008,32.205929],[54.984772,32.2495],[55.009338,32.288151],[55.014061,32.29557],[55.01635,32.299301],[55.017502,32.302029],[55.02364,32.323231],[55.028831,32.340839],[55.029331,32.342609],[55.029751,32.344479],[55.02998,32.34597],[55.030151,32.347591],[55.032341,32.372421],[55.033009,32.38018],[55.033112,32.381931],[55.033699,32.402451],[55.03381,32.404652],[55.033901,32.405529],[55.034019,32.4063],[55.03429,32.407921],[55.055199,32.499489],[55.055729,32.501888],[55.056099,32.504452],[55.056629,32.51738],[55.05714,32.530281],[55.05822,32.55682],[55.059029,32.576729],[55.059422,32.586262],[55.059818,32.595951],[55.059959,32.597309],[55.060169,32.598701],[55.060711,32.601089],[55.066109,32.62178],[55.072861,32.647812],[55.073879,32.65197],[55.076351,32.664532],[55.077229,32.66922],[55.078171,32.674419],[55.07835,32.676239],[55.078659,32.678799],[55.078911,32.681412],[55.079029,32.684189],[55.079021,32.687019],[55.07896,32.69241],[55.07901,32.69603],[55.07906,32.696899],[55.079109,32.697769],[55.07943,32.70303],[55.079578,32.70578],[55.07967,32.708408],[55.07967,32.7094],[55.079659,32.710388],[55.079651,32.712261],[55.079632,32.716011],[55.079201,32.743149],[55.079231,32.7444],[55.079319,32.745689],[55.080929,32.757801],[55.081959,32.764309],[55.085812,32.792412],[55.09552,32.86187],[55.100609,32.89822],[55.101082,32.90139],[55.103889,32.921909],[55.105289,32.931881],[55.107571,32.952911],[55.11404,33.01384],[55.11478,33.020802],[55.116661,33.038502],[55.118839,33.05909],[55.11903,33.06097],[55.120232,33.07328],[55.12038,33.074821],[55.122749,33.097221],[55.12476,33.11731],[55.127258,33.141972],[55.12812,33.150501],[55.128658,33.155849],[55.12941,33.164082],[55.129551,33.167191],[55.130001,33.171902],[55.130329,33.174858],[55.13203,33.194359],[55.132179,33.19561],[55.132408,33.196869],[55.13242,33.196911],[55.133831,33.202961],[55.134621,33.206329],[55.13612,33.212269],[55.136971,33.21603],[55.138378,33.226891],[55.13974,33.23716],[55.140041,33.239479],[55.140072,33.239712],[55.140381,33.242279],[55.141708,33.25333],[55.142391,33.260139],[55.142422,33.26049],[55.14365,33.273491],[55.14463,33.283451],[55.144981,33.286999],[55.145432,33.290569],[55.145931,33.294651],[55.1493,33.320049],[55.15123,33.334499],[55.152111,33.340832],[55.15263,33.344742],[55.15284,33.346119],[55.15303,33.347069],[55.153801,33.350552],[55.157761,33.367619],[55.162682,33.38887],[55.16927,33.417389],[55.174042,33.43829],[55.17432,33.439339],[55.177589,33.450409],[55.178169,33.452431],[55.178768,33.454479],[55.17944,33.456749],[55.181782,33.46479],[55.182529,33.467381],[55.18285,33.468639],[55.183102,33.469921],[55.183289,33.471249],[55.183418,33.472778],[55.18343,33.474361],[55.183338,33.481991],[55.183201,33.492451],[55.182751,33.514259],[55.18269,33.517471],[55.182621,33.521042],[55.18235,33.535782],[55.181499,33.586811],[55.181259,33.603691],[55.181171,33.605801],[55.18055,33.617359],[55.180248,33.624809],[55.179798,33.634941],[55.179279,33.646099],[55.17955,33.6507],[55.180851,33.665352],[55.181721,33.67519],[55.185951,33.722252],[55.186932,33.733372],[55.188869,33.755901],[55.19022,33.769772],[55.19437,33.816299],[55.197609,33.853371],[55.198872,33.86784],[55.19912,33.874069],[55.199169,33.87693],[55.199551,33.897419],[55.19949,33.902531],[55.19912,33.9081],[55.197571,33.918049],[55.19138,33.95414],[55.190868,33.95586],[55.190411,33.975052],[55.18998,33.992599],[55.18977,34.000889],[55.189209,34.021259],[55.188301,34.037731],[55.18737,34.057541],[55.187382,34.059479],[55.187531,34.061371],[55.203011,34.140369],[55.20351,34.14296],[55.203991,34.144909],[55.20462,34.14682],[55.20575,34.149281],[55.205898,34.14962],[55.210041,34.158669],[55.2104,34.159451],[55.21236,34.171219],[55.220131,34.21777],[55.22076,34.222012],[55.22147,34.232059],[55.221619,34.234131],[55.22179,34.235569],[55.22208,34.237122],[55.222641,34.239288],[55.227921,34.257561],[55.228619,34.259899],[55.231991,34.271622],[55.24136,34.306641],[55.241661,34.307739],[55.24202,34.309109],[55.242371,34.310398],[55.243389,34.314209],[55.2435,34.314339],[55.245979,34.323818],[55.249329,34.336559],[55.249599,34.337589],[55.260361,34.372532],[55.261391,34.375931],[55.2654,34.389042],[55.266911,34.393532],[55.269669,34.401371],[55.288132,34.453289],[55.294189,34.472851],[55.315491,34.531731],[55.32428,34.562809],[55.356602,34.639191],[55.362381,34.65646],[55.36401,34.661339],[55.366451,34.668381],[55.370159,34.677132],[55.37426,34.68692],[55.383419,34.70425],[55.389469,34.713871],[55.41082,34.76725],[55.418419,34.78442],[55.425541,34.80146],[55.433361,34.82016],[55.43346,34.8204],[55.446468,34.851879],[55.448391,34.856579],[55.45153,34.864239],[55.470219,34.909729],[55.487339,34.948181],[55.49308,34.976509],[55.496552,35.007629],[55.496891,35.010681],[55.497028,35.011959],[55.49752,35.01646],[55.49955,35.036381],[55.499592,35.036758],[55.503189,35.101479],[55.505718,35.117962],[55.505718,35.120701],[55.503521,35.144611],[55.499298,35.190571],[55.499981,35.215981],[55.49902,35.240929],[55.498859,35.24894],[55.491619,35.31348],[55.491409,35.35181],[55.491329,35.367901],[55.491421,35.397419],[55.49123,35.400509],[55.487518,35.416309],[55.48074,35.444111],[55.48024,35.446171],[55.474239,35.491421],[55.471531,35.511909],[55.470581,35.519581],[55.47044,35.52206],[55.470119,35.529282],[55.468689,35.557758],[55.466881,35.593349],[55.46558,35.618931],[55.464211,35.645908],[55.46402,35.649601],[55.462921,35.676449],[55.461948,35.701061],[55.465279,35.759811],[55.46529,35.761002],[55.465351,35.769691],[55.465382,35.77354],[55.464821,35.826988],[55.464802,35.828949],[55.464779,35.83086],[55.464771,35.8321],[55.464691,35.839359],[55.4646,35.847698],[55.46542,35.903252],[55.46558,35.913269],[55.465382,35.917561],[55.46402,35.94331],[55.45993,36.022961],[55.459179,36.03561],[55.457581,36.060638],[55.457581,36.06271],[55.457821,36.064789],[55.458118,36.066799],[55.458641,36.068619],[55.474209,36.110161],[55.474339,36.11058],[55.49065,36.16309],[55.494148,36.174358],[55.50119,36.207119],[55.50909,36.243801],[55.51041,36.24992],[55.510818,36.251862],[55.51379,36.26569],[55.522362,36.31168],[55.525181,36.326809],[55.525589,36.32901],[55.531239,36.359341],[55.535961,36.384621],[55.536018,36.384899],[55.536072,36.385201],[55.536709,36.388729],[55.538609,36.39875],[55.53883,36.39996],[55.539341,36.40274],[55.53973,36.404888],[55.540291,36.407959],[55.54216,36.417648],[55.54895,36.455029],[55.551121,36.483101],[55.55114,36.483269],[55.551151,36.483429],[55.55167,36.490059],[55.55621,36.54797],[55.556221,36.548161],[55.55801,36.571011],[55.55822,36.573589],[55.55896,36.582569],[55.564362,36.632759],[55.565071,36.639389],[55.56826,36.669849],[55.571011,36.695881],[55.571018,36.69603],[55.571079,36.69664],[55.571091,36.696739],[55.572319,36.708599],[55.572392,36.70932],[55.572491,36.710251],[55.573101,36.716228],[55.573471,36.719952],[55.575031,36.73521],[55.575729,36.74213],[55.576229,36.747021],[55.57666,36.751289],[55.578522,36.76976],[55.57893,36.773891],[55.581409,36.798882],[55.584068,36.824989],[55.587349,36.85857],[55.58794,36.864269],[55.588421,36.869068],[55.58881,36.872978],[55.589039,36.875259],[55.59066,36.891609],[55.591808,36.90316],[55.594059,36.925831],[55.595589,36.93972],[55.595779,36.941292],[55.59602,36.94323],[55.596539,36.94767],[55.59848,36.964432],[55.598991,36.96875],[55.60051,36.981628],[55.60228,36.996632],[55.602638,36.99966],[55.603119,37.004261],[55.603149,37.004681],[55.603199,37.0051],[55.603249,37.005459],[55.60331,37.005859],[55.603821,37.01012],[55.604,37.011539],[55.604519,37.015621],[55.60535,37.02277],[55.605911,37.02747],[55.609039,37.05463],[55.60976,37.061089],[55.610279,37.06546],[55.610531,37.06673],[55.611149,37.069778],[55.61121,37.070091],[55.612518,37.076752],[55.61248,37.077709],[55.613091,37.081009],[55.613289,37.081989],[55.61565,37.093441],[55.616119,37.09626],[55.616531,37.09869],[55.616909,37.101959],[55.62027,37.126701],[55.62133,37.13377],[55.622608,37.142799],[55.62299,37.14724],[55.623268,37.151451],[55.623901,37.161259],[55.624741,37.174],[55.625259,37.181801],[55.625439,37.184681],[55.62553,37.185589],[55.625839,37.188622],[55.626049,37.191921],[55.62619,37.19376],[55.626339,37.195271],[55.62648,37.196281],[55.626652,37.197441],[55.626869,37.198662],[55.627129,37.19978],[55.627392,37.200779],[55.627831,37.202209],[55.628361,37.203701],[55.628811,37.20483],[55.629269,37.205891],[55.629539,37.20652],[55.631119,37.209999],[55.63187,37.211639],[55.632359,37.212799],[55.633801,37.216019],[55.634998,37.21875],[55.635479,37.219841],[55.635929,37.22084],[55.636299,37.22168],[55.637501,37.2244],[55.63868,37.227039],[55.639858,37.229698],[55.64106,37.23241],[55.642269,37.23513],[55.64267,37.236141],[55.643509,37.238441],[55.64431,37.240719],[55.645939,37.245239],[55.646641,37.247131],[55.64769,37.250061],[55.648029,37.251019],[55.648281,37.251839],[55.648548,37.252762],[55.648689,37.253342],[55.649071,37.255032],[55.649429,37.25684],[55.650082,37.260521],[55.65052,37.262779],[55.651131,37.266102],[55.651451,37.26786],[55.652248,37.272171],[55.65284,37.275341],[55.653412,37.278389],[55.654259,37.28299],[55.655399,37.28931],[55.655602,37.29039],[55.655788,37.291409],[55.656269,37.293739],[55.656448,37.29435],[55.656658,37.295059],[55.657089,37.29631],[55.657379,37.296982],[55.657879,37.298019],[55.658489,37.299019],[55.65905,37.29977],[55.659611,37.300468],[55.66087,37.301861],[55.66206,37.303169],[55.662281,37.30341],[55.663811,37.30505],[55.664719,37.306],[55.665619,37.307011],[55.666908,37.308472],[55.66782,37.309441],[55.66853,37.310169],[55.669109,37.31081],[55.66951,37.311241],[55.670639,37.3125],[55.671421,37.31332],[55.67263,37.31464],[55.672989,37.315029],[55.67794,37.320431],[55.67857,37.321129],[55.679428,37.322071],[55.67984,37.322559],[55.680038,37.3228],[55.680191,37.322941],[55.683571,37.326599],[55.683819,37.32687],[55.685791,37.328991],[55.690022,37.333519],[55.693169,37.336971],[55.694759,37.338631],[55.69556,37.339531],[55.69595,37.34],[55.696331,37.340481],[55.696732,37.341011],[55.697109,37.341579],[55.697842,37.3428],[55.698311,37.34359],[55.698471,37.343861],[55.698639,37.344151],[55.698738,37.34433],[55.69949,37.34568],[55.69978,37.34621],[55.700371,37.34729],[55.701241,37.348869],[55.702839,37.351891],[55.703732,37.35355],[55.703949,37.353958],[55.704472,37.354939],[55.705002,37.3559],[55.705441,37.356682],[55.706081,37.357891],[55.706638,37.358891],[55.70705,37.35965],[55.70755,37.360569],[55.707878,37.36121],[55.708172,37.361801],[55.708382,37.36227],[55.70882,37.363319],[55.70911,37.36401],[55.709499,37.36504],[55.709728,37.36573],[55.70998,37.366482],[55.710281,37.367481],[55.710541,37.368431],[55.710812,37.36953],[55.71104,37.37059],[55.711269,37.3717],[55.711849,37.375118],[55.71209,37.376629],[55.71262,37.38015],[55.71286,37.381729],[55.712818,37.382339],[55.712799,37.382561],[55.712742,37.382771],[55.71244,37.38372],[55.712261,37.384258],[55.71199,37.38509],[55.711929,37.385281],[55.71167,37.386082],[55.71138,37.386688],[55.710949,37.387459],[55.710098,37.38821],[55.70993,37.388371],[55.709641,37.38863],[55.70837,37.39016],[55.707981,37.390572],[55.70681,37.392139],[55.70639,37.392712],[55.705299,37.394119],[55.704361,37.395302],[55.70406,37.39571],[55.702068,37.398418],[55.701469,37.399239],[55.700809,37.40015],[55.700291,37.400841],[55.699841,37.401459],[55.699261,37.40226],[55.698799,37.402901],[55.69754,37.404541],[55.693779,37.40976],[55.69265,37.41103],[55.692039,37.411659],[55.691422,37.412251],[55.690071,37.41328],[55.689751,37.413502],[55.689011,37.413952],[55.688309,37.41433],[55.687618,37.41465],[55.686611,37.41502],[55.686401,37.4151],[55.685848,37.41526],[55.685699,37.415272],[55.685081,37.415489],[55.684391,37.415779],[55.684059,37.415932],[55.683659,37.41613],[55.683281,37.41634],[55.68285,37.416599],[55.68243,37.41687],[55.68206,37.41713],[55.680611,37.418221],[55.67614,37.421558],[55.670879,37.425499],[55.669231,37.426739],[55.668152,37.427551],[55.66732,37.428162],[55.666191,37.429008],[55.66576,37.42934],[55.664509,37.430271],[55.664131,37.43058],[55.663528,37.431091],[55.66267,37.43187],[55.661491,37.432999],[55.66053,37.433929],[55.66013,37.434341],[55.659729,37.43478],[55.659309,37.435249],[55.659088,37.43549],[55.658169,37.436569],[55.656479,37.438549],[55.65451,37.440849],[55.65411,37.441319],[55.653751,37.44178],[55.652359,37.4436],[55.652111,37.44389],[55.65086,37.445358],[55.645191,37.451988],[55.643459,37.454021],[55.641281,37.45657],[55.639191,37.459019],[55.6385,37.459839],[55.637131,37.461441],[55.6366,37.462059],[55.635941,37.462818],[55.632431,37.466919],[55.631828,37.467621],[55.63158,37.467899],[55.630939,37.468651],[55.628601,37.471371],[55.627361,37.47282],[55.625629,37.474838],[55.620949,37.48032],[55.617222,37.48468],[55.6157,37.48645],[55.614529,37.48782],[55.61364,37.48885],[55.613361,37.489182],[55.611931,37.490841],[55.611519,37.491322],[55.610699,37.492279],[55.609539,37.493629],[55.608521,37.49482],[55.607571,37.49593],[55.60601,37.497749],[55.6035,37.500671],[55.60091,37.503681],[55.600288,37.504429],[55.599682,37.505211],[55.599121,37.505989],[55.59874,37.506592],[55.598339,37.507221],[55.59782,37.508129],[55.59745,37.508789],[55.597092,37.50948],[55.596691,37.510311],[55.596321,37.51115],[55.59586,37.512249],[55.595428,37.513359],[55.595081,37.51437],[55.594688,37.515591],[55.594349,37.516731],[55.59404,37.517948],[55.593811,37.518921],[55.592319,37.525131],[55.591541,37.528412],[55.59132,37.529339],[55.590912,37.53101],[55.59005,37.534599],[55.587421,37.545601],[55.587139,37.54678],[55.586491,37.549469],[55.584969,37.55584],[55.58287,37.564602],[55.582199,37.567421],[55.581779,37.56916],[55.580719,37.57357],[55.580261,37.57552],[55.579342,37.579361],[55.577278,37.58794],[55.577141,37.588551],[55.577,37.58918],[55.57687,37.589771],[55.576759,37.590408],[55.576641,37.591091],[55.576439,37.59227],[55.57634,37.592911],[55.576241,37.593521],[55.57616,37.594131],[55.576092,37.594742],[55.576019,37.59539],[55.57597,37.596008],[55.575932,37.59655],[55.57589,37.597099],[55.575809,37.598301],[55.575741,37.599659],[55.575611,37.601822],[55.575329,37.606709],[55.575241,37.608158],[55.574982,37.612598],[55.574921,37.613659],[55.574581,37.61935],[55.574409,37.62228],[55.573818,37.632408],[55.573681,37.63475],[55.573589,37.636292],[55.573471,37.638309],[55.57336,37.640308],[55.57325,37.64204],[55.57304,37.645771],[55.572929,37.647671],[55.57283,37.6492],[55.572639,37.652538],[55.572609,37.653061],[55.57254,37.654121],[55.572491,37.655071],[55.571991,37.6633],[55.57196,37.66394],[55.57193,37.664619],[55.571892,37.665298],[55.571869,37.665932],[55.571838,37.666599],[55.571831,37.667271],[55.571819,37.66795],[55.571819,37.66864],[55.571831,37.669312],[55.571861,37.669998],[55.57188,37.67067],[55.571918,37.671349],[55.571972,37.67202],[55.572029,37.672691],[55.57209,37.673359],[55.57217,37.67403],[55.57225,37.674702],[55.57233,37.675362],[55.572418,37.67601],[55.572529,37.67667],[55.57275,37.677952],[55.572861,37.678589],[55.573002,37.679241],[55.573139,37.679871],[55.573299,37.680489],[55.57346,37.68108],[55.573608,37.68166],[55.57375,37.68219],[55.573929,37.682758],[55.5741,37.683331],[55.57428,37.683868],[55.574459,37.68441],[55.574631,37.684891],[55.575432,37.687099],[55.575649,37.687721],[55.576092,37.688889],[55.577709,37.69323],[55.579571,37.698189],[55.581402,37.703121],[55.581951,37.704578],[55.582272,37.705448],[55.582729,37.70668],[55.584511,37.711472],[55.585201,37.71331],[55.585819,37.714989],[55.586071,37.715672],[55.58654,37.716949],[55.587009,37.71822],[55.58749,37.719452],[55.587688,37.719952],[55.588299,37.72142],[55.588951,37.723],[55.589619,37.724548],[55.59016,37.725842],[55.591499,37.729031],[55.591949,37.73011],[55.593449,37.733688],[55.59478,37.736851],[55.594959,37.737309],[55.5952,37.737869],[55.595829,37.739429],[55.599812,37.748901],[55.600319,37.750092],[55.600761,37.751122],[55.601151,37.752041],[55.60165,37.753132],[55.602089,37.75404],[55.602669,37.755161],[55.603168,37.756088],[55.6063,37.761768],[55.60696,37.762981],[55.612579,37.77314],[55.616131,37.779572],[55.616459,37.78017],[55.616638,37.780491],[55.617081,37.7813],[55.617619,37.78228],[55.618858,37.784519],[55.619438,37.785568],[55.619869,37.786461],[55.620838,37.788631],[55.621399,37.789799],[55.621929,37.790821],[55.622391,37.791649],[55.624439,37.795361],[55.62495,37.796268],[55.625351,37.796909],[55.62574,37.797508],[55.626129,37.7981],[55.62619,37.798199],[55.626411,37.79847],[55.62669,37.798851],[55.62711,37.79945],[55.627621,37.800201],[55.62772,37.800331],[55.63179,37.806599],[55.638611,37.817032],[55.63908,37.817719],[55.640419,37.819771],[55.640659,37.820141],[55.643909,37.825119],[55.645351,37.827309],[55.647419,37.83049],[55.648521,37.83213],[55.648972,37.832802],[55.649021,37.83287],[55.649658,37.833721],[55.650372,37.834641],[55.65123,37.835602],[55.65181,37.83617],[55.652519,37.8368],[55.653511,37.837551],[55.654282,37.838051],[55.65493,37.838428],[55.655941,37.83894],[55.656559,37.839191],[55.657131,37.83939],[55.65794,37.839581],[55.65889,37.839771],[55.65974,37.839859],[55.660549,37.839901],[55.661308,37.839901],[55.662201,37.839809],[55.662971,37.839668],[55.663738,37.83947],[55.664799,37.839111],[55.670181,37.837132],[55.679001,37.83392],[55.682739,37.832371],[55.68362,37.832031],[55.68544,37.83136],[55.687061,37.830761],[55.6875,37.830589],[55.687778,37.830502],[55.68898,37.83012],[55.690079,37.829849],[55.691051,37.829689],[55.692001,37.829571],[55.692879,37.829521],[55.693741,37.829529],[55.694759,37.82959],[55.69569,37.829708],[55.696659,37.82988],[55.697041,37.82999],[55.697418,37.83009],[55.697479,37.830109],[55.69804,37.830269],[55.698479,37.830421],[55.69883,37.83054],[55.69899,37.830608],[55.6996,37.830849],[55.70039,37.831211],[55.701149,37.831589],[55.704849,37.833591],[55.705349,37.833851],[55.707619,37.83506],[55.708229,37.835381],[55.709419,37.83601],[55.709961,37.8363],[55.71011,37.83638],[55.712391,37.837589],[55.71328,37.838032],[55.71402,37.838322],[55.714729,37.838558],[55.715511,37.838741],[55.71656,37.838909],[55.72023,37.839359],[55.72298,37.839691],[55.728729,37.840382],[55.731949,37.840771],[55.732861,37.84087],[55.734409,37.841068],[55.736671,37.841351],[55.74012,37.841801],[55.740929,37.841881],[55.74213,37.84201],[55.74361,37.842098],[55.745289,37.842159],[55.747231,37.842251],[55.748741,37.8423],[55.74939,37.842319],[55.749931,37.842361],[55.75071,37.842419],[55.752129,37.84251],[55.753551,37.84259],[55.75523,37.84272],[55.755501,37.842739],[55.757359,37.84288],[55.757561,37.84288],[55.757641,37.84288],[55.758911,37.842892],[55.759331,37.842899],[55.760319,37.84296],[55.760971,37.842991],[55.762878,37.843102],[55.76572,37.843239],[55.766689,37.843288],[55.76738,37.843319],[55.767891,37.843349],[55.768021,37.843361],[55.768501,37.843391],[55.770119,37.843491],[55.770489,37.843491],[55.77145,37.843491],[55.772919,37.843342],[55.774342,37.843208],[55.77499,37.84338],[55.775249,37.843491],[55.775452,37.843689],[55.776039,37.844742],[55.77623,37.844978],[55.77705,37.845612],[55.777222,37.845779],[55.777351,37.84594],[55.777531,37.846272],[55.777889,37.847328],[55.778801,37.85104],[55.779202,37.852638],[55.779339,37.853279],[55.779732,37.85498],[55.782631,37.867538],[55.782661,37.867661],[55.783169,37.869801],[55.783279,37.870251],[55.78421,37.874069],[55.784538,37.875488],[55.78471,37.87619],[55.784889,37.876949],[55.78561,37.880032],[55.786098,37.882141],[55.78651,37.883801],[55.786739,37.884609],[55.78746,37.88699],[55.788448,37.890148],[55.78949,37.893379],[55.789871,37.894581],[55.790169,37.89555],[55.790199,37.895641],[55.791199,37.8988],[55.792561,37.903049],[55.793041,37.904652],[55.793282,37.905579],[55.793419,37.906479],[55.793461,37.90691],[55.793468,37.907089],[55.79348,37.907341],[55.793499,37.907871],[55.793499,37.908539],[55.79351,37.916191],[55.793522,37.91724],[55.79353,37.918259],[55.793549,37.921631],[55.79361,37.92384],[55.793732,37.927231],[55.793892,37.931759],[55.79398,37.934212],[55.793991,37.934639],[55.794022,37.935371],[55.794041,37.936089],[55.794109,37.937531],[55.794331,37.942131],[55.794441,37.944149],[55.794559,37.946301],[55.794571,37.946381],[55.794628,37.947529],[55.794731,37.948898],[55.794922,37.950771],[55.79525,37.95372],[55.795479,37.955669],[55.795589,37.95673],[55.795792,37.958351],[55.79586,37.9589],[55.79657,37.965309],[55.79681,37.96735],[55.796989,37.96891],[55.79707,37.969711],[55.797421,37.972721],[55.798012,37.97784],[55.798828,37.984989],[55.798981,37.98632],[55.799068,37.987122],[55.799309,37.989269],[55.799389,37.989929],[55.79995,37.99477],[55.800179,37.996861],[55.800678,38.001228],[55.80167,38.009972],[55.802582,38.017769],[55.802711,38.018841],[55.80275,38.019249],[55.804459,38.034031],[55.804798,38.036968],[55.805111,38.03968],[55.806099,38.048382],[55.80703,38.056568],[55.807659,38.062111],[55.807812,38.0634],[55.80801,38.065159],[55.808071,38.065659],[55.8083,38.067612],[55.808739,38.071411],[55.80938,38.07703],[55.809841,38.081131],[55.809959,38.082241],[55.81068,38.088501],[55.810719,38.08881],[55.81139,38.094582],[55.812359,38.10323],[55.81303,38.1092],[55.813881,38.116638],[55.81868,38.15852],[55.819,38.161419],[55.820221,38.172131],[55.820431,38.17411],[55.82132,38.181702],[55.821442,38.182949],[55.821461,38.183102],[55.821499,38.18354],[55.82225,38.190128],[55.822361,38.191101],[55.823551,38.20171],[55.824329,38.208481],[55.824909,38.213718],[55.8251,38.215611],[55.825329,38.218121],[55.82571,38.223591],[55.82608,38.228828],[55.826542,38.23563],[55.826778,38.239231],[55.827629,38.25211],[55.82795,38.25732],[55.828331,38.263401],[55.828781,38.2701],[55.829109,38.275379],[55.829342,38.280701],[55.829639,38.28738],[55.829659,38.287949],[55.82967,38.288231],[55.830051,38.29707],[55.830502,38.30489],[55.83194,38.33017],[55.83239,38.338009],[55.83342,38.35574],[55.833599,38.358952],[55.83403,38.366322],[55.834381,38.372669],[55.834702,38.377949],[55.83482,38.380878],[55.834839,38.382549],[55.83477,38.383881],[55.834599,38.385471],[55.833721,38.390701],[55.832951,38.395111],[55.832809,38.395908],[55.831779,38.401699],[55.8312,38.40456],[55.83094,38.405682],[55.830631,38.406898],[55.82999,38.408829],[55.82972,38.409592],[55.829151,38.41106],[55.828331,38.412979],[55.826809,38.416618],[55.826031,38.418549],[55.825748,38.419392],[55.825581,38.419949],[55.825089,38.42218],[55.824982,38.42305],[55.824871,38.42392],[55.82478,38.425251],[55.82473,38.426109],[55.82473,38.427311],[55.82476,38.428051],[55.824749,38.428509],[55.82481,38.429169],[55.824989,38.430969],[55.825199,38.432529],[55.825371,38.433399],[55.825699,38.434738],[55.826401,38.43708],[55.828979,38.44458],[55.83062,38.449169],[55.83115,38.45071],[55.832279,38.453861],[55.832829,38.455311],[55.833351,38.456581],[55.835171,38.46122],[55.83836,38.47044],[55.83844,38.47068],[55.839958,38.474972],[55.84132,38.47831],[55.842251,38.480808],[55.843899,38.484718],[55.849442,38.496941],[55.850368,38.499081],[55.851299,38.501099],[55.852501,38.50391],[55.853249,38.505562],[55.853828,38.507092],[55.854752,38.510052],[55.855492,38.5131],[55.85606,38.516289],[55.856522,38.519611],[55.85675,38.522591],[55.85672,38.52573],[55.8564,38.533169],[55.855999,38.541279],[55.85569,38.548031],[55.855461,38.55389],[55.855381,38.556011],[55.85527,38.558819],[55.855179,38.56089],[55.855011,38.565231],[55.854752,38.572048],[55.854591,38.575989],[55.854359,38.580959],[55.854198,38.58392],[55.853821,38.590309],[55.85355,38.594608],[55.853199,38.600342],[55.852901,38.605492],[55.852631,38.609772],[55.852612,38.610142],[55.85257,38.611061],[55.852402,38.613701],[55.85223,38.6166],[55.8522,38.617729],[55.85215,38.62241],[55.8521,38.625439],[55.852089,38.627972],[55.85202,38.63319],[55.851978,38.6376],[55.851929,38.641621],[55.851929,38.641899],[55.851871,38.646179],[55.85181,38.651909],[55.851761,38.656639],[55.851719,38.657131],[55.851452,38.658691],[55.850929,38.660412],[55.849529,38.664989],[55.848789,38.667549],[55.84853,38.668701],[55.84827,38.670448],[55.848209,38.671341],[55.848202,38.672771],[55.848221,38.674671],[55.84837,38.681469],[55.848541,38.689041],[55.848701,38.69688],[55.848831,38.70393],[55.84893,38.708691],[55.849152,38.718632],[55.849251,38.72348],[55.849361,38.728699],[55.849468,38.73336],[55.849529,38.736099],[55.849739,38.747841],[55.84996,38.75782],[55.85006,38.762772],[55.850109,38.76535],[55.85014,38.766449],[55.85014,38.76672],[55.850151,38.767639],[55.850201,38.77037],[55.850281,38.774529],[55.850449,38.782619],[55.85054,38.787449],[55.850739,38.797169],[55.85083,38.801781],[55.850929,38.806992],[55.851028,38.811989],[55.851151,38.817791],[55.851349,38.826908],[55.851452,38.83194],[55.851559,38.836769],[55.851669,38.84137],[55.85183,38.850101],[55.851959,38.854939],[55.852131,38.85675],[55.85244,38.859402],[55.852741,38.861851],[55.85297,38.86401],[55.853298,38.86705],[55.853371,38.86755],[55.853649,38.86882],[55.853851,38.869652],[55.854881,38.8736],[55.855572,38.876369],[55.856621,38.880428],[55.857498,38.883888],[55.857632,38.884441],[55.857899,38.885509],[55.858608,38.888271],[55.858761,38.888851],[55.859509,38.89172],[55.859638,38.892189],[55.86071,38.89637],[55.861301,38.898579],[55.86179,38.900471],[55.862309,38.90255],[55.866249,38.917938],[55.867081,38.921101],[55.869419,38.930328],[55.872372,38.945221],[55.873741,38.952301],[55.875,38.958649],[55.876041,38.962421],[55.876839,38.965401],[55.877029,38.96616],[55.878761,38.97385],[55.880711,38.982849],[55.88147,38.986351],[55.883362,38.9953],[55.88361,38.99654],[55.884048,38.998951],[55.884491,39.00079],[55.885399,39.004181],[55.886238,39.007469],[55.88715,39.010571],[55.88763,39.0121],[55.88805,39.013111],[55.896252,39.043819],[55.897362,39.047932],[55.897861,39.049789],[55.898151,39.051102],[55.898708,39.054008],[55.899109,39.05714],[55.899559,39.061008],[55.899792,39.063019],[55.899811,39.0634],[55.89986,39.063911],[55.899899,39.064449],[55.900002,39.065868],[55.900299,39.071079],[55.900551,39.0737],[55.90118,39.077179],[55.901691,39.079651],[55.901829,39.080311],[55.90213,39.081772],[55.905811,39.098789],[55.90694,39.10458],[55.91214,39.137428],[55.913052,39.14325],[55.913601,39.14687],[55.914108,39.150108],[55.91431,39.151501],[55.914421,39.152279],[55.914471,39.152599],[55.914822,39.154758],[55.915722,39.160469],[55.917042,39.168201],[55.9174,39.171108],[55.917789,39.17503],[55.918152,39.178669],[55.918442,39.181862],[55.91853,39.18288],[55.918919,39.186878],[55.919079,39.188759],[55.91988,39.199379],[55.920479,39.208561],[55.921219,39.21978],[55.921299,39.220951],[55.921619,39.22559],[55.92292,39.244621],[55.923351,39.250851],[55.926182,39.29248],[55.92696,39.3041],[55.927559,39.313049],[55.927952,39.318871],[55.928181,39.322529],[55.92836,39.325321],[55.92836,39.325371],[55.928421,39.326351],[55.928478,39.327202],[55.931431,39.37112],[55.93227,39.38385],[55.932812,39.391972],[55.933029,39.39529],[55.933151,39.397049],[55.934731,39.42107],[55.93491,39.423988],[55.936069,39.441189],[55.93721,39.45771],[55.93779,39.467388],[55.938061,39.46907],[55.93853,39.471161],[55.93972,39.475498],[55.941811,39.483219],[55.943611,39.499222],[55.943939,39.502159],[55.944931,39.511028],[55.94593,39.519939],[55.945969,39.520309],[55.952301,39.577099],[55.953369,39.586811],[55.955349,39.60461],[55.955799,39.60836],[55.956348,39.613419],[55.957291,39.622089],[55.957088,39.626629],[55.95681,39.632778],[55.95673,39.634609],[55.956711,39.635139],[55.956791,39.638279],[55.957359,39.64682],[55.958721,39.66798],[55.960369,39.69347],[55.960659,39.697731],[55.96085,39.700539],[55.96191,39.716789],[55.9622,39.72086],[55.96225,39.721691],[55.964409,39.75536],[55.964851,39.762169],[55.96489,39.762718],[55.96524,39.768108],[55.965439,39.774719],[55.965809,39.777882],[55.96764,39.784889],[55.98246,39.840961],[56.000141,39.908619],[56.000488,39.909969],[56.001431,39.913559],[56.001511,39.91383],[56.001701,39.91441],[56.002071,39.915791],[56.002529,39.917],[56.005741,39.92347],[56.007729,39.92849],[56.008629,39.931511],[56.008701,39.931782],[56.010071,39.936958],[56.011211,39.941299],[56.012619,39.94664],[56.013988,39.95166],[56.014,39.951679],[56.014729,39.95438],[56.017101,39.963089],[56.019081,39.970409],[56.019932,39.973541],[56.020969,39.97736],[56.021751,39.98024],[56.022251,39.982071],[56.022449,39.9828],[56.024139,39.989029],[56.024891,39.991821],[56.029888,40.01022],[56.033798,40.024639],[56.034512,40.027241],[56.036812,40.035728],[56.04406,40.06221],[56.04781,40.075932],[56.048531,40.07859],[56.050949,40.087429],[56.051281,40.08868],[56.05249,40.093159],[56.05315,40.095581],[56.060669,40.123489],[56.060928,40.1245],[56.06554,40.141541],[56.072929,40.169151],[56.073399,40.170849],[56.073719,40.172039],[56.076439,40.182251],[56.076839,40.1838],[56.0769,40.184021],[56.077229,40.185268],[56.078369,40.1894],[56.0798,40.195129],[56.08007,40.196331],[56.080158,40.196941],[56.080238,40.197891],[56.08025,40.19841],[56.080231,40.199059],[56.080151,40.19973],[56.080009,40.200539],[56.078861,40.20388],[56.078739,40.20433],[56.077461,40.207958],[56.075371,40.213879],[56.07259,40.221809],[56.07198,40.224579],[56.071739,40.22599],[56.071541,40.22797],[56.07151,40.231892],[56.071579,40.239571],[56.071621,40.242199],[56.071671,40.247181],[56.07172,40.251339],[56.071819,40.25576],[56.071899,40.264408],[56.072021,40.275421],[56.07201,40.277401],[56.071911,40.279362],[56.071751,40.281521],[56.071301,40.284851],[56.070419,40.289349],[56.070091,40.29105],[56.066311,40.311272],[56.065369,40.317341],[56.06509,40.320469],[56.064861,40.32436],[56.064812,40.32885],[56.06509,40.357712],[56.065109,40.36055],[56.064899,40.362999],[56.064381,40.365318],[56.063999,40.36647],[56.06348,40.368031],[56.062969,40.36956],[56.060211,40.37785],[56.058392,40.385189],[56.05584,40.401508],[56.05529,40.40506],[56.05397,40.413551],[56.053379,40.41769],[56.053059,40.422169],[56.053268,40.426491],[56.053631,40.429062],[56.054138,40.431789],[56.054539,40.433529],[56.055012,40.435131],[56.056149,40.438919],[56.057251,40.442509],[56.059212,40.448811],[56.059971,40.450859],[56.060799,40.45266],[56.061741,40.45451],[56.062462,40.455631],[56.063801,40.4575],[56.064159,40.457951],[56.06485,40.45874],[56.068939,40.462528],[56.07304,40.466202],[56.075062,40.468109],[56.076439,40.469688],[56.078892,40.473],[56.080009,40.47448],[56.080471,40.47506],[56.081928,40.476929],[56.082432,40.4776],[56.083141,40.478611],[56.0839,40.47998],[56.08466,40.481571],[56.085461,40.483891],[56.08606,40.486351],[56.089851,40.509869],[56.090389,40.513908],[56.092449,40.530998],[56.094212,40.545502],[56.095581,40.557201],[56.096889,40.568321],[56.097149,40.570969],[56.097328,40.57296],[56.09763,40.57518],[56.09798,40.577381],[56.098412,40.580799],[56.098591,40.58226],[56.099152,40.587151],[56.099369,40.589512],[56.099529,40.591148],[56.099812,40.593361],[56.100121,40.59547],[56.10041,40.597481],[56.102051,40.611118],[56.103661,40.624569],[56.103882,40.62677],[56.10405,40.629089],[56.10413,40.633461],[56.104019,40.641369],[56.103821,40.64497],[56.103828,40.648499],[56.10384,40.65242],[56.10363,40.661339],[56.103519,40.66444],[56.103489,40.667622],[56.103519,40.67067],[56.10334,40.683609],[56.103329,40.68642],[56.102959,40.711189],[56.102249,40.763199],[56.102329,40.76741],[56.102589,40.771111],[56.102612,40.771339],[56.102779,40.773022],[56.102951,40.774342],[56.103111,40.7756],[56.104851,40.787209],[56.10527,40.79002],[56.108238,40.809799],[56.111141,40.828381],[56.11182,40.83308],[56.112591,40.83646],[56.113392,40.839539],[56.114681,40.843609],[56.11602,40.84687],[56.118992,40.85318],[56.129902,40.876259],[56.13113,40.879059],[56.132191,40.881241],[56.132561,40.881989],[56.13348,40.88377],[56.134041,40.884899],[56.134701,40.88633],[56.137161,40.891621],[56.138111,40.893848],[56.139389,40.89642],[56.14061,40.898788],[56.146461,40.911152],[56.14753,40.91304],[56.14859,40.914761],[56.149818,40.91655],[56.151058,40.918201],[56.154869,40.922371],[56.158642,40.926521],[56.16753,40.93631],[56.173779,40.94326],[56.175091,40.94445],[56.176392,40.945431],[56.177738,40.946201],[56.1791,40.946781],[56.19043,40.950539],[56.190891,40.950729],[56.192089,40.95116],[56.192841,40.951611],[56.193321,40.95216],[56.193722,40.952839],[56.193989,40.95359],[56.19418,40.954418],[56.194321,40.955502],[56.19463,40.9617],[56.194931,40.968739],[56.195351,40.9744],[56.196018,40.986382],[56.196251,40.99144],[56.196758,41.00251],[56.197819,41.02309],[56.20219,41.11478],[56.20306,41.133041],[56.20385,41.149139],[56.2043,41.158642],[56.204361,41.15974],[56.206051,41.196301],[56.206631,41.206532],[56.207371,41.222488],[56.20882,41.251839],[56.211048,41.30019],[56.211201,41.303452],[56.212311,41.326351],[56.212448,41.33046],[56.216839,41.43071],[56.21756,41.447971],[56.218842,41.474659],[56.223141,41.56255],[56.225788,41.630322],[56.226082,41.63707],[56.226181,41.639389],[56.227459,41.669319],[56.22855,41.694981],[56.228828,41.701469],[56.228859,41.702179],[56.229172,41.709389],[56.230148,41.732349],[56.230259,41.73505],[56.230331,41.736679],[56.232471,41.786751],[56.232738,41.794498],[56.23291,41.79882],[56.23296,41.79998],[56.23317,41.805161],[56.233189,41.805889],[56.233589,41.817379],[56.234089,41.838871],[56.234402,41.85252],[56.23465,41.866039],[56.2351,41.8848],[56.23513,41.885979],[56.235168,41.887909],[56.2355,41.903431],[56.235889,41.921749],[56.236118,41.931831],[56.23632,41.94083],[56.23634,41.941792],[56.236351,41.94276],[56.23637,41.94421],[56.236561,41.952782],[56.23658,41.954411],[56.236591,41.95488],[56.236629,41.956581],[56.236629,41.956711],[56.236881,41.966068],[56.236931,41.97105],[56.236969,41.973549],[56.237,41.974812],[56.237041,41.976479],[56.237049,41.97715],[56.237061,41.97784],[56.23724,41.98439],[56.237301,41.98632],[56.23732,41.98719],[56.23737,41.98933],[56.237419,41.992352],[56.23745,41.993832],[56.237461,41.994499],[56.237541,41.99876],[56.237549,41.99931],[56.237621,42.00243],[56.237652,42.004131],[56.237789,42.009571],[56.23793,42.017139],[56.237999,42.02042],[56.238091,42.02457],[56.238201,42.02961],[56.238239,42.030991],[56.238331,42.034069],[56.238392,42.036381],[56.238419,42.037552],[56.238468,42.039661],[56.23851,42.041389],[56.238541,42.042309],[56.238659,42.047852],[56.238789,42.053452],[56.238899,42.058681],[56.238918,42.059441],[56.238991,42.062641],[56.239029,42.06456],[56.239059,42.066071],[56.239079,42.066719],[56.23912,42.068748],[56.23912,42.069061],[56.239128,42.069359],[56.239159,42.070831],[56.239262,42.075661],[56.239281,42.0765],[56.239319,42.07877],[56.23938,42.081821],[56.239422,42.083851],[56.23946,42.086319],[56.239498,42.088009],[56.239571,42.090832],[56.239658,42.09568],[56.2397,42.097988],[56.239719,42.099369],[56.239738,42.101269],[56.23975,42.101719],[56.239712,42.102219],[56.2397,42.102371],[56.239609,42.10305],[56.239429,42.10384],[56.239231,42.104568],[56.23909,42.105],[56.238941,42.105389],[56.238762,42.10577],[56.238419,42.106441],[56.238049,42.10704],[56.23793,42.10722],[56.23737,42.10807],[56.236279,42.109791],[56.235409,42.11121],[56.234341,42.112789],[56.23365,42.113869],[56.232689,42.115391],[56.231682,42.117001],[56.230629,42.11869],[56.22974,42.120159],[56.22879,42.121719],[56.22765,42.12347],[56.226768,42.124859],[56.22617,42.125839],[56.225601,42.126751],[56.225189,42.127468],[56.224949,42.127869],[56.224731,42.12825],[56.224499,42.128681],[56.22414,42.129459],[56.223801,42.130241],[56.22337,42.131451],[56.222969,42.132702],[56.222679,42.13369],[56.22237,42.13488],[56.222351,42.134972],[56.222271,42.13533],[56.222191,42.13578],[56.221951,42.136971],[56.221802,42.137798],[56.22171,42.138329],[56.22163,42.13887],[56.221539,42.139568],[56.22147,42.140251],[56.221359,42.141621],[56.22126,42.14344],[56.22121,42.144508],[56.221111,42.1465],[56.221081,42.147301],[56.221039,42.147991],[56.220989,42.149342],[56.220951,42.150242],[56.22086,42.151829],[56.220829,42.152328],[56.22076,42.153728],[56.220661,42.156261],[56.22057,42.158321],[56.220482,42.16037],[56.22044,42.16106],[56.220379,42.162239],[56.220242,42.1651],[56.220131,42.167999],[56.22007,42.169552],[56.220032,42.17033],[56.21991,42.172489],[56.219849,42.17411],[56.21983,42.17485],[56.219749,42.17614],[56.219639,42.17831],[56.219559,42.180012],[56.219509,42.181019],[56.21946,42.182041],[56.219452,42.182171],[56.219391,42.183201],[56.219341,42.18401],[56.219269,42.185101],[56.219189,42.18644],[56.219109,42.187599],[56.218929,42.190868],[56.218849,42.192341],[56.218769,42.193939],[56.218719,42.19487],[56.218681,42.195591],[56.218639,42.196548],[56.218578,42.19772],[56.218491,42.199581],[56.21841,42.201229],[56.21833,42.202839],[56.218288,42.203579],[56.218239,42.204659],[56.218159,42.206322],[56.218151,42.206532],[56.218102,42.207401],[56.218021,42.209061],[56.217918,42.211029],[56.21785,42.212399],[56.217781,42.213848],[56.217659,42.216492],[56.217541,42.218849],[56.217419,42.221321],[56.21735,42.222679],[56.217281,42.22393],[56.217239,42.22472],[56.21714,42.226871],[56.217079,42.228149],[56.21703,42.229679],[56.216999,42.230999],[56.216961,42.2323],[56.216888,42.233879],[56.216831,42.235279],[56.216728,42.237122],[56.21664,42.238911],[56.21656,42.24078],[56.216412,42.243759],[56.216209,42.245811],[56.215931,42.247929],[56.215611,42.24984],[56.215359,42.251202],[56.215031,42.25272],[56.21471,42.254009],[56.214241,42.255501],[56.213951,42.25647],[56.21389,42.25666],[56.2136,42.25761],[56.213039,42.259548],[56.212559,42.261139],[56.211979,42.263111],[56.21138,42.26503],[56.210609,42.267651],[56.209949,42.269829],[56.209171,42.272491],[56.208221,42.275631],[56.207611,42.277748],[56.20694,42.27998],[56.206249,42.282349],[56.205791,42.283871],[56.205238,42.28566],[56.20525,42.28627],[56.20401,42.290192],[56.203461,42.2924],[56.20311,42.31216],[56.202709,42.350479],[56.202141,42.353569],[56.20055,42.358742],[56.19643,42.370819],[56.192322,42.383091],[56.187889,42.39357],[56.180851,42.4077],[56.174171,42.41687],[56.173489,42.41782],[56.17289,42.41898],[56.172581,42.42009],[56.172379,42.421188],[56.170639,42.432362],[56.169659,42.43837],[56.16935,42.441959],[56.165829,42.482651],[56.164501,42.491241],[56.159721,42.51355],[56.15876,42.520081],[56.159119,42.531361],[56.15947,42.544979],[56.160858,42.594921],[56.161251,42.60453],[56.16552,42.619999],[56.172901,42.646759],[56.173481,42.649509],[56.178452,42.65913],[56.191662,42.686031],[56.19186,42.686432],[56.193371,42.689461],[56.196049,42.695148],[56.196758,42.698891],[56.197948,42.70261],[56.218712,42.76685],[56.220501,42.772598],[56.221661,42.77668],[56.223629,42.782749],[56.224579,42.78558],[56.226028,42.789421],[56.226971,42.792339],[56.22842,42.79681],[56.229061,42.798882],[56.23,42.802238],[56.230999,42.805901],[56.24231,42.84774],[56.242371,42.84795],[56.249691,42.874859],[56.256721,42.90099],[56.260399,42.91436],[56.26405,42.927792],[56.27478,42.967529],[56.275219,42.969231],[56.27552,42.970509],[56.275791,42.971901],[56.275982,42.973129],[56.27615,42.97443],[56.27631,42.976299],[56.276451,42.978531],[56.276951,42.98867],[56.277401,42.998749],[56.278488,43.02235],[56.280121,43.058609],[56.2817,43.09417],[56.28487,43.16291],[56.285,43.165661],[56.28511,43.16753],[56.286179,43.19146],[56.28981,43.27335],[56.293308,43.355141],[56.293659,43.3633],[56.298222,43.473461],[56.298351,43.476559],[56.298439,43.478661],[56.30085,43.538639],[56.300961,43.541592],[56.301022,43.542969],[56.30117,43.54668],[56.301609,43.557201],[56.301689,43.559189],[56.301788,43.56168],[56.302059,43.56789],[56.302711,43.58334],[56.30302,43.590809],[56.303028,43.59116],[56.303051,43.591572],[56.303471,43.601101],[56.304211,43.618938],[56.304508,43.625919],[56.304779,43.63308],[56.30534,43.648609],[56.305931,43.66502],[56.3064,43.678478],[56.306499,43.681099],[56.306599,43.684059],[56.30685,43.690491],[56.306889,43.691631],[56.30698,43.693989],[56.307541,43.709881],[56.308159,43.726921],[56.308701,43.742699],[56.308842,43.746109],[56.308861,43.74688],[56.309269,43.759121],[56.309689,43.770309],[56.309891,43.77544],[56.31036,43.788029],[56.31041,43.78923],[56.31052,43.79203],[56.31076,43.798061],[56.310822,43.799671],[56.310879,43.800941],[56.31118,43.808899],[56.311352,43.81353],[56.311588,43.819901],[56.31181,43.825691],[56.311871,43.826111],[56.311878,43.82626],[56.311951,43.828098],[56.312481,43.84042],[56.312481,43.84058],[56.3125,43.84108],[56.312569,43.84277],[56.312729,43.846748],[56.312771,43.847858],[56.312908,43.851131],[56.313179,43.858212],[56.313381,43.86322],[56.313339,43.86388],[56.31329,43.864182],[56.31319,43.864399],[56.31303,43.864601],[56.312889,43.864811],[56.312809,43.86499],[56.312752,43.865238],[56.312729,43.86554],[56.31271,43.865829],[56.312649,43.866119],[56.312569,43.866451],[56.312401,43.86694],[56.31234,43.867142],[56.31226,43.867359],[56.312019,43.868],[56.31189,43.868252],[56.311749,43.868431],[56.311569,43.86861],[56.311371,43.868721],[56.31123,43.86879],[56.311039,43.868851],[56.310219,43.869301],[56.309959,43.869438],[56.308971,43.86998],[56.30854,43.870209],[56.307701,43.87067],[56.30727,43.870861],[56.306358,43.871262],[56.30381,43.872391],[56.30378,43.87241],[56.302429,43.873341],[56.301121,43.874241],[56.300819,43.874489],[56.300529,43.874741],[56.30027,43.87495],[56.299419,43.875721],[56.298512,43.876701],[56.296959,43.878609],[56.29636,43.87933],[56.296249,43.879471],[56.295639,43.880219],[56.292381,43.884319],[56.29105,43.88586],[56.290588,43.886318],[56.290161,43.886688],[56.289589,43.887131],[56.288311,43.88802],[56.285702,43.889679],[56.28524,43.890011],[56.284592,43.890591],[56.284111,43.89122],[56.283798,43.891769],[56.283489,43.89238],[56.283249,43.89304],[56.282909,43.894009],[56.28241,43.895481],[56.28233,43.895679],[56.282242,43.895889],[56.282108,43.896191],[56.281689,43.896961],[56.281368,43.897442],[56.280849,43.898109],[56.279018,43.900459],[56.277939,43.90184],[56.275742,43.904671],[56.275139,43.905418],[56.273869,43.907001],[56.271389,43.910061],[56.27079,43.910809],[56.27037,43.91135],[56.26947,43.912491],[56.268799,43.913399],[56.267921,43.914761],[56.26685,43.916649],[56.265621,43.918991],[56.26532,43.919529],[56.265091,43.919971],[56.26498,43.92017],[56.264561,43.92083],[56.26289,43.923988],[56.259861,43.9296],[56.258461,43.93219],[56.257511,43.93396],[56.25581,43.937119],[56.255291,43.93811],[56.25526,43.93816],[56.254051,43.940411],[56.253658,43.94112],[56.25359,43.94136],[56.247311,43.952999],[56.24699,43.953442],[56.246658,43.954079],[56.246319,43.954781],[56.2458,43.956051],[56.245468,43.956982],[56.245251,43.957668],[56.244961,43.95874],[56.244759,43.959629],[56.244659,43.96011],[56.24461,43.960312],[56.244431,43.96151],[56.244259,43.9632],[56.24329,43.969559],[56.242779,43.972801],[56.242569,43.974159],[56.241779,43.979431],[56.24115,43.98365],[56.240299,43.989269],[56.240002,43.991211],[56.239479,43.994652],[56.239391,43.995251],[56.239059,43.997501],[56.238861,43.998791],[56.23848,44.001282],[56.237991,44.00481],[56.237598,44.007809],[56.236511,44.016102],[56.23597,44.020561],[56.235611,44.023499],[56.23531,44.025822],[56.235142,44.027859],[56.234989,44.029701],[56.234871,44.031559],[56.234852,44.033421],[56.234821,44.035389],[56.234798,44.037701],[56.234859,44.039421],[56.23494,44.041561],[56.234959,44.042831],[56.23494,44.04459],[56.234901,44.046188],[56.234798,44.04805],[56.234711,44.04911],[56.234631,44.050011],[56.234371,44.052341],[56.234089,44.054321],[56.23373,44.056801],[56.233471,44.058552],[56.233158,44.060539],[56.232841,44.062511],[56.232368,44.064899],[56.23204,44.066311],[56.231579,44.067959],[56.230968,44.06966],[56.230179,44.071381],[56.22961,44.07238],[56.229092,44.07309],[56.228531,44.073719],[56.22784,44.074341],[56.227322,44.07473],[56.22718,44.074841],[56.226452,44.07531],[56.225849,44.07563],[56.225422,44.07584],[56.224709,44.076099],[56.224461,44.07616],[56.224079,44.076279],[56.222832,44.076618],[56.222149,44.076801],[56.221401,44.077],[56.221279,44.07703],[56.221031,44.077099],[56.219299,44.077549],[56.218559,44.077789],[56.218239,44.0779],[56.21714,44.078289],[56.216202,44.07869],[56.214901,44.07935],[56.213631,44.080139],[56.212791,44.080719],[56.2122,44.0812],[56.21196,44.081409],[56.210991,44.08226],[56.209549,44.084049],[56.208542,44.085522],[56.20752,44.087189],[56.206581,44.088951],[56.20557,44.091019],[56.204281,44.093899],[56.202381,44.098438],[56.200378,44.103588],[56.1991,44.10717],[56.19838,44.109509],[56.197811,44.111912],[56.197239,44.11475],[56.196892,44.116421],[56.19648,44.11845],[56.1959,44.120911],[56.195431,44.122639],[56.19519,44.12355],[56.194889,44.124451],[56.194031,44.126621],[56.19368,44.127392],[56.192139,44.130371],[56.184631,44.1441],[56.18375,44.145748],[56.183289,44.14687],[56.18206,44.149559],[56.181019,44.151909],[56.18055,44.152851],[56.180149,44.153339],[56.179749,44.153751],[56.179279,44.154121],[56.178768,44.15432],[56.17852,44.1544],[56.17807,44.154442],[56.17754,44.154362],[56.1758,44.153782],[56.17519,44.15361],[56.174358,44.1534],[56.172741,44.153111],[56.171921,44.153011],[56.170971,44.153091],[56.1702,44.153309],[56.169479,44.15358],[56.167912,44.154518],[56.167179,44.154819],[56.166439,44.155022],[56.165722,44.15506],[56.164558,44.154861],[56.162151,44.154259],[56.16098,44.154011],[56.16011,44.153992],[56.15934,44.154072],[56.159271,44.154091],[56.158569,44.154289],[56.157799,44.154652],[56.15654,44.155418],[56.154202,44.156952],[56.152458,44.158081],[56.152191,44.15826],[56.151131,44.158859],[56.150391,44.15918],[56.149712,44.15934],[56.148991,44.159351],[56.14843,44.159248],[56.147739,44.159031],[56.146961,44.15876],[56.14455,44.15778],[56.142811,44.157021],[56.14106,44.156429],[56.139969,44.156181],[56.13829,44.15604],[56.13681,44.15617],[56.13583,44.156361],[56.134491,44.156769],[56.132931,44.157539],[56.131821,44.158249],[56.130699,44.159069],[56.128441,44.161259],[56.12693,44.162819],[56.126362,44.163399],[56.12606,44.163509],[56.12534,44.163601],[56.125229,44.163601],[56.12508,44.163631],[56.124931,44.163719],[56.12479,44.163849],[56.12468,44.16404],[56.124569,44.164322],[56.124561,44.164581],[56.12447,44.165009],[56.124352,44.16531],[56.124161,44.165581],[56.11639,44.172829],[56.114761,44.175751],[56.114281,44.18227],[56.113708,44.20322],[56.118099,44.20797],[56.120731,44.212132],[56.122238,44.217312],[56.123001,44.221142],[56.124619,44.233261],[56.124748,44.236141],[56.124519,44.23875],[56.123379,44.245941],[56.123192,44.248219],[56.123291,44.25174],[56.123562,44.253281],[56.123821,44.254478],[56.124229,44.25581],[56.124779,44.257179],[56.125118,44.257881],[56.125809,44.259491],[56.126011,44.260029],[56.126171,44.260712],[56.126259,44.261318],[56.126282,44.26189],[56.12627,44.26244],[56.12616,44.263191],[56.125919,44.264118],[56.125099,44.265911],[56.124939,44.2663],[56.124069,44.267879],[56.123779,44.26833],[56.12331,44.26902],[56.122421,44.270199],[56.12162,44.271191],[56.119259,44.273941],[56.118172,44.275181],[56.116798,44.276749],[56.116131,44.277519],[56.116051,44.277611],[56.110699,44.283699],[56.110271,44.284191],[56.109791,44.284729],[56.109711,44.28484],[56.10701,44.287941],[56.106419,44.288818],[56.105862,44.289761],[56.105419,44.290649],[56.105,44.29166],[56.10062,44.3041],[56.100159,44.305382],[56.099739,44.306492],[56.099602,44.306808],[56.099461,44.307152],[56.099281,44.307499],[56.09911,44.3078],[56.09856,44.308731],[56.098141,44.309391],[56.097229,44.31078],[56.096748,44.311501],[56.096439,44.311989],[56.096069,44.312691],[56.095699,44.313511],[56.09544,44.314381],[56.095169,44.315392],[56.09502,44.316132],[56.094589,44.31863],[56.094391,44.319469],[56.094189,44.32019],[56.093269,44.323238],[56.092361,44.326302],[56.092079,44.327221],[56.091511,44.32906],[56.09087,44.33099],[56.089882,44.33382],[56.08746,44.34079],[56.085609,44.346218],[56.08498,44.348091],[56.078499,44.367161],[56.07822,44.367901],[56.0779,44.368568],[56.077641,44.369019],[56.077221,44.369598],[56.076939,44.36993],[56.07653,44.370312],[56.076092,44.37064],[56.075611,44.37093],[56.07449,44.37151],[56.072449,44.37249],[56.07077,44.37331],[56.070179,44.3736],[56.06971,44.373821],[56.06889,44.374222],[56.06757,44.374809],[56.06712,44.37505],[56.066761,44.375278],[56.06636,44.37561],[56.066021,44.375938],[56.06572,44.376289],[56.065331,44.376808],[56.06496,44.37743],[56.064522,44.378269],[56.06411,44.37928],[56.06295,44.382271],[56.061211,44.386551],[56.06065,44.38792],[56.060341,44.388691],[56.059681,44.390308],[56.058399,44.393452],[56.05621,44.3988],[56.048389,44.418091],[56.046501,44.422661],[56.046261,44.423382],[56.04607,44.42403],[56.045879,44.42485],[56.0457,44.425869],[56.045631,44.426609],[56.045601,44.427601],[56.04567,44.43103],[56.045658,44.43306],[56.045601,44.433769],[56.045422,44.43491],[56.045189,44.43594],[56.044868,44.43692],[56.04438,44.438099],[56.043289,44.44075],[56.042999,44.441589],[56.042721,44.442501],[56.042519,44.443401],[56.04229,44.444969],[56.04158,44.452389],[56.040192,44.46664],[56.03883,44.480659],[56.038719,44.481689],[56.03862,44.48259],[56.038479,44.483471],[56.0383,44.48428],[56.03804,44.485199],[56.032162,44.502251],[56.031761,44.503448],[56.03149,44.50462],[56.031231,44.505871],[56.031078,44.50705],[56.030899,44.510342],[56.029461,44.545521],[56.028801,44.55407],[56.028011,44.56155],[56.02747,44.568169],[56.027908,44.584888],[56.027229,44.601978],[56.027962,44.60656],[56.02803,44.60738],[56.028179,44.608879],[56.027988,44.613171],[56.02737,44.620541],[56.026791,44.622929],[56.025871,44.624432],[56.025089,44.624889],[56.023769,44.625179],[56.01659,44.625172],[56.015221,44.62529],[56.014061,44.625511],[56.01297,44.625832],[56.011951,44.626362],[56.007408,44.628609],[56.006721,44.629009],[56.0061,44.62944],[56.005871,44.629589],[56.005348,44.630001],[56.004879,44.63052],[56.004238,44.631302],[56.003769,44.631981],[56.002949,44.633129],[56.001518,44.635151],[55.99966,44.63776],[55.998241,44.63979],[55.99741,44.640949],[55.99712,44.641411],[55.996738,44.642159],[55.996521,44.642689],[55.996262,44.643299],[55.996029,44.64399],[55.99559,44.645599],[55.995281,44.647511],[55.995129,44.649059],[55.994919,44.652161],[55.994518,44.658161],[55.99395,44.666309],[55.993889,44.667858],[55.9939,44.66943],[55.998219,44.71011],[55.998539,44.712761],[55.998741,44.713772],[55.999039,44.71479],[55.99942,44.715759],[56,44.71698],[56.00106,44.719109],[56.00182,44.720669],[56.002209,44.721561],[56.00251,44.722279],[56.002708,44.7229],[56.002911,44.72369],[56.003139,44.72504],[56.00322,44.72617],[56.003151,44.72768],[56.002838,44.730659],[56.00259,44.734131],[56.001751,44.74255],[56.00153,44.744381],[56.00132,44.74527],[56.00106,44.745949],[56.00074,44.74662],[55.999279,44.748779],[55.992989,44.757961],[55.990791,44.761318],[55.99033,44.762321],[55.990009,44.76318],[55.989819,44.764069],[55.989719,44.76498],[55.9897,44.765968],[55.99073,44.773331],[55.992962,44.788288],[55.997372,44.81881],[55.997601,44.820049],[55.99781,44.82066],[55.999069,44.823261],[56.004459,44.834709],[56.005829,44.837769],[56.006161,44.83881],[56.006748,44.841309],[56.011189,44.860889],[56.011292,44.861591],[56.011341,44.862282],[56.011372,44.863121],[56.011292,44.86404],[56.01112,44.864929],[56.01088,44.865551],[56.009129,44.869228],[56.008862,44.870022],[56.008659,44.87093],[56.008221,44.873871],[56.005791,44.88974],[56.005718,44.890362],[56.005669,44.890942],[56.005661,44.891472],[56.00568,44.89201],[56.005779,44.89299],[56.007172,44.900478],[56.010979,44.920929],[56.011169,44.922211],[56.011269,44.923309],[56.01128,44.924629],[56.011219,44.925812],[56.01107,44.92696],[56.01088,44.928028],[56.01038,44.92984],[56.009178,44.934361],[56.00882,44.936081],[56.00861,44.93779],[56.008499,44.939602],[56.00845,44.941158],[56.008499,44.94244],[56.008629,44.943741],[56.016418,44.996269],[56.016571,44.997238],[56.016651,44.998199],[56.016651,44.999229],[56.016579,45.000408],[56.01646,45.001598],[56.015572,45.008961],[56.014961,45.014542],[56.01482,45.015701],[56.01453,45.018242],[56.013649,45.026249],[56.013618,45.02721],[56.013519,45.03426],[56.013458,45.039619],[56.0135,45.04118],[56.013618,45.042728],[56.013851,45.044189],[56.01667,45.059238],[56.016972,45.061581],[56.017262,45.06358],[56.017792,45.06654],[56.01825,45.068859],[56.01857,45.069988],[56.019001,45.071701],[56.019669,45.07513],[56.021061,45.082458],[56.021461,45.084579],[56.022079,45.087971],[56.022369,45.089191],[56.023079,45.09153],[56.032928,45.121109],[56.033489,45.122829],[56.03371,45.1236],[56.03389,45.12447],[56.033981,45.125229],[56.034012,45.125919],[56.033951,45.140442],[56.033981,45.141682],[56.03405,45.142712],[56.034149,45.143501],[56.034302,45.14452],[56.03447,45.14547],[56.036381,45.15469],[56.037941,45.162331],[56.03825,45.163601],[56.038639,45.164841],[56.04472,45.18079],[56.0452,45.182331],[56.045761,45.18428],[56.046219,45.18568],[56.05463,45.209648],[56.055241,45.21146],[56.056541,45.215519],[56.05685,45.216721],[56.05695,45.21751],[56.056931,45.218281],[56.056839,45.219101],[56.055882,45.224049],[56.055679,45.224819],[56.05537,45.225571],[56.055038,45.226059],[56.054619,45.226501],[56.052269,45.22813],[56.05188,45.228588],[56.051609,45.228958],[56.051338,45.229519],[56.051128,45.230221],[56.050152,45.234531],[56.050018,45.235241],[56.04998,45.235939],[56.049992,45.236629],[56.050049,45.237339],[56.050549,45.241348],[56.050812,45.24242],[56.05117,45.243542],[56.054352,45.252941],[56.054729,45.254261],[56.057491,45.26442],[56.057732,45.265572],[56.057899,45.266819],[56.06147,45.302731],[56.06155,45.30365],[56.061569,45.3046],[56.06155,45.305679],[56.059879,45.333832],[56.059811,45.334759],[56.05975,45.335331],[56.05962,45.335831],[56.059311,45.336651],[56.05505,45.3456],[56.054668,45.346481],[56.054428,45.347198],[56.054138,45.348209],[56.053459,45.350941],[56.048328,45.371361],[56.045738,45.383511],[56.045441,45.385231],[56.045231,45.386841],[56.045151,45.388439],[56.045139,45.390099],[56.045349,45.412231],[56.04546,45.416229],[56.045818,45.427399],[56.04599,45.433071],[56.046089,45.43544],[56.046261,45.43782],[56.048069,45.462238],[56.048229,45.464199],[56.048649,45.4678],[56.04969,45.476719],[56.049881,45.478939],[56.050049,45.481541],[56.05159,45.50951],[56.05167,45.511181],[56.051689,45.512569],[56.051651,45.513699],[56.051338,45.521839],[56.051022,45.52972],[56.05093,45.531212],[56.050331,45.5387],[56.050159,45.542641],[56.04998,45.547421],[56.049931,45.549541],[56.049801,45.556591],[56.04974,45.558392],[56.049622,45.559582],[56.04945,45.560902],[56.042751,45.60685],[56.042622,45.608101],[56.042542,45.609371],[56.0425,45.610531],[56.042519,45.611721],[56.043781,45.639339],[56.043911,45.642521],[56.043968,45.64629],[56.043991,45.648689],[56.044109,45.65126],[56.044941,45.669449],[56.046001,45.69286],[56.047169,45.718689],[56.047298,45.721008],[56.047428,45.72295],[56.04747,45.723801],[56.047531,45.72514],[56.047611,45.72768],[56.047642,45.729301],[56.047729,45.73056],[56.047878,45.732529],[56.0481,45.73505],[56.049339,45.76276],[56.05212,45.825199],[56.052471,45.833271],[56.052521,45.834949],[56.052521,45.83625],[56.052479,45.837379],[56.052319,45.83881],[56.05183,45.8419],[56.05162,45.843281],[56.051498,45.844559],[56.05138,45.84687],[56.05125,45.8498],[56.051159,45.851379],[56.050831,45.854912],[56.050701,45.856312],[56.049992,45.862358],[56.049831,45.864239],[56.049709,45.86623],[56.049679,45.86813],[56.049728,45.876091],[56.049679,45.88908],[56.04977,45.914181],[56.04974,45.917419],[56.049679,45.918701],[56.049541,45.919899],[56.04932,45.921299],[56.049019,45.9226],[56.04644,45.932362],[56.043549,45.943329],[56.040409,45.955261],[56.038261,45.96336],[56.03299,45.983471],[56.031689,45.988319],[56.03056,45.99202],[56.029942,45.994209],[56.029259,45.997021],[56.02877,45.999298],[56.02837,46.0009],[56.027851,46.002811],[56.027481,46.00399],[56.027149,46.005001],[56.024632,46.011688],[56.0242,46.01265],[56.023731,46.01347],[56.023338,46.013981],[56.022781,46.014511],[56.013191,46.021309],[56.01276,46.021709],[56.01244,46.02203],[56.012001,46.022621],[56.010399,46.025391],[56.000919,46.041672],[56.000729,46.042179],[56.000549,46.042931],[56.0005,46.043468],[56.000519,46.044189],[56.001808,46.052929],[56.00206,46.05484],[56.002281,46.057281],[56.002369,46.059891],[56.002361,46.062141],[56.0023,46.06382],[56.00206,46.06641],[56.001732,46.06881],[56.00156,46.07061],[56.001492,46.071232],[56.001389,46.07185],[56.001308,46.072269],[56.001221,46.072941],[56.00119,46.07328],[56.00116,46.07373],[56.001141,46.073952],[56.001122,46.074341],[56.001099,46.074928],[56.001091,46.075539],[56.00108,46.076149],[56.001049,46.076752],[56.00053,46.083248],[55.999199,46.09798],[55.99498,46.14637],[55.994808,46.148331],[55.99472,46.149422],[55.994701,46.149609],[55.99176,46.183311],[55.991692,46.18539],[55.991638,46.186008],[55.991428,46.188259],[55.991402,46.19009],[55.991539,46.191662],[55.991871,46.193192],[55.99226,46.19455],[55.99284,46.195869],[55.993382,46.196812],[55.99437,46.198441],[55.995071,46.199669],[55.999889,46.20805],[56.00531,46.217491],[56.023251,46.24873],[56.02623,46.251999],[56.0299,46.251999],[56.03352,46.251999],[56.035919,46.251999],[56.037731,46.254398],[56.038311,46.25835],[56.039459,46.27895],[56.041672,46.29525],[56.046558,46.307789],[56.048191,46.31345],[56.048672,46.31723],[56.04723,46.332329],[56.04541,46.343491],[56.041759,46.352589],[56.041859,46.360661],[56.043789,46.388691],[56.043659,46.392811],[56.043491,46.39859],[56.043449,46.401878],[56.043591,46.405979],[56.04475,46.41238],[56.046619,46.41885],[56.053459,46.44117],[56.05431,46.446171],[56.054729,46.451389],[56.054611,46.45636],[56.05423,46.461418],[56.05331,46.47226],[56.053188,46.473629],[56.053181,46.474159],[56.053089,46.481258],[56.052898,46.485489],[56.052528,46.489059],[56.052441,46.49054],[56.05159,46.49752],[56.0509,46.50153],[56.049671,46.506149],[56.04829,46.509941],[56.046009,46.515419],[56.04472,46.51873],[56.044022,46.521999],[56.043678,46.529739],[56.04335,46.53318],[56.042351,46.53688],[56.035011,46.55698],[56.033741,46.56041],[56.032841,46.563221],[56.032211,46.565639],[56.031391,46.57016],[56.029469,46.585281],[56.028889,46.595551],[56.028278,46.6063],[56.027569,46.619801],[56.027309,46.626148],[56.027309,46.627911],[56.027512,46.629749],[56.027939,46.632141],[56.02964,46.639069],[56.031391,46.645939],[56.033852,46.656311],[56.034889,46.660709],[56.035099,46.66254],[56.036781,46.69265],[56.037251,46.697632],[56.0387,46.703979],[56.0387,46.707932],[56.037731,46.721489],[56.039558,46.728699],[56.042339,46.737801],[56.04314,46.746071],[56.04319,46.748631],[56.042961,46.750309],[56.041538,46.754669],[56.040661,46.758701],[56.040581,46.759079],[56.040421,46.759769],[56.03957,46.765049],[56.03772,46.77631],[56.036991,46.780369],[56.0368,46.78244],[56.036869,46.786209],[56.0392,46.803761],[56.039871,46.80917],[56.039822,46.810558],[56.038109,46.81823],[56.036789,46.824089],[56.036869,46.82579],[56.03714,46.826839],[56.038311,46.831009],[56.03957,46.835312],[56.041149,46.839378],[56.04311,46.844231],[56.043839,46.846352],[56.04438,46.848721],[56.045879,46.855339],[56.04665,46.8587],[56.047611,46.86174],[56.047932,46.86235],[56.049171,46.864792],[56.050739,46.868031],[56.05175,46.870609],[56.055851,46.88237],[56.05761,46.887409],[56.062759,46.901951],[56.064739,46.907742],[56.065029,46.90863],[56.06554,46.910461],[56.066238,46.912868],[56.066681,46.91515],[56.067039,46.91732],[56.067291,46.920391],[56.067451,46.923191],[56.067589,46.927719],[56.067719,46.931561],[56.068031,46.935589],[56.068279,46.938339],[56.068352,46.942348],[56.068211,46.946701],[56.068069,46.948849],[56.067928,46.951],[56.067291,46.957489],[56.06702,46.962231],[56.06741,46.966591],[56.070992,46.979061],[56.072788,46.985001],[56.07473,46.98983],[56.076599,46.994331],[56.078522,46.998268],[56.08009,46.9995],[56.08173,47.000271],[56.086712,47.000271],[56.09016,47.000099],[56.093441,47.00481],[56.09473,47.007542],[56.095901,47.010571],[56.097309,47.017738],[56.098011,47.021351],[56.099701,47.029541],[56.100319,47.031738],[56.10128,47.034081],[56.103828,47.039719],[56.105461,47.043171],[56.105839,47.043861],[56.106319,47.045059],[56.10738,47.05011],[56.107681,47.0527],[56.1077,47.055019],[56.107552,47.0574],[56.10709,47.06049],[56.1063,47.063309],[56.105301,47.065731],[56.101891,47.073051],[56.09856,47.08017],[56.097729,47.08242],[56.096951,47.085232],[56.095699,47.090679],[56.095421,47.092789],[56.095249,47.096661],[56.095261,47.102612],[56.095139,47.104542],[56.09481,47.107121],[56.094398,47.109299],[56.09375,47.11121],[56.093029,47.11285],[56.091702,47.11507],[56.091091,47.116089],[56.091,47.116241],[56.089619,47.118511],[56.085571,47.125172],[56.08503,47.125961],[56.084919,47.12611],[56.084301,47.126968],[56.082741,47.12915],[56.082001,47.130772],[56.081478,47.132332],[56.08107,47.13361],[56.08086,47.134651],[56.080711,47.135799],[56.080631,47.136902],[56.08065,47.137569],[56.0807,47.13879],[56.080799,47.140129],[56.080929,47.142139],[56.081001,47.145439],[56.080872,47.14772],[56.08075,47.149818],[56.079498,47.161301],[56.07925,47.163631],[56.07827,47.1726],[56.07814,47.17382],[56.07724,47.18169],[56.07579,47.192719],[56.07357,47.20916],[56.073471,47.20993],[56.073029,47.213341],[56.07275,47.215809],[56.072189,47.223049],[56.071972,47.22517],[56.071758,47.226429],[56.071571,47.227032],[56.071289,47.227921],[56.070801,47.228939],[56.070629,47.229309],[56.069908,47.23064],[56.068779,47.23275],[56.067348,47.235401],[56.06498,47.239841],[56.064011,47.242249],[56.063122,47.244579],[56.062851,47.245441],[56.062271,47.247372],[56.06118,47.251011],[56.056301,47.26749],[56.054482,47.273621],[56.053581,47.27618],[56.05265,47.278511],[56.05154,47.280701],[56.050781,47.282139],[56.05019,47.283138],[56.04969,47.283932],[56.048931,47.285118],[56.048679,47.285511],[56.04755,47.287201],[56.047009,47.287998],[56.04649,47.288818],[56.045841,47.289921],[56.044739,47.291401],[56.04414,47.291889],[56.042969,47.292278],[56.04179,47.292721],[56.039879,47.29364],[56.038231,47.294399],[56.037552,47.294621],[56.037109,47.294861],[56.03508,47.29686],[56.034489,47.29744],[56.03326,47.298691],[56.031361,47.300598],[56.030918,47.30106],[56.028469,47.303589],[56.027229,47.30484],[56.026321,47.305721],[56.025711,47.306198],[56.025188,47.306469],[56.023659,47.306641],[56.022579,47.306549],[56.02203,47.306499],[56.020481,47.306591],[56.019878,47.306801],[56.015999,47.308731],[56.01519,47.30917],[56.014252,47.309811],[56.01292,47.311291],[56.012001,47.31255],[56.006481,47.320141],[56.001209,47.327278],[55.999889,47.329128],[55.99604,47.335972],[55.995331,47.337238],[55.993549,47.340099],[55.991451,47.342548],[55.98999,47.34383],[55.988159,47.345169],[55.986809,47.346241],[55.981941,47.349789],[55.980881,47.35088],[55.979839,47.352501],[55.97887,47.3545],[55.977589,47.357769],[55.976109,47.361542],[55.975159,47.363609],[55.974258,47.36512],[55.973839,47.365681],[55.973351,47.36636],[55.972488,47.367199],[55.971161,47.368111],[55.967972,47.369289],[55.955429,47.373619],[55.954979,47.373798],[55.953979,47.37418],[55.952679,47.374729],[55.94875,47.376019],[55.946899,47.376781],[55.945938,47.377571],[55.943161,47.380451],[55.940948,47.38271],[55.939751,47.384411],[55.936741,47.389381],[55.935101,47.391281],[55.933262,47.392971],[55.93121,47.394451],[55.929211,47.395889],[55.927551,47.39724],[55.926399,47.398449],[55.9226,47.403091],[55.921741,47.404148],[55.920528,47.405579],[55.918819,47.40807],[55.91716,47.41069],[55.916698,47.411671],[55.916309,47.412498],[55.914101,47.418381],[55.913441,47.41946],[55.912418,47.420738],[55.908581,47.424839],[55.90633,47.426651],[55.901878,47.42955],[55.901161,47.430031],[55.895618,47.433651],[55.894421,47.434689],[55.892799,47.43697],[55.88855,47.443161],[55.888069,47.443851],[55.887871,47.44413],[55.88583,47.446899],[55.883289,47.45002],[55.88179,47.4515],[55.880421,47.452499],[55.879139,47.45322],[55.875099,47.455521],[55.873589,47.456379],[55.87035,47.45821],[55.867191,47.460121],[55.865879,47.460709],[55.864021,47.461391],[55.862419,47.46183],[55.86158,47.462151],[55.861351,47.462231],[55.859638,47.46286],[55.859451,47.462879],[55.859299,47.46291],[55.859112,47.462898],[55.85899,47.46286],[55.858898,47.46283],[55.858799,47.46283],[55.858669,47.462811],[55.858521,47.46286],[55.858379,47.462978],[55.85828,47.463181],[55.858189,47.463459],[55.85804,47.463772],[55.857811,47.46413],[55.856998,47.46505],[55.856281,47.466],[55.855221,47.467789],[55.854542,47.46933],[55.853779,47.471619],[55.853168,47.474701],[55.852329,47.47958],[55.851681,47.483719],[55.851299,47.48711],[55.851219,47.49049],[55.85128,47.498058],[55.851151,47.502029],[55.845791,47.519192],[55.838692,47.54253],[55.83746,47.545639],[55.83424,47.549709],[55.822781,47.554779],[55.822071,47.555401],[55.8214,47.55621],[55.82056,47.557529],[55.819908,47.55875],[55.819012,47.560822],[55.815189,47.571041],[55.81255,47.578011],[55.812,47.579971],[55.81171,47.581741],[55.81152,47.583],[55.811409,47.584469],[55.811451,47.59251],[55.811501,47.600479],[55.81134,47.603279],[55.81094,47.605721],[55.809799,47.61113],[55.809341,47.612709],[55.808788,47.614182],[55.807251,47.617229],[55.805641,47.62014],[55.804741,47.622139],[55.804001,47.624081],[55.796421,47.655689],[55.790298,47.67799],[55.790199,47.687599],[55.78907,47.721489],[55.788929,47.727829],[55.788792,47.732651],[55.788681,47.737221],[55.788841,47.739471],[55.788872,47.739948],[55.789661,47.75219],[55.791161,47.77618],[55.79425,47.819092],[55.796959,47.839352],[55.798401,47.845871],[55.799179,47.85342],[55.803902,47.910759],[55.809399,47.984749],[55.811138,48.006031],[55.809589,48.024609],[55.808731,48.035042],[55.808239,48.037788],[55.805061,48.045681],[55.796379,48.063881],[55.795891,48.068169],[55.79628,48.075378],[55.796959,48.099411],[55.797729,48.12001],[55.79744,48.122929],[55.79174,48.140961],[55.79081,48.14307],[55.787991,48.147861],[55.786129,48.151039],[55.785351,48.153011],[55.784908,48.154751],[55.784889,48.157612],[55.783482,48.167641],[55.783218,48.17033],[55.782959,48.17271],[55.78307,48.175579],[55.783562,48.181591],[55.7841,48.18906],[55.78397,48.1908],[55.7836,48.191669],[55.78286,48.19384],[55.78233,48.19453],[55.781609,48.194939],[55.77676,48.197281],[55.775921,48.197571],[55.774609,48.197338],[55.769562,48.195862],[55.767288,48.19524],[55.767208,48.195221],[55.766178,48.195019],[55.764969,48.195171],[55.763771,48.195541],[55.762272,48.19659],[55.76128,48.197472],[55.75486,48.20602],[55.754292,48.206829],[55.753349,48.20816],[55.751961,48.21014],[55.750992,48.212811],[55.748829,48.221031],[55.74847,48.222401],[55.74749,48.226292],[55.746792,48.228279],[55.745819,48.230492],[55.740162,48.241928],[55.736431,48.249859],[55.735241,48.252369],[55.734249,48.255829],[55.734001,48.25742],[55.73391,48.258011],[55.733479,48.260769],[55.733292,48.263561],[55.73196,48.28344],[55.729641,48.31657],[55.728531,48.33514],[55.726929,48.358971],[55.726551,48.365829],[55.727131,48.378361],[55.727901,48.391411],[55.728291,48.399479],[55.726261,48.420422],[55.72374,48.442909],[55.723259,48.449261],[55.72435,48.473381],[55.724442,48.475319],[55.724609,48.479351],[55.724628,48.479721],[55.724689,48.481239],[55.72472,48.481918],[55.724812,48.4837],[55.725609,48.501598],[55.726059,48.513119],[55.725769,48.521702],[55.723808,48.537479],[55.72298,48.544708],[55.722809,48.546188],[55.722778,48.546421],[55.722511,48.548721],[55.72242,48.549431],[55.72216,48.551521],[55.720852,48.56385],[55.71925,48.587608],[55.718788,48.594051],[55.71841,48.600231],[55.718651,48.60326],[55.71933,48.60606],[55.720329,48.608978],[55.721291,48.6115],[55.721859,48.61425],[55.722092,48.617691],[55.721741,48.621189],[55.720551,48.624641],[55.71751,48.632191],[55.71529,48.637199],[55.71262,48.64547],[55.710941,48.65123],[55.709511,48.659721],[55.709011,48.666119],[55.709049,48.672401],[55.70961,48.679729],[55.713921,48.70715],[55.71434,48.709961],[55.717049,48.726921],[55.720501,48.741638],[55.7239,48.750832],[55.726299,48.75732],[55.72715,48.759762],[55.73185,48.77322],[55.736031,48.781219],[55.73642,48.781841],[55.737579,48.783642],[55.738392,48.784809],[55.739342,48.786091],[55.740749,48.788021],[55.745781,48.794651],[55.75082,48.8013],[55.751629,48.80241],[55.752258,48.80331],[55.7528,48.804081],[55.756809,48.809929],[55.75943,48.813789],[55.76038,48.815289],[55.761608,48.817402],[55.76215,48.818352],[55.76366,48.821548],[55.76429,48.822929],[55.767189,48.830311],[55.767399,48.830799],[55.76833,48.832699],[55.769058,48.833981],[55.769821,48.835091],[55.770969,48.836609],[55.77169,48.837471],[55.77243,48.838051],[55.773232,48.838661],[55.774052,48.839119],[55.775669,48.839828],[55.776451,48.840069],[55.77763,48.84024],[55.77924,48.840401],[55.780281,48.84042],[55.78125,48.840401],[55.78252,48.84037],[55.79047,48.840889],[55.79126,48.840981],[55.79628,48.84124],[55.810371,48.842041],[55.81245,48.842159],[55.81451,48.842449],[55.817261,48.843128],[55.81889,48.843719],[55.82074,48.84462],[55.82346,48.8461],[55.824162,48.846531],[55.825279,48.84721],[55.826191,48.847801],[55.82811,48.848751],[55.82967,48.849312],[55.831299,48.849709],[55.842369,48.85191],[55.85397,48.854259],[55.857552,48.854969],[55.858131,48.855091],[55.858681,48.855209],[55.86179,48.85582],[55.862728,48.85601],[55.86491,48.85643],[55.866829,48.856758],[55.867088,48.856812],[55.86832,48.857052],[55.87402,48.85825],[55.874458,48.858341],[55.875801,48.85862],[55.87849,48.859192],[55.879089,48.859379],[55.879398,48.859482],[55.88028,48.859791],[55.881779,48.86042],[55.88269,48.86084],[55.883381,48.86121],[55.883549,48.861309],[55.884319,48.861851],[55.885052,48.86253],[55.885811,48.863361],[55.886429,48.86414],[55.886959,48.86504],[55.887611,48.866402],[55.889069,48.86982],[55.894341,48.882118],[55.89912,48.893269],[55.899479,48.89418],[55.899811,48.895111],[55.899948,48.895519],[55.900108,48.896061],[55.900341,48.896919],[55.900639,48.898281],[55.900841,48.899288],[55.90115,48.901321],[55.901241,48.90221],[55.90131,48.903439],[55.901371,48.908951],[55.901489,48.934219],[55.901569,48.94532],[55.901619,48.94698],[55.901718,48.94865],[55.901871,48.950539],[55.90263,48.958179],[55.903069,48.962841],[55.9035,48.96714],[55.903839,48.96991],[55.904228,48.972649],[55.904598,48.975201],[55.904678,48.975761],[55.904968,48.977859],[55.905239,48.98037],[55.905411,48.98254],[55.90551,48.984798],[55.90564,48.996738],[55.905651,48.997532],[55.905701,49.000679],[55.905739,49.002041],[55.905849,49.004139],[55.90646,49.01107],[55.90659,49.01252],[55.906952,49.016472],[55.907299,49.021412],[55.907688,49.028358],[55.90789,49.031841],[55.908131,49.03532],[55.909142,49.048611],[55.91011,49.061829],[55.91058,49.0681],[55.91304,49.10125],[55.913399,49.105782],[55.91375,49.108921],[55.914108,49.111359],[55.915451,49.11953],[55.917259,49.13028],[55.917542,49.13213],[55.917751,49.13401],[55.917919,49.136051],[55.918011,49.138062],[55.918079,49.140659],[55.918079,49.140942],[55.918079,49.141891],[55.91806,49.14267],[55.918011,49.143711],[55.91785,49.14669],[55.91774,49.14798],[55.917671,49.148739],[55.91758,49.149448],[55.9175,49.15007],[55.91737,49.150928],[55.917122,49.15247],[55.91684,49.153858],[55.916649,49.1548],[55.916538,49.155289],[55.916382,49.15575],[55.91571,49.157372],[55.91449,49.15987],[55.914261,49.160358],[55.913288,49.162361],[55.913029,49.16288],[55.91275,49.163441],[55.911339,49.166302],[55.909439,49.17012],[55.90852,49.171951],[55.907379,49.17429],[55.90675,49.175739],[55.9063,49.177059],[55.906059,49.177879],[55.903801,49.187191],[55.90324,49.189468],[55.902882,49.19091],[55.90094,49.197899],[55.899979,49.20108],[55.897701,49.208038],[55.89743,49.20879],[55.896938,49.210251],[55.896599,49.211151],[55.896229,49.212002],[55.895828,49.212769],[55.895222,49.21386],[55.891121,49.220089],[55.88998,49.22205],[55.889542,49.22287],[55.88913,49.223881],[55.887421,49.229141],[55.887131,49.230061],[55.88678,49.231129],[55.885368,49.235481],[55.883381,49.241539],[55.88155,49.247051],[55.880661,49.249741],[55.880192,49.25145],[55.879341,49.255569],[55.87923,49.256111],[55.879009,49.257191],[55.87899,49.25724],[55.878139,49.261341],[55.877831,49.262829],[55.875278,49.275089],[55.874748,49.277889],[55.874599,49.279041],[55.87447,49.280949],[55.874432,49.281898],[55.874409,49.282921],[55.874451,49.286308],[55.874409,49.287281],[55.874321,49.288139],[55.874249,49.288631],[55.874149,49.289082],[55.873909,49.28989],[55.87376,49.290329],[55.873589,49.290722],[55.87318,49.291531],[55.872768,49.292179],[55.868851,49.297501],[55.864491,49.303478],[55.864029,49.304119],[55.863571,49.304741],[55.8629,49.305691],[55.862179,49.306919],[55.8615,49.30843],[55.861099,49.30941],[55.86034,49.311329],[55.856941,49.320042],[55.855289,49.3242],[55.85498,49.32497],[55.854019,49.327141],[55.852772,49.329521],[55.8521,49.330669],[55.85125,49.33194],[55.849388,49.334419],[55.84597,49.33873],[55.845089,49.339859],[55.842171,49.343578],[55.841888,49.343948],[55.839329,49.347221],[55.83844,49.348289],[55.837448,49.349178],[55.83709,49.349449],[55.83672,49.34967],[55.835918,49.350029],[55.835232,49.350281],[55.8344,49.350449],[55.833851,49.350479],[55.833279,49.35046],[55.827381,49.349319],[55.82436,49.348759],[55.820412,49.347988],[55.817551,49.347408],[55.814449,49.34679],[55.80788,49.345421],[55.806519,49.34499],[55.805069,49.34449],[55.80228,49.34269],[55.801941,49.342461],[55.801262,49.341991],[55.800152,49.34124],[55.79987,49.34111],[55.79977,49.341061],[55.798828,49.34063],[55.79855,49.34053],[55.797771,49.340229],[55.796341,49.33971],[55.795601,49.339581],[55.79493,49.33939],[55.794128,49.339191],[55.79306,49.338909],[55.790668,49.338329],[55.78896,49.338009],[55.787819,49.337959],[55.786671,49.338039],[55.7854,49.33828],[55.784168,49.338711],[55.7826,49.339481],[55.781071,49.340549],[55.77916,49.342152],[55.777271,49.34399],[55.775661,49.345612],[55.770809,49.350368],[55.768848,49.352299],[55.766171,49.354881],[55.764488,49.356651],[55.76366,49.35759],[55.762871,49.35865],[55.761959,49.360008],[55.761108,49.361549],[55.760429,49.363079],[55.75985,49.36475],[55.759171,49.367229],[55.75901,49.367901],[55.75864,49.369801],[55.758389,49.371201],[55.75779,49.375252],[55.757118,49.379761],[55.756821,49.38129],[55.7565,49.382751],[55.7561,49.384159],[55.755611,49.38562],[55.755081,49.386921],[55.75423,49.388512],[55.75375,49.389259],[55.753201,49.38998],[55.75185,49.391521],[55.750408,49.392879],[55.74662,49.396191],[55.74567,49.396999],[55.74464,49.397919],[55.742962,49.399429],[55.73914,49.402771],[55.737881,49.4039],[55.736629,49.405258],[55.735451,49.406811],[55.734341,49.40852],[55.733452,49.410141],[55.732689,49.41172],[55.731949,49.41349],[55.73106,49.416012],[55.72821,49.42469],[55.72747,49.426868],[55.72681,49.429169],[55.726109,49.432178],[55.72559,49.435211],[55.723309,49.454868],[55.721859,49.467388],[55.721828,49.468811],[55.721088,49.475471],[55.72084,49.47847],[55.72049,49.48299],[55.720322,49.48457],[55.71999,49.486889],[55.719212,49.491779],[55.71891,49.494171],[55.717731,49.504021],[55.715759,49.51825],[55.715542,49.520241],[55.715351,49.522381],[55.71505,49.526329],[55.714691,49.529739],[55.714272,49.53249],[55.713779,49.535],[55.712921,49.539001],[55.71228,49.543491],[55.711769,49.546242],[55.711349,49.548149],[55.710831,49.550201],[55.710312,49.55209],[55.70977,49.553822],[55.709358,49.55508],[55.708321,49.557899],[55.707878,49.559269],[55.70607,49.565182],[55.704769,49.56871],[55.703491,49.57159],[55.70248,49.57373],[55.700901,49.577671],[55.698959,49.58271],[55.698479,49.58408],[55.698391,49.584381],[55.697769,49.58646],[55.697399,49.588139],[55.697121,49.589901],[55.696781,49.593609],[55.69672,49.596779],[55.696941,49.60041],[55.69894,49.620121],[55.699268,49.623772],[55.699329,49.626282],[55.699429,49.63052],[55.699188,49.635651],[55.699131,49.636211],[55.698631,49.6409],[55.697899,49.645988],[55.697361,49.6493],[55.696671,49.652451],[55.695919,49.655079],[55.694691,49.658611],[55.6931,49.662861],[55.692421,49.66433],[55.686729,49.673569],[55.68568,49.675289],[55.682789,49.680199],[55.681389,49.682941],[55.680019,49.68642],[55.677219,49.69487],[55.676929,49.695751],[55.67514,49.701241],[55.674641,49.702789],[55.673882,49.70512],[55.67276,49.708469],[55.671028,49.713631],[55.670712,49.714882],[55.670368,49.716511],[55.670109,49.718151],[55.66991,49.719311],[55.669762,49.721729],[55.669689,49.725491],[55.66991,49.728981],[55.670898,49.735821],[55.67218,49.744549],[55.676151,49.77142],[55.677071,49.778099],[55.677879,49.78434],[55.679729,49.806068],[55.680698,49.81786],[55.68087,49.821381],[55.680851,49.824558],[55.680698,49.82822],[55.680328,49.832458],[55.67968,49.837151],[55.678848,49.840969],[55.67778,49.84499],[55.675209,49.852699],[55.669899,49.868599],[55.66441,49.884682],[55.662361,49.890949],[55.661579,49.89394],[55.661129,49.896309],[55.66074,49.898891],[55.6605,49.901852],[55.66032,49.90493],[55.66037,49.908569],[55.66069,49.91169],[55.6618,49.924728],[55.661781,49.929359],[55.661308,49.934101],[55.66082,49.93692],[55.660252,49.939541],[55.65942,49.942471],[55.652618,49.964859],[55.650421,49.9725],[55.650299,49.972931],[55.646881,49.98391],[55.64555,49.98941],[55.644489,49.996422],[55.644161,50.000069],[55.644138,50.000751],[55.644032,50.004379],[55.644161,50.009281],[55.64423,50.010761],[55.645821,50.02383],[55.649719,50.05447],[55.653332,50.083469],[55.65374,50.08638],[55.654129,50.088669],[55.654652,50.091179],[55.655239,50.093651],[55.656609,50.098728],[55.657021,50.100281],[55.65707,50.100449],[55.661041,50.11528],[55.663261,50.123562],[55.664349,50.12772],[55.665371,50.13192],[55.668301,50.14389],[55.669769,50.149879],[55.670509,50.15292],[55.67086,50.15456],[55.67112,50.15593],[55.67136,50.157249],[55.671612,50.159081],[55.672039,50.162979],[55.672371,50.166901],[55.67392,50.186131],[55.6749,50.19799],[55.67572,50.20845],[55.67588,50.20982],[55.676208,50.212551],[55.676651,50.215321],[55.676979,50.217072],[55.67733,50.218658],[55.678268,50.22224],[55.681259,50.23251],[55.684158,50.24255],[55.687481,50.253929],[55.690571,50.264641],[55.691029,50.266361],[55.691422,50.268101],[55.691738,50.269581],[55.692032,50.271111],[55.692532,50.274361],[55.696041,50.307381],[55.696362,50.31065],[55.696678,50.313869],[55.69672,50.31422],[55.697319,50.32008],[55.697498,50.322521],[55.697578,50.324661],[55.697609,50.32692],[55.697601,50.328941],[55.697521,50.330891],[55.697411,50.33284],[55.697239,50.334782],[55.69635,50.344231],[55.695911,50.348961],[55.695419,50.354191],[55.69521,50.356339],[55.690521,50.406368],[55.688931,50.423382],[55.68734,50.440971],[55.686909,50.447571],[55.686771,50.45068],[55.686459,50.468208],[55.686249,50.480068],[55.68605,50.492432],[55.685509,50.524719],[55.685299,50.53756],[55.685349,50.540649],[55.685429,50.54372],[55.68549,50.54525],[55.685581,50.54636],[55.686039,50.549801],[55.686821,50.554131],[55.687618,50.558208],[55.688141,50.561829],[55.68832,50.563541],[55.688499,50.566299],[55.68853,50.568859],[55.688549,50.570358],[55.688499,50.572529],[55.688351,50.57476],[55.68792,50.579449],[55.68745,50.583328],[55.68634,50.59124],[55.685959,50.593609],[55.685711,50.594891],[55.685169,50.596901],[55.684582,50.598881],[55.68396,50.60078],[55.683239,50.602749],[55.682251,50.605331],[55.681309,50.607971],[55.680618,50.610081],[55.68,50.61237],[55.679581,50.614182],[55.67915,50.616341],[55.678841,50.618198],[55.678539,50.620289],[55.67601,50.641548],[55.675159,50.648911],[55.675049,50.650261],[55.6749,50.652691],[55.674831,50.654949],[55.67482,50.657501],[55.67487,50.65955],[55.674999,50.662289],[55.67524,50.66497],[55.675529,50.667419],[55.675892,50.669891],[55.676929,50.675911],[55.677311,50.67804],[55.677631,50.679859],[55.678249,50.683979],[55.678711,50.687851],[55.678951,50.690338],[55.679119,50.692928],[55.679279,50.696079],[55.679291,50.699471],[55.677898,50.740601],[55.677589,50.748569],[55.677399,50.75116],[55.67709,50.753811],[55.676601,50.757061],[55.675961,50.760399],[55.675301,50.763119],[55.674541,50.7659],[55.6731,50.77002],[55.67226,50.77206],[55.670979,50.774719],[55.657162,50.800831],[55.653919,50.80698],[55.652611,50.80941],[55.651291,50.812],[55.65049,50.813931],[55.64954,50.81675],[55.648701,50.82],[55.64806,50.823479],[55.64769,50.826519],[55.64753,50.82851],[55.647369,50.83252],[55.646912,50.845772],[55.64653,50.855751],[55.645721,50.876942],[55.645618,50.87822],[55.64547,50.879902],[55.645351,50.88089],[55.64489,50.883621],[55.64452,50.88567],[55.644138,50.887661],[55.64341,50.89093],[55.641479,50.897221],[55.640289,50.90099],[55.63921,50.90485],[55.638802,50.906441],[55.638439,50.90807],[55.63805,50.910309],[55.637718,50.912609],[55.63747,50.91502],[55.637211,50.918209],[55.63657,50.928921],[55.636181,50.935612],[55.63575,50.943008],[55.635681,50.94548],[55.6357,50.948002],[55.63588,50.951729],[55.636238,50.955761],[55.636669,50.958931],[55.64035,50.980049],[55.642658,50.9935],[55.64296,50.995331],[55.643372,50.99828],[55.643719,51.00169],[55.64389,51.00452],[55.643951,51.007172],[55.643959,51.00975],[55.643959,51.012459],[55.644058,51.045509],[55.644169,51.047729],[55.64426,51.049591],[55.64455,51.051651],[55.64481,51.052929],[55.645081,51.054119],[55.645432,51.055191],[55.645721,51.055988],[55.646141,51.056919],[55.64666,51.057919],[55.647259,51.05896],[55.648029,51.060108],[55.64978,51.062431],[55.651482,51.064861],[55.652489,51.066429],[55.65332,51.068008],[55.654209,51.07019],[55.654709,51.07193],[55.655071,51.073841],[55.65519,51.07539],[55.655231,51.076809],[55.655201,51.07851],[55.654999,51.08028],[55.654659,51.082531],[55.65414,51.085091],[55.653461,51.08786],[55.652431,51.091888],[55.652142,51.093651],[55.651909,51.095669],[55.651859,51.09763],[55.651951,51.098869],[55.652279,51.100891],[55.652721,51.102619],[55.65324,51.104309],[55.655621,51.110699],[55.656132,51.112202],[55.656609,51.11422],[55.65707,51.11644],[55.65733,51.118481],[55.65736,51.119492],[55.657299,51.123192],[55.6572,51.124001],[55.656769,51.127159],[55.656479,51.128868],[55.655319,51.134979],[55.65453,51.139481],[55.65419,51.14172],[55.653759,51.145229],[55.653679,51.14616],[55.65345,51.149071],[55.653511,51.152081],[55.65374,51.15472],[55.654388,51.158871],[55.65506,51.16201],[55.65617,51.16552],[55.660042,51.17598],[55.661221,51.179111],[55.66349,51.186131],[55.665001,51.19173],[55.665798,51.195229],[55.66663,51.19968],[55.667809,51.207119],[55.66964,51.221359],[55.671249,51.234001],[55.671398,51.235371],[55.6717,51.2383],[55.67186,51.240551],[55.671921,51.242199],[55.671921,51.243191],[55.671909,51.244572],[55.67178,51.24646],[55.671631,51.247921],[55.671429,51.249191],[55.671162,51.250542],[55.670811,51.251888],[55.670368,51.2533],[55.6693,51.25629],[55.66856,51.258011],[55.665871,51.263908],[55.665352,51.265091],[55.66431,51.2677],[55.66396,51.268631],[55.663422,51.270229],[55.663052,51.271381],[55.662579,51.273159],[55.66235,51.27433],[55.662182,51.275089],[55.6619,51.27692],[55.66177,51.277821],[55.661591,51.279369],[55.661449,51.281639],[55.661331,51.284241],[55.66127,51.286369],[55.661259,51.287922],[55.661282,51.293129],[55.661301,51.295361],[55.661388,51.30225],[55.66135,51.304352],[55.661129,51.308788],[55.660969,51.311001],[55.660889,51.31181],[55.66048,51.314831],[55.660172,51.316669],[55.656269,51.33997],[55.65115,51.370121],[55.650101,51.376541],[55.64996,51.37743],[55.64954,51.37999],[55.64949,51.38031],[55.64912,51.38258],[55.648979,51.383911],[55.64893,51.384609],[55.648899,51.386002],[55.64896,51.387772],[55.649071,51.389061],[55.64941,51.39122],[55.649799,51.393108],[55.650059,51.39418],[55.650391,51.39518],[55.65134,51.396999],[55.65202,51.398102],[55.652679,51.398991],[55.653431,51.399872],[55.656631,51.402611],[55.657398,51.403191],[55.658329,51.403831],[55.661049,51.405479],[55.66185,51.406189],[55.66246,51.406811],[55.66296,51.407379],[55.66349,51.40807],[55.663818,51.40855],[55.66394,51.40873],[55.664612,51.40992],[55.665001,51.41077],[55.66539,51.4118],[55.66584,51.41317],[55.666321,51.414791],[55.66888,51.423191],[55.66972,51.4259],[55.67144,51.43161],[55.671909,51.433189],[55.672352,51.43462],[55.677689,51.452171],[55.67905,51.45612],[55.680439,51.459789],[55.68087,51.4608],[55.682091,51.463509],[55.6828,51.465],[55.68573,51.470791],[55.688469,51.476189],[55.689339,51.477989],[55.690701,51.481079],[55.690971,51.481758],[55.69199,51.48439],[55.693562,51.48893],[55.695011,51.493679],[55.695518,51.495628],[55.695889,51.497108],[55.70332,51.531422],[55.706501,51.5462],[55.706989,51.548721],[55.7075,51.55143],[55.708221,51.555592],[55.70882,51.559441],[55.709221,51.562199],[55.709591,51.565022],[55.7099,51.567551],[55.710339,51.571621],[55.711189,51.58115],[55.71254,51.596439],[55.712711,51.599602],[55.712811,51.60178],[55.712841,51.60294],[55.712849,51.60466],[55.712799,51.607578],[55.7122,51.624611],[55.712151,51.62603],[55.712101,51.627251],[55.711441,51.644531],[55.711319,51.64764],[55.711281,51.650318],[55.711288,51.652691],[55.711349,51.655529],[55.711559,51.659061],[55.7117,51.66074],[55.71188,51.662609],[55.712219,51.665421],[55.71246,51.66711],[55.71402,51.676769],[55.71463,51.679581],[55.715221,51.681911],[55.71693,51.687439],[55.718941,51.69244],[55.719601,51.694069],[55.720299,51.695671],[55.721561,51.698292],[55.721901,51.69891],[55.722099,51.699261],[55.72261,51.700039],[55.723381,51.701118],[55.72575,51.70401],[55.726799,51.705551],[55.727711,51.70739],[55.73074,51.71487],[55.731682,51.717339],[55.732731,51.72094],[55.73333,51.723331],[55.733871,51.725269],[55.734291,51.726639],[55.735668,51.730011],[55.736431,51.731579],[55.737579,51.733879],[55.738319,51.735439],[55.738831,51.736679],[55.739491,51.73859],[55.739899,51.739891],[55.74033,51.741421],[55.742481,51.75071],[55.743118,51.753731],[55.746429,51.768318],[55.748341,51.776112],[55.752659,51.790218],[55.759251,51.811508],[55.7607,51.815601],[55.762489,51.819321],[55.764339,51.822701],[55.766369,51.82571],[55.772129,51.832142],[55.77663,51.837151],[55.778831,51.839802],[55.780842,51.842659],[55.782471,51.84565],[55.78384,51.848549],[55.785179,51.851929],[55.786469,51.855801],[55.787449,51.859379],[55.788342,51.86385],[55.79689,51.908421],[55.797081,51.909882],[55.797611,51.916401],[55.79763,51.918541],[55.79763,51.9207],[55.7976,51.92284],[55.797409,51.927021],[55.797329,51.928532],[55.79726,51.930019],[55.797081,51.93383],[55.7971,51.934799],[55.79718,51.936218],[55.797249,51.937019],[55.797352,51.937721],[55.797501,51.938511],[55.79768,51.939339],[55.79784,51.93996],[55.797989,51.940491],[55.798161,51.941002],[55.798321,51.941448],[55.79866,51.942322],[55.79887,51.942741],[55.799332,51.9436],[55.799671,51.944172],[55.807259,51.956848],[55.807739,51.957722],[55.808239,51.95879],[55.808701,51.959949],[55.808979,51.96093],[55.813591,51.980122],[55.813961,51.981949],[55.814171,51.983379],[55.81432,51.985371],[55.814339,51.98695],[55.814251,51.998631],[55.814232,52.000389],[55.813709,52.06361],[55.81366,52.069031],[55.813648,52.070789],[55.81361,52.075951],[55.813301,52.108681],[55.81324,52.11496],[55.81319,52.1203],[55.813122,52.121632],[55.812851,52.123539],[55.812431,52.125431],[55.811821,52.12714],[55.811001,52.128849],[55.80444,52.139221],[55.803692,52.140442],[55.783829,52.171841],[55.783279,52.17284],[55.782768,52.174129],[55.782219,52.176041],[55.781929,52.17728],[55.781521,52.179192],[55.781361,52.18087],[55.781311,52.182621],[55.781311,52.183571],[55.781399,52.185379],[55.781429,52.186661],[55.781429,52.188091],[55.781399,52.188881],[55.78133,52.189789],[55.78125,52.190899],[55.781189,52.191502],[55.781132,52.192032],[55.78101,52.19265],[55.780819,52.193741],[55.780529,52.194908],[55.780361,52.195518],[55.78014,52.19622],[55.779881,52.196972],[55.779598,52.19767],[55.77927,52.19833],[55.778961,52.198971],[55.778599,52.199551],[55.77718,52.202],[55.77422,52.207008],[55.771309,52.211922],[55.76897,52.215889],[55.76841,52.216808],[55.766151,52.2206],[55.765202,52.222229],[55.759621,52.23164],[55.75816,52.234112],[55.757721,52.234821],[55.756699,52.236328],[55.75634,52.236832],[55.755852,52.2374],[55.755569,52.237671],[55.755348,52.237869],[55.75518,52.237999],[55.754238,52.238701],[55.75383,52.23904],[55.753559,52.239319],[55.7533,52.239639],[55.752312,52.240871],[55.751579,52.241791],[55.75127,52.242111],[55.75106,52.24229],[55.750519,52.242691],[55.749741,52.24321],[55.73579,52.251579],[55.727631,52.256451],[55.725208,52.2579],[55.72377,52.258781],[55.7234,52.25906],[55.722851,52.25956],[55.720501,52.262089],[55.720291,52.262321],[55.717449,52.265339],[55.71051,52.273041],[55.709721,52.273708],[55.709179,52.274078],[55.708549,52.274391],[55.703751,52.276489],[55.69817,52.278881],[55.69619,52.27977],[55.695301,52.280201],[55.693359,52.281471],[55.692009,52.282261],[55.69125,52.282619],[55.690701,52.282829],[55.690102,52.28297],[55.689499,52.283031],[55.689041,52.283051],[55.68858,52.28299],[55.68829,52.282959],[55.687962,52.282848],[55.68729,52.2826],[55.686741,52.282341],[55.68317,52.279949],[55.682301,52.279339],[55.682011,52.279148],[55.681671,52.278999],[55.681419,52.27898],[55.681149,52.27903],[55.68087,52.27919],[55.68074,52.279301],[55.680401,52.279739],[55.680061,52.280331],[55.679749,52.28075],[55.679111,52.281368],[55.67849,52.28191],[55.677841,52.282661],[55.677471,52.283279],[55.675369,52.28727],[55.674358,52.289181],[55.673279,52.29121],[55.673019,52.291721],[55.672562,52.292591],[55.672119,52.29343],[55.670609,52.296329],[55.67033,52.29686],[55.668861,52.299648],[55.66848,52.300381],[55.668339,52.30064],[55.667721,52.301811],[55.667461,52.30241],[55.667068,52.303429],[55.66674,52.304699],[55.666561,52.30563],[55.666439,52.30658],[55.66637,52.30748],[55.66637,52.308411],[55.666401,52.309368],[55.66655,52.310638],[55.666729,52.311661],[55.6674,52.314411],[55.668072,52.317181],[55.6684,52.318241],[55.668812,52.319221],[55.67284,52.32666],[55.675659,52.33189],[55.67635,52.33313],[55.676819,52.333981],[55.677719,52.335609],[55.677879,52.335911],[55.68063,52.340981],[55.68615,52.351101],[55.690151,52.35844],[55.69622,52.369579],[55.69659,52.370281],[55.696629,52.370338],[55.699631,52.375858],[55.69989,52.376339],[55.700821,52.37804],[55.70174,52.379749],[55.701801,52.379841],[55.702808,52.38171],[55.7033,52.382549],[55.703899,52.383709],[55.704239,52.384331],[55.704979,52.385731],[55.705872,52.387321],[55.707142,52.389622],[55.707169,52.389671],[55.707378,52.39027],[55.70742,52.39061],[55.707409,52.39093],[55.707371,52.39156],[55.707409,52.392189],[55.707409,52.39275],[55.707321,52.39315],[55.707191,52.393452],[55.706982,52.39381],[55.706039,52.39542],[55.705978,52.395531],[55.70512,52.396999],[55.704239,52.398479],[55.70282,52.400879],[55.701019,52.403938],[55.70005,52.405579],[55.69923,52.406952],[55.697472,52.40995],[55.696301,52.411949],[55.69445,52.415131],[55.68821,52.4258],[55.68763,52.42662],[55.68729,52.426929],[55.686039,52.427731],[55.685669,52.428059],[55.68531,52.428501],[55.68504,52.428982],[55.68483,52.429401],[55.684631,52.430019],[55.684139,52.43232],[55.68396,52.432941],[55.683769,52.433361],[55.68354,52.43383],[55.682079,52.436249],[55.67815,52.44297],[55.67725,52.444481],[55.676971,52.44495],[55.67622,52.446251],[55.675152,52.448051],[55.674011,52.45002],[55.670921,52.455299],[55.67057,52.455898],[55.670471,52.456181],[55.670429,52.45647],[55.67049,52.456779],[55.670609,52.457119],[55.67086,52.4576],[55.678631,52.471859],[55.682621,52.479179],[55.685921,52.485222],[55.685619,52.485741],[55.685261,52.486542],[55.685101,52.486881],[55.684761,52.487549],[55.682831,52.49123],[55.679352,52.497681],[55.677639,52.50095],[55.67712,52.50198],[55.67664,52.503071],[55.676079,52.504501],[55.675571,52.505939],[55.675209,52.50713],[55.67466,52.509109],[55.673908,52.511829],[55.673679,52.512699],[55.673489,52.513561],[55.67337,52.51432],[55.673328,52.514912],[55.673271,52.516418],[55.673241,52.517658],[55.67305,52.523499],[55.67292,52.528938],[55.67281,52.532299],[55.672661,52.537601],[55.6726,52.538269],[55.672451,52.539371],[55.672199,52.54076],[55.671501,52.543941],[55.670971,52.545891],[55.669621,52.54969],[55.667969,52.554371],[55.66539,52.563148],[55.66473,52.564739],[55.66301,52.56778],[55.662319,52.569321],[55.66164,52.571339],[55.658588,52.58429],[55.65654,52.593121],[55.655369,52.597691],[55.654362,52.601082],[55.65126,52.60873],[55.64576,52.622341],[55.643822,52.62743],[55.643391,52.628719],[55.643169,52.630539],[55.643108,52.63242],[55.64323,52.634209],[55.64381,52.641621],[55.645309,52.66272],[55.645321,52.665001],[55.645222,52.667549],[55.64325,52.682449],[55.642529,52.68782],[55.639309,52.712391],[55.637852,52.722641],[55.63607,52.733749],[55.635971,52.73761],[55.636169,52.743118],[55.636471,52.751598],[55.63649,52.754292],[55.636131,52.761169],[55.636269,52.7631],[55.63707,52.766842],[55.637798,52.77449],[55.63829,52.77763],[55.642929,52.80006],[55.643501,52.805939],[55.644241,52.815681],[55.644779,52.822552],[55.645939,52.83707],[55.646069,52.838692],[55.64642,52.84306],[55.64658,52.846931],[55.64695,52.849682],[55.64827,52.855042],[55.648991,52.85799],[55.65287,52.873421],[55.653889,52.876011],[55.65781,52.884899],[55.660789,52.892078],[55.661629,52.894821],[55.670052,52.921558],[55.674309,52.934212],[55.67485,52.935478],[55.682678,52.952129],[55.68465,52.958199],[55.691521,52.978222],[55.692421,52.981289],[55.69302,52.983971],[55.693562,52.987148],[55.694321,52.993038],[55.697681,53.011028],[55.69928,53.01918],[55.704781,53.040829],[55.70789,53.052311],[55.710011,53.059601],[55.710178,53.060631],[55.71014,53.061729],[55.709648,53.064369],[55.70866,53.068539],[55.70723,53.072842],[55.704472,53.079929],[55.702789,53.08424],[55.699131,53.093811],[55.694149,53.106819],[55.692871,53.110142],[55.676922,53.151619],[55.668449,53.173512],[55.660149,53.195129],[55.65966,53.196121],[55.650101,53.21085],[55.637341,53.230019],[55.628769,53.23912],[55.62315,53.245098],[55.619541,53.248459],[55.61657,53.250809],[55.613331,53.253071],[55.61142,53.255001],[55.60989,53.256939],[55.608349,53.259449],[55.60717,53.261848],[55.604401,53.268929],[55.598129,53.284931],[55.594898,53.292999],[55.581131,53.328781],[55.564869,53.370869],[55.550812,53.406952],[55.550091,53.40863],[55.548779,53.41198],[55.547771,53.415569],[55.547058,53.419151],[55.546749,53.420689],[55.546619,53.422409],[55.54705,53.434429],[55.548222,53.464298],[55.548389,53.46764],[55.54985,53.48539],[55.549969,53.487419],[55.5499,53.488548],[55.549671,53.489529],[55.548119,53.49712],[55.546909,53.503609],[55.542259,53.530602],[55.542068,53.531681],[55.541752,53.53487],[55.5392,53.56073],[55.53825,53.570389],[55.537701,53.575939],[55.537392,53.57917],[55.537182,53.580139],[55.536591,53.582211],[55.53326,53.59341],[55.53297,53.594631],[55.530918,53.608089],[55.530819,53.609329],[55.53083,53.610641],[55.531311,53.619499],[55.531189,53.622349],[55.52932,53.64687],[55.526699,53.66592],[55.524429,53.682209],[55.52264,53.694988],[55.52021,53.711361],[55.516571,53.739811],[55.514339,53.75666],[55.513729,53.76046],[55.51334,53.76226],[55.512871,53.763851],[55.51223,53.765751],[55.509541,53.773739],[55.508492,53.777111],[55.502892,53.803589],[55.50111,53.811771],[55.494579,53.834061],[55.490639,53.84745],[55.490189,53.849079],[55.489601,53.852291],[55.489239,53.856819],[55.48904,53.864101],[55.488972,53.867031],[55.488731,53.870461],[55.48848,53.87254],[55.488159,53.875191],[55.48772,53.878819],[55.48727,53.880661],[55.48658,53.882549],[55.484219,53.88773],[55.48243,53.892479],[55.481289,53.895081],[55.47945,53.898918],[55.477989,53.901131],[55.474831,53.90564],[55.47131,53.911831],[55.467682,53.918968],[55.46714,53.92078],[55.466629,53.923649],[55.466049,53.92635],[55.465599,53.927929],[55.46487,53.929932],[55.462429,53.936199],[55.461441,53.938709],[55.460609,53.941231],[55.460091,53.95723],[55.459911,53.962921],[55.45985,53.964741],[55.46014,53.965679],[55.47105,53.991089],[55.471519,53.992229],[55.47184,53.99353],[55.475712,54.01577],[55.477589,54.025909],[55.47768,54.02668],[55.477581,54.027409],[55.476978,54.029301],[55.47562,54.033089],[55.472099,54.042679],[55.46788,54.054298],[55.467541,54.055519],[55.466969,54.062222],[55.466251,54.07093],[55.46756,54.08437],[55.468208,54.091629],[55.469379,54.104031],[55.46936,54.105049],[55.4678,54.12318],[55.466782,54.134659],[55.466579,54.13686],[55.466011,54.138771],[55.465939,54.14032],[55.465542,54.151291],[55.465172,54.16132],[55.464439,54.181629],[55.464352,54.183262],[55.464069,54.18449],[55.46048,54.194721],[55.459839,54.19688],[55.458569,54.201759],[55.45583,54.212189],[55.45314,54.222198],[55.452351,54.22514],[55.450249,54.235771],[55.44936,54.240509],[55.448101,54.2467],[55.445122,54.260769],[55.443291,54.26936],[55.441669,54.277119],[55.440521,54.28236],[55.439941,54.285179],[55.43869,54.291149],[55.43848,54.292141],[55.437771,54.29549],[55.437672,54.29628],[55.437771,54.297291],[55.439812,54.306301],[55.440399,54.30888],[55.440369,54.309509],[55.44022,54.31002],[55.439949,54.31076],[55.438702,54.314041],[55.438412,54.315071],[55.438278,54.31609],[55.43832,54.317341],[55.438801,54.32312],[55.43996,54.328449],[55.440269,54.330811],[55.440929,54.33857],[55.441071,54.341572],[55.44125,54.354111],[55.44125,54.35651],[55.441471,54.37236],[55.441689,54.39426],[55.441898,54.396351],[55.443249,54.399651],[55.44857,54.412609],[55.453491,54.424721],[55.457619,54.434971],[55.459049,54.438339],[55.464409,54.449371],[55.472149,54.465191],[55.472691,54.466339],[55.473259,54.46796],[55.479778,54.48851],[55.48167,54.494282],[55.482269,54.4963],[55.482269,54.49688],[55.482208,54.497639],[55.480141,54.523861],[55.480061,54.52449],[55.479851,54.52504],[55.47739,54.529381],[55.477249,54.529961],[55.477139,54.531151],[55.476219,54.541729],[55.474201,54.56496],[55.472179,54.588112],[55.470009,54.602631],[55.46994,54.603722],[55.470009,54.60487],[55.47002,54.606098],[55.4697,54.607128],[55.466881,54.614262],[55.466309,54.615631],[55.465858,54.61721],[55.46109,54.641659],[55.45863,54.65427],[55.450989,54.692638],[55.448528,54.705078],[55.44825,54.706329],[55.447842,54.707321],[55.443432,54.714001],[55.44199,54.716171],[55.441441,54.717289],[55.44091,54.71899],[55.437439,54.732639],[55.436798,54.736691],[55.433289,54.762531],[55.429932,54.788712],[55.42807,54.804649],[55.42786,54.8064],[55.42186,54.808319],[55.415779,54.813831],[55.40538,54.82312],[55.403271,54.82542],[55.40086,54.828671],[55.397289,54.834862],[55.386391,54.854118],[55.380249,54.864861],[55.369701,54.8834],[55.358471,54.902908],[55.35318,54.912109],[55.351509,54.91544],[55.349781,54.919559],[55.342049,54.93811],[55.3386,54.946571],[55.336929,54.950459],[55.336231,54.951691],[55.334591,54.954632],[55.3298,54.96291],[55.312511,54.993309],[55.311871,54.994419],[55.308102,55.000999],[55.30405,55.008072],[55.3022,55.010731],[55.28294,55.035019],[55.279598,55.03928],[55.268822,55.05315],[55.267792,55.054459],[55.26683,55.05555],[55.265709,55.05661],[55.252621,55.067379],[55.25045,55.069149],[55.243279,55.07502],[55.224491,55.089691],[55.207741,55.103001],[55.199909,55.10997],[55.1982,55.111778],[55.19545,55.11475],[55.191879,55.118969],[55.19067,55.1203],[55.18932,55.12162],[55.186298,55.12389],[55.183521,55.125851],[55.181499,55.127331],[55.18042,55.128021],[55.179428,55.12838],[55.177521,55.12801],[55.16737,55.125011],[55.165501,55.124741],[55.164558,55.124889],[55.16367,55.125469],[55.16188,55.12706],[55.161518,55.127361],[55.160049,55.12886],[55.158371,55.131279],[55.155941,55.135269],[55.153461,55.1399],[55.15033,55.145969],[55.150051,55.146511],[55.149441,55.14777],[55.14867,55.149139],[55.14415,55.1558],[55.143341,55.15712],[55.142609,55.158779],[55.139751,55.16539],[55.138371,55.168598],[55.137951,55.169781],[55.1376,55.17123],[55.137371,55.173859],[55.1362,55.20266],[55.1362,55.205269],[55.13681,55.21809],[55.13707,55.223808],[55.137791,55.240391],[55.138359,55.25322],[55.138321,55.255421],[55.137699,55.262341],[55.136608,55.274231],[55.135632,55.28524],[55.135288,55.288342],[55.134731,55.2915],[55.133968,55.29459],[55.133099,55.297482],[55.132069,55.30043],[55.13176,55.301201],[55.131229,55.302311],[55.130878,55.30302],[55.12941,55.305309],[55.12796,55.307301],[55.126549,55.30899],[55.12381,55.311699],[55.11132,55.323582],[55.110668,55.324211],[55.108189,55.3265],[55.10717,55.327438],[55.105671,55.328819],[55.10144,55.332741],[55.09919,55.334999],[55.097191,55.336868],[55.09584,55.338089],[55.09359,55.34045],[55.092049,55.342411],[55.090729,55.344521],[55.089588,55.346729],[55.087269,55.35218],[55.08271,55.362839],[55.082249,55.36393],[55.081749,55.365261],[55.080891,55.36813],[55.080441,55.369781],[55.079609,55.37392],[55.07925,55.376831],[55.079079,55.37896],[55.079021,55.381001],[55.07909,55.384651],[55.079231,55.388241],[55.079262,55.388969],[55.079369,55.391682],[55.07935,55.394051],[55.07914,55.395279],[55.07906,55.395779],[55.078541,55.397449],[55.071011,55.4119],[55.0662,55.418678],[55.058552,55.429279],[55.056671,55.431881],[55.055168,55.433979],[55.054169,55.435371],[55.047668,55.444351],[55.043839,55.448471],[55.039921,55.452671],[55.036121,55.45673],[55.031078,55.462132],[55.02993,55.463169],[55.025261,55.46817],[55.022678,55.47121],[55.015419,55.479031],[55.011471,55.48325],[55.00721,55.487881],[55.005341,55.489841],[55.004292,55.490971],[55.00346,55.49194],[54.99976,55.498241],[54.998421,55.50032],[54.99715,55.502731],[54.995659,55.505291],[54.994041,55.508141],[54.992279,55.511211],[54.990582,55.51408],[54.990299,55.514549],[54.98629,55.521851],[54.985031,55.524109],[54.98386,55.526711],[54.982948,55.52956],[54.982239,55.53286],[54.981892,55.534679],[54.981621,55.536919],[54.9813,55.544868],[54.980869,55.552792],[54.980659,55.555901],[54.980492,55.557461],[54.980221,55.559052],[54.979321,55.562901],[54.97818,55.566582],[54.976959,55.569439],[54.975311,55.57222],[54.974522,55.573341],[54.973621,55.574402],[54.971722,55.576469],[54.971329,55.576859],[54.96925,55.57906],[54.96706,55.58123],[54.96434,55.583359],[54.963219,55.584129],[54.9617,55.584751],[54.960991,55.58493],[54.960312,55.585121],[54.95866,55.585331],[54.95718,55.585369],[54.955688,55.58519],[54.954731,55.58482],[54.95295,55.584179],[54.95126,55.583809],[54.94902,55.583092],[54.936508,55.579128],[54.929699,55.576931],[54.928501,55.576672],[54.927219,55.576641],[54.925781,55.57695],[54.924301,55.57769],[54.92363,55.578098],[54.922749,55.578892],[54.921341,55.580318],[54.920849,55.581131],[54.917332,55.586761],[54.912281,55.594929],[54.91058,55.598148],[54.909321,55.601109],[54.90807,55.604259],[54.907341,55.60648],[54.907028,55.607632],[54.906559,55.60955],[54.906288,55.611069],[54.904819,55.617901],[54.904518,55.619251],[54.904251,55.620491],[54.903919,55.623051],[54.90332,55.625488],[54.90237,55.628021],[54.89941,55.632771],[54.897282,55.636261],[54.895359,55.639481],[54.89484,55.640339],[54.893181,55.64394],[54.892159,55.646889],[54.891472,55.649391],[54.890732,55.652821],[54.88763,55.66811],[54.884869,55.681709],[54.88084,55.701359],[54.8797,55.707031],[54.879181,55.708351],[54.878559,55.709251],[54.877338,55.710411],[54.876289,55.710949],[54.875462,55.710911],[54.87104,55.70813],[54.868149,55.70644],[54.865608,55.705261],[54.86319,55.704411],[54.860741,55.703659],[54.859039,55.70335],[54.85738,55.70327],[54.85548,55.703381],[54.853649,55.703701],[54.851921,55.704239],[54.850761,55.704659],[54.849751,55.70525],[54.848782,55.70591],[54.84721,55.70734],[54.845921,55.708721],[54.844639,55.710331],[54.84071,55.715698],[54.836929,55.72089],[54.8363,55.72171],[54.834869,55.72319],[54.833141,55.72448],[54.83075,55.725441],[54.825741,55.726768],[54.824032,55.72728],[54.82127,55.728668],[54.819839,55.729481],[54.817902,55.73098],[54.81694,55.731861],[54.81477,55.734138],[54.812309,55.73679],[54.802979,55.746792],[54.800652,55.749561],[54.799351,55.751381],[54.79845,55.752991],[54.796921,55.75589],[54.795879,55.758228],[54.794369,55.761349],[54.79351,55.763039],[54.79216,55.76535],[54.79192,55.765701],[54.79015,55.768139],[54.787418,55.77142],[54.78384,55.775379],[54.782242,55.777538],[54.78157,55.77866],[54.780529,55.780682],[54.77985,55.782009],[54.77916,55.783081],[54.778511,55.783878],[54.777679,55.78474],[54.776909,55.78529],[54.775822,55.785759],[54.773682,55.785789],[54.767872,55.784031],[54.767189,55.783829],[54.763988,55.78289],[54.759991,55.781792],[54.75808,55.781342],[54.756199,55.781139],[54.754761,55.781101],[54.752392,55.781139],[54.750481,55.781422],[54.745941,55.782139],[54.742882,55.7826],[54.74194,55.782761],[54.737862,55.783428],[54.73595,55.783138],[54.73439,55.78228],[54.73304,55.78133],[54.727871,55.777618],[54.726528,55.777081],[54.72509,55.776852],[54.722149,55.776829],[54.716301,55.776749],[54.71484,55.776451],[54.713188,55.77586],[54.702301,55.769932],[54.701519,55.769451],[54.699902,55.768169],[54.698761,55.76675],[54.69836,55.76622],[54.697201,55.763741],[54.696548,55.762081],[54.694908,55.75774],[54.692669,55.752022],[54.692101,55.750641],[54.690891,55.748219],[54.689869,55.746479],[54.686829,55.74213],[54.682739,55.736439],[54.68071,55.733608],[54.67926,55.731918],[54.678429,55.73122],[54.677441,55.730518],[54.675678,55.72998],[54.67395,55.73003],[54.672249,55.730549],[54.667721,55.733021],[54.66748,55.733139],[54.665081,55.734409],[54.6642,55.734871],[54.66375,55.734989],[54.663479,55.73489],[54.663288,55.73465],[54.663139,55.734032],[54.66317,55.733631],[54.663349,55.733261],[54.66354,55.73307],[54.663929,55.73312],[54.664181,55.733551],[54.664421,55.734371],[54.664551,55.735081],[54.664921,55.737061],[54.66534,55.73914],[54.666069,55.743031],[54.67001,55.764301],[54.672119,55.77565],[54.673309,55.782028],[54.674702,55.79158],[54.67527,55.79491],[54.67614,55.799492],[54.676418,55.80175],[54.67643,55.802879],[54.67638,55.804379],[54.676319,55.80537],[54.676239,55.806561],[54.67598,55.809849],[54.675838,55.811871],[54.67556,55.81443],[54.67535,55.81543],[54.674171,55.820782],[54.672138,55.82967],[54.669331,55.841999],[54.66674,55.853401],[54.665531,55.858742],[54.6642,55.864491],[54.66288,55.870319],[54.66124,55.87759],[54.659679,55.8843],[54.65884,55.887218],[54.65807,55.88958],[54.657139,55.89201],[54.656559,55.893372],[54.655449,55.89584],[54.65424,55.89856],[54.65205,55.903351],[54.650982,55.905739],[54.649849,55.90834],[54.649391,55.90958],[54.648708,55.911469],[54.648022,55.913471],[54.647282,55.916161],[54.646801,55.918159],[54.6465,55.919479],[54.645939,55.922279],[54.645641,55.924271],[54.64521,55.926781],[54.6451,55.927639],[54.644539,55.930771],[54.64452,55.93137],[54.644321,55.932629],[54.644161,55.933701],[54.643681,55.937119],[54.643181,55.94035],[54.64291,55.942261],[54.642731,55.943569],[54.642559,55.94508],[54.642441,55.946609],[54.642399,55.947449],[54.642368,55.94833],[54.642349,55.949909],[54.64238,55.951591],[54.64246,55.95335],[54.64257,55.955132],[54.643391,55.967979],[54.643871,55.974979],[54.644112,55.9758],[54.645401,55.995911],[54.645649,55.999821],[54.64595,56.004421],[54.646801,56.017712],[54.64777,56.032749],[54.648731,56.047531],[54.649361,56.057251],[54.649399,56.057941],[54.650101,56.068951],[54.65044,56.074249],[54.650661,56.07782],[54.650669,56.078011],[54.650871,56.080952],[54.65089,56.081348],[54.65107,56.08419],[54.651089,56.08453],[54.651299,56.087551],[54.651409,56.08976],[54.652229,56.102268],[54.65279,56.10857],[54.653149,56.11108],[54.654079,56.115681],[54.654282,56.116501],[54.654678,56.118099],[54.655411,56.120739],[54.65723,56.127541],[54.659191,56.134892],[54.660511,56.139309],[54.662338,56.144741],[54.665249,56.153381],[54.66642,56.15691],[54.668629,56.16354],[54.672539,56.17519],[54.67445,56.180859],[54.675129,56.182831],[54.6763,56.185509],[54.677559,56.18787],[54.678829,56.18977],[54.681629,56.19302],[54.685379,56.1973],[54.687679,56.199921],[54.69323,56.206329],[54.69767,56.211479],[54.700779,56.21513],[54.70499,56.220051],[54.70713,56.222591],[54.70863,56.224312],[54.719292,56.236759],[54.72155,56.239792],[54.722988,56.242111],[54.724621,56.244949],[54.72646,56.248669],[54.728119,56.25267],[54.729301,56.255981],[54.730671,56.26046],[54.732208,56.266048],[54.73465,56.274929],[54.737309,56.284599],[54.740238,56.29528],[54.741459,56.299759],[54.742451,56.30331],[54.74308,56.305641],[54.743328,56.306549],[54.744011,56.309292],[54.744431,56.310799],[54.745178,56.313339],[54.746929,56.319698],[54.74913,56.327782],[54.75127,56.335579],[54.751911,56.337952],[54.752621,56.34087],[54.753189,56.343601],[54.75383,56.347221],[54.754681,56.352612],[54.755508,56.357979],[54.757141,56.368118],[54.758308,56.375591],[54.759369,56.38224],[54.760269,56.387981],[54.761181,56.393742],[54.76202,56.399109],[54.763481,56.408401],[54.764179,56.412868],[54.764912,56.417439],[54.766361,56.426579],[54.767849,56.436069],[54.769329,56.44548],[54.77029,56.451439],[54.77095,56.455681],[54.771599,56.459869],[54.772919,56.467838],[54.773529,56.471001],[54.77557,56.48167],[54.779339,56.501308],[54.782982,56.520302],[54.784142,56.526348],[54.78595,56.535759],[54.786251,56.537338],[54.786739,56.539989],[54.788971,56.551559],[54.791481,56.564621],[54.793541,56.575432],[54.7953,56.584549],[54.796471,56.590401],[54.802078,56.612301],[54.80304,56.616119],[54.80336,56.617279],[54.804211,56.620689],[54.80545,56.625519],[54.806412,56.629318],[54.807411,56.63324],[54.80817,56.636829],[54.808491,56.63871],[54.80912,56.643742],[54.809792,56.649261],[54.810619,56.656109],[54.811432,56.662949],[54.812271,56.66996],[54.813332,56.67894],[54.813869,56.683289],[54.81422,56.686359],[54.814671,56.69001],[54.815281,56.69503],[54.81559,56.697639],[54.81612,56.702271],[54.81625,56.703381],[54.816319,56.70443],[54.816441,56.706532],[54.816559,56.709141],[54.816639,56.714771],[54.816681,56.722599],[54.816738,56.729401],[54.81675,56.730419],[54.816799,56.73798],[54.81686,56.749969],[54.816921,56.757],[54.816921,56.757542],[54.81715,56.793861],[54.817181,56.799141],[54.817402,56.839279],[54.81752,56.863491],[54.817558,56.866192],[54.817768,56.868931],[54.818138,56.871922],[54.818588,56.874352],[54.81926,56.877159],[54.820061,56.87973],[54.82132,56.88287],[54.825951,56.893631],[54.826462,56.894989],[54.82671,56.896278],[54.8269,56.89827],[54.826988,56.900848],[54.827091,56.903469],[54.827251,56.90778],[54.827751,56.91758],[54.828339,56.922459],[54.82917,56.927349],[54.82991,56.93148],[54.830528,56.935371],[54.83102,56.939499],[54.831219,56.942089],[54.83136,56.944679],[54.83186,56.96133],[54.832298,56.976261],[54.832489,56.981819],[54.832611,56.98418],[54.832748,56.98595],[54.832909,56.987659],[54.841751,57.05891],[54.842751,57.066971],[54.845871,57.092319],[54.846611,57.098259],[54.847,57.1012],[54.847179,57.10244],[54.847271,57.103039],[54.847351,57.1035],[54.847511,57.104221],[54.847729,57.105179],[54.850578,57.11689],[54.85368,57.12962],[54.853931,57.13068],[54.856098,57.13966],[54.857651,57.146091],[54.859219,57.152538],[54.860199,57.156212],[54.86039,57.156841],[54.860592,57.157551],[54.86079,57.158089],[54.860989,57.15863],[54.861271,57.15929],[54.86327,57.164169],[54.865829,57.170479],[54.870941,57.183079],[54.873699,57.189919],[54.874222,57.191341],[54.874599,57.192589],[54.87492,57.193729],[54.875172,57.19487],[54.875389,57.19598],[54.87561,57.197201],[54.875809,57.198551],[54.87598,57.199921],[54.876228,57.20211],[54.879848,57.23526],[54.883839,57.271709],[54.88488,57.281361],[54.885391,57.286228],[54.885761,57.289349],[54.886009,57.291],[54.88623,57.29237],[54.88662,57.29438],[54.88707,57.296478],[54.887661,57.298771],[54.888168,57.30069],[54.888451,57.30154],[54.88868,57.30225],[54.88908,57.30341],[54.889408,57.304249],[54.889931,57.305592],[54.890362,57.306591],[54.89061,57.307152],[54.891491,57.309158],[54.893631,57.313969],[54.8983,57.324348],[54.90033,57.328899],[54.902451,57.333641],[54.902882,57.334629],[54.903229,57.33551],[54.903599,57.336491],[54.904221,57.338348],[54.904751,57.340061],[54.90514,57.341339],[54.905849,57.343498],[54.905949,57.344791],[54.907589,57.352791],[54.90855,57.35762],[54.909931,57.364521],[54.910099,57.365318],[54.911282,57.370911],[54.911678,57.372929],[54.911949,57.37447],[54.91214,57.375969],[54.912251,57.37751],[54.912239,57.379021],[54.91217,57.380489],[54.912048,57.382011],[54.911758,57.385181],[54.911671,57.386372],[54.911621,57.38739],[54.91164,57.388378],[54.911709,57.389439],[54.9118,57.390491],[54.911961,57.391682],[54.912128,57.392632],[54.912338,57.393501],[54.912579,57.394428],[54.913738,57.398151],[54.915539,57.40395],[54.915821,57.404789],[54.916302,57.406052],[54.916759,57.40707],[54.91745,57.40836],[54.918049,57.409409],[54.91856,57.410229],[54.91906,57.410919],[54.919621,57.41161],[54.920891,57.412979],[54.92168,57.41362],[54.922581,57.41423],[54.922661,57.41428],[54.923611,57.414799],[54.92411,57.415031],[54.924591,57.415218],[54.92514,57.41539],[54.925991,57.41552],[54.927502,57.41568],[54.928959,57.415852],[54.930241,57.41597],[54.931141,57.416088],[54.931541,57.41621],[54.93187,57.41637],[54.932251,57.416611],[54.932732,57.416939],[54.93317,57.417301],[54.933681,57.417839],[54.934261,57.418579],[54.934978,57.419701],[54.936569,57.422218],[54.9384,57.425159],[54.93906,57.42614],[54.93964,57.426949],[54.940189,57.42765],[54.940929,57.42841],[54.941841,57.429161],[54.942799,57.429859],[54.943611,57.430462],[54.944111,57.430882],[54.944618,57.431351],[54.945148,57.431881],[54.945789,57.432579],[54.946369,57.433239],[54.946819,57.4338],[54.94735,57.434559],[54.947849,57.43528],[54.948238,57.435871],[54.948559,57.43642],[54.94891,57.437119],[54.94923,57.438049],[54.949471,57.43898],[54.94981,57.44046],[54.951229,57.4473],[54.952629,57.454121],[54.953041,57.456089],[54.953308,57.45726],[54.953541,57.458179],[54.953732,57.458931],[54.953999,57.459751],[54.9543,57.46064],[54.954609,57.46146],[54.95499,57.46244],[54.955421,57.463322],[54.95623,57.46487],[54.956848,57.465889],[54.95752,57.466869],[54.959419,57.469212],[54.961609,57.471859],[54.964561,57.476082],[54.966679,57.479179],[54.96748,57.480358],[54.967831,57.480942],[54.968151,57.48151],[54.96851,57.482231],[54.969051,57.48349],[54.969601,57.484901],[54.969872,57.48568],[54.970131,57.48679],[54.970421,57.488289],[54.971851,57.496109],[54.973801,57.507069],[54.9743,57.509739],[54.974812,57.51218],[54.976761,57.520279],[54.97905,57.529819],[54.980228,57.53471],[54.980942,57.537682],[54.981831,57.541401],[54.982738,57.5452],[54.983238,57.547199],[54.983589,57.54863],[54.98391,57.54998],[54.984211,57.551189],[54.984638,57.553089],[54.985069,57.555191],[54.98534,57.556782],[54.986221,57.562389],[54.987881,57.573261],[54.989071,57.58107],[54.990009,57.587139],[54.990292,57.588848],[54.99073,57.59108],[54.991402,57.594082],[54.991611,57.594971],[54.991829,57.595711],[54.9921,57.596432],[54.992481,57.597321],[54.993031,57.598309],[54.99374,57.599461],[54.99625,57.603321],[54.996559,57.603901],[54.99678,57.604401],[54.997028,57.605068],[54.997261,57.60582],[54.997509,57.606812],[54.997761,57.60796],[54.99929,57.614929],[54.999401,57.615528],[54.999569,57.616638],[54.99963,57.617451],[54.999649,57.61824],[54.999619,57.619141],[54.999561,57.62038],[54.999458,57.621529],[54.999352,57.622421],[54.999161,57.62368],[54.998989,57.625019],[54.99894,57.62561],[54.998909,57.626289],[54.998932,57.626961],[54.999008,57.627781],[54.999111,57.628422],[54.999241,57.628922],[55.00016,57.631901],[55.000332,57.632721],[55.000439,57.63356],[55.000511,57.63483],[55.00053,57.636471],[55.00045,57.640511],[55.00042,57.641621],[55.000351,57.64259],[55.00021,57.643822],[55.00005,57.64492],[54.999748,57.646561],[54.999561,57.647572],[54.99942,57.648769],[54.999329,57.649891],[54.999298,57.6511],[54.999359,57.652069],[54.999569,57.65411],[54.99979,57.655891],[55.00016,57.658321],[55.000462,57.65979],[55.00074,57.660851],[55.00108,57.66193],[55.002369,57.66563],[55.00433,57.671101],[55.00518,57.67347],[55.005989,57.675831],[55.006229,57.676601],[55.00647,57.677422],[55.006779,57.678558],[55.00705,57.679668],[55.00732,57.68092],[55.007439,57.681728],[55.0075,57.682461],[55.007542,57.683418],[55.007561,57.684841],[55.007568,57.686138],[55.007542,57.687408],[55.007469,57.688499],[55.007381,57.689579],[55.007271,57.690868],[55.006889,57.69455],[55.006748,57.69582],[55.006229,57.701149],[55.006039,57.703571],[55.005871,57.70657],[55.005852,57.70681],[55.00584,57.70705],[55.0056,57.711048],[55.005508,57.711979],[55.005371,57.712799],[55.004532,57.716129],[55.004219,57.716888],[55.003811,57.71769],[55.003349,57.718189],[55.002869,57.718571],[55.002399,57.7188],[55.00169,57.718868],[55.001129,57.71875],[55.000629,57.718449],[55.00013,57.71801],[54.99934,57.71719],[54.998329,57.71587],[54.99786,57.715302],[54.99728,57.71468],[54.996689,57.71402],[54.996109,57.713409],[54.995838,57.713181],[54.99559,57.713032],[54.99535,57.712971],[54.995129,57.712978],[54.994869,57.713051],[54.994678,57.713169],[54.994511,57.713322],[54.994339,57.713558],[54.994171,57.71394],[54.994041,57.71434],[54.993969,57.71484],[54.993961,57.71534],[54.99408,57.71619],[54.994362,57.71743],[54.994888,57.719109],[54.995029,57.71981],[54.995121,57.720612],[54.99514,57.721199],[54.995071,57.721741],[54.99469,57.723579],[54.992451,57.73497],[54.99155,57.739571],[54.99041,57.745319],[54.986382,57.765751],[54.98336,57.777149],[54.982868,57.77919],[54.9827,57.780079],[54.982578,57.781471],[54.982521,57.7831],[54.982521,57.784019],[54.9827,57.78746],[54.982929,57.791069],[54.983139,57.794201],[54.983219,57.79554],[54.983261,57.79657],[54.98328,57.79734],[54.983231,57.798279],[54.98299,57.79966],[54.982281,57.802799],[54.981541,57.806122],[54.980991,57.80854],[54.980259,57.811661],[54.980068,57.812382],[54.97966,57.813519],[54.979259,57.81432],[54.978779,57.815109],[54.978222,57.815849],[54.977699,57.816441],[54.977139,57.81702],[54.975739,57.81852],[54.974232,57.82011],[54.97271,57.821732],[54.971359,57.823158],[54.970249,57.824379],[54.969761,57.82505],[54.96928,57.825802],[54.96904,57.826241],[54.96875,57.82695],[54.968449,57.827839],[54.968182,57.828892],[54.967529,57.832352],[54.965641,57.842831],[54.965321,57.846352],[54.965778,57.850979],[54.9683,57.866692],[54.96925,57.87114],[54.97163,57.87743],[54.97298,57.884399],[54.97345,57.88818],[54.973621,57.891861],[54.973221,57.896992],[54.971889,57.90617],[54.971489,57.90847],[54.971142,57.910809],[54.971001,57.911911],[54.970871,57.913189],[54.97076,57.914551],[54.97068,57.915878],[54.970631,57.917332],[54.970612,57.918831],[54.970772,57.925819],[54.970879,57.931122],[54.971111,57.93475],[54.970661,57.93922],[54.968941,57.954922],[54.968201,57.96059],[54.967072,57.96685],[54.966282,57.97089],[54.962391,57.982052],[54.959461,57.98822],[54.95628,57.993069],[54.947769,58.001431],[54.94186,58.00684],[54.93618,58.012051],[54.929489,58.01952],[54.922199,58.028999],[54.920761,58.031719],[54.919991,58.035351],[54.918999,58.04007],[54.91861,58.044579],[54.919621,58.05241],[54.919849,58.055222],[54.919689,58.057919],[54.918949,58.061138],[54.91687,58.066639],[54.914459,58.072941],[54.914261,58.07449],[54.914009,58.07719],[54.914108,58.080021],[54.91412,58.083241],[54.913422,58.08646],[54.910488,58.09568],[54.909309,58.099461],[54.90794,58.10371],[54.907349,58.105831],[54.90641,58.109039],[54.905319,58.111012],[54.904041,58.113071],[54.90316,58.115429],[54.90276,58.118912],[54.902111,58.122169],[54.901131,58.125],[54.89925,58.12878],[54.897621,58.13118],[54.896839,58.133331],[54.896439,58.137531],[54.896599,58.142029],[54.89621,58.14418],[54.896099,58.144779],[54.894371,58.152939],[54.8923,58.160568],[54.88839,58.16972],[54.877441,58.192841],[54.87616,58.19817],[54.87537,58.20314],[54.875019,58.205891],[54.872601,58.227779],[54.86969,58.252331],[54.86937,58.25486],[54.868851,58.257912],[54.86615,58.263439],[54.859852,58.274681],[54.85759,58.27953],[54.8568,58.282619],[54.855759,58.28717],[54.855221,58.2901],[54.855209,58.293781],[54.85516,58.296181],[54.854931,58.297989],[54.85429,58.300251],[54.85218,58.303909],[54.851109,58.30648],[54.85067,58.31023],[54.851349,58.315891],[54.852242,58.322498],[54.853432,58.328251],[54.855499,58.334511],[54.857578,58.339748],[54.860001,58.346272],[54.86356,58.359058],[54.864639,58.361889],[54.865711,58.363682],[54.866711,58.365101],[54.868511,58.367081],[54.870312,58.368992],[54.871632,58.370708],[54.87188,58.37104],[54.87233,58.371769],[54.87291,58.372799],[54.873981,58.375439],[54.875271,58.37883],[54.875259,58.378799],[54.87561,58.37991],[54.875881,58.381222],[54.876209,58.38335],[54.876369,58.38538],[54.876419,58.38731],[54.876549,58.388569],[54.876701,58.38958],[54.876888,58.39056],[54.87957,58.398319],[54.88208,58.405579],[54.88253,58.406719],[54.88303,58.407761],[54.883709,58.408772],[54.88446,58.409649],[54.884811,58.410118],[54.885071,58.410519],[54.885342,58.41114],[54.885609,58.41198],[54.88562,58.41209],[54.88588,58.413651],[54.885891,58.413731],[54.885941,58.414082],[54.886341,58.416908],[54.886429,58.4179],[54.886471,58.41938],[54.886478,58.420269],[54.88649,58.420891],[54.88662,58.423191],[54.88681,58.425011],[54.887581,58.43187],[54.88773,58.433399],[54.887829,58.434341],[54.887871,58.434719],[54.887932,58.435169],[54.88805,58.43618],[54.888119,58.43681],[54.888599,58.440239],[54.88921,58.444561],[54.88932,58.44585],[54.88929,58.447071],[54.889229,58.44799],[54.889091,58.44886],[54.888939,58.449711],[54.888691,58.450562],[54.888458,58.451302],[54.88821,58.451981],[54.88789,58.45269],[54.887508,58.453259],[54.886829,58.454208],[54.88588,58.45509],[54.884529,58.456032],[54.882469,58.457481],[54.881641,58.458061],[54.88073,58.458912],[54.88039,58.45937],[54.880058,58.459999],[54.876789,58.467121],[54.87598,58.469059],[54.87574,58.470112],[54.87542,58.47274],[54.875141,58.474892],[54.87492,58.475681],[54.874619,58.47641],[54.87336,58.47868],[54.871059,58.481972],[54.87067,58.482498],[54.869678,58.48386],[54.868858,58.485409],[54.868279,58.48671],[54.867729,58.488331],[54.867222,58.490761],[54.86694,58.492859],[54.866859,58.49493],[54.866859,58.4967],[54.867031,58.498428],[54.867279,58.500332],[54.868,58.505741],[54.86858,58.510281],[54.868698,58.512032],[54.86861,58.513531],[54.868351,58.51495],[54.867569,58.517971],[54.867329,58.519619],[54.867149,58.521931],[54.867031,58.524361],[54.86684,58.526409],[54.86652,58.528271],[54.865879,58.53072],[54.865391,58.532169],[54.864849,58.533569],[54.864231,58.534939],[54.86356,58.536221],[54.862251,58.53828],[54.860821,58.540161],[54.860008,58.54134],[54.859348,58.54269],[54.858711,58.544571],[54.85836,58.545929],[54.858109,58.547569],[54.857948,58.549541],[54.857922,58.558102],[54.858021,58.59304],[54.85812,58.601959],[54.858089,58.603661],[54.858028,58.607029],[54.857792,58.612381],[54.856152,58.65015],[54.856312,58.65461],[54.857529,58.67363],[54.8578,58.677269],[54.858101,58.67989],[54.85878,58.68224],[54.862438,58.69508],[54.86359,58.69994],[54.864601,58.708519],[54.865471,58.714401],[54.86536,58.716499],[54.864891,58.71854],[54.862438,58.724091],[54.8615,58.726311],[54.861301,58.726791],[54.861118,58.727341],[54.86076,58.72858],[54.86063,58.729568],[54.86055,58.730579],[54.860531,58.731232],[54.86055,58.73188],[54.860729,58.733189],[54.860821,58.733551],[54.861,58.734329],[54.861229,58.73505],[54.8615,58.735748],[54.861801,58.736431],[54.8633,58.739399],[54.864861,58.7425],[54.86726,58.747711],[54.86792,58.749409],[54.868431,58.75082],[54.86969,58.754509],[54.87112,58.75959],[54.872021,58.763599],[54.872471,58.766411],[54.873249,58.77142],[54.873669,58.77515],[54.874531,58.78252],[54.87529,58.78838],[54.875992,58.794739],[54.877651,58.804951],[54.87949,58.812359],[54.880798,58.817051],[54.881649,58.820202],[54.88184,58.8209],[54.882408,58.823139],[54.88818,58.84444],[54.889549,58.849411],[54.891258,58.85582],[54.89296,58.862019],[54.894009,58.865898],[54.895599,58.87178],[54.896351,58.874321],[54.897129,58.87656],[54.897869,58.87851],[54.898602,58.88028],[54.900181,58.883518],[54.90126,58.885422],[54.902088,58.886688],[54.90332,58.888519],[54.904209,58.88969],[54.905102,58.890732],[54.906528,58.892269],[54.90789,58.893501],[54.90921,58.894581],[54.916771,58.89999],[54.919979,58.902191],[54.921471,58.903381],[54.922241,58.904099],[54.922901,58.9048],[54.92342,58.905418],[54.923889,58.90612],[54.924431,58.906921],[54.92514,58.908249],[54.925701,58.909481],[54.926109,58.910461],[54.92659,58.911919],[54.926949,58.913349],[54.92717,58.914471],[54.927391,58.91584],[54.92757,58.91724],[54.927689,58.918709],[54.9277,58.92009],[54.927662,58.922642],[54.927521,58.92664],[54.927521,58.928459],[54.92762,58.930641],[54.92783,58.932461],[54.928108,58.93409],[54.928509,58.935711],[54.929001,58.937309],[54.929451,58.938568],[54.92981,58.939369],[54.930222,58.940151],[54.930569,58.94088],[54.93317,58.945461],[54.933681,58.946121],[54.9342,58.946751],[54.93483,58.947361],[54.935421,58.94783],[54.936131,58.948261],[54.93689,58.948669],[54.937778,58.948921],[54.938148,58.949032],[54.939041,58.949299],[54.941181,58.949848],[54.94286,58.950291],[54.948559,58.951759],[54.95015,58.952301],[54.951408,58.95293],[54.952469,58.953609],[54.953579,58.954441],[54.955879,58.95702],[54.956718,58.95816],[54.957458,58.959309],[54.95826,58.96077],[54.958961,58.962231],[54.960209,58.96526],[54.964561,58.97612],[54.966148,58.979691],[54.96846,58.98386],[54.971909,58.99012],[54.980068,59.004581],[54.98201,59.00872],[54.98317,59.011841],[54.984291,59.01524],[54.988029,59.02697],[54.988899,59.02961],[54.989639,59.031521],[54.990528,59.033482],[54.991428,59.03516],[54.992359,59.036671],[54.993172,59.037769],[54.995762,59.04158],[54.996811,59.043549],[54.997601,59.04528],[54.998409,59.047291],[54.998871,59.048698],[54.99931,59.050179],[54.999981,59.053009],[55.000969,59.05806],[55.001591,59.06147],[55.001881,59.063049],[55.002171,59.064411],[55.002541,59.0658],[55.002892,59.066929],[55.00325,59.067959],[55.003639,59.069],[55.004219,59.07024],[55.004688,59.071232],[55.00515,59.072071],[55.005798,59.073101],[55.00671,59.074471],[55.007648,59.075871],[55.009418,59.078602],[55.009991,59.07967],[55.010441,59.080662],[55.010929,59.081841],[55.012039,59.085289],[55.012371,59.08654],[55.012691,59.087978],[55.012901,59.089668],[55.013199,59.092682],[55.013451,59.095551],[55.013618,59.097679],[55.014332,59.106461],[55.014641,59.108871],[55.01498,59.110481],[55.01545,59.112091],[55.015831,59.11319],[55.016281,59.114239],[55.01688,59.115341],[55.017479,59.116329],[55.018269,59.11747],[55.019199,59.11871],[55.02042,59.120419],[55.020988,59.12122],[55.022541,59.123219],[55.02383,59.124649],[55.024811,59.125702],[55.025921,59.12674],[55.027531,59.128071],[55.032501,59.13216],[55.03307,59.132671],[55.034271,59.133629],[55.034901,59.134151],[55.038521,59.137138],[55.04015,59.138451],[55.04047,59.138741],[55.0415,59.139599],[55.04211,59.140049],[55.042591,59.140411],[55.044239,59.141479],[55.048489,59.144131],[55.050339,59.145309],[55.0509,59.145729],[55.0513,59.14603],[55.051731,59.14637],[55.05204,59.146629],[55.052319,59.14687],[55.05254,59.147079],[55.05278,59.147301],[55.053009,59.14753],[55.05452,59.149109],[55.059559,59.15451],[55.059799,59.154812],[55.059978,59.155022],[55.0602,59.155281],[55.06039,59.155529],[55.060558,59.15575],[55.060749,59.15601],[55.060982,59.156349],[55.061241,59.156769],[55.061508,59.157219],[55.062092,59.15831],[55.062199,59.158562],[55.06229,59.158798],[55.062382,59.159039],[55.062721,59.160069],[55.062908,59.16066],[55.06308,59.161221],[55.06321,59.161732],[55.063381,59.16238],[55.063568,59.163151],[55.063931,59.16457],[55.064159,59.16555],[55.064491,59.166882],[55.064751,59.167938],[55.065479,59.17107],[55.066669,59.17609],[55.068981,59.18594],[55.069931,59.18998],[55.07061,59.193001],[55.071239,59.19614],[55.071812,59.19902],[55.07225,59.2015],[55.073051,59.206139],[55.074249,59.21299],[55.07515,59.2183],[55.07552,59.220089],[55.076321,59.223579],[55.077019,59.226261],[55.07766,59.228409],[55.078308,59.230431],[55.078972,59.232281],[55.081261,59.238392],[55.08535,59.249168],[55.087631,59.255032],[55.0886,59.25729],[55.089062,59.258221],[55.089828,59.259731],[55.090889,59.26157],[55.09185,59.262989],[55.09269,59.264252],[55.093651,59.265469],[55.095951,59.26833],[55.096569,59.26907],[55.097462,59.27026],[55.098019,59.27116],[55.098541,59.272079],[55.099072,59.273102],[55.099758,59.27475],[55.100288,59.276279],[55.10078,59.277931],[55.10117,59.279331],[55.101639,59.281368],[55.1022,59.283661],[55.10268,59.285751],[55.102859,59.28648],[55.103088,59.287189],[55.103279,59.287701],[55.103519,59.28817],[55.103828,59.288639],[55.105659,59.29092],[55.105881,59.291321],[55.106079,59.29174],[55.106312,59.292301],[55.107021,59.29454],[55.10857,59.299801],[55.108898,59.30117],[55.10918,59.30238],[55.109459,59.303768],[55.109989,59.307079],[55.110519,59.310341],[55.110611,59.31094],[55.11068,59.311699],[55.110729,59.31263],[55.110748,59.31324],[55.110771,59.31432],[55.110649,59.319199],[55.110519,59.32346],[55.11042,59.326061],[55.110359,59.32769],[55.110298,59.330109],[55.110298,59.331009],[55.110321,59.33194],[55.110359,59.332951],[55.110401,59.333839],[55.110489,59.334721],[55.1106,59.335812],[55.110729,59.33691],[55.110939,59.33815],[55.11116,59.339218],[55.111439,59.34045],[55.111809,59.34206],[55.115021,59.35487],[55.115238,59.355801],[55.11562,59.357689],[55.11581,59.35886],[55.115959,59.360001],[55.116051,59.361031],[55.116119,59.361969],[55.11618,59.36314],[55.116192,59.364391],[55.11618,59.3657],[55.11615,59.36681],[55.116112,59.36787],[55.115879,59.372749],[55.11573,59.37569],[55.115589,59.378368],[55.115589,59.379139],[55.115589,59.379799],[55.11562,59.380531],[55.115688,59.381241],[55.115761,59.381802],[55.115879,59.38242],[55.116951,59.387329],[55.11702,59.38776],[55.117081,59.388271],[55.117142,59.388809],[55.11718,59.389301],[55.11721,59.389919],[55.117161,59.392971],[55.11702,59.396809],[55.11697,59.397652],[55.116909,59.398319],[55.116859,59.398869],[55.11676,59.399422],[55.11652,59.40028],[55.11618,59.401199],[55.11586,59.401741],[55.115501,59.402359],[55.115372,59.402531],[55.11528,59.402649],[55.114738,59.403351],[55.113369,59.40509],[55.113029,59.40559],[55.112659,59.4062],[55.112339,59.40704],[55.112171,59.407681],[55.11203,59.408379],[55.1119,59.409279],[55.111889,59.410118],[55.111919,59.41098],[55.112122,59.413879],[55.112259,59.415508],[55.112492,59.417099],[55.11264,59.417912],[55.112801,59.41848],[55.112968,59.418949],[55.113232,59.419601],[55.11351,59.420078],[55.113861,59.420631],[55.114769,59.421959],[55.11721,59.425442],[55.119701,59.428822],[55.12006,59.429211],[55.120548,59.429661],[55.123482,59.432072],[55.123798,59.432362],[55.124062,59.43261],[55.124298,59.432892],[55.124489,59.43317],[55.12468,59.433472],[55.12487,59.433842],[55.125092,59.43438],[55.125721,59.43589],[55.12719,59.440029],[55.127319,59.44051],[55.127441,59.440941],[55.127571,59.441521],[55.127651,59.442081],[55.127708,59.44273],[55.12772,59.44334],[55.12772,59.443851],[55.12767,59.44434],[55.127609,59.444851],[55.127529,59.445351],[55.127369,59.446049],[55.127171,59.446621],[55.12693,59.447201],[55.126621,59.447781],[55.126202,59.448399],[55.125,59.449959],[55.124748,59.45034],[55.124531,59.45076],[55.12431,59.451248],[55.12331,59.454609],[55.122761,59.456589],[55.12199,59.459351],[55.121761,59.46022],[55.121529,59.46106],[55.12133,59.46196],[55.121208,59.462841],[55.120991,59.46529],[55.12093,59.46587],[55.12085,59.466599],[55.120781,59.467098],[55.120689,59.467541],[55.12056,59.468079],[55.120338,59.468811],[55.120121,59.46944],[55.119888,59.47002],[55.11961,59.470581],[55.117699,59.47393],[55.117489,59.47438],[55.117229,59.47504],[55.117031,59.475651],[55.116879,59.476311],[55.116711,59.477131],[55.11657,59.477951],[55.116161,59.48074],[55.115761,59.483471],[55.11483,59.49308],[55.114189,59.501492],[55.112179,59.51009],[55.110081,59.516941],[55.10947,59.519161],[55.109039,59.52121],[55.10873,59.523621],[55.10865,59.525982],[55.10873,59.528],[55.108952,59.529942],[55.109409,59.532139],[55.10984,59.53363],[55.110432,59.535252],[55.111099,59.53677],[55.113239,59.541359],[55.113789,59.542641],[55.11425,59.543861],[55.114868,59.545769],[55.115292,59.547199],[55.115841,59.549469],[55.11694,59.554329],[55.11747,59.556259],[55.118118,59.558281],[55.11927,59.561562],[55.11972,59.562962],[55.12011,59.56435],[55.12056,59.565922],[55.121151,59.567581],[55.122509,59.571259],[55.122978,59.572731],[55.123299,59.574089],[55.123619,59.575611],[55.123989,59.577789],[55.124439,59.58099],[55.124989,59.584999],[55.12516,59.586498],[55.12524,59.58778],[55.12524,59.588848],[55.125092,59.590099],[55.124939,59.590851],[55.124748,59.591572],[55.124481,59.592289],[55.12418,59.59288],[55.123409,59.59404],[55.123329,59.594139],[55.122601,59.59499],[55.11953,59.59798],[55.117321,59.600151],[55.116501,59.600948],[55.115921,59.601379],[55.115299,59.60165],[55.114639,59.601711],[55.11412,59.601608],[55.11351,59.601299],[55.11026,59.599369],[55.109241,59.59885],[55.108608,59.59866],[55.107189,59.598419],[55.10659,59.598202],[55.105968,59.59779],[55.10545,59.597221],[55.10495,59.59642],[55.103981,59.59449],[55.103279,59.59317],[55.102772,59.592411],[55.102291,59.591862],[55.101688,59.591351],[55.10051,59.590549],[55.09898,59.589611],[55.09766,59.588779],[55.096279,59.58794],[55.094761,59.587158],[55.09462,59.58709],[55.093159,59.586491],[55.09169,59.586109],[55.090179,59.585899],[55.087391,59.585678],[55.08651,59.585609],[55.085659,59.58543],[55.084679,59.585098],[55.083912,59.584839],[55.083149,59.58469],[55.082291,59.584641],[55.07872,59.58461],[55.076729,59.58466],[55.075802,59.584759],[55.075039,59.585018],[55.074181,59.58556],[55.073639,59.586201],[55.072979,59.587341],[55.072472,59.588779],[55.072281,59.589512],[55.07201,59.590611],[55.068249,59.610561],[55.06686,59.617882],[55.066792,59.61824],[55.064869,59.628311],[55.064369,59.630939],[55.063782,59.63372],[55.063171,59.636219],[55.062881,59.63715],[55.062511,59.63834],[55.061649,59.640789],[55.06097,59.6423],[55.060009,59.64397],[55.059361,59.64513],[55.05859,59.646542],[55.05806,59.647812],[55.057621,59.649422],[55.057251,59.651299],[55.05698,59.653542],[55.056862,59.655731],[55.05669,59.6618],[55.05632,59.673031],[55.055679,59.696388],[55.055641,59.697941],[55.05545,59.70269],[55.055229,59.706039],[55.05479,59.70961],[55.054371,59.711731],[55.05373,59.714111],[55.052979,59.71627],[55.052181,59.71796],[55.05088,59.720058],[55.049549,59.721661],[55.048141,59.72298],[55.046951,59.723701],[55.045479,59.724319],[55.044159,59.724628],[55.04253,59.724789],[55.04084,59.724709],[55.039009,59.72438],[55.034672,59.723301],[55.032082,59.72263],[55.031349,59.722511],[55.030609,59.722439],[55.029442,59.722469],[55.02808,59.72274],[55.026699,59.72327],[55.025501,59.723991],[55.024311,59.724892],[55.022549,59.726681],[55.021229,59.72855],[55.019981,59.730789],[55.019112,59.7328],[55.01836,59.734989],[55.017818,59.73703],[55.017281,59.739811],[55.016949,59.742611],[55.016781,59.744831],[55.016548,59.752708],[55.016479,59.758751],[55.016541,59.760941],[55.01675,59.763359],[55.01712,59.765491],[55.01791,59.7687],[55.018188,59.77018],[55.018391,59.771759],[55.018471,59.77317],[55.01844,59.774551],[55.018261,59.776371],[55.017941,59.7784],[55.017021,59.782459],[55.01545,59.78944],[55.014591,59.792622],[55.013741,59.795219],[55.012909,59.797359],[55.011108,59.801861],[55.009972,59.80434],[55.00528,59.814522],[55.001629,59.82243],[54.998661,59.828949],[54.998161,59.83004],[54.99617,59.833672],[54.994751,59.83762],[54.993271,59.845428],[54.990711,59.852638],[54.988449,59.857792],[54.984798,59.864231],[54.983311,59.8666],[54.9762,59.877918],[54.975151,59.879589],[54.972931,59.882938],[54.971111,59.88689],[54.96899,59.892891],[54.966721,59.904572],[54.964111,59.922588],[54.963081,59.928169],[54.961498,59.93375],[54.958889,59.93924],[54.95475,59.948601],[54.953461,59.951599],[54.950409,59.955978],[54.948441,59.959332],[54.946911,59.96328],[54.946072,59.966621],[54.945499,59.96957],[54.945301,59.97123],[54.945251,59.972099],[54.94519,59.972939],[54.945091,59.974689],[54.945049,59.97646],[54.944969,59.983688],[54.944931,59.98642],[54.944809,59.995998],[54.944618,60.010189],[54.944569,60.012428],[54.944439,60.014481],[54.944302,60.017578],[54.94421,60.019371],[54.943981,60.023159],[54.943939,60.024429],[54.94384,60.027279],[54.94389,60.03072],[54.94389,60.031479],[54.944149,60.050861],[54.944229,60.054852],[54.94426,60.057011],[54.944279,60.05846],[54.944649,60.08567],[54.944889,60.102211],[54.944839,60.10564],[54.94466,60.10783],[54.94437,60.109631],[54.94392,60.111649],[54.94326,60.11367],[54.94249,60.11581],[54.941429,60.118179],[54.937809,60.126369],[54.93663,60.12925],[54.93581,60.131908],[54.934238,60.138969],[54.934101,60.13953],[54.932701,60.1455],[54.931992,60.14938],[54.931629,60.151779],[54.931301,60.155849],[54.93108,60.15937],[54.93087,60.165771],[54.930271,60.178749],[54.929359,60.198689],[54.929211,60.19973],[54.926651,60.217232],[54.924358,60.232849],[54.92395,60.235291],[54.923698,60.23925],[54.923599,60.242512],[54.92342,60.259071],[54.92326,60.27956],[54.923092,60.284538],[54.920158,60.315289],[54.92004,60.316509],[54.919449,60.322781],[54.919201,60.325329],[54.9189,60.32843],[54.918819,60.3293],[54.918621,60.33147],[54.916981,60.34874],[54.91441,60.374008],[54.911572,60.402851],[54.91098,60.409698],[54.91048,60.41692],[54.910339,60.42078],[54.910252,60.426491],[54.910351,60.434891],[54.910801,60.455132],[54.911251,60.486462],[54.911621,60.51305],[54.912979,60.534969],[54.91325,60.538929],[54.913342,60.54007],[54.913952,60.54858],[54.916229,60.584351],[54.919479,60.633011],[54.919842,60.638851],[54.920479,60.64851],[54.921619,60.675339],[54.92107,60.67408],[54.921509,60.69199],[54.921612,60.69524],[54.921799,60.69796],[54.922371,60.70192],[54.924622,60.71656],[54.925159,60.7192],[54.927841,60.729431],[54.9282,60.730999],[54.928398,60.73328],[54.92902,60.73719],[54.930241,60.74353],[54.930801,60.745392],[54.932491,60.752548],[54.932629,60.753159],[54.936001,60.767448],[54.936451,60.769508],[54.937248,60.773232],[54.93771,60.775459],[54.938122,60.77766],[54.93803,60.779171],[54.938332,60.78286],[54.939419,60.785549],[54.940842,60.794399],[54.94128,60.7971],[54.941471,60.798279],[54.942089,60.801979],[54.942909,60.807018],[54.94331,60.809681],[54.944839,60.818668],[54.94495,60.819389],[54.945629,60.824699],[54.94928,60.852829],[54.95261,60.882751],[54.954609,60.901951],[54.954708,60.904129],[54.95509,60.906891],[54.955589,60.909828],[54.956261,60.912861],[54.9576,60.917679],[54.958611,60.921341],[54.964859,60.94379],[54.96888,60.958241],[54.969551,60.961021],[54.97187,60.971321],[54.972969,60.976131],[54.977161,60.99435],[54.98082,61.010262],[54.982491,61.017448],[54.983349,61.021061],[54.986229,61.033569],[54.987339,61.038368],[54.988258,61.042351],[54.989109,61.046051],[54.989288,61.046822],[54.989632,61.048321],[54.98996,61.0499],[54.990189,61.05109],[54.990421,61.052479],[54.99057,61.05357],[54.9907,61.054642],[54.99081,61.055851],[54.990898,61.057018],[54.991009,61.058819],[54.991089,61.060139],[54.99128,61.063751],[54.99176,61.071911],[54.992748,61.08934],[54.993912,61.10981],[54.993931,61.110161],[54.99408,61.112862],[54.994148,61.11396],[54.994549,61.121311],[54.99472,61.123779],[54.994831,61.125111],[54.994862,61.125519],[54.994999,61.126659],[54.99522,61.12833],[54.99548,61.12981],[54.995819,61.1315],[54.99609,61.132759],[54.996498,61.134472],[54.996761,61.135448],[54.997131,61.136761],[54.997581,61.138161],[54.998871,61.142101],[54.999329,61.143509],[55.000858,61.148209],[55.001511,61.150211],[55.001968,61.151829],[55.002369,61.153412],[55.00272,61.1548],[55.002941,61.155941],[55.002979,61.156281],[55.002991,61.156651],[55.002991,61.156971],[55.002911,61.15749],[55.002781,61.158169],[55.002171,61.160671],[55.001949,61.161549],[55.00172,61.162239],[55.00148,61.16283],[55.001259,61.16333],[55.0009,61.163971],[55.000141,61.165058],[54.996979,61.168869],[54.993469,61.1731],[54.992802,61.173901],[54.99239,61.174412],[54.991531,61.175449],[54.990662,61.176491],[54.9874,61.180519],[54.98365,61.185501],[54.9804,61.19133],[54.977051,61.19854],[54.974892,61.20438],[54.97282,61.211929],[54.97171,61.217461],[54.971439,61.2188],[54.97065,61.224979],[54.96986,61.23476],[54.969269,61.249008],[54.968681,61.262569],[54.96751,61.29174],[54.967461,61.29483],[54.967461,61.299309],[54.967628,61.32032],[54.967682,61.326801],[54.967682,61.329762],[54.967461,61.33461],[54.967361,61.33614],[54.967041,61.341091],[54.96685,61.345928],[54.966789,61.34951],[54.966759,61.35709],[54.96685,61.360802],[54.96703,61.365589],[54.9673,61.37249],[54.96756,61.37883],[54.9678,61.383862],[54.967819,61.384609],[54.967812,61.385429],[54.96777,61.38623],[54.967701,61.386978],[54.967602,61.387669],[54.967529,61.3881],[54.96735,61.389259],[54.967232,61.38987],[54.967041,61.391029],[54.966961,61.391479],[54.966942,61.39185],[54.966949,61.39222],[54.967018,61.39257],[54.96711,61.39283],[54.967239,61.393101],[54.9674,61.393311],[54.967579,61.39344],[54.96777,61.393509],[54.967979,61.39352],[54.968208,61.393478],[54.968811,61.39325],[54.969051,61.3932],[54.969299,61.3932],[54.969582,61.393242],[54.96981,61.393341],[54.969978,61.393471],[54.970119,61.393631],[54.97057,61.394379],[54.972691,61.39875],[54.973919,61.40144],[54.97477,61.403461],[54.9786,61.413589],[54.97929,61.415291],[54.980492,61.418209],[54.980968,61.419491],[54.9814,61.42099],[54.981701,61.422161],[54.98204,61.42374],[54.982349,61.425129],[54.98278,61.426861],[54.983089,61.42791],[54.983528,61.4291],[54.983879,61.430061],[54.984329,61.431099],[54.988491,61.440079],[54.98954,61.442242],[54.990509,61.443989],[54.991692,61.445782],[54.99292,61.44733],[54.99382,61.448318],[54.994579,61.449471],[54.99509,61.450371],[54.995461,61.451359],[54.995789,61.452339],[54.996151,61.453629],[54.996479,61.454491],[54.997021,61.455688],[54.99786,61.45694],[54.998058,61.457169],[54.99876,61.457989],[54.999859,61.459122],[55.00042,61.459549],[55.00108,61.46006],[55.001888,61.460609],[55.002708,61.461159],[55.00367,61.46183],[55.004639,61.4627],[55.005379,61.46357],[55.00602,61.46452],[55.00666,61.465801],[55.00713,61.466999],[55.007519,61.46833],[55.007858,61.46986],[55.008099,61.471519],[55.008171,61.472672],[55.00824,61.487968],[55.008251,61.4897],[55.00827,61.491631],[55.008282,61.492649],[55.008331,61.495178],[55.00843,61.496571],[55.008659,61.498852],[55.008991,61.501289],[55.009682,61.504978],[55.01041,61.507641],[55.011532,61.511021],[55.012581,61.51416],[55.013309,61.516312],[55.01548,61.522869],[55.016811,61.527439],[55.017639,61.531071],[55.018478,61.53603],[55.019588,61.543861],[55.021111,61.554241],[55.023998,61.57375],[55.024578,61.578789],[55.024818,61.582489],[55.024849,61.58744],[55.02467,61.59557],[55.02454,61.601311],[55.024609,61.60276],[55.024769,61.605431],[55.025021,61.6078],[55.025421,61.61084],[55.026749,61.619942],[55.029579,61.638821],[55.031319,61.65118],[55.034569,61.680481],[55.035259,61.688889],[55.035259,61.69593],[55.034569,61.703819],[55.03339,61.71249],[55.032059,61.723049],[55.032009,61.72665],[55.03231,61.729401],[55.032799,61.731548],[55.03344,61.733521],[55.04266,61.757488],[55.043159,61.758759],[55.04372,61.759941],[55.04438,61.761181],[55.045071,61.762299],[55.04578,61.763302],[55.04644,61.764141],[55.04697,61.764709],[55.047508,61.76524],[55.048679,61.766232],[55.0494,61.766689],[55.050129,61.76709],[55.05154,61.76767],[55.054871,61.768799],[55.06678,61.77285],[55.078411,61.77684],[55.079399,61.7771],[55.080681,61.777309],[55.08197,61.777409],[55.08297,61.77739],[55.084461,61.77729],[55.085041,61.777222],[55.08564,61.777119],[55.087132,61.77673],[55.08857,61.776218],[55.089409,61.77586],[55.09024,61.775459],[55.102551,61.768341],[55.106609,61.765961],[55.107342,61.76545],[55.11039,61.763729],[55.13361,61.750259],[55.137341,61.748631],[55.14967,61.745499],[55.15696,61.743649],[55.163601,61.742901],[55.165352,61.742981],[55.167831,61.743301],[55.170029,61.743801],[55.17173,61.744308],[55.171921,61.744381],[55.17342,61.74498],[55.175461,61.745899],[55.182289,61.74913],[55.186352,61.75108],[55.18853,61.751949],[55.190708,61.75256],[55.198181,61.75436],[55.20409,61.75584],[55.20697,61.756569],[55.208,61.756641],[55.208752,61.756569],[55.20924,61.756451],[55.210201,61.7561],[55.21088,61.75573],[55.211529,61.755268],[55.212528,61.75436],[55.213451,61.75325],[55.21397,61.75246],[55.21537,61.75016],[55.218601,61.7449],[55.221039,61.740891],[55.22345,61.736889],[55.22403,61.73605],[55.224651,61.735291],[55.224831,61.735111],[55.225269,61.734669],[55.22604,61.734032],[55.226971,61.73336],[55.228149,61.732979],[55.228642,61.733219],[55.23011,61.73447],[55.23177,61.73605],[55.232601,61.736912],[55.232922,61.737339],[55.234909,61.743431],[55.236519,61.74818],[55.237141,61.75024],[55.237549,61.751659],[55.240261,61.762218],[55.242809,61.772251],[55.245392,61.782318],[55.2486,61.79491],[55.249069,61.796661],[55.24947,61.798],[55.25161,61.804279],[55.252178,61.805759],[55.252621,61.806992],[55.2551,61.813889],[55.256981,61.819141],[55.257702,61.82119],[55.261089,61.830421],[55.264759,61.840389],[55.26614,61.843891],[55.266972,61.846279],[55.26722,61.847141],[55.267529,61.848389],[55.26783,61.85033],[55.268002,61.853001],[55.26807,61.85487],[55.268059,61.857052],[55.267948,61.858978],[55.267818,61.86047],[55.26495,61.88015],[55.263599,61.888641],[55.26321,61.891022],[55.262878,61.89325],[55.261162,61.904709],[55.260529,61.908791],[55.25972,61.914051],[55.25898,61.91872],[55.25766,61.927021],[55.247292,61.971561],[55.23119,62.039539],[55.230511,62.044521],[55.230061,62.050442],[55.230049,62.055191],[55.230019,62.066662],[55.22987,62.07954],[55.229542,62.082401],[55.229229,62.08503],[55.221161,62.120651],[55.219151,62.130779],[55.218861,62.134121],[55.218761,62.149231],[55.219051,62.221668],[55.219009,62.249611],[55.219002,62.25959],[55.218861,62.359859],[55.21719,62.386688],[55.216511,62.397709],[55.212669,62.458649],[55.212589,62.460918],[55.212551,62.462688],[55.212608,62.466721],[55.21273,62.470371],[55.21286,62.47298],[55.212978,62.474522],[55.213112,62.47604],[55.21339,62.47887],[55.21376,62.48177],[55.214149,62.484749],[55.21566,62.49527],[55.216599,62.501961],[55.219742,62.524139],[55.223789,62.552738],[55.22406,62.555309],[55.22427,62.557701],[55.22443,62.55999],[55.22456,62.56229],[55.224659,62.565819],[55.22467,62.569351],[55.22464,62.572048],[55.224529,62.574848],[55.224239,62.580269],[55.222969,62.603519],[55.222839,62.605961],[55.222801,62.60849],[55.222431,62.62851],[55.22234,62.634449],[55.222141,62.646141],[55.22184,62.6637],[55.221802,62.665722],[55.221828,62.667389],[55.22197,62.669109],[55.222191,62.67083],[55.222462,62.672588],[55.222809,62.6744],[55.22324,62.676208],[55.223721,62.67812],[55.224659,62.68137],[55.225441,62.684299],[55.226212,62.687679],[55.227039,62.691471],[55.227581,62.693821],[55.228748,62.698212],[55.230701,62.705421],[55.231861,62.709789],[55.234619,62.71941],[55.235989,62.72533],[55.236671,62.731159],[55.23682,62.736401],[55.235512,62.767021],[55.23497,62.78035],[55.234951,62.781029],[55.234859,62.783001],[55.234791,62.78511],[55.234329,62.799831],[55.234081,62.829102],[55.234001,62.852989],[55.233929,62.871929],[55.233681,62.929691],[55.233479,62.976898],[55.233459,62.986481],[55.233471,62.988838],[55.233551,62.99118],[55.235119,63.02404],[55.23579,63.037411],[55.23819,63.08873],[55.24054,63.138859],[55.24284,63.165291],[55.244209,63.180828],[55.245461,63.191582],[55.248169,63.214821],[55.253731,63.247841],[55.254421,63.251881],[55.25444,63.252239],[55.254379,63.25293],[55.254311,63.25317],[55.254292,63.253479],[55.254318,63.253819],[55.254391,63.254139],[55.254532,63.25423],[55.25478,63.254688],[55.255001,63.255291],[55.25552,63.258629],[55.25597,63.261429],[55.257401,63.269409],[55.257729,63.270859],[55.258121,63.272518],[55.25856,63.274281],[55.25898,63.27586],[55.259392,63.277309],[55.26033,63.280411],[55.261299,63.28331],[55.26223,63.28582],[55.26289,63.28751],[55.263641,63.28928],[55.26524,63.29282],[55.269779,63.30257],[55.272469,63.308239],[55.289742,63.344082],[55.312511,63.391201],[55.334339,63.437031],[55.33736,63.445621],[55.339611,63.453171],[55.352982,63.506691],[55.361198,63.53952],[55.361931,63.543209],[55.36245,63.547668],[55.36264,63.551231],[55.362099,63.560669],[55.35981,63.590931],[55.357052,63.626511],[55.354858,63.6544],[55.354111,63.664101],[55.352779,63.681179],[55.35252,63.687321],[55.352711,63.724781],[55.352829,63.747829],[55.352982,63.775299],[55.354881,63.7995],[55.35918,63.850399],[55.360851,63.8708],[55.360981,63.872459],[55.361229,63.880951],[55.361519,63.89983],[55.36158,63.900051],[55.361858,63.91151],[55.362202,63.918461],[55.363369,63.92704],[55.36974,63.973782],[55.375999,64.019569],[55.379372,64.044548],[55.379829,64.049911],[55.379879,64.055313],[55.379761,64.058708],[55.379318,64.063507],[55.376541,64.081451],[55.37191,64.109947],[55.37093,64.116043],[55.37001,64.123421],[55.369659,64.128487],[55.369469,64.134583],[55.36961,64.140419],[55.371361,64.170288],[55.37162,64.175087],[55.37418,64.221138],[55.37513,64.237747],[55.37561,64.253632],[55.376541,64.287361],[55.377541,64.322197],[55.377998,64.327454],[55.378731,64.333282],[55.38308,64.359459],[55.387169,64.384857],[55.38763,64.388939],[55.389191,64.41568],[55.38924,64.416542],[55.390659,64.441994],[55.391781,64.46209],[55.392021,64.466301],[55.392231,64.469879],[55.394241,64.505539],[55.395802,64.532097],[55.397911,64.568993],[55.399921,64.603783],[55.401649,64.634758],[55.40313,64.661453],[55.404289,64.682663],[55.404331,64.683434],[55.40469,64.686127],[55.407791,64.702011],[55.415829,64.744667],[55.417759,64.754837],[55.420971,64.771858],[55.42157,64.775002],[55.424469,64.790497],[55.427631,64.807411],[55.428741,64.813278],[55.429642,64.818176],[55.430649,64.823486],[55.43095,64.825287],[55.431149,64.826813],[55.431431,64.829514],[55.431728,64.833153],[55.43198,64.836067],[55.432388,64.840958],[55.432781,64.845383],[55.433781,64.857193],[55.4375,64.902077],[55.441929,64.950661],[55.446789,65.001953],[55.44928,65.028252],[55.45269,65.089447],[55.453121,65.094482],[55.453541,65.098083],[55.453979,65.100883],[55.454521,65.103813],[55.45499,65.105957],[55.455479,65.108009],[55.4561,65.110352],[55.45676,65.112663],[55.45739,65.114647],[55.458172,65.116867],[55.464298,65.13385],[55.472229,65.155891],[55.474258,65.161232],[55.475731,65.165649],[55.476761,65.168533],[55.477951,65.172058],[55.478729,65.174263],[55.47884,65.174583],[55.479229,65.175957],[55.480709,65.180946],[55.481098,65.182266],[55.48172,65.184776],[55.483768,65.191566],[55.484459,65.194237],[55.486099,65.199707],[55.486172,65.199951],[55.486328,65.200493],[55.48645,65.200882],[55.48711,65.20311],[55.489799,65.212097],[55.493038,65.223244],[55.493221,65.223869],[55.493568,65.225082],[55.496841,65.23587],[55.501091,65.24958],[55.50132,65.250618],[55.501362,65.25132],[55.50132,65.251556],[55.50132,65.251862],[55.501381,65.252136],[55.501492,65.252357],[55.501572,65.252441],[55.501701,65.252533],[55.502048,65.253029],[55.50243,65.253777],[55.508209,65.272163],[55.51358,65.289261],[55.513599,65.289337],[55.51458,65.292801],[55.51572,65.29776],[55.51659,65.303421],[55.516941,65.308128],[55.516979,65.31089],[55.51701,65.312027],[55.516911,65.316544],[55.516769,65.31958],[55.516659,65.320442],[55.515739,65.328087],[55.51572,65.328232],[55.51038,65.346527],[55.506351,65.360077],[55.504719,65.36557],[55.503799,65.368629],[55.503262,65.370483],[55.501572,65.376152],[55.500092,65.381126],[55.499531,65.383018],[55.49836,65.386993],[55.497669,65.388397],[55.49757,65.388428],[55.497429,65.38855],[55.497341,65.388687],[55.497269,65.388947],[55.497261,65.389183],[55.49728,65.38942],[55.497318,65.389572],[55.49707,65.390923],[55.495461,65.395638],[55.494221,65.3992],[55.493561,65.401131],[55.493019,65.403038],[55.492779,65.404213],[55.492599,65.40538],[55.492359,65.407806],[55.492359,65.409523],[55.492439,65.411186],[55.492779,65.41362],[55.493252,65.415863],[55.49398,65.4179],[55.49477,65.419724],[55.496449,65.422722],[55.497082,65.424553],[55.49754,65.426537],[55.4977,65.428101],[55.497669,65.429817],[55.497311,65.432121],[55.496719,65.434174],[55.495869,65.435898],[55.495258,65.436653],[55.494282,65.437592],[55.493229,65.438118],[55.4921,65.438217],[55.491268,65.438026],[55.4902,65.437492],[55.489349,65.436729],[55.488659,65.43602],[55.488022,65.435287],[55.487789,65.435051],[55.487331,65.434776],[55.487068,65.434753],[55.48687,65.434776],[55.486629,65.434929],[55.480099,65.443237],[55.477669,65.447357],[55.474899,65.455009],[55.473259,65.459709],[55.468029,65.474663],[55.467461,65.476288],[55.459759,65.498352],[55.4585,65.503067],[55.45787,65.507019],[55.457432,65.512604],[55.455971,65.537918],[55.454269,65.564079],[55.453831,65.573692],[55.453732,65.576553],[55.45319,65.580566],[55.452759,65.583],[55.44976,65.59417],[55.445061,65.611649],[55.44495,65.612061],[55.429741,65.669823],[55.419739,65.707779],[55.394691,65.801437],[55.39352,65.805794],[55.38797,65.828491],[55.387482,65.830513],[55.386089,65.838669],[55.383629,65.853172],[55.382309,65.861343],[55.38002,65.87558],[55.37661,65.896263],[55.374458,65.911629],[55.3708,65.938843],[55.370121,65.945618],[55.369831,65.951973],[55.369781,65.961411],[55.370701,65.972397],[55.377041,66.022263],[55.382309,66.062943],[55.38818,66.089546],[55.389969,66.097618],[55.39669,66.128433],[55.397812,66.136932],[55.40147,66.178818],[55.4062,66.234261],[55.40659,66.248772],[55.40567,66.270103],[55.405609,66.271431],[55.404301,66.3013],[55.402439,66.343353],[55.39996,66.401802],[55.39893,66.433823],[55.39645,66.473557],[55.395969,66.481934],[55.39489,66.500603],[55.391869,66.54969],[55.38982,66.584198],[55.388779,66.599937],[55.38855,66.60041],[55.388321,66.601143],[55.388229,66.601692],[55.388309,66.602173],[55.388512,66.602852],[55.388649,66.603073],[55.388489,66.605331],[55.38826,66.609299],[55.387779,66.616966],[55.387039,66.629768],[55.384701,66.669167],[55.381729,66.717056],[55.381451,66.721474],[55.381241,66.724518],[55.380951,66.727364],[55.38055,66.73053],[55.380138,66.733421],[55.3797,66.73613],[55.379211,66.738777],[55.37851,66.742157],[55.377899,66.744591],[55.376991,66.747993],[55.370651,66.769859],[55.368019,66.778954],[55.360748,66.804863],[55.35627,66.820229],[55.355,66.824783],[55.352791,66.831543],[55.351139,66.835831],[55.34845,66.841583],[55.337379,66.865288],[55.324001,66.894043],[55.310959,66.922279],[55.307251,66.931549],[55.30529,66.939789],[55.303539,66.951118],[55.29982,66.992661],[55.29871,67.004959],[55.29689,67.025284],[55.292389,67.079521],[55.290241,67.089478],[55.28183,67.117592],[55.269909,67.157463],[55.266579,67.169472],[55.25782,67.219833],[55.25647,67.225433],[55.24807,67.253098],[55.244831,67.263847],[55.24469,67.263779],[55.244511,67.263779],[55.244339,67.263893],[55.244202,67.264091],[55.24411,67.264374],[55.24408,67.264687],[55.244122,67.264992],[55.244209,67.265259],[55.24435,67.265457],[55.240101,67.278992],[55.227638,67.317841],[55.214691,67.355843],[55.211689,67.365967],[55.204689,67.397057],[55.196541,67.432419],[55.195518,67.436813],[55.18961,67.463318],[55.188999,67.476341],[55.187962,67.50354],[55.188782,67.511383],[55.192871,67.533623],[55.194649,67.546417],[55.194962,67.553429],[55.19413,67.565613],[55.192741,67.580162],[55.192039,67.602631],[55.191132,67.621902],[55.189522,67.629898],[55.178429,67.668518],[55.174301,67.684967],[55.172569,67.693893],[55.164768,67.734177],[55.163471,67.737984],[55.149719,67.768517],[55.131649,67.807831],[55.12394,67.824364],[55.10191,67.865738],[55.09697,67.875008],[55.094269,67.883163],[55.092571,67.894051],[55.092621,67.918877],[55.092621,67.924637],[55.092609,67.925743],[55.092831,67.976692],[55.093311,67.983856],[55.097321,68.026131],[55.099781,68.05143],[55.104031,68.095139],[55.104511,68.104431],[55.10429,68.114708],[55.103031,68.132607],[55.099152,68.18882],[55.096649,68.203423],[55.092152,68.227898],[55.09082,68.240196],[55.091709,68.253601],[55.0938,68.267563],[55.094559,68.277641],[55.093231,68.286392],[55.087719,68.30201],[55.079151,68.324707],[55.068371,68.35363],[55.054989,68.390182],[55.046741,68.41256],[55.027309,68.466507],[55.014111,68.500633],[54.9939,68.554237],[54.99123,68.560219],[54.98875,68.562553],[54.973499,68.573959],[54.95079,68.59079],[54.924641,68.610069],[54.92448,68.610443],[54.924301,68.611618],[54.923611,68.616402],[54.923111,68.61998],[54.922451,68.624489],[54.92197,68.627922],[54.9212,68.633369],[54.920101,68.640846],[54.919559,68.644333],[54.91917,68.648529],[54.919128,68.653183],[54.919319,68.663483],[54.919361,68.672462],[54.919449,68.681358],[54.91954,68.690643],[54.919628,68.698692],[54.91967,68.706421],[54.919788,68.71479],[54.9198,68.718513],[54.919849,68.724922],[54.919941,68.735184],[54.92001,68.746468],[54.92009,68.758133],[54.920219,68.774109],[54.920429,68.799072],[54.920792,68.843628],[54.920818,68.854874],[54.919331,68.878441],[54.917,68.91478],[54.91502,68.944328],[54.912788,68.978416],[54.910358,69.015228],[54.909859,69.021294],[54.90905,69.034103],[54.908852,69.037292],[54.908489,69.042999],[54.90765,69.055283],[54.90731,69.05954],[54.90712,69.062553],[54.906719,69.065102],[54.906189,69.067772],[54.90509,69.07119],[54.905769,69.073486],[54.905869,69.073723],[54.907501,69.07753],[54.910469,69.085258],[54.911518,69.088371],[54.912521,69.091713],[54.913689,69.094673],[54.914989,69.097481],[54.91534,69.099037],[54.915409,69.100037],[54.915379,69.10125],[54.91354,69.114662],[54.91309,69.117012],[54.912762,69.118294],[54.912628,69.118797],[54.91246,69.119926],[54.912411,69.121162],[54.91267,69.125023],[54.912819,69.127327],[54.912109,69.127617],[54.911671,69.127953],[54.911308,69.128349],[54.911041,69.12896],[54.910751,69.129601],[54.910431,69.130463],[54.910229,69.131439],[54.910198,69.131683],[54.910179,69.131866],[54.910172,69.132111],[54.91016,69.132294],[54.910141,69.132477],[54.910141,69.132881],[54.91016,69.133003],[54.910221,69.133171],[54.9104,69.133217],[54.91058,69.133087],[54.91066,69.132919],[54.910721,69.132637],[54.910801,69.132362],[54.910881,69.132042],[54.910961,69.131866],[54.91153,69.131157],[54.91222,69.130302],[54.912338,69.13015],[54.912861,69.129601],[54.914219,69.128349],[54.915661,69.127457],[54.91748,69.12674],[54.919159,69.126549],[54.92194,69.126427],[54.92292,69.126663],[54.92358,69.12719],[54.924122,69.127861],[54.924679,69.128799],[54.92506,69.129837],[54.926399,69.13607],[54.926281,69.136269],[54.926189,69.136574],[54.926231,69.136848],[54.9263,69.137016],[54.926411,69.137169],[54.926559,69.137253],[54.926628,69.137207],[54.926579,69.137527],[54.924191,69.148048],[54.91798,69.17437],[54.917919,69.174316],[54.917728,69.174271],[54.917542,69.174347],[54.917469,69.174622],[54.91748,69.175148],[54.917549,69.175613],[54.917622,69.175697],[54.91769,69.175789],[54.917992,69.175819],[54.918091,69.175751],[54.91811,69.175591],[54.918251,69.176224],[54.93475,69.219063],[54.93576,69.220993],[54.937019,69.222343],[54.93795,69.222893],[54.945759,69.225929],[54.946678,69.226593],[54.94788,69.228241],[54.948399,69.229248],[54.954651,69.248573],[54.95512,69.250549],[54.955231,69.253548],[54.95219,69.281349],[54.951382,69.285461],[54.914391,69.430771],[54.913651,69.435097],[54.913269,69.439484],[54.913391,69.454674],[54.913952,69.525223],[54.914669,69.599983],[54.914902,69.623459],[54.91605,69.798088],[54.909809,69.909576],[54.90976,69.912453],[54.91502,70.140343],[54.915451,70.190514],[54.917278,70.354233],[54.918461,70.369408],[54.918449,70.374023],[54.918018,70.381271],[54.919399,70.435493],[54.92009,70.462624],[54.919998,70.466408],[54.91975,70.469276],[54.91795,70.480713],[54.91774,70.483856],[54.91927,70.528839],[54.930779,70.631973],[54.940411,70.762863],[54.94083,70.776108],[54.940651,70.779343],[54.93998,70.7827],[54.939251,70.784447],[54.937462,70.787086],[54.921299,70.801826],[54.91959,70.80442],[54.91851,70.807426],[54.91806,70.810226],[54.91798,70.81279],[54.919258,70.882713],[54.921379,70.984528],[54.921398,70.985802],[54.921959,71.016243],[54.92207,71.022346],[54.922741,71.059174],[54.923,71.080643],[54.921589,71.136688],[54.921612,71.140411],[54.922001,71.146027],[54.923069,71.153809],[54.923981,71.157944],[54.92514,71.161377],[54.925671,71.162971],[54.927711,71.167511],[54.929909,71.171478],[54.931171,71.174133],[54.93224,71.176979],[54.937721,71.19474],[54.947842,71.227577],[54.949181,71.232407],[54.950802,71.239929],[54.951969,71.247871],[54.952911,71.25663],[54.955811,71.283669],[54.95607,71.286148],[54.956211,71.287483],[54.973251,71.448219],[54.97401,71.453117],[54.974918,71.457787],[54.976719,71.465149],[54.978142,71.469757],[54.9804,71.476341],[54.981201,71.479446],[54.98233,71.483841],[54.98402,71.492989],[54.99025,71.540962],[54.990749,71.546097],[54.991131,71.555542],[54.987789,71.697289],[54.983429,71.778908],[54.983311,71.78492],[54.983589,71.79248],[54.99284,71.913406],[54.9963,71.958504],[54.996449,71.962212],[54.996399,71.966888],[54.996078,71.97171],[54.978851,72.105797],[54.978149,72.112457],[54.977421,72.122673],[54.972771,72.248459],[54.9659,72.335892],[54.965721,72.33828],[54.965549,72.341904],[54.965488,72.345627],[54.965611,72.34996],[54.96624,72.372711],[54.96669,72.391632],[54.966759,72.395111],[54.966591,72.398827],[54.966301,72.403053],[54.964802,72.419296],[54.963531,72.434708],[54.963501,72.436478],[54.963921,72.454826],[54.964569,72.483093],[54.966141,72.539192],[54.9664,72.543533],[54.96698,72.54879],[54.967319,72.551041],[54.96767,72.552994],[54.968491,72.557251],[54.984421,72.617264],[54.985882,72.625191],[54.98658,72.631699],[54.986809,72.635223],[54.990509,72.690758],[54.990501,72.820793],[54.990311,72.82589],[54.9897,72.831818],[54.98793,72.842369],[54.987728,72.843071],[54.985649,72.850288],[54.976269,72.875366],[54.97007,72.891907],[54.96825,72.896843],[54.96804,72.897087],[54.96788,72.897186],[54.96653,72.897278],[54.965801,72.897331],[54.961491,72.897469],[54.958618,72.897636],[54.956902,72.898079],[54.950729,72.900253],[54.940731,72.903793],[54.935379,72.905693],[54.930721,72.907242],[54.928219,72.908211],[54.92672,72.909103],[54.924301,72.911133],[54.922729,72.912666],[54.913921,72.925461],[54.913521,72.926041],[54.906811,72.935799],[54.904121,72.940048],[54.9016,72.944641],[54.895439,72.955879],[54.887291,72.970757],[54.885941,72.974823],[54.88472,72.978493],[54.883831,72.983292],[54.883438,72.987579],[54.883591,72.994751],[54.883598,72.995728],[54.883911,73.017487],[54.883961,73.024017],[54.88361,73.030411],[54.883308,73.033073],[54.88126,73.045387],[54.877781,73.066292],[54.875408,73.080193],[54.87376,73.090279],[54.87175,73.102318],[54.86882,73.119629],[54.866821,73.131432],[54.866501,73.133957],[54.866371,73.135094],[54.866341,73.135803],[54.866371,73.136703],[54.866741,73.139847],[54.86747,73.146378],[54.867661,73.148499],[54.86784,73.151398],[54.86797,73.156677],[54.867882,73.173286],[54.867519,73.213791],[54.86726,73.237701],[54.867352,73.241989],[54.869431,73.262611],[54.869598,73.264427],[54.869781,73.266312],[54.86998,73.268311],[54.870171,73.270348],[54.870232,73.27092],[54.870258,73.271248],[54.87048,73.273521],[54.870739,73.276932],[54.870739,73.277641],[54.870708,73.278999],[54.87059,73.280632],[54.87038,73.282341],[54.869789,73.285683],[54.86961,73.286743],[54.869431,73.287987],[54.86932,73.288872],[54.86924,73.289886],[54.86916,73.2911],[54.86916,73.292717],[54.869209,73.295464],[54.869141,73.296242],[54.869061,73.296532],[54.868969,73.296753],[54.868969,73.296951],[54.869011,73.29718],[54.869148,73.297836],[54.869148,73.299477],[54.869221,73.300499],[54.869221,73.30645],[54.869251,73.316261],[54.86927,73.321907],[54.869289,73.322884],[54.869301,73.323563],[54.86935,73.324303],[54.869438,73.325089],[54.86953,73.325798],[54.86969,73.326767],[54.869949,73.328011],[54.870258,73.329247],[54.87059,73.330307],[54.87093,73.331169],[54.87138,73.332222],[54.872211,73.33371],[54.873138,73.335159],[54.874279,73.336884],[54.875111,73.338219],[54.875809,73.339592],[54.87616,73.340462],[54.876678,73.342049],[54.87764,73.345131],[54.877991,73.346313],[54.878899,73.349327],[54.880051,73.353203],[54.879929,73.353333],[54.879822,73.353561],[54.879768,73.353767],[54.879749,73.353928],[54.879749,73.354073],[54.879768,73.354309],[54.879829,73.354507],[54.879959,73.354736],[54.880119,73.354889],[54.88031,73.354919],[54.880482,73.354843],[54.880611,73.355293],[54.88126,73.357567],[54.88139,73.358124],[54.881481,73.358727],[54.881741,73.36132],[54.881889,73.363533],[54.88192,73.365334],[54.881729,73.371681],[54.881451,73.379997],[54.881481,73.382294],[54.881592,73.384979],[54.881802,73.388153],[54.88195,73.389641],[54.882149,73.391228],[54.882778,73.395287],[54.883202,73.397476],[54.883801,73.400017],[54.884659,73.403008],[54.887199,73.410408],[54.887531,73.411636],[54.887829,73.412773],[54.887951,73.413879],[54.88802,73.414963],[54.888062,73.420387],[54.888081,73.420929],[54.888142,73.421219],[54.88821,73.421471],[54.88829,73.421638],[54.88842,73.421829],[54.888569,73.421951],[54.888809,73.422203],[54.889042,73.422394],[54.888618,73.423233],[54.88821,73.424088],[54.88789,73.424751],[54.887329,73.425941],[54.88715,73.426353],[54.88644,73.427856],[54.884941,73.431084],[54.882381,73.436417],[54.880909,73.439507],[54.880482,73.440399],[54.868172,73.466171],[54.86668,73.469353],[54.866322,73.470123],[54.866039,73.47081],[54.865761,73.471573],[54.86517,73.473412],[54.85984,73.490753],[54.85368,73.510521],[54.85284,73.512589],[54.8466,73.526047],[54.83498,73.548721],[54.83453,73.549553],[54.834049,73.550377],[54.833618,73.55098],[54.83321,73.551537],[54.832729,73.552147],[54.830601,73.55468],[54.827888,73.557899],[54.822762,73.564011],[54.820751,73.566383],[54.819462,73.567703],[54.817711,73.569542],[54.814739,73.572647],[54.81332,73.574203],[54.811901,73.57592],[54.808929,73.579613],[54.80759,73.581291],[54.80563,73.583649],[54.804951,73.584381],[54.802879,73.586372],[54.801941,73.587173],[54.800018,73.588654],[54.797569,73.590477],[54.792831,73.594032],[54.790249,73.595993],[54.785229,73.599648],[54.783138,73.601173],[54.7789,73.604309],[54.777069,73.605827],[54.775532,73.607147],[54.773121,73.609169],[54.770748,73.611153],[54.769341,73.612419],[54.768372,73.613197],[54.767658,73.613731],[54.766941,73.614067],[54.765961,73.614388],[54.765011,73.614693],[54.762569,73.615463],[54.761711,73.615753],[54.756569,73.617012],[54.754822,73.617607],[54.75317,73.61837],[54.75164,73.61927],[54.74894,73.621391],[54.745152,73.625214],[54.74316,73.62812],[54.741089,73.63163],[54.73513,73.641647],[54.730511,73.64946],[54.728809,73.652367],[54.721882,73.664207],[54.718559,73.669907],[54.71759,73.671562],[54.71666,73.673203],[54.715672,73.674896],[54.71521,73.67569],[54.71471,73.676537],[54.714008,73.677742],[54.713322,73.678917],[54.712662,73.680054],[54.712009,73.68116],[54.71133,73.68232],[54.710011,73.684593],[54.709129,73.686089],[54.708408,73.687332],[54.70797,73.688103],[54.706661,73.690353],[54.705219,73.692848],[54.704529,73.694031],[54.70319,73.69635],[54.697128,73.706757],[54.689751,73.717232],[54.689121,73.718262],[54.688412,73.719704],[54.685791,73.725609],[54.682621,73.732887],[54.681629,73.735649],[54.678638,73.74453],[54.676231,73.752121],[54.675499,73.754539],[54.67506,73.756592],[54.67461,73.759506],[54.669811,73.787872],[54.669552,73.789726],[54.66946,73.790932],[54.66943,73.793213],[54.669441,73.796127],[54.669491,73.80822],[54.669498,73.813004],[54.66938,73.815773],[54.669189,73.818489],[54.66906,73.819817],[54.66888,73.821373],[54.66692,73.835472],[54.664951,73.849541],[54.66441,73.853378],[54.664131,73.856163],[54.66404,73.859467],[54.664108,73.868423],[54.664131,73.870811],[54.664131,73.872337],[54.664139,73.874138],[54.664139,73.875427],[54.664082,73.876633],[54.66396,73.877777],[54.66383,73.878563],[54.663601,73.879478],[54.661869,73.884644],[54.661739,73.884933],[54.661201,73.886253],[54.66032,73.887688],[54.658298,73.890327],[54.657089,73.891907],[54.653198,73.896843],[54.65168,73.8992],[54.650318,73.901703],[54.648449,73.905403],[54.64526,73.911743],[54.637871,73.926323],[54.63044,73.941048],[54.626869,73.948608],[54.625771,73.951218],[54.624969,73.953522],[54.624229,73.956398],[54.623772,73.958412],[54.623428,73.960419],[54.623169,73.962578],[54.622849,73.966873],[54.621651,73.982079],[54.621319,73.984642],[54.62075,73.987991],[54.619888,73.991478],[54.61832,73.99633],[54.6152,74.003807],[54.614269,74.005737],[54.613159,74.007507],[54.61132,74.009789],[54.610828,74.010269],[54.609489,74.011414],[54.607498,74.012581],[54.604549,74.013771],[54.60173,74.014954],[54.5989,74.016251],[54.597881,74.01693],[54.597019,74.017609],[54.595379,74.019257],[54.59425,74.020737],[54.59322,74.022461],[54.59129,74.02655],[54.588409,74.032707],[54.587582,74.034554],[54.587109,74.035896],[54.586449,74.038002],[54.56488,74.108017],[54.564659,74.109169],[54.564449,74.110786],[54.564301,74.112923],[54.56377,74.130463],[54.563648,74.134773],[54.563492,74.136871],[54.563049,74.14006],[54.561069,74.153923],[54.560181,74.160744],[54.560211,74.16169],[54.560322,74.162651],[54.560509,74.163544],[54.567749,74.19046],[54.56805,74.191902],[54.568218,74.193542],[54.568199,74.194687],[54.567101,74.211533],[54.566978,74.212936],[54.5667,74.214546],[54.566319,74.215927],[54.562851,74.228378],[54.559299,74.240852],[54.552349,74.265221],[54.548969,74.276917],[54.54813,74.279793],[54.547531,74.281807],[54.546871,74.283401],[54.546299,74.28463],[54.545761,74.285744],[54.544842,74.287163],[54.54385,74.288544],[54.541809,74.290909],[54.538528,74.294937],[54.536869,74.297394],[54.536251,74.298447],[54.508018,74.353081],[54.506748,74.355583],[54.505489,74.358482],[54.504688,74.360657],[54.501949,74.369324],[54.496738,74.385857],[54.495602,74.389122],[54.494999,74.39032],[54.493629,74.392097],[54.493038,74.392776],[54.492298,74.393509],[54.491581,74.394119],[54.490971,74.394417],[54.49036,74.394653],[54.482731,74.396332],[54.481281,74.396652],[54.47961,74.397217],[54.47773,74.398064],[54.47562,74.399193],[54.474232,74.400238],[54.472851,74.401466],[54.471191,74.403214],[54.465809,74.409119],[54.45887,74.417],[54.445148,74.432838],[54.443569,74.434883],[54.44215,74.43718],[54.438179,74.444542],[54.43362,74.453758],[54.431332,74.458389],[54.429119,74.462929],[54.428329,74.464737],[54.42783,74.46611],[54.427052,74.468918],[54.413139,74.523643],[54.408821,74.545128],[54.4081,74.548126],[54.407089,74.55146],[54.405781,74.555069],[54.404621,74.557716],[54.40308,74.560806],[54.397282,74.571693],[54.395721,74.574806],[54.394821,74.577019],[54.393589,74.580391],[54.390739,74.589546],[54.386841,74.602287],[54.384472,74.608887],[54.381611,74.616341],[54.380341,74.619423],[54.378719,74.622581],[54.377731,74.624138],[54.373112,74.630463],[54.372139,74.631493],[54.370991,74.632347],[54.368649,74.633347],[54.364368,74.634827],[54.361431,74.635269],[54.357738,74.635162],[54.354401,74.635063],[54.350929,74.635101],[54.35017,74.635292],[54.34927,74.635674],[54.347839,74.636597],[54.346142,74.638138],[54.343109,74.641037],[54.340832,74.643372],[54.338032,74.646744],[54.332062,74.654007],[54.330589,74.655312],[54.329369,74.655983],[54.32576,74.657303],[54.32243,74.658546],[54.31868,74.659607],[54.29874,74.664368],[54.28014,74.66861],[54.278061,74.669518],[54.277,74.670227],[54.27573,74.671837],[54.27396,74.674751],[54.270531,74.681053],[54.266659,74.687439],[54.265072,74.68988],[54.26413,74.69091],[54.263069,74.69165],[54.26123,74.69252],[54.258911,74.692818],[54.256908,74.692574],[54.252628,74.692329],[54.243259,74.69162],[54.242008,74.691994],[54.24091,74.692574],[54.23978,74.693321],[54.23801,74.695251],[54.232651,74.700867],[54.230331,74.703293],[54.228249,74.705643],[54.226002,74.708588],[54.217861,74.718651],[54.209229,74.729713],[54.208382,74.731133],[54.205688,74.735611],[54.204262,74.737709],[54.20097,74.741524],[54.1954,74.747887],[54.190639,74.753242],[54.1852,74.759453],[54.17564,74.770332],[54.17469,74.771637],[54.173908,74.773117],[54.173279,74.774544],[54.172661,74.776466],[54.17202,74.77993],[54.17197,74.781616],[54.171879,74.783997],[54.17141,74.797913],[54.1712,74.802879],[54.170959,74.805511],[54.170601,74.80851],[54.170292,74.810463],[54.169842,74.812538],[54.16922,74.815399],[54.16898,74.816101],[54.168621,74.817009],[54.168159,74.818069],[54.167782,74.81871],[54.167339,74.819366],[54.166931,74.819893],[54.166618,74.820236],[54.16618,74.820663],[54.164379,74.822258],[54.163761,74.8228],[54.16143,74.824837],[54.157959,74.828072],[54.15588,74.830551],[54.15414,74.833023],[54.14859,74.841667],[54.145859,74.846199],[54.143539,74.850693],[54.126171,74.884651],[54.124008,74.888924],[54.12291,74.891113],[54.121391,74.893867],[54.119881,74.896347],[54.118961,74.897758],[54.11771,74.89959],[54.114922,74.90313],[54.112419,74.906281],[54.107731,74.912079],[54.095638,74.927193],[54.082512,74.94352],[54.079971,74.946693],[54.07436,74.953697],[54.071671,74.957077],[54.07008,74.958763],[54.06942,74.959419],[54.06868,74.960037],[54.06826,74.960327],[54.0672,74.961037],[54.06625,74.96151],[54.065159,74.961899],[54.06414,74.962181],[54.06308,74.96244],[54.062809,74.962463],[54.06152,74.962547],[54.052841,74.96302],[54.042881,74.963631],[54.03878,74.963852],[54.036629,74.963966],[54.034752,74.964188],[54.032211,74.964867],[54.029732,74.965874],[54.029461,74.966057],[54.02747,74.967407],[54.025749,74.96875],[54.018269,74.976044],[54.003441,74.990593],[53.999821,74.994102],[53.99894,74.995117],[53.998291,74.99604],[53.997601,74.997261],[53.996941,74.998703],[53.984928,75.026604],[53.981758,75.034012],[53.978291,75.04216],[53.970989,75.059402],[53.969181,75.063629],[53.966042,75.071037],[53.96199,75.080719],[53.961559,75.081619],[53.961201,75.082138],[53.96077,75.082573],[53.9603,75.082916],[53.959782,75.083122],[53.958988,75.083282],[53.952808,75.083763],[53.9506,75.083946],[53.93763,75.085129],[53.922729,75.086388],[53.92065,75.086517],[53.919949,75.086433],[53.91959,75.086357],[53.919189,75.08625],[53.918758,75.086113],[53.917461,75.085457],[53.91608,75.084793],[53.89254,75.073143],[53.886509,75.070107],[53.885971,75.069847],[53.885059,75.069397],[53.85207,75.053047],[53.845581,75.049728],[53.84314,75.048271],[53.841831,75.047333],[53.84074,75.046448],[53.840061,75.04612],[53.83939,75.045952],[53.834179,75.045486],[53.827469,75.045013],[53.822979,75.044693],[53.816269,75.044777],[53.814781,75.044838],[53.81382,75.044991],[53.809139,75.046387],[53.80328,75.048576],[53.797321,75.051277],[53.79525,75.052208],[53.790722,75.054222],[53.789162,75.054916],[53.788269,75.055367],[53.78756,75.055847],[53.786701,75.056519],[53.78455,75.058311],[53.778759,75.063278],[53.770481,75.070412],[53.757198,75.081909],[53.743389,75.093674],[53.73756,75.098572],[53.73172,75.103493],[53.720261,75.113182],[53.71302,75.11937],[53.707291,75.124252],[53.701962,75.128807],[53.69809,75.131989],[53.696869,75.132973],[53.69524,75.133926],[53.694248,75.134338],[53.69186,75.135223],[53.68578,75.13723],[53.677029,75.140228],[53.668419,75.143494],[53.659451,75.147034],[53.655479,75.148529],[53.653591,75.149269],[53.652241,75.150063],[53.65065,75.151268],[53.649139,75.152771],[53.64782,75.154587],[53.64653,75.156967],[53.645119,75.159668],[53.64109,75.167503],[53.617321,75.213669],[53.616631,75.214951],[53.615372,75.21682],[53.614319,75.218132],[53.61301,75.219513],[53.609341,75.223221],[53.604671,75.22805],[53.600021,75.232803],[53.596169,75.236603],[53.593948,75.239014],[53.59288,75.240448],[53.591839,75.242027],[53.58976,75.245743],[53.581951,75.260193],[53.58073,75.262482],[53.579708,75.264648],[53.57502,75.274643],[53.563271,75.299721],[53.562321,75.301727],[53.56139,75.303436],[53.56044,75.304993],[53.559071,75.306717],[53.55759,75.308319],[53.555511,75.310303],[53.553242,75.312363],[53.541851,75.323303],[53.537479,75.327553],[53.536171,75.32901],[53.53511,75.330566],[53.534489,75.331772],[53.534012,75.33287],[53.53347,75.334244],[53.53289,75.33622],[53.53075,75.345459],[53.528622,75.355003],[53.528259,75.356331],[53.52763,75.357857],[53.526871,75.359642],[53.519531,75.37545],[53.511829,75.391869],[53.507961,75.400261],[53.50388,75.409187],[53.496349,75.425369],[53.49411,75.429611],[53.487141,75.440918],[53.481949,75.449371],[53.480419,75.451622],[53.47884,75.453377],[53.477699,75.454468],[53.471352,75.459686],[53.45953,75.469933],[53.45129,75.47657],[53.4426,75.484047],[53.423809,75.499657],[53.405899,75.514816],[53.403011,75.517319],[53.400982,75.519676],[53.39257,75.529907],[53.379131,75.546082],[53.376369,75.549454],[53.373638,75.552551],[53.368839,75.557251],[53.361271,75.564484],[53.354622,75.57151],[53.346741,75.579842],[53.33374,75.593536],[53.332199,75.59507],[53.33054,75.596237],[53.32309,75.600822],[53.313171,75.60701],[53.303429,75.614983],[53.292061,75.625847],[53.28054,75.636963],[53.274841,75.642403],[53.269409,75.647438],[53.257622,75.658234],[53.25679,75.659019],[53.256062,75.659882],[53.25528,75.661018],[53.236881,75.692253],[53.224159,75.71373],[53.210369,75.737007],[53.184189,75.781197],[53.1828,75.783539],[53.18124,75.786362],[53.179989,75.7892],[53.178551,75.792747],[53.144051,75.880463],[53.13903,75.893288],[53.137718,75.896294],[53.121521,75.928673],[53.104469,75.962639],[53.103729,75.964798],[53.103119,75.967133],[53.098629,75.986427],[53.093159,76.010643],[53.08239,76.056717],[53.080021,76.06707],[53.079861,76.068283],[53.079788,76.06926],[53.079781,76.070702],[53.080002,76.072983],[53.083778,76.089394],[53.084011,76.092072],[53.083801,76.095413],[53.083351,76.098213],[53.081211,76.11013],[53.08083,76.112244],[53.079491,76.12011],[53.07848,76.123863],[53.077518,76.126373],[53.07658,76.128304],[53.075481,76.130173],[53.074551,76.131371],[53.073181,76.132782],[53.066799,76.138641],[53.060459,76.144562],[53.059891,76.145302],[53.058708,76.147507],[53.057671,76.150543],[53.046391,76.198189],[53.033669,76.251053],[53.03017,76.261673],[53.023602,76.281303],[53.01313,76.312683],[53.0103,76.321152],[52.99239,76.374603],[52.99131,76.377548],[52.988701,76.383408],[52.975609,76.412643],[52.959789,76.447762],[52.92849,76.517548],[52.927078,76.520401],[52.92522,76.523666],[52.923599,76.526367],[52.920731,76.531143],[52.912281,76.545067],[52.895981,76.571693],[52.894341,76.573639],[52.892899,76.575043],[52.89151,76.576134],[52.889301,76.577538],[52.879879,76.583122],[52.865108,76.59198],[52.838959,76.607697],[52.810711,76.624588],[52.79121,76.636238],[52.78701,76.638847],[52.78595,76.63945],[52.784939,76.640167],[52.736191,76.680183],[52.68597,76.721161],[52.684212,76.722443],[52.672199,76.730026],[52.656841,76.739647],[52.62907,76.757202],[52.618359,76.763992],[52.605968,76.771767],[52.58215,76.78669],[52.5345,76.816727],[52.52211,76.821098],[52.50993,76.825706],[52.485432,76.834663],[52.466202,76.84169],[52.40942,76.862663],[52.396179,76.868889],[52.37986,76.876846],[52.35146,76.890556],[52.35067,76.890938],[52.34148,76.89537],[52.329899,76.900993],[52.329559,76.901169],[52.32811,76.901947],[52.327049,76.902847],[52.326469,76.903397],[52.32436,76.90583],[52.313049,76.919693],[52.310089,76.923309],[52.309891,76.928452],[52.309071,76.94117],[52.308632,76.947121],[52.308498,76.949203],[52.308369,76.951317],[52.308079,76.955162],[52.307919,76.957283],[52.307789,76.958031],[52.307579,76.958633],[52.304588,76.960541],[52.302189,76.962097],[52.300522,76.963142],[52.29739,76.965118],[52.296429,76.965652],[52.296188,76.965668],[52.293209,76.965912],[52.291851,76.965919],[52.291389,76.965927],[52.290791,76.965988],[52.287601,76.966316],[52.285809,76.966431],[52.285671,76.966454],[52.28458,76.966713],[52.284031,76.967018],[52.28352,76.967438],[52.28307,76.967552],[52.275909,76.968437],[52.270489,76.96904],[52.268452,76.969261],[52.26461,76.969704],[52.264389,76.969749],[52.256741,76.970581],[52.25338,76.971031],[52.2528,76.97126],[52.252251,76.971741],[52.249111,76.976593],[52.24733,76.979172],[52.245079,76.982422],[52.245258,76.982758],[52.246681,76.985359],[52.245049,76.987846],[52.243629,76.985168],[52.24118,76.988808],[52.23851,76.992683],[52.23737,76.994247],[52.236721,76.995132],[52.232681,77.00103],[52.231129,77.003418],[52.22633,77.009827],[52.224651,77.011932],[52.223228,77.01329],[52.22081,77.014862],[52.20134,77.027008],[52.192451,77.033051],[52.155258,77.060623],[52.128948,77.078407],[52.120579,77.085007],[52.115608,77.089149],[52.114368,77.090462],[52.110329,77.095573],[52.087749,77.126488],[52.02565,77.220383],[52.017818,77.23365],[52.014431,77.238632],[52.009892,77.244614],[52.008942,77.245781],[52.003288,77.252037],[51.994431,77.26181],[51.987881,77.268944],[51.926472,77.334503],[51.91893,77.343452],[51.913319,77.350563],[51.91114,77.354134],[51.909191,77.358391],[51.90554,77.370628],[51.902649,77.381416],[51.90229,77.38253],[51.901718,77.384003],[51.900742,77.38607],[51.891979,77.400917],[51.8848,77.414436],[51.882252,77.419601],[51.881031,77.421867],[51.876968,77.426117],[51.86919,77.435799],[51.863548,77.443611],[51.861462,77.446404],[51.859451,77.448517],[51.856781,77.450691],[51.854179,77.452042],[51.828972,77.461777],[51.824478,77.463768],[51.820309,77.466713],[51.811329,77.473358],[51.805752,77.477402],[51.80146,77.480957],[51.79636,77.485367],[51.789841,77.490677],[51.770279,77.50605],[51.768761,77.507408],[51.76709,77.509178],[51.765709,77.510872],[51.73035,77.557549],[51.729481,77.558502],[51.728081,77.559578],[51.726379,77.560402],[51.725151,77.560593],[51.723949,77.560516],[51.722801,77.560226],[51.701229,77.551262],[51.70013,77.55098],[51.698509,77.550873],[51.697948,77.550949],[51.696819,77.5513],[51.681561,77.556793],[51.67968,77.557678],[51.67807,77.558594],[51.67651,77.559669],[51.65694,77.573929],[51.654819,77.5756],[51.6525,77.577698],[51.650768,77.579529],[51.637829,77.594147],[51.637039,77.594841],[51.635929,77.595558],[51.634789,77.5961],[51.633911,77.596329],[51.615162,77.599907],[51.614288,77.600143],[51.612862,77.600708],[51.61203,77.601196],[51.61095,77.60202],[51.597519,77.613213],[51.594929,77.615112],[51.5923,77.616814],[51.589958,77.61821],[51.54343,77.643517],[51.540958,77.644943],[51.539619,77.645889],[51.537781,77.647423],[51.53088,77.653717],[51.527859,77.656578],[51.52644,77.658257],[51.52536,77.659866],[51.522968,77.663757],[51.507431,77.6903],[51.5005,77.706619],[51.49971,77.708763],[51.491711,77.729446],[51.48793,77.741676],[51.487179,77.746033],[51.479191,77.798149],[51.477859,77.808937],[51.478561,77.820137],[51.47921,77.829269],[51.47839,77.838791],[51.473591,77.889008],[51.472099,77.898453],[51.47068,77.90657],[51.469509,77.91227],[51.468201,77.917809],[51.465511,77.928558],[51.46513,77.931038],[51.465,77.93309],[51.464909,77.935493],[51.464779,77.937134],[51.464298,77.945389],[51.463741,77.956268],[51.461029,77.989197],[51.460812,77.991142],[51.458012,78.012352],[51.45776,78.014717],[51.448521,78.092888],[51.44817,78.096573],[51.448158,78.098442],[51.4487,78.141037],[51.448662,78.141899],[51.447891,78.145554],[51.427341,78.207191],[51.418861,78.225723],[51.41803,78.22789],[51.40752,78.26239],[51.396679,78.298233],[51.39542,78.302254],[51.394371,78.304718],[51.394211,78.304947],[51.39386,78.305511],[51.393478,78.306084],[51.366341,78.342201],[51.358009,78.354073],[51.35482,78.360786],[51.233669,78.603119],[51.220341,78.630928],[51.188259,78.696838],[51.18729,78.69886],[51.186729,78.700058],[51.18626,78.701118],[51.124222,78.829292],[51.12355,78.830757],[51.12236,78.833801],[51.121422,78.837013],[51.12114,78.838249],[51.12051,78.841789],[51.095852,79.064957],[51.095509,79.068718],[51.095379,79.069504],[51.095032,79.071701],[51.09404,79.073753],[51.09264,79.075302],[51.079861,79.086357],[51.078751,79.087646],[51.07251,79.098297],[51.071159,79.100227],[51.05582,79.115723],[51.049122,79.122276],[51.046509,79.123253],[51.041889,79.123398],[51.039131,79.123734],[51.037231,79.125229],[51.035229,79.12896],[51.027439,79.144852],[51.026489,79.147476],[51.02626,79.148773],[51.02179,79.177223],[51.021488,79.178841],[51.020741,79.18203],[51.01981,79.187233],[51.01717,79.20491],[51.016891,79.206558],[51.016541,79.208183],[51.016029,79.210136],[51.015579,79.211617],[51.007591,79.234901],[51.005562,79.242317],[51.003342,79.251389],[51.003021,79.252533],[51.002659,79.253593],[51.001808,79.255669],[50.98951,79.284027],[50.98748,79.287827],[50.962818,79.324883],[50.962559,79.325447],[50.962379,79.326103],[50.962212,79.327141],[50.959042,79.355682],[50.958809,79.356934],[50.958149,79.358727],[50.957802,79.359367],[50.953659,79.365479],[50.930439,79.399277],[50.926579,79.403992],[50.918289,79.412323],[50.916969,79.413887],[50.913879,79.419724],[50.893089,79.460503],[50.872532,79.485619],[50.866772,79.489517],[50.82011,79.513809],[50.816929,79.5168],[50.814468,79.520363],[50.80534,79.535316],[50.795849,79.544861],[50.793091,79.548866],[50.770229,79.570343],[50.766281,79.576218],[50.758541,79.596062],[50.746498,79.631073],[50.731331,79.676567],[50.720749,79.708328],[50.703209,79.74054],[50.69994,79.747147],[50.69088,79.768768],[50.683689,79.79467],[50.67292,79.832642],[50.670799,79.840111],[50.662849,79.868134],[50.661018,79.872467],[50.65765,79.878677],[50.655571,79.882507],[50.63998,79.910912],[50.636139,79.916557],[50.620838,79.939331],[50.61507,79.951691],[50.600399,79.982117],[50.585468,80.013718],[50.580212,80.02227],[50.577808,80.02652],[50.57518,80.034264],[50.573009,80.041977],[50.57056,80.050537],[50.56884,80.056877],[50.566608,80.062363],[50.559872,80.072617],[50.553612,80.081573],[50.54895,80.091049],[50.54501,80.096603],[50.542839,80.097717],[50.533352,80.099632],[50.530899,80.100929],[50.525398,80.104149],[50.522221,80.105339],[50.51479,80.106903],[50.508839,80.10836],[50.507149,80.109169],[50.50613,80.109894],[50.505871,80.110092],[50.505508,80.110397],[50.499519,80.118111],[50.49921,80.118668],[50.498772,80.119797],[50.49789,80.123573],[50.49752,80.124908],[50.496269,80.129204],[50.495819,80.130363],[50.495411,80.131073],[50.49308,80.133904],[50.491718,80.135551],[50.490509,80.136971],[50.490189,80.137268],[50.486549,80.139992],[50.485451,80.140953],[50.481461,80.144653],[50.480961,80.14537],[50.480141,80.147072],[50.479561,80.148903],[50.479019,80.150627],[50.47871,80.151627],[50.478321,80.152977],[50.4776,80.156029],[50.477539,80.156303],[50.474152,80.174263],[50.473228,80.17939],[50.472271,80.184387],[50.47208,80.185463],[50.47179,80.187027],[50.47139,80.18969],[50.470718,80.196457],[50.470322,80.200493],[50.470058,80.202507],[50.469769,80.20388],[50.469521,80.204887],[50.469299,80.205589],[50.46806,80.20974],[50.46624,80.216202],[50.465012,80.21991],[50.46447,80.221497],[50.464031,80.222557],[50.463169,80.224312],[50.461349,80.227753],[50.460651,80.228928],[50.45948,80.230789],[50.458599,80.232033],[50.458118,80.232437],[50.456772,80.233307],[50.453121,80.235207],[50.448212,80.237793],[50.447819,80.237923],[50.447571,80.23793],[50.44733,80.237831],[50.447201,80.237694],[50.4459,80.236343],[50.44566,80.23613],[50.445492,80.235977],[50.445301,80.235924],[50.444969,80.23587],[50.444519,80.236481],[50.443932,80.237343],[50.443802,80.237633],[50.443722,80.237961],[50.443378,80.24015],[50.443199,80.241318],[50.44313,80.242111],[50.443039,80.243042],[50.442871,80.243759],[50.44278,80.244011],[50.442669,80.244308],[50.44231,80.24485],[50.441528,80.245911],[50.440762,80.24691],[50.440552,80.247276],[50.440559,80.251106],[50.440559,80.251862],[50.440571,80.255997],[50.44059,80.259911],[50.439892,80.258827],[50.438789,80.257118],[50.437721,80.25544],[50.437061,80.254433],[50.436649,80.253639],[50.436298,80.253082],[50.435532,80.251907],[50.434078,80.249634],[50.4338,80.249153],[50.432331,80.246696],[50.430851,80.244049],[50.429489,80.241982],[50.427849,80.239441],[50.426769,80.237717],[50.425671,80.235977],[50.424549,80.234207],[50.42345,80.232437],[50.422421,80.230797],[50.422329,80.230598],[50.422291,80.230423],[50.422272,80.230331],[50.422272,80.230019],[50.422218,80.229637],[50.422138,80.229317],[50.421902,80.228851],[50.4217,80.228592],[50.4216,80.228523],[50.42128,80.228302],[50.420979,80.228241],[50.420738,80.228401],[50.420589,80.228691],[50.42046,80.228798],[50.420231,80.228882],[50.419559,80.228821],[50.418201,80.228569],[50.41748,80.228432],[50.416191,80.22805],[50.415661,80.227791],[50.414989,80.227432],[50.414131,80.226929],[50.4053,80.221863],[50.40469,80.221527],[50.403019,80.221031],[50.402401,80.220863],[50.401581,80.220741],[50.401031,80.220657],[50.399311,80.22039],[50.39875,80.220543],[50.398548,80.220642],[50.398361,80.220787],[50.398159,80.220871],[50.397999,80.220901],[50.397629,80.220718],[50.3974,80.220711],[50.397072,80.220772],[50.396671,80.221039],[50.396351,80.221352],[50.395809,80.221992],[50.395439,80.222527],[50.395168,80.223038],[50.39502,80.223373],[50.39489,80.223763],[50.394798,80.223953],[50.394661,80.224113],[50.39455,80.224182],[50.394402,80.224228],[50.39402,80.224243],[50.39362,80.224319],[50.393101,80.224457],[50.392429,80.224716],[50.391159,80.225403],[50.390282,80.226082],[50.389118,80.22702],[50.385971,80.229622],[50.38485,80.23037],[50.38287,80.231682],[50.38155,80.232513],[50.380508,80.233391],[50.37973,80.234268],[50.37862,80.235771],[50.378281,80.236259],[50.378132,80.236458],[50.37574,80.239532],[50.37561,80.239922],[50.374352,80.241722],[50.37109,80.24633],[50.370972,80.246513],[50.368279,80.250412],[50.366982,80.252296],[50.36483,80.254951],[50.364552,80.255524],[50.363361,80.256828],[50.363029,80.256187],[50.36293,80.256058],[50.36277,80.255997],[50.36264,80.256119],[50.362091,80.25679],[50.361591,80.25737],[50.36013,80.259033],[50.359909,80.259407],[50.359852,80.25985],[50.359909,80.260277],[50.35997,80.260773],[50.3601,80.26178],[50.360271,80.263077],[50.36031,80.263931],[50.360378,80.265427],[50.360409,80.266212],[50.360451,80.267143],[50.360451,80.267761],[50.360378,80.268303],[50.36002,80.269943],[50.359829,80.27034],[50.359718,80.270462],[50.35952,80.270691],[50.358528,80.271301],[50.358398,80.271477],[50.357769,80.272652],[50.355282,80.276718],[50.353569,80.279518],[50.352551,80.281174],[50.349991,80.285347],[50.348801,80.287376],[50.34771,80.28933],[50.34613,80.292107],[50.344971,80.294273],[50.34164,80.300957],[50.339989,80.30381],[50.31815,80.339973],[50.317699,80.3405],[50.3097,80.352638],[50.29863,80.370323],[50.288872,80.387657],[50.254799,80.438637],[50.1786,80.543793],[50.147369,80.586998],[50.140499,80.595627],[50.129791,80.608902],[50.12748,80.611763],[50.125332,80.61425],[50.048908,80.68779],[50.013439,80.721893],[49.99485,80.740593],[49.99086,80.744957],[49.980228,80.756561],[49.977631,80.759216],[49.964771,80.772614],[49.960129,80.776558],[49.954281,80.780327],[49.948589,80.782913],[49.837891,80.833717],[49.83419,80.835533],[49.832191,80.837158],[49.80888,80.859039],[49.806938,80.860931],[49.797581,80.872002],[49.795361,80.87458],[49.794201,80.875519],[49.792919,80.875862],[49.782131,80.879662],[49.781448,80.879898],[49.77985,80.880836],[49.77879,80.882042],[49.777302,80.88385],[49.736259,80.945213],[49.733879,80.948143],[49.73111,80.950974],[49.673931,81.008041],[49.668369,81.014137],[49.662201,81.021088],[49.65498,81.028976],[49.646358,81.037537],[49.632919,81.050873],[49.631248,81.052078],[49.62986,81.052513],[49.625141,81.053543],[49.62352,81.054222],[49.621738,81.055252],[49.620129,81.056877],[49.605228,81.073448],[49.603111,81.076279],[49.59388,81.089241],[49.553799,81.14563],[49.5425,81.163139],[49.537991,81.17009],[49.53754,81.17112],[49.536152,81.171982],[49.532249,81.178162],[49.53075,81.180733],[49.523109,81.196442],[49.52261,81.198761],[49.52261,81.200989],[49.523109,81.203651],[49.52306,81.205711],[49.519772,81.231293],[49.5191,81.234207],[49.51704,81.241158],[49.509689,81.271461],[49.500149,81.299011],[49.499371,81.300636],[49.498089,81.302361],[49.48444,81.315964],[49.477909,81.323692],[49.474449,81.328407],[49.4725,81.331413],[49.470879,81.334503],[49.469261,81.338371],[49.455101,81.372704],[49.45393,81.374329],[49.45314,81.375107],[49.452301,81.37545],[49.445,81.376297],[49.443039,81.376823],[49.441429,81.377678],[49.44009,81.378883],[49.436741,81.383087],[49.435452,81.38472],[49.434219,81.38652],[49.433159,81.388237],[49.42725,81.401108],[49.421219,81.414253],[49.418541,81.419479],[49.411678,81.429916],[49.400391,81.447113],[49.39827,81.450287],[49.39156,81.461533],[49.38866,81.466682],[49.382511,81.47673],[49.380718,81.480247],[49.372341,81.49939],[49.37133,81.502136],[49.37072,81.504883],[49.36927,81.512001],[49.368649,81.514236],[49.367981,81.516037],[49.36647,81.518959],[49.364799,81.521713],[49.362339,81.525047],[49.356628,81.532257],[49.35479,81.53389],[49.34597,81.540771],[49.344952,81.541206],[49.343632,81.541473],[49.34333,81.541527],[49.340672,81.541313],[49.33812,81.541054],[49.335979,81.540817],[49.33514,81.540771],[49.334141,81.540863],[49.333038,81.54113],[49.332169,81.54155],[49.331421,81.542183],[49.329498,81.544533],[49.328152,81.546356],[49.32795,81.546631],[49.324299,81.551483],[49.322681,81.553627],[49.321751,81.554893],[49.321259,81.555237],[49.321011,81.555313],[49.32069,81.555267],[49.320511,81.555206],[49.320339,81.555031],[49.320141,81.554764],[49.32,81.554527],[49.319931,81.554253],[49.31987,81.553459],[49.319889,81.551407],[49.320042,81.544144],[49.320061,81.54332],[49.320091,81.541809],[49.320278,81.532089],[49.320541,81.520844],[49.321339,81.486343],[49.321339,81.484283],[49.321331,81.481621],[49.321308,81.47982],[49.32077,81.477058],[49.318619,81.468513],[49.318211,81.467102],[49.317501,81.464767],[49.31506,81.459068],[49.313931,81.456322],[49.29652,81.414993],[49.275181,81.364922],[49.254799,81.316856],[49.235931,81.271873],[49.23465,81.269058],[49.23217,81.264801],[49.230999,81.263184],[49.22913,81.261017],[49.226669,81.258499],[49.218109,81.250893],[49.19363,81.229141],[49.190189,81.22509],[49.189041,81.222366],[49.188091,81.219749],[49.187592,81.217003],[49.187149,81.214172],[49.187019,81.210899],[49.187302,81.204613],[49.187271,81.202583],[49.187061,81.200394],[49.186401,81.197197],[49.185638,81.195068],[49.18441,81.192802],[49.182369,81.190697],[49.179611,81.188919],[49.176208,81.187088],[49.174641,81.186363],[49.173618,81.185463],[49.172539,81.184052],[49.171612,81.182587],[49.17041,81.180519],[49.167099,81.174347],[49.16547,81.171173],[49.160641,81.158813],[49.15929,81.156151],[49.158119,81.154266],[49.1511,81.144478],[49.14925,81.141388],[49.147961,81.138901],[49.14621,81.134613],[49.145481,81.133408],[49.144531,81.132378],[49.142342,81.130493],[49.141048,81.128937],[49.140091,81.127403],[49.129929,81.109627],[49.128189,81.107323],[49.099369,81.076927],[49.09729,81.074699],[49.09594,81.072723],[49.09499,81.070839],[49.094372,81.069122],[49.09425,81.067413],[49.094372,81.065514],[49.0942,81.06337],[49.09351,81.059097],[49.091969,81.054367],[49.091129,81.052399],[49.089951,81.050339],[49.088772,81.048798],[49.071232,81.026314],[49.069771,81.024513],[49.068298,81.023216],[49.06707,81.02253],[49.059021,81.019096],[49.05661,81.017982],[49.048618,81.012573],[49.047379,81.011276],[49.037762,80.998329],[49.03619,80.996353],[49.03511,80.995407],[49.03371,80.994461],[49.020882,80.985367],[49.019501,80.984467],[49.014061,80.979347],[49.012428,80.978073],[49.01086,80.977211],[49.008888,80.976097],[49.00737,80.97464],[49.000839,80.966827],[48.999088,80.965027],[48.997849,80.963913],[48.99498,80.96199],[48.993118,80.960442],[48.99165,80.958298],[48.988419,80.95253],[48.987301,80.950897],[48.985722,80.94944],[48.984138,80.948486],[48.980709,80.947212],[48.978569,80.945923],[48.976822,80.944473],[48.95203,80.920937],[48.950581,80.919563],[48.94915,80.917877],[48.946911,80.913948],[48.913811,80.859528],[48.912689,80.8573],[48.9119,80.855164],[48.91127,80.852921],[48.910431,80.848801],[48.909691,80.846657],[48.903042,80.833443],[48.901741,80.831551],[48.900612,80.830002],[48.898918,80.828293],[48.89711,80.827003],[48.89357,80.825073],[48.887291,80.82206],[48.882999,80.819962],[48.881439,80.819473],[48.867081,80.817131],[48.866169,80.816963],[48.865391,80.816933],[48.864559,80.817062],[48.826309,80.825882],[48.824501,80.82666],[48.82275,80.827507],[48.82127,80.828537],[48.819519,80.830093],[48.80703,80.84082],[48.805389,80.84211],[48.803699,80.842957],[48.80172,80.843483],[48.798328,80.844597],[48.784302,80.850937],[48.783058,80.851288],[48.77718,80.851967],[48.775928,80.851967],[48.773079,80.85186],[48.76965,80.851547],[48.75919,80.850693],[48.756359,80.85054],[48.75177,80.848717],[48.739208,80.843727],[48.73711,80.842453],[48.735809,80.841164],[48.72823,80.829567],[48.726398,80.827591],[48.72459,80.826653],[48.722832,80.826393],[48.715981,80.82486],[48.71294,80.823891],[48.697102,80.817177],[48.691078,80.81456],[48.688881,80.813606],[48.687199,80.81292],[48.685501,80.812332],[48.683559,80.811493],[48.682331,80.810928],[48.68079,80.809769],[48.674721,80.80381],[48.670029,80.798843],[48.654549,80.782288],[48.652519,80.779533],[48.56625,80.656357],[48.562111,80.650528],[48.56052,80.649063],[48.558701,80.648117],[48.521759,80.631844],[48.514252,80.626694],[48.506981,80.62014],[48.470058,80.584862],[48.451328,80.564262],[48.445351,80.558434],[48.431862,80.544952],[48.428841,80.542213],[48.386341,80.499123],[48.384232,80.496117],[48.381611,80.492157],[48.36536,80.463501],[48.36467,80.462471],[48.36404,80.461952],[48.363251,80.4617],[48.359138,80.461868],[48.358231,80.461609],[48.35714,80.460922],[48.335468,80.440071],[48.334209,80.439377],[48.332901,80.43895],[48.33136,80.438698],[48.329479,80.438522],[48.303791,80.436546],[48.282089,80.435089],[48.280609,80.435013],[48.278839,80.435089],[48.276951,80.435349],[48.2565,80.442299],[48.218819,80.454918],[48.201778,80.461182],[48.199951,80.4617],[48.189301,80.464272],[48.18261,80.467102],[48.180321,80.467621],[48.178551,80.467789],[48.175289,80.467697],[48.151119,80.465637],[48.140419,80.464531],[48.138809,80.464012],[48.137661,80.463074],[48.13583,80.462547],[48.133202,80.462044],[48.129929,80.46067],[48.127239,80.459549],[48.125061,80.458183],[48.123798,80.457657],[48.120941,80.457237],[48.11853,80.456459],[48.114059,80.453888],[48.112919,80.453712],[48.110909,80.453712],[48.108559,80.454491],[48.102139,80.455261],[48.100361,80.455261],[48.094521,80.454659],[48.087639,80.453369],[48.082821,80.451309],[48.081959,80.450706],[48.0802,80.448807],[48.078949,80.446602],[48.07795,80.444893],[48.07597,80.443291],[48.073978,80.442009],[48.069759,80.440331],[48.068878,80.439133],[48.067829,80.436317],[48.066292,80.434669],[48.06041,80.433647],[48.05928,80.43306],[48.057381,80.43177],[48.05444,80.429626],[48.053261,80.428909],[48.051949,80.428711],[48.0438,80.429039],[48.0415,80.428818],[48.040199,80.428123],[48.03611,80.425949],[48.032051,80.423782],[48.030571,80.422501],[48.029652,80.421471],[48.02541,80.419167],[48.021198,80.416908],[48.019539,80.416183],[48.018749,80.4161],[48.017658,80.41629],[47.991871,80.420624],[47.99033,80.420883],[47.987949,80.420197],[47.987068,80.419563],[47.984379,80.416069],[47.98214,80.413673],[47.974831,80.406982],[47.963409,80.398438],[47.961182,80.397171],[47.958969,80.396156],[47.957169,80.395592],[47.955151,80.39521],[47.952431,80.394997],[47.948669,80.395233],[47.945518,80.395798],[47.940239,80.396606],[47.92968,80.398376],[47.927811,80.398933],[47.926281,80.399696],[47.924911,80.400841],[47.923679,80.402428],[47.92281,80.403801],[47.92189,80.405907],[47.921028,80.408737],[47.920361,80.413338],[47.920189,80.414627],[47.919071,80.421181],[47.917919,80.424767],[47.916519,80.42717],[47.915371,80.428757],[47.91367,80.430153],[47.912231,80.431068],[47.91,80.431641],[47.90947,80.431587],[47.908821,80.431511],[47.90741,80.43129],[47.90609,80.431107],[47.9039,80.430817],[47.901539,80.430519],[47.901409,80.430496],[47.901131,80.430527],[47.900841,80.430603],[47.9007,80.430649],[47.900421,80.430794],[47.900139,80.430977],[47.899738,80.43132],[47.89922,80.4319],[47.89888,80.432373],[47.89835,80.433281],[47.89814,80.433678],[47.897732,80.434517],[47.897449,80.43515],[47.897202,80.43576],[47.89706,80.436172],[47.896961,80.436607],[47.89687,80.437271],[47.896801,80.43882],[47.896111,80.441483],[47.8895,80.466629],[47.888458,80.469467],[47.88308,80.481781],[47.88253,80.484047],[47.88242,80.485947],[47.884239,80.498688],[47.884121,80.500748],[47.883259,80.503113],[47.872631,80.519592],[47.87114,80.521431],[47.86964,80.522461],[47.868599,80.523232],[47.867851,80.524094],[47.867081,80.525513],[47.865028,80.529671],[47.860371,80.535767],[47.846722,80.551987],[47.84539,80.552849],[47.843552,80.553879],[47.8428,80.554573],[47.84193,80.555679],[47.838188,80.558769],[47.824478,80.568977],[47.81485,80.57679],[47.79208,80.597733],[47.79047,80.599449],[47.788731,80.601768],[47.78735,80.603996],[47.785561,80.606148],[47.782742,80.608887],[47.762951,80.62709],[47.759609,80.629578],[47.752739,80.634468],[47.751869,80.635406],[47.75037,80.637993],[47.749512,80.639267],[47.748291,80.640556],[47.737209,80.650352],[47.735249,80.651627],[47.733231,80.652321],[47.730869,80.652496],[47.71777,80.652618],[47.71574,80.652786],[47.713951,80.653442],[47.71117,80.654472],[47.69194,80.662369],[47.684441,80.665321],[47.681252,80.667],[47.67836,80.667343],[47.67588,80.667603],[47.673679,80.668213],[47.672119,80.66906],[47.668591,80.671379],[47.66703,80.671982],[47.665409,80.671982],[47.66021,80.671204],[47.65744,80.670433],[47.655472,80.669144],[47.653679,80.667603],[47.650089,80.663834],[47.648769,80.661926],[47.64645,80.657806],[47.645531,80.656616],[47.644371,80.655586],[47.638119,80.650703],[47.636971,80.64949],[47.636341,80.648239],[47.635181,80.646782],[47.634201,80.645752],[47.632408,80.64489],[47.63055,80.644043],[47.628189,80.643257],[47.609489,80.641586],[47.595901,80.638283],[47.589649,80.636833],[47.587109,80.635887],[47.58363,80.633636],[47.578072,80.629959],[47.568802,80.623444],[47.56736,80.622231],[47.566078,80.621803],[47.564869,80.621628],[47.55537,80.622414],[47.549568,80.623093],[47.546799,80.623444],[47.543732,80.62336],[47.539551,80.622658],[47.532768,80.622917],[47.529751,80.623001],[47.526279,80.622147],[47.510658,80.61721],[47.487869,80.608543],[47.485722,80.607773],[47.480671,80.605751],[47.47731,80.604637],[47.43161,80.593521],[47.42905,80.592323],[47.421242,80.586311],[47.418598,80.584167],[47.416599,80.582916],[47.396759,80.579399],[47.392311,80.578667],[47.389759,80.579742],[47.387699,80.580429],[47.374851,80.580688],[47.372471,80.581078],[47.363312,80.584846],[47.360371,80.586273],[47.35825,80.586739],[47.352638,80.586647],[47.349819,80.587341],[47.34119,80.59259],[47.331879,80.597717],[47.319569,80.605148],[47.314831,80.610023],[47.300751,80.622543],[47.298939,80.623947],[47.296761,80.625023],[47.295071,80.626427],[47.292019,80.630363],[47.272099,80.654472],[47.270119,80.656708],[47.267269,80.658943],[47.260921,80.663689],[47.257599,80.666351],[47.25127,80.675407],[47.247211,80.683594],[47.246471,80.684959],[47.244949,80.686447],[47.243061,80.68705],[47.239849,80.687317],[47.233131,80.687828],[47.189499,80.691467],[47.144661,80.694481],[47.07082,80.699287],[47.052109,80.699966],[46.981419,80.698601],[46.977669,80.698257],[46.97451,80.696716],[46.971809,80.695],[46.969471,80.692078],[46.967251,80.688477],[46.935261,80.630463],[46.93327,80.626846],[46.930679,80.623589],[46.92189,80.6138],[46.89727,80.5858],[46.892929,80.58168],[46.890121,80.579361],[46.887299,80.57756],[46.861721,80.563393],[46.85849,80.562187],[46.85614,80.561417],[46.853561,80.560738],[46.839649,80.561081],[46.806992,80.561958],[46.728088,80.562302],[46.72385,80.56282],[46.721378,80.564018],[46.717739,80.56694],[46.714088,80.57106],[46.711262,80.575348],[46.709259,80.578957],[46.708199,80.581703],[46.706791,80.58342],[46.703732,80.583588],[46.68948,80.58342],[46.686069,80.583763],[46.683949,80.584793],[46.680531,80.588387],[46.678532,80.590446],[46.676289,80.591827],[46.674171,80.592346],[46.671822,80.59166],[46.666519,80.587883],[46.63953,80.570541],[46.635288,80.568657],[46.631519,80.568138],[46.628571,80.568481],[46.62513,80.569603],[46.557652,80.610458],[46.524948,80.630287],[46.49506,80.64814],[46.45723,80.670799],[46.428841,80.687798],[46.414989,80.696037],[46.413479,80.696259],[46.411678,80.696121],[46.41032,80.695602],[46.409321,80.695183],[46.40836,80.694923],[46.407001,80.694923],[46.405579,80.695351],[46.404751,80.695953],[46.402981,80.697411],[46.396648,80.703484],[46.384979,80.714737],[46.342571,80.749603],[46.303871,80.781372],[46.22459,80.846413],[46.207008,80.860657],[46.204029,80.863136],[46.19865,80.867607],[46.198219,80.868042],[46.197861,80.868729],[46.197861,80.869667],[46.198341,80.870354],[46.199711,80.87233],[46.200661,80.873878],[46.20298,80.880402],[46.203388,80.881767],[46.203449,80.883583],[46.20285,80.889503],[46.202621,80.89164],[46.201191,80.901688],[46.200062,80.904427],[46.19846,80.907349],[46.196499,80.910439],[46.190979,80.928886],[46.186642,80.939537],[46.185211,80.943008],[46.183781,80.947128],[46.182949,80.951332],[46.182598,80.955193],[46.182419,80.971069],[46.180462,80.972443],[46.176182,80.974503],[46.122959,81.002571],[46.11903,81.004288],[46.1157,81.006767],[46.086899,81.024117],[46.085949,81.024971],[46.085411,81.02626],[46.085171,81.027718],[46.084808,81.029182],[46.06403,81.067802],[46.061291,81.072441],[46.05891,81.075699],[46.01363,81.126251],[46.011719,81.128754],[46.010529,81.131401],[45.999378,81.170197],[45.99699,81.176643],[45.98489,81.20359],[45.983398,81.207283],[45.98209,81.2108],[45.974869,81.251556],[45.966999,81.295174],[45.96574,81.300751],[45.952202,81.352943],[45.92617,81.46151],[45.92474,81.467003],[45.923431,81.471207],[45.907719,81.513351],[45.884838,81.574379],[45.883888,81.576439],[45.88311,81.577553],[45.87851,81.58287],[45.841572,81.624672],[45.83918,81.627853],[45.82835,81.650421],[45.82291,81.661407],[45.782639,81.745087],[45.770489,81.775818],[45.711369,81.934608],[45.706032,81.947403],[45.701962,81.955116],[45.697521,81.961212],[45.695599,81.962929],[45.69392,81.963867],[45.69212,81.963959],[45.691051,81.963707],[45.686371,81.962837],[45.683491,81.962761],[45.682468,81.963188],[45.68079,81.964821],[45.58416,82.071327],[45.53891,82.121536],[45.502449,82.168114],[45.47237,82.206497],[45.435539,82.253471],[45.43288,82.256813],[45.352539,82.358437],[45.34301,82.370888],[45.295689,82.430367],[45.287159,82.441269],[45.282871,82.446083],[45.276649,82.452087],[45.258049,82.468567],[45.257339,82.469673],[45.256802,82.471046],[45.25655,82.472603],[45.256371,82.474907],[45.255772,82.476196],[45.255081,82.476967],[45.24276,82.492943],[45.24107,82.495087],[45.23835,82.500153],[45.23605,82.505562],[45.235748,82.50676],[45.235748,82.508476],[45.236408,82.513367],[45.23629,82.51474],[45.235691,82.516289],[45.234779,82.517754],[45.221298,82.542213],[45.217979,82.546928],[45.21302,82.553284],[45.21175,82.554398],[45.210171,82.555344],[45.208,82.556198],[45.2057,82.556969],[45.204491,82.557907],[45.200378,82.561691],[45.197479,82.564438],[45.195782,82.565468],[45.19421,82.56633],[45.19318,82.566406],[45.189789,82.565552],[45.17136,82.560516],[45.166561,82.559196],[45.163719,82.55809],[45.158691,82.556969],[45.152882,82.556717],[45.084499,82.560577],[45.081108,82.560997],[45.071529,82.563843],[45.0508,82.570007],[45.04612,82.571747],[45.04187,82.574661],[45.039688,82.57827],[45.01506,82.595444],[45.01239,82.597504],[45.005718,82.605743],[45.002682,82.608307],[44.99564,82.617073],[44.978771,82.627373],[44.958,82.636978],[44.947311,82.640244],[44.94281,82.639549],[44.936371,82.637833],[44.931629,82.632507],[44.93111,82.630547],[44.9258,82.610367],[44.903549,82.542389],[44.844742,82.543419],[44.835861,82.53981],[44.834709,82.554497],[44.825001,82.547546],[44.808102,82.535461],[44.803349,82.525513],[44.802368,82.523788],[44.798359,82.516747],[44.798481,82.514],[44.79129,82.502159],[44.78569,82.496147],[44.778252,82.493919],[44.77277,82.48774],[44.765209,82.48774],[44.7616,82.496841],[44.755459,82.512283],[44.755829,82.539062],[44.74157,82.540092],[44.725101,82.544388],[44.70644,82.549362],[44.700699,82.548683],[44.683128,82.544563],[44.676418,82.539917],[44.664211,82.517776],[44.65704,82.51091],[44.653099,82.507133],[44.595058,82.5037],[44.58345,82.503532],[44.582352,82.522926],[44.580879,82.523453],[44.557529,82.522873],[44.534039,82.522293],[44.52557,82.522072],[44.52927,82.554169],[44.5313,82.571716],[44.534229,82.594208],[44.53619,82.611549],[44.536442,82.617043],[44.536678,82.620987],[44.544998,82.64502],[44.546589,82.650337],[44.547451,82.655663],[44.548061,82.671463],[44.547199,82.679176],[44.547699,82.683823],[44.547699,82.686737],[44.546959,82.691711],[44.547451,82.696007],[44.547329,82.702187],[44.547569,82.705963],[44.545731,82.742699],[44.546101,82.745613],[44.554199,82.764877],[44.55444,82.765709],[44.557529,82.773193],[44.558979,82.777283],[44.56015,82.781342],[44.568581,82.81691],[44.569359,82.820198],[44.57032,82.823631],[44.571289,82.826576],[44.582081,82.85862],[44.582989,82.861427],[44.584259,82.865913],[44.585281,82.870201],[44.589359,82.889977],[44.590691,82.896233],[44.590988,82.897942],[44.59103,82.898331],[44.591629,82.901283],[44.592972,82.907463],[44.593128,82.908318],[44.594398,82.914139],[44.5956,82.919319],[44.595772,82.919952],[44.596539,82.921898],[44.597641,82.923813],[44.599129,82.92556],[44.59964,82.926018],[44.60025,82.926498],[44.601158,82.927078],[44.602718,82.927742],[44.608871,82.929962],[44.613121,82.931633],[44.61327,82.931717],[44.613789,82.93187],[44.617851,82.933357],[44.619282,82.933968],[44.628521,82.937401],[44.633331,82.93927],[44.63562,82.940033],[44.63689,82.940529],[44.637329,82.94075],[44.637859,82.940918],[44.641899,82.942482],[44.643261,82.943153],[44.643501,82.943359],[44.644581,82.944077],[44.645691,82.945137],[44.64632,82.945908],[44.647072,82.947403],[44.64753,82.948624],[44.647732,82.949257],[44.648071,82.950394],[44.648041,82.952026],[44.648121,82.954086],[44.647881,82.957283],[44.646622,82.960457],[44.645519,82.962517],[44.64283,82.96595],[44.640511,82.969559],[44.638519,82.972366],[44.63554,82.978752],[44.633381,82.985313],[44.632469,82.990089],[44.629028,83.018311],[44.627201,83.026718],[44.621578,83.048523],[44.615349,83.086113],[44.614861,83.091438],[44.615471,83.154221],[44.615681,83.190536],[44.61544,83.220917],[44.612629,83.238258],[44.601631,83.288887],[44.595638,83.3004],[44.59034,83.305893],[44.58234,83.314774],[44.57122,83.328331],[44.569988,83.330223],[44.565102,83.345497],[44.560581,83.365227],[44.551159,83.38755],[44.543209,83.426353],[44.542961,83.428749],[44.542839,83.452782],[44.549931,83.520592],[44.55006,83.523163],[44.549931,83.525574],[44.549568,83.527802],[44.54847,83.530891],[44.522888,83.596626],[44.51738,83.607964],[44.515301,83.610542],[44.493999,83.625816],[44.492531,83.626503],[44.49033,83.626678],[44.482121,83.626846],[44.480289,83.627708],[44.476238,83.630623],[44.474899,83.632339],[44.474159,83.634064],[44.473431,83.637154],[44.46228,83.72023],[44.46032,83.748039],[44.460442,83.753021],[44.464611,83.786148],[44.464851,83.791473],[44.462521,83.859108],[44.453579,83.898933],[44.43998,83.961418],[44.438141,83.967079],[44.41766,84.027496],[44.415581,84.031113],[44.38406,84.079178],[44.382961,84.081062],[44.381969,84.083122],[44.381359,84.086037],[44.379848,84.10498],[44.374119,84.176682],[44.371559,84.24231],[44.37125,84.250366],[44.371029,84.255867],[44.36956,84.293549],[44.369381,84.298866],[44.369419,84.305313],[44.369339,84.310707],[44.36924,84.314056],[44.368771,84.329811],[44.36895,84.336533],[44.369949,84.346283],[44.373421,84.381859],[44.374149,84.38546],[44.401112,84.488602],[44.401451,84.489929],[44.401489,84.49025],[44.401718,84.491364],[44.401939,84.492889],[44.402012,84.49366],[44.40205,84.494843],[44.40202,84.496437],[44.401958,84.497253],[44.401669,84.499237],[44.401421,84.500412],[44.401112,84.501549],[44.40057,84.503014],[44.399769,84.504753],[44.399059,84.506104],[44.39526,84.512733],[44.38364,84.533234],[44.382381,84.535522],[44.381882,84.536552],[44.381409,84.537643],[44.38113,84.538383],[44.38063,84.539909],[44.38044,84.54071],[44.38015,84.542343],[44.37999,84.543556],[44.379902,84.544807],[44.37986,84.546066],[44.37989,84.548592],[44.380539,84.571327],[44.38081,84.584824],[44.38163,84.621742],[44.38187,84.631577],[44.38195,84.634491],[44.38224,84.646912],[44.382339,84.648911],[44.382622,84.652283],[44.382851,84.654289],[44.383221,84.656693],[44.383591,84.65873],[44.38401,84.660812],[44.384491,84.662949],[44.38493,84.66465],[44.387989,84.675621],[44.395012,84.701317],[44.39798,84.712379],[44.398918,84.716614],[44.399319,84.718773],[44.399849,84.722267],[44.40015,84.724907],[44.400311,84.726669],[44.400551,84.730438],[44.401211,84.745941],[44.401871,84.761391],[44.40197,84.763748],[44.402451,84.774986],[44.40266,84.779877],[44.403,84.787857],[44.403179,84.791451],[44.40366,84.803093],[44.40369,84.805023],[44.40366,84.806641],[44.403519,84.809212],[44.403332,84.811028],[44.403172,84.812218],[44.40279,84.814468],[44.402401,84.816269],[44.401421,84.820137],[44.401199,84.821136],[44.400791,84.822662],[44.399288,84.828644],[44.399052,84.829597],[44.397511,84.835991],[44.396,84.842293],[44.39402,84.850548],[44.393211,84.855598],[44.392689,84.859741],[44.392189,84.865494],[44.39209,84.872017],[44.392109,84.87764],[44.39323,84.896751],[44.393291,84.902847],[44.393311,84.907852],[44.39307,84.916458],[44.393051,84.917793],[44.391701,84.944908],[44.391331,84.952461],[44.390469,84.958641],[44.38924,84.965851],[44.37661,85.01683],[44.373291,85.02816],[44.36483,85.052711],[44.36237,85.062317],[44.361019,85.069527],[44.360161,85.077087],[44.359669,85.083946],[44.359299,85.09185],[44.359669,85.099747],[44.36372,85.137863],[44.36433,85.146263],[44.36446,85.15313],[44.36433,85.160858],[44.36348,85.168922],[44.362,85.177849],[44.360039,85.184891],[44.357342,85.192963],[44.33942,85.237083],[44.33696,85.244797],[44.335121,85.251839],[44.333771,85.259743],[44.33316,85.267632],[44.333031,85.275528],[44.333889,85.284798],[44.334751,85.292862],[44.335121,85.299042],[44.335121,85.304192],[44.334511,85.310028],[44.334511,85.314323],[44.334869,85.322731],[44.336349,85.331833],[44.33831,85.342819],[44.338799,85.347282],[44.339169,85.352432],[44.339291,85.359642],[44.33905,85.365479],[44.337582,85.375954],[44.336472,85.384697],[44.335979,85.392601],[44.335979,85.403236],[44.33672,85.415077],[44.33979,85.453369],[44.340279,85.458],[44.341999,85.468483],[44.342731,85.474312],[44.343102,85.478783],[44.34322,85.484093],[44.343102,85.489243],[44.342491,85.495422],[44.338558,85.521858],[44.33794,85.528381],[44.337818,85.53405],[44.33807,85.545891],[44.33807,85.551041],[44.33733,85.556534],[44.336102,85.56237],[44.333771,85.568733],[44.33131,85.573883],[44.327141,85.579369],[44.322109,85.584343],[44.316212,85.588814],[44.312401,85.592758],[44.309212,85.596878],[44.306019,85.602028],[44.30331,85.607857],[44.30085,85.614899],[44.299011,85.622627],[44.298271,85.630524],[44.298149,85.639961],[44.29987,85.69558],[44.299381,85.703308],[44.298401,85.710693],[44.296799,85.718071],[44.28685,85.761147],[44.28574,85.768539],[44.284882,85.776947],[44.283161,85.799103],[44.282051,85.807854],[44.280331,85.816597],[44.27763,85.826042],[44.258949,85.880463],[44.256611,85.889732],[44.255131,85.898483],[44.25415,85.906563],[44.25354,85.914108],[44.25243,85.949982],[44.251942,85.956497],[44.25071,85.965431],[44.247509,85.98243],[44.246769,85.989639],[44.246399,85.995819],[44.246399,86.00354],[44.247021,86.009903],[44.25095,86.031181],[44.25563,86.052467],[44.25956,86.063797],[44.265461,86.077187],[44.26952,86.086113],[44.272099,86.093491],[44.273941,86.101387],[44.275169,86.109123],[44.275539,86.114433],[44.275661,86.120956],[44.275421,86.126793],[44.274681,86.133148],[44.273201,86.141037],[44.26226,86.187561],[44.246159,86.230133],[44.243328,86.239059],[44.24136,86.247993],[44.239891,86.257263],[44.23521,86.288498],[44.23312,86.298447],[44.2314,86.306183],[44.221561,86.339653],[44.216511,86.356651],[44.21455,86.363518],[44.21307,86.370728],[44.21233,86.377251],[44.21196,86.384277],[44.21233,86.39064],[44.212818,86.39682],[44.21418,86.403168],[44.216881,86.412613],[44.217991,86.418793],[44.218479,86.425659],[44.218479,86.432693],[44.217621,86.439217],[44.216019,86.445572],[44.213558,86.452606],[44.20052,86.483513],[44.198429,86.490196],[44.196701,86.497917],[44.195591,86.506851],[44.195221,86.515953],[44.195251,86.543556],[44.19471,86.554619],[44.19352,86.564163],[44.190159,86.588669],[44.189831,86.596909],[44.189831,86.604279],[44.19178,86.646683],[44.19178,86.655891],[44.1908,86.66391],[44.189499,86.671829],[44.186901,86.679314],[44.18372,86.68718],[44.18166,86.691147],[44.18071,86.692917],[44.178638,86.696259],[44.17778,86.697723],[44.176701,86.699837],[44.17556,86.702438],[44.174561,86.70517],[44.17395,86.70713],[44.17337,86.709412],[44.17284,86.71209],[44.172352,86.715782],[44.172249,86.71701],[44.17215,86.71917],[44.172009,86.728439],[44.171959,86.746559],[44.171791,86.759918],[44.171539,86.764847],[44.171219,86.768806],[44.17086,86.772324],[44.170589,86.774559],[44.1702,86.777046],[44.169151,86.782753],[44.16835,86.786324],[44.167511,86.789742],[44.166519,86.793556],[44.164181,86.802719],[44.16357,86.805313],[44.162861,86.808769],[44.16214,86.812958],[44.16148,86.818092],[44.161091,86.822517],[44.16058,86.831001],[44.160439,86.832359],[44.16008,86.834793],[44.159649,86.837013],[44.158669,86.840912],[44.157921,86.843369],[44.15683,86.846336],[44.155701,86.848953],[44.154442,86.851357],[44.153419,86.853218],[44.151951,86.855492],[44.15044,86.858032],[44.14957,86.859619],[44.148289,86.862106],[44.146641,86.865753],[44.145729,86.867897],[44.143909,86.872673],[44.14275,86.875504],[44.141731,86.877777],[44.1404,86.88047],[44.139519,86.882133],[44.13802,86.884773],[44.136848,86.886597],[44.13483,86.889458],[44.133209,86.891541],[44.131359,86.89373],[44.129169,86.896019],[44.119942,86.904999],[44.11771,86.907303],[44.114632,86.910797],[44.111851,86.914253],[44.109699,86.917122],[44.1073,86.920486],[44.105091,86.923759],[44.101471,86.928864],[44.097431,86.934837],[44.092442,86.942001],[44.091,86.944183],[44.08979,86.946167],[44.087761,86.949821],[44.086342,86.952797],[44.085121,86.955643],[44.083771,86.959244],[44.08276,86.962158],[44.08242,86.96331],[44.081749,86.96566],[44.08078,86.969597],[44.080059,86.973022],[44.076771,86.989891],[44.076229,86.992317],[44.07518,86.996613],[44.074291,86.999908],[44.072842,87.004631],[44.070599,87.010902],[44.069149,87.014557],[44.067589,87.018158],[44.066078,87.021446],[44.064331,87.024857],[44.06308,87.027153],[44.060379,87.031731],[44.053638,87.042503],[44.04911,87.049896],[44.046768,87.053978],[44.045158,87.056976],[44.043751,87.059807],[44.042549,87.062439],[44.037979,87.073174],[44.032749,87.085258],[44.03149,87.087898],[44.028469,87.093567],[44.027111,87.095787],[44.024738,87.099281],[44.022659,87.102112],[44.020248,87.105118],[44.017658,87.107986],[44.01181,87.113861],[44.006989,87.118851],[44.00354,87.122307],[44.0014,87.124702],[43.999149,87.127373],[43.995361,87.132362],[43.992489,87.136711],[43.990841,87.139389],[43.974121,87.167473],[43.972591,87.170227],[43.9706,87.174049],[43.969471,87.176369],[43.967602,87.180603],[43.966541,87.183228],[43.965569,87.185707],[43.96439,87.188911],[43.963001,87.192917],[43.954929,87.21653],[43.954769,87.216988],[43.953381,87.221046],[43.951832,87.226028],[43.950878,87.229561],[43.94986,87.233673],[43.9491,87.237152],[43.948372,87.240967],[43.94772,87.244904],[43.946381,87.25338],[43.945599,87.258263],[43.943878,87.26899],[43.943729,87.269943],[43.943661,87.270348],[43.94339,87.272049],[43.943081,87.273956],[43.94278,87.275772],[43.941769,87.280762],[43.941509,87.281837],[43.94083,87.284477],[43.940159,87.287323],[43.939629,87.289253],[43.939541,87.289574],[43.938251,87.293716],[43.93816,87.294029],[43.93755,87.295952],[43.935711,87.301018],[43.93557,87.301392],[43.93351,87.30648],[43.933399,87.306717],[43.9277,87.320503],[43.924629,87.327827],[43.924469,87.328171],[43.922958,87.331383],[43.92083,87.335472],[43.917881,87.340439],[43.915852,87.343498],[43.914989,87.344727],[43.9133,87.346977],[43.911129,87.349716],[43.908119,87.353493],[43.90696,87.35508],[43.905602,87.357002],[43.9044,87.358856],[43.90316,87.360962],[43.901939,87.36319],[43.900761,87.365501],[43.899651,87.367943],[43.898571,87.370491],[43.897621,87.373047],[43.89674,87.375633],[43.89579,87.37886],[43.895031,87.381783],[43.894871,87.382446],[43.894279,87.385109],[43.893951,87.386879],[43.893879,87.387268],[43.893501,87.389687],[43.893108,87.392593],[43.892899,87.394691],[43.892689,87.397362],[43.892529,87.400497],[43.892509,87.400887],[43.892479,87.404518],[43.89249,87.407967],[43.89249,87.411003],[43.89246,87.414047],[43.892361,87.415756],[43.892189,87.417381],[43.89196,87.419029],[43.891548,87.42086],[43.891022,87.422783],[43.8904,87.424583],[43.88958,87.426697],[43.88855,87.429367],[43.888359,87.42984],[43.88744,87.43222],[43.887341,87.43248],[43.886429,87.434799],[43.886311,87.435089],[43.88559,87.436859],[43.88485,87.438332],[43.884232,87.439407],[43.883789,87.440033],[43.883591,87.440277],[43.882641,87.441483],[43.881592,87.442558],[43.880539,87.443443],[43.879509,87.444138],[43.878349,87.444763],[43.87767,87.44503],[43.877491,87.445091],[43.876438,87.445389],[43.875191,87.445633],[43.873199,87.445862],[43.87233,87.446022],[43.871521,87.446297],[43.8708,87.446678],[43.86998,87.447144],[43.869301,87.447701],[43.868549,87.44841],[43.867981,87.449081],[43.86739,87.449913],[43.866821,87.450859],[43.866261,87.452019],[43.865822,87.453217],[43.864849,87.456688],[43.86478,87.456963],[43.86433,87.458298],[43.863811,87.459641],[43.863071,87.461128],[43.862381,87.462318],[43.861549,87.463501],[43.860691,87.464523],[43.85965,87.465569],[43.859409,87.465797],[43.85841,87.466583],[43.85751,87.467148],[43.85651,87.467682],[43.855469,87.468079],[43.854439,87.468384],[43.853588,87.46859],[43.853081,87.468727],[43.851749,87.469116],[43.8503,87.469673],[43.849232,87.470154],[43.848011,87.470772],[43.847389,87.471123],[43.84705,87.471336],[43.8461,87.47197],[43.844799,87.472923],[43.84341,87.474068],[43.842701,87.474693],[43.84201,87.475243],[43.84111,87.475983],[43.83971,87.476959],[43.83831,87.477814],[43.83717,87.478394],[43.8358,87.478996],[43.83424,87.479584],[43.832649,87.480026],[43.832432,87.480072],[43.830681,87.480377],[43.814949,87.482323],[43.813801,87.482513],[43.81266,87.482819],[43.81208,87.482986],[43.811771,87.483124],[43.810558,87.483627],[43.809471,87.4842],[43.808338,87.48494],[43.807209,87.485786],[43.806221,87.486656],[43.80513,87.487793],[43.804131,87.489014],[43.803341,87.490128],[43.802521,87.491386],[43.801628,87.492851],[43.80098,87.493896],[43.800289,87.494873],[43.79995,87.495247],[43.799122,87.496063],[43.798279,87.496712],[43.797352,87.497269],[43.796452,87.497643],[43.79562,87.497864],[43.79528,87.497917],[43.794739,87.497971],[43.79393,87.497971],[43.793282,87.497902],[43.792622,87.497749],[43.79195,87.497513],[43.79126,87.497223],[43.790421,87.496727],[43.78997,87.496391],[43.789669,87.496162],[43.78923,87.495773],[43.788609,87.495148],[43.786831,87.492996],[43.784351,87.489883],[43.78339,87.4888],[43.78244,87.487953],[43.781559,87.487282],[43.780479,87.486618],[43.779621,87.486221],[43.778622,87.485832],[43.777359,87.485489],[43.768581,87.484177],[43.7672,87.483994],[43.765968,87.483688],[43.76461,87.483208],[43.763302,87.482597],[43.762199,87.481934],[43.760948,87.481003],[43.759979,87.480133],[43.75798,87.478256],[43.75629,87.476753],[43.755219,87.475883],[43.75386,87.475052],[43.752739,87.474487],[43.751438,87.473969],[43.750031,87.473557],[43.749001,87.473343],[43.747791,87.473244],[43.74649,87.47319],[43.745319,87.473297],[43.744019,87.473534],[43.742809,87.473877],[43.741699,87.474297],[43.74049,87.474876],[43.739391,87.47554],[43.738281,87.476303],[43.73737,87.477051],[43.73629,87.478119],[43.735081,87.479286],[43.733238,87.481216],[43.72575,87.488892],[43.72366,87.490959],[43.722832,87.491814],[43.722229,87.492439],[43.721432,87.493263],[43.719742,87.494972],[43.717701,87.497032],[43.715801,87.499092],[43.713329,87.501373],[43.711281,87.503128],[43.708069,87.505676],[43.705551,87.507523],[43.702839,87.509422],[43.70277,87.509468],[43.688221,87.519676],[43.686871,87.520798],[43.685829,87.521828],[43.68462,87.523239],[43.683552,87.524712],[43.682499,87.526443],[43.68145,87.528549],[43.680691,87.530472],[43.68005,87.532501],[43.679531,87.534561],[43.679199,87.536484],[43.678959,87.538696],[43.6786,87.543793],[43.67857,87.544243],[43.67757,87.558968],[43.67749,87.560387],[43.677399,87.561157],[43.67728,87.562157],[43.677139,87.563583],[43.67701,87.564293],[43.67683,87.564903],[43.676601,87.565376],[43.676239,87.56588],[43.675919,87.566231],[43.675499,87.566544],[43.674992,87.56675],[43.674511,87.566833],[43.67387,87.566788],[43.67218,87.566673],[43.67149,87.566566],[43.667702,87.566078],[43.66563,87.565826],[43.664051,87.56575],[43.662689,87.565804],[43.661449,87.565971],[43.660259,87.566231],[43.659241,87.566559],[43.65818,87.566978],[43.657131,87.567467],[43.655708,87.568199],[43.649658,87.571487],[43.639301,87.577278],[43.637989,87.578117],[43.636768,87.579117],[43.635891,87.580017],[43.635071,87.58107],[43.634281,87.582336],[43.633598,87.583778],[43.633041,87.585251],[43.63274,87.586411],[43.632462,87.587967],[43.63224,87.589622],[43.632118,87.591454],[43.631851,87.597633],[43.63166,87.602814],[43.631641,87.603279],[43.631451,87.607712],[43.631241,87.612137],[43.631008,87.615463],[43.630951,87.616127],[43.630699,87.618637],[43.630329,87.621849],[43.62991,87.62468],[43.629162,87.629738],[43.627029,87.64415],[43.626369,87.648972],[43.626221,87.650948],[43.626209,87.652649],[43.626259,87.654282],[43.626381,87.655884],[43.626579,87.657341],[43.626831,87.658737],[43.627178,87.6605],[43.628189,87.664627],[43.62838,87.665329],[43.629429,87.669518],[43.629879,87.671638],[43.630192,87.673363],[43.63036,87.674721],[43.630501,87.676178],[43.630569,87.677811],[43.63055,87.679382],[43.630421,87.681129],[43.63026,87.682762],[43.630001,87.684677],[43.62574,87.709663],[43.62455,87.716537],[43.624481,87.717003],[43.624031,87.719711],[43.623959,87.720032],[43.62365,87.721848],[43.62323,87.724319],[43.619122,87.748306],[43.618641,87.750763],[43.618141,87.753036],[43.617962,87.754066],[43.60783,87.790024],[43.606331,87.79483],[43.604469,87.798782],[43.598629,87.809593],[43.5658,87.868134],[43.56356,87.873283],[43.562561,87.877747],[43.553478,87.936623],[43.550369,87.947952],[43.548012,87.953453],[43.545639,87.958076],[43.54229,87.962029],[43.51017,87.990517],[43.5047,87.995667],[43.501419,87.997803],[43.498638,87.998932],[43.49448,88],[43.492001,88.000366],[43.490589,88.001099],[43.48933,88.002701],[43.487259,88.007523],[43.485432,88.01181],[43.473808,88.040779],[43.471821,88.044037],[43.451771,88.064278],[43.42305,88.092621],[43.421719,88.094742],[43.418388,88.102074],[43.41431,88.110977],[43.40517,88.127991],[43.40303,88.132248],[43.401909,88.137573],[43.401039,88.144524],[43.401039,88.14724],[43.401409,88.150192],[43.40102,88.15242],[43.398079,88.160744],[43.39703,88.162621],[43.395271,88.164429],[43.388039,88.171944],[43.386688,88.174652],[43.37188,88.212837],[43.369881,88.215889],[43.367619,88.218224],[43.363781,88.220337],[43.352619,88.226151],[43.350868,88.227867],[43.350121,88.229424],[43.348751,88.233704],[43.346882,88.247093],[43.347191,88.253166],[43.347919,88.274597],[43.347969,88.280197],[43.3475,88.284607],[43.343578,88.307373],[43.343201,88.309288],[43.342369,88.311203],[43.34161,88.312332],[43.340641,88.313347],[43.336269,88.316933],[43.335411,88.31813],[43.333851,88.322166],[43.332958,88.323196],[43.331371,88.325027],[43.329269,88.329193],[43.328281,88.330704],[43.32671,88.331947],[43.324421,88.333443],[43.31831,88.337143],[43.317211,88.338058],[43.316551,88.338982],[43.316002,88.339928],[43.312481,88.348618],[43.311829,88.349541],[43.308739,88.353241],[43.307331,88.3545],[43.305771,88.355309],[43.304501,88.35553],[43.303329,88.355553],[43.302132,88.355293],[43.301041,88.354797],[43.299999,88.354073],[43.299019,88.352921],[43.29567,88.347366],[43.294922,88.34639],[43.29427,88.345863],[43.293468,88.345444],[43.292549,88.345306],[43.286049,88.345741],[43.28421,88.346138],[43.279449,88.348213],[43.278389,88.348846],[43.277592,88.349823],[43.275612,88.354141],[43.275002,88.354927],[43.27446,88.355331],[43.273899,88.355469],[43.273232,88.355362],[43.272732,88.355019],[43.27166,88.353889],[43.270939,88.353447],[43.27021,88.353317],[43.26955,88.35347],[43.268181,88.354393],[43.264778,88.35762],[43.263809,88.358849],[43.263401,88.360359],[43.26244,88.370163],[43.261951,88.37146],[43.261261,88.372208],[43.26041,88.372498],[43.25938,88.372566],[43.256512,88.372383],[43.255489,88.372543],[43.25478,88.372917],[43.24931,88.377213],[43.246029,88.379967],[43.244301,88.382111],[43.23455,88.400726],[43.232761,88.408127],[43.232342,88.411072],[43.232262,88.423782],[43.231758,88.42601],[43.227589,88.431534],[43.22604,88.433823],[43.224918,88.436653],[43.222912,88.445251],[43.222118,88.44709],[43.220909,88.448799],[43.217781,88.45314],[43.21653,88.454224],[43.214489,88.455139],[43.21336,88.455887],[43.211441,88.458023],[43.2104,88.458809],[43.206848,88.46019],[43.20443,88.461479],[43.199009,88.465073],[43.196541,88.467239],[43.19408,88.470032],[43.192829,88.471207],[43.191368,88.472076],[43.189159,88.473167],[43.188202,88.473831],[43.186279,88.47554],[43.185108,88.476303],[43.183319,88.476707],[43.180149,88.477287],[43.17802,88.477966],[43.174019,88.479759],[43.172951,88.480476],[43.172161,88.481453],[43.169781,88.484947],[43.168968,88.485672],[43.168079,88.486183],[43.167301,88.486397],[43.16626,88.48629],[43.162991,88.485527],[43.161709,88.485367],[43.16024,88.485497],[43.158871,88.485817],[43.157822,88.486397],[43.15678,88.487129],[43.15575,88.488297],[43.15485,88.489777],[43.15295,88.493713],[43.151932,88.495148],[43.150249,88.497177],[43.147289,88.499817],[43.145618,88.500908],[43.11911,88.508789],[43.113972,88.510857],[43.10878,88.514526],[43.104771,88.516747],[43.095871,88.520363],[43.08585,88.524307],[43.085049,88.52462],[43.084221,88.527397],[43.083469,88.533073],[43.064529,88.645844],[43.063782,88.650993],[43.06353,88.655983],[43.064659,88.704552],[43.062901,88.758797],[43.062149,88.766693],[43.061272,88.770302],[43.060139,88.773048],[43.054749,88.780937],[43.034679,88.809776],[43.031158,88.816467],[43.022129,88.835701],[43.020741,88.840851],[43.01685,88.861969],[43.01511,88.895157],[43.014431,88.903923],[43.01189,88.944511],[43.010181,88.985939],[43.008678,89.023689],[43.00766,89.051407],[43.006378,89.084343],[43.00621,89.086533],[43.00592,89.088699],[43.005348,89.091614],[43.004471,89.094673],[42.995232,89.121597],[42.994888,89.122597],[42.993141,89.127441],[42.986832,89.144073],[42.986031,89.1464],[42.983082,89.154968],[42.980911,89.161613],[42.97858,89.169212],[42.975029,89.179268],[42.974419,89.18145],[42.974018,89.182877],[42.970001,89.211029],[42.96912,89.214462],[42.968922,89.214996],[42.967739,89.218063],[42.957939,89.240379],[42.949902,89.258751],[42.931519,89.301567],[42.922131,89.323463],[42.92075,89.327423],[42.919739,89.332222],[42.919361,89.336693],[42.920872,89.430923],[42.92112,89.450844],[42.920872,89.456848],[42.91634,89.50766],[42.91534,89.513321],[42.912819,89.523277],[42.912071,89.528427],[42.91132,89.550583],[42.91169,89.55246],[42.912701,89.55452],[42.916729,89.560028],[42.917099,89.560532],[42.91848,89.563278],[42.919609,89.566368],[42.921749,89.569633],[42.924389,89.571167],[42.926029,89.572372],[42.929161,89.573227],[42.93055,89.574257],[42.931801,89.575813],[42.93243,89.578209],[42.93243,89.584053],[42.93306,89.586617],[42.935951,89.593658],[42.93721,89.597092],[42.937969,89.6007],[42.938339,89.604637],[42.938091,89.609283],[42.936081,89.6213],[42.934952,89.625237],[42.933819,89.628853],[42.933441,89.632111],[42.933441,89.634857],[42.933941,89.645332],[42.933689,89.64962],[42.931801,89.66198],[42.92263,89.702316],[42.921879,89.705238],[42.921879,89.708328],[42.922249,89.711418],[42.924259,89.721718],[42.9245,89.722847],[42.925522,89.727898],[42.926029,89.730988],[42.926029,89.734077],[42.92577,89.736481],[42.901379,89.832443],[42.900501,89.836906],[42.900249,89.841187],[42.900249,89.845154],[42.902519,89.868317],[42.903271,89.875359],[42.903271,89.879303],[42.902889,89.882736],[42.90189,89.887199],[42.89333,89.916039],[42.882519,89.957413],[42.879749,89.968567],[42.87484,89.992432],[42.875099,90.001534],[42.876228,90.003593],[42.877361,90.007881],[42.87812,90.013542],[42.87849,90.033287],[42.87925,90.038597],[42.880501,90.043587],[42.883518,90.048897],[42.8839,90.050797],[42.883518,90.052513],[42.882019,90.064011],[42.882389,90.07534],[42.885159,90.088043],[42.887299,90.107613],[42.887299,90.111557],[42.885658,90.118088],[42.884529,90.125473],[42.884529,90.155167],[42.884781,90.160141],[42.88755,90.178169],[42.89032,90.194313],[42.891571,90.202888],[42.892578,90.218163],[42.89283,90.225548],[42.894341,90.255417],[42.89547,90.257637],[42.897228,90.260223],[42.91433,90.276871],[42.916088,90.278587],[42.92572,90.286217],[42.926281,90.286659],[42.928669,90.289574],[42.954681,90.325447],[42.965561,90.339417],[42.969109,90.352364],[42.96933,90.354347],[42.97477,90.391518],[42.975849,90.398308],[42.976601,90.404121],[42.976608,90.404427],[42.979778,90.425003],[42.980309,90.428658],[42.981098,90.434731],[42.983521,90.450653],[42.98632,90.469856],[42.986919,90.474617],[42.987289,90.476891],[42.98819,90.483231],[42.98856,90.485153],[42.98893,90.486382],[42.989491,90.487823],[42.998089,90.50766],[42.998421,90.508636],[42.998821,90.510246],[42.999931,90.518677],[43.000271,90.520767],[43.000511,90.522957],[43.001389,90.528778],[43.00177,90.531792],[43.001911,90.532593],[43.002289,90.5355],[43.003151,90.540283],[43.00349,90.541817],[43.00515,90.55069],[43.005402,90.551743],[43.005741,90.553596],[43.00655,90.559807],[43.006821,90.561119],[43.010551,90.585213],[43.010761,90.586189],[43.01086,90.586868],[43.011879,90.59243],[43.012051,90.593674],[43.014481,90.607651],[43.015041,90.611397],[43.01532,90.612556],[43.016499,90.6185],[43.016621,90.618858],[43.01749,90.624069],[43.017841,90.625748],[43.01783,90.625999],[43.01865,90.62989],[43.019321,90.633347],[43.019691,90.634842],[43.019711,90.635452],[43.020451,90.639526],[43.023109,90.652611],[43.0243,90.659431],[43.025982,90.66787],[43.026249,90.669579],[43.027802,90.678146],[43.028332,90.680779],[43.028751,90.683296],[43.028961,90.684067],[43.029202,90.685738],[43.02927,90.686523],[43.030109,90.691254],[43.030991,90.695862],[43.031811,90.700508],[43.03191,90.701439],[43.033859,90.712013],[43.034119,90.713043],[43.034389,90.713882],[43.034821,90.714951],[43.035488,90.716331],[43.037731,90.720207],[43.038509,90.721474],[43.03936,90.722672],[43.039669,90.723244],[43.039711,90.723442],[43.041012,90.7258],[43.049889,90.741318],[43.078011,90.789993],[43.079781,90.793114],[43.091789,90.813927],[43.094238,90.818253],[43.105728,90.83815],[43.127251,90.875664],[43.128132,90.877113],[43.129059,90.878807],[43.152161,90.918983],[43.15641,90.926468],[43.15712,90.927567],[43.15815,90.928741],[43.160381,90.930939],[43.16106,90.931686],[43.161839,90.932793],[43.162491,90.934036],[43.162708,90.934593],[43.163059,90.935707],[43.167259,90.954353],[43.174629,90.9879],[43.177311,90.999687],[43.186829,91.042557],[43.18734,91.045181],[43.193069,91.070633],[43.197281,91.089661],[43.198051,91.092934],[43.200958,91.105988],[43.201221,91.106888],[43.201569,91.107857],[43.2425,91.200439],[43.247059,91.210648],[43.26371,91.248741],[43.269489,91.261757],[43.271019,91.265343],[43.275181,91.274818],[43.277649,91.280586],[43.28059,91.287086],[43.282509,91.291519],[43.285599,91.298424],[43.296082,91.322212],[43.296822,91.323753],[43.297359,91.324638],[43.303131,91.333267],[43.309929,91.343613],[43.311359,91.345619],[43.315521,91.3517],[43.31625,91.352943],[43.31702,91.354584],[43.32486,91.374878],[43.32983,91.387619],[43.33807,91.410332],[43.343979,91.426453],[43.347961,91.437576],[43.348209,91.438461],[43.348942,91.440407],[43.3494,91.441437],[43.352039,91.44873],[43.352589,91.451378],[43.3535,91.460182],[43.354031,91.465851],[43.354301,91.468117],[43.355129,91.476349],[43.355499,91.478973],[43.361481,91.501579],[43.363602,91.509407],[43.364449,91.512863],[43.37183,91.539879],[43.3741,91.548363],[43.374298,91.548882],[43.374851,91.549858],[43.375061,91.550453],[43.375771,91.553467],[43.37603,91.555138],[43.375938,91.555389],[43.37709,91.559853],[43.377621,91.562492],[43.380009,91.581299],[43.381809,91.596481],[43.382011,91.597931],[43.382099,91.598396],[43.382301,91.598907],[43.382561,91.601357],[43.382629,91.602577],[43.382641,91.604263],[43.382542,91.606644],[43.382259,91.609413],[43.381939,91.611397],[43.37965,91.621933],[43.378841,91.625473],[43.3764,91.634987],[43.37545,91.637947],[43.37505,91.639877],[43.374619,91.641647],[43.370998,91.655388],[43.37027,91.658417],[43.365871,91.675323],[43.365059,91.678452],[43.364731,91.67955],[43.363499,91.684471],[43.361439,91.692139],[43.359531,91.699547],[43.359241,91.701263],[43.359169,91.702637],[43.35928,91.703987],[43.359509,91.705276],[43.359982,91.707161],[43.36982,91.742973],[43.372631,91.753021],[43.37392,91.757812],[43.37442,91.759483],[43.375198,91.762428],[43.375401,91.763397],[43.375561,91.764717],[43.375599,91.765999],[43.375408,91.768929],[43.37521,91.770554],[43.374908,91.772171],[43.37463,91.773232],[43.374088,91.774811],[43.373291,91.776604],[43.364761,91.792717],[43.364399,91.793503],[43.363998,91.794601],[43.36359,91.796387],[43.36343,91.797989],[43.363441,91.799316],[43.363579,91.800652],[43.364021,91.802567],[43.366032,91.808868],[43.37429,91.834282],[43.375271,91.837433],[43.381149,91.855637],[43.382408,91.8592],[43.38306,91.861214],[43.393181,91.890991],[43.394131,91.893608],[43.404839,91.925247],[43.407921,91.934532],[43.408772,91.936867],[43.410931,91.943413],[43.411652,91.945847],[43.41333,91.951942],[43.41539,91.959442],[43.4156,91.960617],[43.415649,91.961197],[43.415649,91.961807],[43.415539,91.963013],[43.415421,91.963593],[43.41518,91.964447],[43.413719,91.968903],[43.408131,91.984978],[43.38829,92.04274],[43.38768,92.044403],[43.384071,92.055069],[43.383888,92.055931],[43.383739,92.062576],[43.383549,92.063652],[43.383751,92.077217],[43.383621,92.07988],[43.379551,92.111923],[43.3783,92.121323],[43.37817,92.12278],[43.378181,92.123451],[43.378139,92.123787],[43.37804,92.124077],[43.378078,92.124092],[43.377602,92.12693],[43.376678,92.134521],[43.37648,92.134933],[43.37635,92.13591],[43.376438,92.136101],[43.37492,92.146538],[43.3741,92.150238],[43.373829,92.150787],[43.373161,92.151619],[43.371979,92.152588],[43.371311,92.152802],[43.368759,92.1539],[43.343491,92.165489],[43.336319,92.16864],[43.33614,92.16864],[43.333519,92.169991],[43.322121,92.175133],[43.315922,92.177841],[43.315189,92.178223],[43.31448,92.17868],[43.31414,92.178963],[43.313519,92.179672],[43.31295,92.180489],[43.311031,92.183868],[43.309029,92.187683],[43.308578,92.188721],[43.308182,92.190086],[43.30558,92.201569],[43.305191,92.203537],[43.305031,92.204117],[43.304661,92.205032],[43.304211,92.205818],[43.303791,92.206337],[43.300419,92.209373],[43.29726,92.213799],[43.29509,92.219322],[43.293221,92.224327],[43.29282,92.225693],[43.29261,92.226868],[43.29121,92.236771],[43.290798,92.238876],[43.290199,92.241379],[43.290039,92.241692],[43.289768,92.243027],[43.289742,92.243393],[43.289631,92.243736],[43.289581,92.245827],[43.2896,92.249359],[43.28965,92.249733],[43.28944,92.251373],[43.28904,92.253258],[43.288872,92.253853],[43.288399,92.254959],[43.28759,92.2565],[43.286591,92.257843],[43.28548,92.259117],[43.266258,92.280243],[43.26268,92.284241],[43.258411,92.288857],[43.257809,92.289658],[43.25742,92.290321],[43.256969,92.29129],[43.256691,92.292053],[43.256378,92.293137],[43.2561,92.294647],[43.25592,92.296593],[43.255692,92.301987],[43.255619,92.306412],[43.255081,92.324226],[43.254978,92.326187],[43.254929,92.3265],[43.25465,92.327293],[43.25452,92.328056],[43.254539,92.331291],[43.254822,92.3321],[43.25502,92.332977],[43.25502,92.33429],[43.255081,92.334824],[43.255112,92.336983],[43.25491,92.351593],[43.25494,92.351967],[43.255192,92.352547],[43.255161,92.358383],[43.255341,92.369583],[43.255348,92.373428],[43.25544,92.37973],[43.255489,92.381088],[43.25544,92.38237],[43.255562,92.386459],[43.255569,92.38871],[43.255501,92.3909],[43.255562,92.41449],[43.255508,92.41684],[43.25544,92.417953],[43.255112,92.442863],[43.255032,92.44442],[43.254902,92.451012],[43.254879,92.455528],[43.254799,92.458504],[43.254829,92.460274],[43.254902,92.460899],[43.255131,92.46122],[43.255089,92.468697],[43.25489,92.477119],[43.254978,92.48597],[43.25494,92.488167],[43.25486,92.489609],[43.254711,92.507919],[43.25457,92.517036],[43.254532,92.517326],[43.254589,92.518883],[43.25581,92.530167],[43.25584,92.53196],[43.25576,92.533012],[43.255421,92.53582],[43.253208,92.549698],[43.252701,92.552528],[43.252499,92.553307],[43.251751,92.555443],[43.250801,92.557281],[43.250229,92.55851],[43.243992,92.570717],[43.242409,92.573624],[43.242149,92.574242],[43.236401,92.585487],[43.230221,92.597183],[43.22961,92.598503],[43.228851,92.599838],[43.2285,92.600647],[43.227299,92.602959],[43.22636,92.604622],[43.225151,92.607018],[43.222401,92.612137],[43.221802,92.61338],[43.219791,92.61718],[43.218559,92.61972],[43.2174,92.62175],[43.216888,92.622757],[43.2164,92.624069],[43.214039,92.628708],[43.213139,92.630333],[43.2122,92.632301],[43.212051,92.632523],[43.211658,92.63279],[43.210991,92.632889],[43.21035,92.633072],[43.210129,92.633209],[43.20993,92.633461],[43.207069,92.639236],[43.206989,92.639481],[43.205688,92.641998],[43.20525,92.64299],[43.204369,92.644783],[43.20388,92.645653],[43.19825,92.65416],[43.197201,92.655479],[43.196789,92.656464],[43.196609,92.657181],[43.19635,92.6577],[43.196079,92.65802],[43.190941,92.662827],[43.190338,92.663452],[43.188599,92.665031],[43.186859,92.666748],[43.185692,92.668007],[43.184761,92.669159],[43.183418,92.670967],[43.180092,92.676376],[43.172909,92.687592],[43.17234,92.688583],[43.169239,92.693604],[43.168331,92.695328],[43.167881,92.696358],[43.167221,92.698227],[43.166851,92.6996],[43.165169,92.706772],[43.16357,92.714363],[43.163559,92.714729],[43.161999,92.72184],[43.16135,92.722961],[43.15799,92.729736],[43.156681,92.732277],[43.155411,92.734993],[43.154388,92.737671],[43.153999,92.739197],[43.15382,92.740334],[43.153301,92.742409],[43.152962,92.744377],[43.15284,92.745354],[43.152012,92.750618],[43.151588,92.752319],[43.15163,92.752579],[43.151291,92.753853],[43.150669,92.755867],[43.150249,92.757011],[43.14949,92.75869],[43.14801,92.761574],[43.14732,92.762558],[43.145931,92.7649],[43.144001,92.767769],[43.1413,92.771973],[43.139622,92.77475],[43.138191,92.777542],[43.13784,92.778351],[43.136761,92.78141],[43.133678,92.791237],[43.133209,92.792923],[43.132771,92.79425],[43.132648,92.794487],[43.13208,92.796402],[43.130611,92.801697],[43.130001,92.804459],[43.129471,92.807159],[43.12764,92.815422],[43.12764,92.815628],[43.127708,92.816093],[43.128059,92.817108],[43.12809,92.817642],[43.127239,92.822151],[43.124889,92.833717],[43.12468,92.834572],[43.124001,92.836807],[43.123409,92.83847],[43.121769,92.843559],[43.117249,92.856644],[43.116928,92.857742],[43.097961,92.913582],[43.09219,92.930397],[43.091251,92.932861],[43.089909,92.936729],[43.08939,92.938499],[43.088219,92.941933],[43.085678,92.949699],[43.08448,92.953049],[43.084339,92.95372],[43.083939,92.954758],[43.081841,92.961029],[43.081139,92.962883],[43.077202,92.974609],[43.073639,92.984818],[43.07309,92.986237],[43.072651,92.98764],[43.071579,92.990761],[43.070629,92.993958],[43.06773,93.002113],[43.06179,93.019722],[43.059059,93.027451],[43.05798,93.03083],[43.05611,93.036209],[43.055599,93.037857],[43.054531,93.040833],[43.0536,93.043671],[43.050701,93.051971],[43.048828,93.05748],[43.04847,93.058357],[43.04398,93.071747],[43.04361,93.072983],[43.036949,93.0923],[43.030769,93.110497],[43.030392,93.111504],[43.02821,93.117996],[43.02644,93.122902],[43.02552,93.125717],[43.021511,93.137383],[43.020081,93.141777],[43.019531,93.143211],[43.018318,93.146812],[43.014252,93.158577],[43.012951,93.162216],[43.012581,93.163368],[43.012489,93.163933],[43.011021,93.167953],[43.01017,93.170631],[43.009911,93.171303],[42.956379,93.327377],[42.943939,93.363609],[42.93602,93.384903],[42.923698,93.417068],[42.914711,93.439667],[42.90744,93.457962],[42.906872,93.459129],[42.90659,93.460068],[42.90519,93.464157],[42.90258,93.470917],[42.902351,93.471611],[42.90118,93.474586],[42.89896,93.47998],[42.897121,93.484833],[42.895458,93.488991],[42.89336,93.494431],[42.892899,93.495789],[42.892529,93.496559],[42.88739,93.512894],[42.887272,93.517189],[42.888271,93.531914],[42.862091,93.564423],[42.861511,93.564209],[42.861229,93.564102],[42.86145,93.564613],[42.861591,93.565399],[42.861431,93.566383],[42.86108,93.567436],[42.860889,93.568802],[42.860519,93.574074],[42.860298,93.582787],[42.859718,93.588753],[42.859089,93.594093],[42.858608,93.596024],[42.858109,93.597328],[42.85775,93.598083],[42.844662,93.621597],[42.833488,93.641823],[42.828079,93.651497],[42.825699,93.655746],[42.824928,93.657333],[42.82415,93.659142],[42.823341,93.661308],[42.82259,93.663757],[42.821941,93.666389],[42.821411,93.669212],[42.82106,93.672157],[42.820869,93.675217],[42.820148,93.715927],[42.819351,93.749474],[42.819149,93.751984],[42.81884,93.754433],[42.81839,93.756721],[42.817348,93.760773],[42.816341,93.763344],[42.815842,93.763969],[42.81535,93.764908],[42.814701,93.766747],[42.812519,93.771149],[42.812069,93.772324],[42.811932,93.773102],[42.727871,93.941811],[42.721931,93.953537],[42.720589,93.955933],[42.719109,93.958252],[42.717548,93.960472],[42.699131,93.982513],[42.699059,93.983383],[42.698891,93.983681],[42.698071,93.984612],[42.696949,93.986053],[42.695301,93.987839],[42.69413,93.989487],[42.69381,93.99012],[42.69331,93.990646],[42.692101,93.991898],[42.69136,93.992996],[42.69014,93.994179],[42.687519,93.99733],[42.687038,93.997597],[42.686771,93.99736],[42.686432,93.997581],[42.65414,94.036118],[42.646832,94.044739],[42.645691,94.045403],[42.644489,94.046288],[42.644058,94.046982],[42.643921,94.047897],[42.64352,94.048683],[42.615822,94.081642],[42.615479,94.082474],[42.61515,94.083054],[42.61348,94.085068],[42.613319,94.085991],[42.612419,94.087349],[42.611771,94.087723],[42.610729,94.087997],[42.610352,94.088097],[42.5938,94.107742],[42.591869,94.110123],[42.591282,94.110817],[42.576759,94.127983],[42.57444,94.130577],[42.574371,94.130829],[42.55592,94.152588],[42.5546,94.153893],[42.552959,94.1549],[42.55114,94.155441],[42.549179,94.155487],[42.511021,94.154877],[42.50568,94.154716],[42.48864,94.154488],[42.479259,94.154243],[42.455231,94.153893],[42.45348,94.15358],[42.452808,94.153816],[42.416431,94.153236],[42.404751,94.152946],[42.390621,94.152786],[42.387569,94.152687],[42.38446,94.152702],[42.37709,94.15255],[42.375671,94.152588],[42.374401,94.152344],[42.37154,94.150558],[42.36993,94.14994],[42.368191,94.150368],[42.36639,94.151428],[42.364391,94.152222],[42.36224,94.152328],[42.34985,94.15213],[42.347618,94.152443],[42.345421,94.153099],[42.343281,94.154137],[42.341251,94.155533],[42.33934,94.15728],[42.33762,94.159363],[42.323891,94.17894],[42.299648,94.213142],[42.29924,94.213348],[42.29882,94.213783],[42.292431,94.222908],[42.292061,94.223824],[42.291611,94.224564],[42.26054,94.268501],[42.259979,94.269096],[42.258591,94.268639],[42.25832,94.269371],[42.258259,94.271477],[42.25798,94.272148],[42.221859,94.32328],[42.21785,94.328712],[42.201809,94.351463],[42.186401,94.3731],[42.18565,94.374268],[42.182468,94.378754],[42.17992,94.382103],[42.07518,94.501556],[42.07399,94.503014],[42.071751,94.506172],[42.070728,94.507843],[42.069248,94.510452],[42.05822,94.531387],[42.05555,94.536324],[42.034328,94.57663],[42.028992,94.586594],[42.01165,94.619476],[42.006409,94.629227],[42.002441,94.636864],[41.996479,94.647957],[41.97168,94.694656],[41.970669,94.696457],[41.96846,94.699707],[41.964611,94.704811],[41.961651,94.708549],[41.953011,94.719757],[41.951698,94.721367],[41.93182,94.747139],[41.928169,94.751717],[41.92601,94.754211],[41.917702,94.764259],[41.907219,94.776627],[41.906189,94.778198],[41.905659,94.779518],[41.90535,94.780724],[41.905182,94.781952],[41.905979,94.819061],[41.905891,94.82193],[41.904789,94.824211],[41.896778,94.833511],[41.889599,94.842018],[41.88821,94.843773],[41.886959,94.845734],[41.885899,94.847763],[41.872711,94.87912],[41.87204,94.881699],[41.871601,94.88427],[41.87085,94.886482],[41.86935,94.887657],[41.86618,94.889374],[41.864529,94.890427],[41.854229,94.897636],[41.853321,94.898354],[41.850658,94.900124],[41.845459,94.90377],[41.843231,94.905518],[41.84193,94.906731],[41.834141,94.91481],[41.83263,94.916656],[41.831348,94.918793],[41.830341,94.921066],[41.822659,94.947006],[41.822681,94.946938],[41.821529,94.950897],[41.811859,94.981277],[41.811451,94.982964],[41.811062,94.987167],[41.80801,95.009956],[41.807579,95.012787],[41.803242,95.035828],[41.80278,95.037987],[41.801811,95.039459],[41.800449,95.040283],[41.79937,95.041672],[41.798981,95.043709],[41.798931,95.046043],[41.79929,95.048683],[41.801491,95.056557],[41.807201,95.081543],[41.807819,95.084007],[41.808601,95.086418],[41.81176,95.094139],[41.812141,95.095657],[41.813389,95.102814],[41.81377,95.104523],[41.813801,95.106232],[41.81308,95.107803],[41.805882,95.116547],[41.79686,95.127617],[41.795639,95.128998],[41.795818,95.128799],[41.795311,95.129143],[41.795021,95.12973],[41.794418,95.130508],[41.793739,95.131241],[41.792912,95.131813],[41.791931,95.132187],[41.787621,95.133377],[41.785759,95.134048],[41.783821,95.13443],[41.77948,95.133087],[41.777401,95.133003],[41.769032,95.136383],[41.767269,95.13694],[41.761452,95.13842],[41.759869,95.138908],[41.758209,95.139793],[41.725281,95.170288],[41.716209,95.178574],[41.713089,95.181328],[41.7062,95.186333],[41.70443,95.187531],[41.702549,95.188553],[41.69426,95.191917],[41.69257,95.192741],[41.69117,95.193787],[41.690331,95.194557],[41.685749,95.199341],[41.67609,95.209084],[41.674431,95.210327],[41.67263,95.21125],[41.670658,95.211891],[41.66626,95.213074],[41.664299,95.214027],[41.662991,95.215828],[41.660839,95.219803],[41.65979,95.221008],[41.65844,95.221863],[41.648361,95.225349],[41.646259,95.226189],[41.644218,95.227188],[41.608528,95.247704],[41.60677,95.248993],[41.605129,95.250458],[41.603642,95.25209],[41.55867,95.303436],[41.557178,95.304878],[41.55547,95.306084],[41.5536,95.306976],[41.537659,95.313148],[41.521111,95.319687],[41.503269,95.326576],[41.499722,95.327744],[41.486279,95.331001],[41.483829,95.33149],[41.48151,95.331749],[41.418961,95.336037],[41.41769,95.336189],[41.34993,95.340813],[41.348049,95.341026],[41.346149,95.341423],[41.309109,95.351532],[41.299801,95.353996],[41.295872,95.355118],[41.286308,95.357643],[41.27911,95.359596],[41.267288,95.36293],[41.239849,95.370354],[41.235882,95.371529],[41.23431,95.371887],[41.230549,95.372963],[41.227638,95.37355],[41.210209,95.375168],[41.1908,95.376801],[41.1786,95.377998],[41.171768,95.378571],[41.170151,95.37912],[41.145889,95.396797],[41.144199,95.398277],[41.142658,95.39991],[41.14127,95.401672],[41.125759,95.42276],[41.12434,95.424553],[41.122841,95.426117],[41.121288,95.427467],[41.112598,95.434418],[41.11095,95.435333],[41.107349,95.436142],[41.10556,95.436951],[41.09116,95.448433],[41.089539,95.449463],[41.084831,95.452087],[41.083542,95.45327],[41.082561,95.454788],[41.078522,95.461853],[41.077301,95.463303],[41.075081,95.464668],[41.07473,95.464867],[41.073681,95.465584],[41.072338,95.466461],[41.06773,95.469482],[41.06414,95.472038],[41.061741,95.472977],[41.059601,95.473038],[41.05727,95.472641],[41.04948,95.469711],[41.047211,95.468109],[41.045151,95.467041],[41.043018,95.467041],[41.04055,95.467773],[41.037159,95.469513],[41.035561,95.469711],[41.033291,95.469711],[41.030491,95.469437],[41.028629,95.469437],[41.024899,95.470383],[41.021969,95.470909],[41.020901,95.470711],[41.019501,95.469383],[41.01804,95.468109],[41.015301,95.466637],[41.013241,95.466309],[41.008911,95.465981],[41.00671,95.466309],[41.004841,95.467308],[41.003052,95.468842],[41.000679,95.471848],[40.997429,95.475533],[40.993698,95.478722],[40.941299,95.523643],[40.882931,95.57193],[40.860771,95.59272],[40.852169,95.60096],[40.85096,95.601868],[40.849178,95.602623],[40.84457,95.604057],[40.84127,95.604858],[40.835602,95.606003],[40.832191,95.606857],[40.827271,95.608528],[40.824211,95.60997],[40.818081,95.613297],[40.815659,95.614197],[40.794498,95.620667],[40.79213,95.62159],[40.790161,95.622757],[40.739639,95.653053],[40.683159,95.68631],[40.560768,95.758293],[40.559139,95.75927],[40.557941,95.760551],[40.55727,95.761803],[40.556862,95.763359],[40.55566,95.769852],[40.55521,95.773392],[40.550732,95.791092],[40.5439,95.818512],[40.54306,95.821533],[40.543018,95.821587],[40.540649,95.831047],[40.53907,95.837341],[40.530319,95.872833],[40.529411,95.877419],[40.528881,95.881477],[40.528851,95.881737],[40.528599,95.886452],[40.528671,95.890549],[40.528831,95.892937],[40.529091,95.895401],[40.531139,95.913231],[40.531509,95.916992],[40.532009,95.922897],[40.532108,95.924156],[40.532829,95.935677],[40.533211,95.940323],[40.533291,95.941277],[40.533428,95.942421],[40.533798,95.945557],[40.534019,95.947113],[40.535252,95.954674],[40.53624,95.964233],[40.537189,95.976349],[40.539242,95.992767],[40.539989,96.005859],[40.54044,96.010193],[40.541,96.01384],[40.542919,96.026047],[40.543171,96.028214],[40.54752,96.070686],[40.54813,96.076599],[40.548721,96.084511],[40.549389,96.096077],[40.550598,96.11734],[40.55098,96.121567],[40.551849,96.128128],[40.556881,96.156647],[40.557098,96.158058],[40.557629,96.161926],[40.557949,96.165993],[40.55872,96.179993],[40.560951,96.199028],[40.563648,96.226624],[40.568291,96.274063],[40.56879,96.278961],[40.569698,96.285233],[40.57069,96.290207],[40.571339,96.292847],[40.57394,96.302109],[40.57439,96.30407],[40.574661,96.305313],[40.575359,96.308998],[40.57552,96.309914],[40.575581,96.310371],[40.575699,96.31115],[40.575871,96.312462],[40.576149,96.314682],[40.576519,96.319397],[40.576649,96.32518],[40.576401,96.338333],[40.57526,96.417137],[40.575562,96.426323],[40.576611,96.438957],[40.57682,96.443626],[40.576698,96.448219],[40.576618,96.451401],[40.576591,96.453537],[40.575729,96.465378],[40.575241,96.483818],[40.574841,96.488899],[40.573952,96.494553],[40.570702,96.510117],[40.569939,96.516006],[40.569469,96.522537],[40.569019,96.527107],[40.568401,96.531517],[40.567451,96.536507],[40.566219,96.54361],[40.565731,96.550591],[40.565731,96.553001],[40.566029,96.558853],[40.566509,96.568413],[40.566341,96.575249],[40.565929,96.582329],[40.565948,96.586288],[40.5662,96.590271],[40.566681,96.594307],[40.56736,96.599838],[40.567348,96.608368],[40.56723,96.61602],[40.567322,96.618179],[40.56736,96.618927],[40.56749,96.620659],[40.56765,96.622299],[40.5686,96.630157],[40.568958,96.634697],[40.571991,96.703812],[40.572929,96.710403],[40.575539,96.721573],[40.576149,96.725319],[40.576641,96.731293],[40.576611,96.736549],[40.576099,96.742088],[40.574718,96.750931],[40.574219,96.758362],[40.57423,96.758377],[40.574219,96.758362],[40.574409,96.762466],[40.575451,96.787216],[40.575531,96.792084],[40.5755,96.794434],[40.57523,96.799507],[40.574692,96.804893],[40.574379,96.807129],[40.570881,96.826408],[40.56163,96.876579],[40.559639,96.891777],[40.558578,96.896599],[40.558071,96.89843],[40.556839,96.9021],[40.555069,96.906273],[40.55328,96.909668],[40.540058,96.932861],[40.537289,96.936836],[40.536251,96.938164],[40.53344,96.941261],[40.530682,96.943817],[40.528179,96.94577],[40.5242,96.948303],[40.504028,96.959183],[40.497231,96.96241],[40.477169,96.971222],[40.476452,96.97155],[40.47179,96.973953],[40.467999,96.976357],[40.460899,96.981567],[40.451939,96.988083],[40.448231,96.990463],[40.44437,96.99221],[40.433559,96.996193],[40.428959,96.998672],[40.425781,97.000961],[40.424198,97.002312],[40.406921,97.019852],[40.404881,97.021606],[40.402088,97.023651],[40.40044,97.024658],[40.396702,97.026466],[40.391609,97.028053],[40.38802,97.028587],[40.381908,97.028717],[40.378609,97.02903],[40.375011,97.029701],[40.372089,97.03054],[40.359791,97.034866],[40.35503,97.03727],[40.35025,97.040588],[40.345829,97.044617],[40.341431,97.049957],[40.333191,97.061417],[40.330521,97.06485],[40.327141,97.068367],[40.323559,97.071114],[40.317268,97.075447],[40.31308,97.077667],[40.30891,97.079277],[40.305,97.080132],[40.30098,97.080467],[40.2971,97.080467],[40.293091,97.080917],[40.288311,97.082108],[40.26688,97.089203],[40.261761,97.091362],[40.257099,97.094933],[40.254799,97.097038],[40.237301,97.113998],[40.235271,97.116211],[40.232948,97.119034],[40.22443,97.130653],[40.220871,97.135269],[40.219921,97.136414],[40.217701,97.138802],[40.205471,97.150963],[40.202042,97.154533],[40.200539,97.156303],[40.198158,97.159508],[40.19643,97.162216],[40.194881,97.164932],[40.189041,97.176514],[40.188332,97.177803],[40.186069,97.181587],[40.185371,97.182716],[40.18232,97.18705],[40.175079,97.196701],[40.172459,97.200439],[40.17054,97.203568],[40.164322,97.214851],[40.157082,97.225838],[40.156799,97.226334],[40.155731,97.228149],[40.154251,97.23082],[40.154121,97.231056],[40.153229,97.232811],[40.151112,97.237022],[40.151009,97.237213],[40.150982,97.237267],[40.15041,97.238358],[40.148998,97.240868],[40.148609,97.241547],[40.146091,97.245667],[40.13966,97.255379],[40.138168,97.257477],[40.134159,97.262863],[40.132679,97.264732],[40.132481,97.264969],[40.131519,97.266159],[40.130619,97.26725],[40.125278,97.273499],[40.12468,97.274246],[40.124599,97.274353],[40.12376,97.275459],[40.123138,97.276314],[40.12138,97.278954],[40.11932,97.282463],[40.11787,97.285347],[40.11655,97.2883],[40.11364,97.29567],[40.112259,97.298973],[40.11026,97.303169],[40.108639,97.30616],[40.105339,97.311546],[40.103359,97.314743],[40.102581,97.315987],[40.0993,97.32074],[40.09594,97.324959],[40.0928,97.328407],[40.06662,97.353867],[40.065639,97.354958],[40.064789,97.355988],[40.063549,97.357536],[40.061871,97.359947],[40.06131,97.360832],[40.05941,97.364128],[40.058689,97.36557],[40.057331,97.368607],[40.05637,97.371147],[40.055241,97.374786],[40.05481,97.376282],[40.053959,97.380447],[40.05278,97.388863],[40.05191,97.393333],[40.050781,97.397476],[40.049431,97.401314],[40.047131,97.406311],[40.045422,97.409241],[40.042198,97.414253],[40.040081,97.417473],[40.037971,97.421021],[40.036121,97.424217],[40.034519,97.427292],[40.034119,97.428253],[40.03228,97.431709],[40.032021,97.43222],[40.029869,97.437187],[40.028511,97.441032],[40.025341,97.452019],[40.024109,97.455811],[40.023418,97.457764],[40.022968,97.458961],[40.02103,97.463692],[40.02071,97.464432],[40.013981,97.47892],[40.0061,97.496628],[40.00304,97.503929],[40.000721,97.509857],[39.995461,97.523727],[39.993599,97.52903],[39.990631,97.53772],[39.989929,97.539772],[39.98962,97.540733],[39.98864,97.543823],[39.988411,97.544548],[39.986259,97.552422],[39.98164,97.571747],[39.97945,97.579453],[39.979401,97.57962],[39.979351,97.579788],[39.979118,97.580513],[39.97887,97.581322],[39.976971,97.587341],[39.97562,97.59185],[39.974819,97.594749],[39.96983,97.615303],[39.96867,97.621437],[39.967949,97.626289],[39.96727,97.630531],[39.967091,97.631401],[39.96701,97.631737],[39.966751,97.63295],[39.966461,97.634132],[39.965889,97.6362],[39.964611,97.64003],[39.96413,97.641243],[39.96328,97.643227],[39.961391,97.647102],[39.95739,97.655563],[39.956459,97.657761],[39.952839,97.667587],[39.951511,97.671204],[39.950329,97.673973],[39.94931,97.676064],[39.948441,97.677696],[39.947762,97.678322],[39.947701,97.679047],[39.945889,97.682449],[39.945339,97.683403],[39.942699,97.687782],[39.940701,97.691788],[39.940109,97.693176],[39.93856,97.697433],[39.937222,97.702263],[39.93539,97.708588],[39.93507,97.709503],[39.933929,97.712547],[39.931839,97.717484],[39.92952,97.723167],[39.926521,97.73188],[39.922089,97.748093],[39.920631,97.752792],[39.920231,97.753883],[39.918991,97.757027],[39.916229,97.762711],[39.9146,97.765404],[39.905449,97.779282],[39.90078,97.786346],[39.90041,97.786903],[39.900028,97.787529],[39.899231,97.788834],[39.897919,97.791153],[39.897499,97.791946],[39.896629,97.793671],[39.896309,97.794373],[39.896091,97.794868],[39.894321,97.799217],[39.891281,97.808968],[39.889759,97.813011],[39.88876,97.81517],[39.886631,97.819153],[39.883789,97.823463],[39.883369,97.824059],[39.879879,97.829247],[39.87809,97.832474],[39.876228,97.836693],[39.875481,97.838623],[39.875309,97.839104],[39.874962,97.840103],[39.874771,97.840714],[39.874722,97.840858],[39.874321,97.842209],[39.87315,97.847214],[39.872742,97.849541],[39.872719,97.849663],[39.871429,97.857353],[39.870522,97.862541],[39.87038,97.863327],[39.869308,97.869034],[39.86927,97.869331],[39.868679,97.872292],[39.868259,97.874458],[39.868149,97.875038],[39.867668,97.877579],[39.867458,97.878647],[39.867161,97.880318],[39.86507,97.893143],[39.864841,97.894348],[39.86422,97.897163],[39.863911,97.898407],[39.863331,97.900642],[39.862461,97.903877],[39.861549,97.907227],[39.860451,97.910782],[39.859531,97.913383],[39.859241,97.914131],[39.85743,97.918419],[39.854691,97.92511],[39.85107,97.93644],[39.84874,97.942169],[39.842659,97.954224],[39.840599,97.958992],[39.839581,97.961853],[39.839069,97.963516],[39.838879,97.964233],[39.8386,97.965218],[39.838329,97.966293],[39.837719,97.969017],[39.83675,97.975533],[39.836411,97.980408],[39.835941,97.993233],[39.835751,97.995903],[39.835651,97.996964],[39.835098,98.001427],[39.83408,98.007278],[39.831661,98.019257],[39.830971,98.021942],[39.830681,98.022926],[39.830608,98.023193],[39.829281,98.027473],[39.827961,98.031921],[39.82518,98.042007],[39.825031,98.042557],[39.824108,98.045792],[39.823841,98.046638],[39.823441,98.047951],[39.82259,98.050499],[39.821659,98.053322],[39.821201,98.054817],[39.821121,98.055061],[39.8181,98.065804],[39.81255,98.082474],[39.808788,98.093147],[39.802261,98.115982],[39.801849,98.117073],[39.80143,98.118294],[39.800541,98.119141],[39.79985,98.119301],[39.799099,98.119057],[39.79842,98.118523],[39.796982,98.117729],[39.797039,98.118134],[39.79652,98.124336],[39.795589,98.126411],[39.795639,98.127251],[39.79586,98.127724],[39.796619,98.128571],[39.797409,98.129433],[39.798111,98.130386],[39.798328,98.130989],[39.798359,98.131729],[39.798031,98.133743],[39.79755,98.134857],[39.797009,98.135643],[39.796982,98.135674],[39.795631,98.137154],[39.793541,98.139603],[39.792252,98.141647],[39.791519,98.143112],[39.790741,98.145149],[39.79002,98.147614],[39.78804,98.154617],[39.780701,98.180634],[39.780441,98.182091],[39.780369,98.184196],[39.780418,98.184914],[39.78051,98.18557],[39.780621,98.186218],[39.780739,98.186783],[39.780972,98.187592],[39.781261,98.188377],[39.78223,98.190567],[39.783298,98.192757],[39.78352,98.193237],[39.784309,98.195053],[39.784859,98.196823],[39.785831,98.202904],[39.786282,98.204277],[39.78849,98.208946],[39.789669,98.211243],[39.790169,98.212196],[39.790649,98.213097],[39.795959,98.22258],[39.796169,98.223091],[39.79623,98.223351],[39.796291,98.223663],[39.79631,98.224037],[39.79631,98.224358],[39.796169,98.225693],[39.796021,98.227623],[39.795841,98.230141],[39.795841,98.23053],[39.79583,98.230713],[39.79578,98.231667],[39.795582,98.233299],[39.795071,98.242218],[39.794651,98.248848],[39.794151,98.250504],[39.79324,98.256889],[39.791481,98.268311],[39.788021,98.290779],[39.787079,98.297058],[39.786751,98.299362],[39.786461,98.301552],[39.786091,98.303917],[39.78603,98.304298],[39.785851,98.305321],[39.785561,98.306793],[39.785389,98.307648],[39.785061,98.309273],[39.784409,98.312523],[39.783039,98.321411],[39.782021,98.326538],[39.78178,98.327927],[39.78056,98.335876],[39.780079,98.339653],[39.779881,98.340431],[39.77956,98.34304],[39.77919,98.345444],[39.779011,98.347023],[39.778999,98.347427],[39.778149,98.352997],[39.777851,98.354439],[39.777699,98.356102],[39.776501,98.364517],[39.77597,98.367798],[39.77401,98.378723],[39.773579,98.380791],[39.770519,98.391006],[39.769279,98.395576],[39.76878,98.397713],[39.768452,98.39946],[39.767502,98.403862],[39.766529,98.408043],[39.765881,98.410362],[39.765621,98.41169],[39.76543,98.413017],[39.765171,98.415977],[39.76498,98.417648],[39.764271,98.422722],[39.764061,98.424698],[39.763851,98.427673],[39.763199,98.432503],[39.76268,98.440178],[39.76162,98.446182],[39.76141,98.447723],[39.761269,98.451622],[39.761139,98.452782],[39.760559,98.456367],[39.760319,98.458473],[39.76017,98.463516],[39.760139,98.469017],[39.759861,98.482643],[39.759819,98.487099],[39.759769,98.487679],[39.759571,98.488739],[39.7593,98.489487],[39.75909,98.489853],[39.75882,98.490143],[39.752739,98.493233],[39.752029,98.493523],[39.748878,98.495064],[39.738289,98.500366],[39.737671,98.500641],[39.736931,98.500282],[39.736752,98.500252],[39.73658,98.500671],[39.73679,98.50193],[39.736031,98.507088],[39.736031,98.507393],[39.735859,98.508347],[39.735641,98.50882],[39.7356,98.509163],[39.735699,98.509377],[39.735691,98.509933],[39.734879,98.515533],[39.734459,98.517387],[39.73423,98.518143],[39.73349,98.519363],[39.731339,98.522148],[39.7281,98.52726],[39.726971,98.529518],[39.72406,98.536087],[39.723068,98.540077],[39.71999,98.550377],[39.716782,98.56115],[39.71537,98.565041],[39.714031,98.566704],[39.713058,98.567459],[39.712219,98.569153],[39.71146,98.570107],[39.710419,98.571487],[39.70673,98.576279],[39.702721,98.58242],[39.69894,98.586761],[39.697819,98.588203],[39.684139,98.604286],[39.683121,98.605476],[39.68119,98.608124],[39.64846,98.658203],[39.644569,98.662773],[39.643269,98.664513],[39.643261,98.664833],[39.640518,98.667847],[39.607601,98.703133],[39.603149,98.708679],[39.601139,98.711227],[39.600971,98.711632],[39.59441,98.719849],[39.593201,98.721451],[39.59219,98.723343],[39.58913,98.733551],[39.587379,98.740196],[39.585281,98.747566],[39.586021,98.747627],[39.58485,98.749229],[39.582649,98.756844],[39.5784,98.772346],[39.576038,98.780312],[39.576111,98.780357],[39.574329,98.787033],[39.571388,98.82679],[39.571251,98.831139],[39.571301,98.872383],[39.571121,98.874039],[39.566021,98.892883],[39.565189,98.89576],[39.564991,98.895973],[39.562901,98.903687],[39.562199,98.905434],[39.561409,98.907211],[39.55806,98.91468],[39.55444,98.923119],[39.551739,98.928078],[39.550549,98.929718],[39.549809,98.930473],[39.543041,98.936996],[39.538151,98.939117],[39.5303,98.942497],[39.52425,98.944443],[39.522961,98.944969],[39.503269,98.959221],[39.49918,98.962677],[39.491112,98.96904],[39.488869,98.970703],[39.48769,98.971458],[39.474831,98.977982],[39.465591,98.982658],[39.464249,98.982803],[39.463219,98.98259],[39.44043,98.976547],[39.435268,98.975197],[39.430759,98.975433],[39.425461,98.975754],[39.419109,98.976158],[39.41626,98.976799],[39.41169,98.978249],[39.4104,98.978859],[39.409111,98.979713],[39.4021,98.985313],[39.380379,99.001549],[39.378712,99.00293],[39.372959,99.013206],[39.37006,99.019577],[39.368221,99.028664],[39.36755,99.030533],[39.365459,99.035042],[39.364899,99.036003],[39.363689,99.03862],[39.363079,99.040916],[39.363289,99.041077],[39.36293,99.042053],[39.363091,99.042236],[39.361801,99.045723],[39.359161,99.054321],[39.357269,99.060623],[39.356419,99.063431],[39.355801,99.069542],[39.35556,99.072449],[39.35223,99.082733],[39.35083,99.087013],[39.350349,99.089203],[39.349941,99.091743],[39.34956,99.092812],[39.348621,99.093613],[39.34539,99.09465],[39.344879,99.094971],[39.34433,99.095482],[39.343491,99.09729],[39.341419,99.103348],[39.341179,99.104057],[39.34127,99.104378],[39.340809,99.105591],[39.340618,99.106758],[39.34029,99.111366],[39.339458,99.122627],[39.339291,99.125473],[39.339031,99.125504],[39.339062,99.128487],[39.338871,99.13018],[39.33667,99.143822],[39.336281,99.145317],[39.32988,99.160294],[39.322922,99.176064],[39.321411,99.179459],[39.320782,99.180527],[39.318958,99.183006],[39.318039,99.184242],[39.317589,99.185204],[39.317451,99.185966],[39.317371,99.193848],[39.317188,99.195152],[39.31657,99.19735],[39.316299,99.198288],[39.315861,99.19986],[39.308239,99.227097],[39.296791,99.268066],[39.28944,99.29332],[39.28841,99.296143],[39.28421,99.303787],[39.280941,99.309776],[39.279888,99.311493],[39.275028,99.316841],[39.27433,99.318031],[39.272221,99.323334],[39.268768,99.333458],[39.26857,99.333878],[39.267639,99.335373],[39.26635,99.336998],[39.257931,99.347504],[39.257141,99.34848],[39.255829,99.350327],[39.254318,99.353149],[39.253361,99.35553],[39.23188,99.428017],[39.229439,99.436272],[39.22887,99.43763],[39.22739,99.439957],[39.227379,99.439842],[39.227371,99.440033],[39.224831,99.45179],[39.224781,99.453484],[39.22506,99.455002],[39.226871,99.460564],[39.2272,99.461502],[39.23122,99.469063],[39.232792,99.472069],[39.235748,99.478867],[39.235939,99.479828],[39.236271,99.48394],[39.236511,99.485748],[39.236938,99.48687],[39.237652,99.487846],[39.238331,99.488426],[39.238541,99.488548],[39.243401,99.489937],[39.24633,99.490753],[39.248489,99.491364],[39.249229,99.491653],[39.250969,99.492699],[39.25309,99.494164],[39.25983,99.497643],[39.261341,99.498772],[39.26313,99.498993],[39.263592,99.499229],[39.263969,99.499763],[39.264339,99.502136],[39.264141,99.505539],[39.26405,99.506943],[39.263851,99.509521],[39.263149,99.512421],[39.263081,99.513512],[39.26321,99.529457],[39.26326,99.543068],[39.265942,99.56086],[39.26627,99.562759],[39.266659,99.563828],[39.273312,99.579262],[39.276791,99.585587],[39.278049,99.588112],[39.27961,99.591179],[39.281841,99.596123],[39.28392,99.60022],[39.284031,99.600441],[39.284969,99.602753],[39.28653,99.607536],[39.292389,99.616859],[39.295189,99.621613],[39.296101,99.62326],[39.298328,99.627823],[39.3046,99.639008],[39.306141,99.642014],[39.30703,99.6437],[39.308552,99.646027],[39.309608,99.647614],[39.310169,99.648857],[39.311272,99.651543],[39.311722,99.653023],[39.314941,99.665878],[39.317089,99.671997],[39.325272,99.695152],[39.32645,99.698471],[39.329399,99.706573],[39.33012,99.709038],[39.330921,99.713821],[39.331009,99.715332],[39.330898,99.717041],[39.330791,99.718712],[39.330509,99.720238],[39.32444,99.733963],[39.321629,99.743492],[39.321362,99.745087],[39.32066,99.749489],[39.320358,99.750679],[39.319859,99.75238],[39.318211,99.756866],[39.315269,99.763817],[39.314651,99.765297],[39.3125,99.77124],[39.31179,99.773804],[39.307232,99.798157],[39.30724,99.798363],[39.30624,99.802261],[39.30579,99.803619],[39.304039,99.806503],[39.303089,99.808601],[39.301231,99.813339],[39.29937,99.818626],[39.29678,99.824249],[39.296059,99.825783],[39.293911,99.835258],[39.292961,99.837967],[39.29208,99.841263],[39.290489,99.84359],[39.289532,99.846039],[39.289379,99.847412],[39.289509,99.847923],[39.28949,99.851601],[39.289471,99.851898],[39.289619,99.854874],[39.289989,99.858093],[39.29121,99.868439],[39.29097,99.882759],[39.290371,99.885643],[39.289841,99.887009],[39.287552,99.891113],[39.286179,99.893799],[39.280209,99.907257],[39.279621,99.90831],[39.278042,99.910347],[39.275551,99.913368],[39.26358,99.931847],[39.247608,99.94902],[39.23772,99.959663],[39.233768,99.964027],[39.23381,99.964043],[39.232891,99.964813],[39.231831,99.965424],[39.229019,99.966759],[39.225101,99.967987],[39.223831,99.968613],[39.22287,99.969307],[39.221859,99.970322],[39.219028,99.973518],[39.217831,99.97477],[39.21484,99.977562],[39.21381,99.978691],[39.212311,99.981117],[39.211529,99.982117],[39.19817,99.993927],[39.19735,99.994827],[39.196949,99.995842],[39.196239,100.002251],[39.195889,100.00692],[39.19577,100.009262],[39.195641,100.010391],[39.19548,100.011673],[39.195061,100.01268],[39.193489,100.014412],[39.19268,100.015167],[39.192551,100.015137],[39.19252,100.01532],[39.19136,100.016487],[39.188541,100.019142],[39.18771,100.019958],[39.186081,100.02076],[39.182491,100.021347],[39.181751,100.021812],[39.181061,100.022751],[39.179779,100.025513],[39.17931,100.026199],[39.177872,100.028793],[39.177399,100.029953],[39.177029,100.031303],[39.176819,100.033096],[39.17691,100.037521],[39.176941,100.039017],[39.176842,100.043663],[39.175491,100.048759],[39.1749,100.050201],[39.174461,100.051987],[39.173759,100.055367],[39.172501,100.060173],[39.172588,100.060211],[39.172401,100.06073],[39.173038,100.069504],[39.17247,100.071899],[39.17226,100.073692],[39.17321,100.080002],[39.173149,100.081558],[39.173031,100.082077],[39.17268,100.083633],[39.172081,100.086273],[39.172218,100.086403],[39.171829,100.086838],[39.169621,100.091873],[39.1684,100.095497],[39.167149,100.098007],[39.16608,100.099167],[39.164761,100.100052],[39.16383,100.100693],[39.161388,100.10215],[39.16087,100.102692],[39.160172,100.103897],[39.157539,100.112488],[39.156929,100.113617],[39.156281,100.11451],[39.154079,100.11734],[39.153561,100.118408],[39.15316,100.119682],[39.15292,100.122673],[39.153061,100.123978],[39.154091,100.125526],[39.15649,100.128166],[39.157162,100.129143],[39.157452,100.130127],[39.156582,100.138634],[39.15657,100.138817],[39.156021,100.142693],[39.15493,100.14962],[39.15379,100.154404],[39.152962,100.157829],[39.151051,100.167427],[39.150871,100.167763],[39.147491,100.171143],[39.14727,100.171333],[39.14608,100.172897],[39.145721,100.173111],[39.143879,100.175812],[39.139511,100.181587],[39.138802,100.182419],[39.136372,100.184402],[39.135288,100.185448],[39.131851,100.192169],[39.131569,100.193153],[39.131149,100.197807],[39.130459,100.201263],[39.130039,100.202682],[39.127258,100.208557],[39.125149,100.213287],[39.121849,100.219254],[39.12056,100.221153],[39.117352,100.224907],[39.1129,100.232071],[39.112129,100.233353],[39.111488,100.234528],[39.110161,100.238693],[39.108261,100.24482],[39.106621,100.253532],[39.10601,100.255219],[39.099529,100.265472],[39.097809,100.267929],[39.09132,100.274979],[39.08886,100.278084],[39.08638,100.282143],[39.085449,100.283142],[39.083241,100.285378],[39.08152,100.287308],[39.079159,100.29039],[39.07848,100.290787],[39.077999,100.291763],[39.07642,100.293739],[39.074471,100.296593],[39.072319,100.299248],[39.07132,100.300247],[39.06966,100.301903],[39.057961,100.314529],[39.05022,100.322197],[39.04755,100.324883],[39.046558,100.325798],[39.043289,100.327919],[39.042301,100.328537],[39.041359,100.329247],[39.04044,100.330383],[39.03764,100.336403],[39.037201,100.337173],[39.031891,100.344978],[39.03001,100.347763],[39.01815,100.358269],[39.017208,100.359367],[39.014439,100.363419],[39.011909,100.366524],[39.011131,100.367569],[39.009892,100.370148],[39.009491,100.371307],[39.009411,100.37294],[39.009701,100.374458],[39.009899,100.376793],[39.009682,100.378067],[39.009171,100.379158],[39.00856,100.379959],[39.00684,100.381622],[39.006271,100.382782],[39.003311,100.390747],[39.000702,100.395638],[38.99966,100.398117],[38.99839,100.401466],[38.997978,100.402969],[38.997711,100.404762],[38.997398,100.406532],[38.996571,100.408501],[38.995571,100.410332],[38.995041,100.411652],[38.994362,100.414619],[38.994259,100.416],[38.994469,100.417084],[38.996239,100.421806],[38.996651,100.423264],[38.996609,100.428879],[38.996151,100.43045],[38.99585,100.430832],[38.991089,100.435509],[38.99017,100.435982],[38.989288,100.435959],[38.985409,100.434433],[38.980579,100.432991],[38.979401,100.433357],[38.97773,100.434357],[38.975861,100.437202],[38.974949,100.437912],[38.972141,100.438797],[38.960949,100.43602],[38.95298,100.433403],[38.95216,100.433128],[38.95126,100.432938],[38.95063,100.433144],[38.94836,100.434303],[38.942612,100.437157],[38.941761,100.437927],[38.938251,100.44165],[38.93692,100.443031],[38.9352,100.443413],[38.93541,100.444107],[38.935711,100.44725],[38.93644,100.452507],[38.93647,100.453751],[38.936588,100.45488],[38.936989,100.461548],[38.937401,100.465958],[38.937389,100.467453],[38.937469,100.468674],[38.937469,100.470398],[38.937439,100.472549],[38.937401,100.47464],[38.93734,100.477226],[38.937359,100.480133],[38.937489,100.482933],[38.937889,100.488083],[38.937908,100.488579],[38.93792,100.488907],[38.937729,100.488991],[38.934582,100.488632],[38.927471,100.487907],[38.92429,100.487694],[38.92131,100.487503],[38.918362,100.487297],[38.915371,100.487099],[38.911781,100.486893],[38.9081,100.486671],[38.906281,100.486549],[38.905769,100.486267],[38.905651,100.486282],[38.905361,100.486313],[38.905312,100.486366],[38.90453,100.487389],[38.903542,100.4888],[38.897739,100.496407],[38.894131,100.499657],[38.89225,100.500999],[38.888939,100.503441],[38.885078,100.50631],[38.878761,100.511673],[38.877159,100.51358],[38.87524,100.515968],[38.87027,100.52195],[38.860298,100.534897],[38.85957,100.537666],[38.85746,100.541687],[38.85574,100.54493],[38.854431,100.547401],[38.853851,100.548477],[38.853451,100.54921],[38.8521,100.551849],[38.851349,100.553253],[38.85001,100.555794],[38.84811,100.559349],[38.846142,100.563026],[38.84539,100.564133],[38.8442,100.565521],[38.839249,100.569122],[38.83136,100.571358],[38.83297,100.576851],[38.82534,100.582687],[38.81625,100.590927],[38.796181,100.60878],[38.763531,100.63195],[38.754429,100.637619],[38.725109,100.655472],[38.708359,100.664742],[38.70488,100.667488],[38.702068,100.670227],[38.688271,100.686203],[38.687061,100.687569],[38.676609,100.705421],[38.675941,100.706451],[38.66629,100.71315],[38.667099,100.716751],[38.6675,100.720528],[38.667759,100.723961],[38.672321,100.771339],[38.655701,100.774429],[38.61655,100.780777],[38.531059,100.795723],[38.483768,100.804131],[38.480141,100.805328],[38.47905,100.805946],[38.468189,100.812027],[38.46254,100.814774],[38.459721,100.815804],[38.448559,100.818031],[38.446949,100.818893],[38.445869,100.820427],[38.443581,100.8237],[38.441841,100.82576],[38.44009,100.82679],[38.43874,100.827637],[38.43565,100.829018],[38.416019,100.837936],[38.360451,100.86335],[38.358158,100.864899],[38.33218,100.886353],[38.31292,100.896477],[38.31076,100.897339],[38.305241,100.898201],[38.302811,100.898888],[38.277481,100.908836],[38.27182,100.911423],[38.267109,100.914162],[38.263329,100.916908],[38.240681,100.934937],[38.23893,100.935966],[38.230438,100.937851],[38.22525,100.938667],[38.22401,100.938904],[38.21764,100.940109],[38.215462,100.939423],[38.214828,100.939209],[38.21431,100.938957],[38.201801,100.93528],[38.20174,100.935257],[38.200401,100.934982],[38.194172,100.932129],[38.19355,100.932167],[38.191509,100.932266],[38.189819,100.932564],[38.188801,100.933067],[38.187191,100.933891],[38.183262,100.935593],[38.18232,100.93589],[38.18116,100.936142],[38.179989,100.936096],[38.178612,100.935837],[38.176151,100.935226],[38.17593,100.935158],[38.17543,100.935127],[38.17474,100.935226],[38.174381,100.935333],[38.173191,100.935997],[38.170811,100.938019],[38.169861,100.938141],[38.169529,100.938133],[38.16922,100.938057],[38.168282,100.936287],[38.166069,100.937134],[38.166561,100.93586],[38.16634,100.935364],[38.16626,100.934853],[38.165741,100.934723],[38.16497,100.93383],[38.162579,100.934982],[38.162231,100.93528],[38.161411,100.936569],[38.161209,100.936867],[38.16053,100.937439],[38.16029,100.937447],[38.15947,100.936722],[38.158779,100.936073],[38.15852,100.93576],[38.153389,100.931503],[38.152328,100.93026],[38.151409,100.928841],[38.1483,100.923149],[38.14677,100.922836],[38.14465,100.922813],[38.13913,100.922333],[38.138729,100.921997],[38.137669,100.920853],[38.13485,100.920441],[38.133919,100.920181],[38.133221,100.920242],[38.132881,100.920341],[38.126369,100.917053],[38.125771,100.917122],[38.12159,100.91671],[38.118771,100.917053],[38.11718,100.916672],[38.11676,100.91642],[38.11602,100.916412],[38.114201,100.916252],[38.113411,100.916367],[38.113071,100.916458],[38.113041,100.916473],[38.112598,100.916527],[38.112209,100.916611],[38.110981,100.917023],[38.11047,100.917229],[38.108398,100.917892],[38.105492,100.918831],[38.10294,100.919861],[38.101051,100.921097],[38.099892,100.921783],[38.09866,100.922501],[38.096241,100.920647],[38.095921,100.920799],[38.09502,100.921738],[38.09444,100.922363],[38.094238,100.922523],[38.092918,100.922768],[38.092659,100.922768],[38.091438,100.922371],[38.091202,100.92234],[38.09095,100.922371],[38.089951,100.92292],[38.089588,100.922997],[38.087589,100.922287],[38.086342,100.921783],[38.086128,100.921959],[38.085819,100.922127],[38.085381,100.922028],[38.08466,100.921509],[38.08456,100.921089],[38.084301,100.920227],[38.084221,100.920036],[38.08353,100.918831],[38.082909,100.91761],[38.08292,100.917099],[38.083038,100.916718],[38.083771,100.915039],[38.083309,100.911873],[38.0812,100.912231],[38.079781,100.910057],[38.077671,100.908447],[38.07642,100.907082],[38.075939,100.907028],[38.075169,100.906967],[38.073582,100.906807],[38.073139,100.906593],[38.072418,100.905533],[38.07119,100.903549],[38.070061,100.902039],[38.069592,100.901604],[38.069229,100.90123],[38.069118,100.901176],[38.068958,100.901093],[38.068691,100.900917],[38.066059,100.89875],[38.06493,100.896889],[38.064602,100.896294],[38.064362,100.895851],[38.064049,100.894623],[38.063911,100.894112],[38.06369,100.893761],[38.063389,100.893471],[38.061901,100.89257],[38.061508,100.892326],[38.061089,100.892036],[38.060539,100.891502],[38.06015,100.891083],[38.060131,100.89106],[38.05999,100.890923],[38.05806,100.889229],[38.057362,100.888283],[38.057281,100.888191],[38.056889,100.887894],[38.056358,100.887466],[38.055229,100.886688],[38.05442,100.886139],[38.053909,100.886078],[38.05283,100.886497],[38.050999,100.887207],[38.04887,100.887001],[38.047798,100.886871],[38.04686,100.887138],[38.04538,100.887756],[38.044159,100.888252],[38.042259,100.888908],[38.040859,100.889023],[38.039219,100.888992],[38.03812,100.889374],[38.035961,100.89048],[38.035191,100.891068],[38.033932,100.892174],[38.032829,100.893143],[38.0313,100.894478],[38.03019,100.89547],[38.029259,100.896149],[38.02895,100.896317],[38.028,100.8964],[38.02663,100.896248],[38.025509,100.896248],[38.024231,100.896317],[38.02322,100.896011],[38.021809,100.895432],[38.02076,100.89502],[38.01973,100.894882],[38.018162,100.894783],[38.016579,100.894653],[38.01572,100.894791],[38.014729,100.895241],[38.013451,100.895851],[38.01292,100.896111],[38.012611,100.896347],[38.0116,100.897499],[38.01049,100.898743],[38.009499,100.89991],[38.00872,100.901077],[38.007912,100.902313],[38.007401,100.903084],[38.006409,100.904556],[38.005939,100.90535],[38.00589,100.90554],[38.005859,100.906082],[38.006119,100.907249],[38.00631,100.907837],[38.006321,100.908043],[38.006199,100.908684],[38.005638,100.909477],[38.004921,100.909714],[38.004341,100.909889],[38.004211,100.909973],[38.00399,100.910172],[38.00354,100.910957],[38.00296,100.912216],[38.002159,100.913986],[38.001869,100.914558],[38.00148,100.915024],[38.000629,100.915543],[38.000141,100.916023],[38.000061,100.916191],[37.999931,100.916763],[37.99995,100.917664],[37.99976,100.918251],[37.999069,100.91922],[37.998081,100.920486],[37.994629,100.922951],[37.993259,100.923653],[37.992119,100.92395],[37.991749,100.924187],[37.991718,100.924271],[37.992081,100.924622],[37.992352,100.924583],[37.993462,100.924759],[37.994831,100.925262],[37.99577,100.925636],[37.995949,100.925858],[37.995369,100.926323],[37.994511,100.92617],[37.99313,100.926003],[37.991619,100.926338],[37.98933,100.927071],[37.988651,100.927277],[37.987629,100.927383],[37.986462,100.927254],[37.985901,100.927437],[37.985729,100.927917],[37.985729,100.928139],[37.985909,100.929626],[37.985851,100.929916],[37.98558,100.929962],[37.985111,100.929047],[37.98457,100.92804],[37.9841,100.927498],[37.983879,100.927353],[37.98291,100.927193],[37.981701,100.927467],[37.98,100.927994],[37.978321,100.928558],[37.976299,100.929497],[37.973499,100.930946],[37.97234,100.931587],[37.970921,100.932564],[37.969349,100.933693],[37.968651,100.934273],[37.96822,100.934914],[37.967701,100.935738],[37.966919,100.936974],[37.965889,100.938133],[37.96278,100.941231],[37.95332,100.950447],[37.95113,100.952316],[37.948059,100.954712],[37.946251,100.956261],[37.942341,100.960251],[37.940208,100.962517],[37.938641,100.964043],[37.925011,100.976463],[37.923859,100.977821],[37.912819,100.993507],[37.91153,100.995216],[37.906441,101.00177],[37.902988,101.006012],[37.897812,101.012581],[37.895741,101.015099],[37.894581,101.016342],[37.893471,101.017319],[37.886219,101.022598],[37.884129,101.0242],[37.882912,101.02549],[37.876579,101.034492],[37.87384,101.037201],[37.87289,101.038643],[37.871059,101.042099],[37.869381,101.045097],[37.865761,101.050629],[37.86404,101.053368],[37.861839,101.05851],[37.86116,101.060448],[37.860329,101.064133],[37.860329,101.065292],[37.8606,101.065331],[37.86047,101.066803],[37.86034,101.069008],[37.86026,101.069633],[37.860062,101.070129],[37.859489,101.070717],[37.85928,101.070801],[37.85873,101.070824],[37.85714,101.070374],[37.855881,101.070053],[37.855511,101.070183],[37.85537,101.070267],[37.854889,101.070847],[37.854771,101.07119],[37.854061,101.072327],[37.85331,101.073563],[37.85252,101.074989],[37.85228,101.075417],[37.85191,101.076263],[37.851521,101.077271],[37.850632,101.080223],[37.85051,101.080566],[37.8503,101.081352],[37.849998,101.082458],[37.84977,101.083717],[37.849621,101.084793],[37.849548,101.085373],[37.849491,101.085854],[37.849098,101.08725],[37.848598,101.088982],[37.847919,101.091454],[37.847698,101.093063],[37.84763,101.09433],[37.847599,101.094627],[37.84753,101.095673],[37.847462,101.096786],[37.847321,101.098503],[37.847118,101.099922],[37.846741,101.101959],[37.846489,101.103348],[37.846371,101.104027],[37.846199,101.104767],[37.8461,101.105431],[37.845741,101.10656],[37.84515,101.107933],[37.844719,101.109108],[37.84457,101.110367],[37.844479,101.112419],[37.844398,101.114662],[37.844311,101.115028],[37.84383,101.115433],[37.843449,101.115288],[37.842651,101.114532],[37.84185,101.11367],[37.840961,101.112709],[37.840488,101.112244],[37.840469,101.11219],[37.840439,101.112259],[37.840351,101.112129],[37.84013,101.111938],[37.839489,101.111588],[37.83905,101.111526],[37.83865,101.111588],[37.8381,101.111923],[37.8377,101.112373],[37.837238,101.113403],[37.8367,101.114769],[37.836479,101.115669],[37.8363,101.117081],[37.83577,101.12207],[37.835499,101.124001],[37.835121,101.125214],[37.834309,101.127197],[37.833679,101.129219],[37.833359,101.130989],[37.83305,101.133148],[37.83321,101.134811],[37.833881,101.137657],[37.834099,101.138351],[37.834702,101.13916],[37.83567,101.139702],[37.836121,101.139923],[37.836418,101.140373],[37.83614,101.140572],[37.835178,101.140648],[37.83382,101.140762],[37.832279,101.14077],[37.830601,101.140587],[37.82917,101.140778],[37.827431,101.140717],[37.825581,101.140388],[37.82452,101.1399],[37.823139,101.139297],[37.82214,101.139259],[37.821178,101.139618],[37.819019,101.140663],[37.817181,101.141411],[37.816669,101.141617],[37.815929,101.142174],[37.814751,101.143822],[37.813019,101.146439],[37.811901,101.148109],[37.811069,101.148567],[37.809551,101.148941],[37.807381,101.149544],[37.806061,101.150299],[37.804459,101.151299],[37.804119,101.151428],[37.80278,101.151962],[37.801182,101.152908],[37.798481,101.154587],[37.79567,101.156326],[37.795521,101.156441],[37.794899,101.157471],[37.793388,101.160606],[37.792149,101.163231],[37.791801,101.164368],[37.791191,101.167183],[37.790531,101.170303],[37.789902,101.173157],[37.789532,101.173958],[37.788589,101.17514],[37.787369,101.176498],[37.786541,101.177071],[37.785759,101.177933],[37.78442,101.179588],[37.783279,101.181313],[37.782421,101.183456],[37.7813,101.186394],[37.780449,101.188187],[37.779011,101.190361],[37.777809,101.191879],[37.77594,101.193947],[37.774529,101.194939],[37.772461,101.196312],[37.770329,101.197906],[37.7682,101.200546],[37.76577,101.203506],[37.76276,101.207207],[37.760689,101.210091],[37.75843,101.213463],[37.757191,101.215767],[37.755589,101.219109],[37.75441,101.222031],[37.753521,101.223457],[37.752949,101.224693],[37.752522,101.226517],[37.751942,101.228729],[37.751259,101.230072],[37.749901,101.232407],[37.749359,101.233803],[37.74844,101.236168],[37.7481,101.236839],[37.746868,101.238503],[37.745739,101.239891],[37.745441,101.240372],[37.74519,101.241577],[37.745049,101.24324],[37.744511,101.244423],[37.743649,101.246094],[37.742661,101.247627],[37.74091,101.249893],[37.739029,101.252281],[37.73679,101.255127],[37.734909,101.257561],[37.733028,101.260033],[37.732281,101.261452],[37.730949,101.264313],[37.730011,101.265556],[37.72863,101.266953],[37.727772,101.26783],[37.727531,101.268387],[37.727402,101.270111],[37.72736,101.27079],[37.727242,101.271141],[37.727051,101.271507],[37.726719,101.272079],[37.726391,101.272667],[37.725971,101.273331],[37.725208,101.274597],[37.724411,101.275932],[37.723999,101.277107],[37.723961,101.278053],[37.72422,101.279388],[37.724289,101.279747],[37.724159,101.28093],[37.723862,101.281448],[37.722301,101.283569],[37.721378,101.284973],[37.720901,101.286507],[37.72065,101.287338],[37.720161,101.288406],[37.719929,101.288811],[37.719589,101.289467],[37.719028,101.290482],[37.718262,101.291878],[37.71706,101.294037],[37.715969,101.296043],[37.714989,101.297813],[37.714699,101.298309],[37.71434,101.299026],[37.713829,101.300072],[37.713799,101.300117],[37.713242,101.300728],[37.712799,101.301132],[37.712601,101.301208],[37.712269,101.301277],[37.71159,101.301208],[37.71125,101.30101],[37.711079,101.300903],[37.71077,101.300743],[37.710209,101.300133],[37.709751,101.29969],[37.709309,101.299187],[37.708691,101.298683],[37.70834,101.298576],[37.707771,101.298767],[37.706871,101.299149],[37.706551,101.299294],[37.70607,101.299492],[37.705238,101.29985],[37.704762,101.300049],[37.704361,101.300217],[37.703651,101.300507],[37.70253,101.300987],[37.700699,101.30172],[37.698448,101.302338],[37.695919,101.302711],[37.69265,101.303146],[37.690048,101.303581],[37.68877,101.304001],[37.686951,101.304588],[37.686069,101.304909],[37.6847,101.305496],[37.68343,101.306107],[37.680759,101.307327],[37.67836,101.308121],[37.67527,101.309196],[37.672642,101.31041],[37.669472,101.311913],[37.668152,101.312767],[37.666481,101.313927],[37.665161,101.314903],[37.664322,101.315666],[37.662891,101.317139],[37.66127,101.318573],[37.660339,101.319321],[37.659191,101.320152],[37.65731,101.321297],[37.655869,101.322144],[37.654308,101.323029],[37.652191,101.324303],[37.648499,101.326591],[37.645439,101.328568],[37.64394,101.329826],[37.643021,101.330872],[37.64254,101.331497],[37.641319,101.333237],[37.639839,101.335373],[37.638199,101.337723],[37.636379,101.340317],[37.634541,101.342957],[37.632141,101.34639],[37.629341,101.350357],[37.627628,101.352814],[37.626659,101.354301],[37.62627,101.355598],[37.625721,101.357979],[37.625141,101.359108],[37.62434,101.360046],[37.62286,101.361603],[37.621571,101.363548],[37.62019,101.365372],[37.619209,101.366013],[37.617599,101.366814],[37.616562,101.367691],[37.61496,101.369507],[37.613701,101.370613],[37.610222,101.373337],[37.607319,101.375664],[37.60474,101.37793],[37.602089,101.380333],[37.598621,101.383461],[37.594391,101.387299],[37.591091,101.390297],[37.58691,101.394119],[37.583401,101.397293],[37.580681,101.399773],[37.580269,101.400131],[37.579899,101.400482],[37.579269,101.401047],[37.5783,101.401932],[37.57708,101.403053],[37.575291,101.404663],[37.57296,101.406754],[37.57003,101.409286],[37.566971,101.411903],[37.56599,101.412727],[37.56562,101.413033],[37.564522,101.413963],[37.563381,101.414726],[37.561989,101.415352],[37.56007,101.416077],[37.557541,101.417061],[37.554241,101.418373],[37.551399,101.419312],[37.547798,101.420357],[37.545071,101.421227],[37.542511,101.42215],[37.540421,101.422928],[37.53783,101.423813],[37.53566,101.424393],[37.534081,101.424332],[37.531898,101.42424],[37.529049,101.424202],[37.525181,101.424263],[37.52179,101.424278],[37.519741,101.424316],[37.516869,101.424393],[37.512939,101.424461],[37.508251,101.424538],[37.503899,101.424629],[37.500198,101.424683],[37.49575,101.424767],[37.492561,101.424797],[37.489559,101.424988],[37.487999,101.425407],[37.48576,101.425972],[37.482288,101.426201],[37.479931,101.426361],[37.4776,101.426498],[37.475159,101.426643],[37.473331,101.426697],[37.471889,101.426514],[37.47049,101.426529],[37.467419,101.426758],[37.46513,101.426933],[37.464211,101.42672],[37.464119,101.426697],[37.463982,101.426659],[37.463848,101.426582],[37.463139,101.426132],[37.46244,101.425659],[37.461079,101.424744],[37.459431,101.423668],[37.457729,101.422523],[37.45628,101.421501],[37.455479,101.420937],[37.45435,101.419746],[37.452621,101.417473],[37.451469,101.415993],[37.44981,101.413803],[37.44854,101.412338],[37.44804,101.412064],[37.44775,101.411888],[37.445492,101.411247],[37.443668,101.410637],[37.441891,101.40976],[37.44035,101.409012],[37.440208,101.408943],[37.43853,101.40863],[37.436539,101.408112],[37.434071,101.406921],[37.433498,101.406593],[37.432201,101.406242],[37.431061,101.406303],[37.42942,101.406502],[37.427738,101.406723],[37.425339,101.407478],[37.422489,101.408386],[37.420898,101.408218],[37.419739,101.407829],[37.417549,101.40773],[37.416061,101.407822],[37.414471,101.408257],[37.412609,101.408791],[37.411018,101.409241],[37.409962,101.409531],[37.40871,101.409767],[37.4076,101.409538],[37.406799,101.409302],[37.40564,101.409393],[37.404781,101.409843],[37.403141,101.410782],[37.401932,101.411163],[37.39996,101.411751],[37.398479,101.412033],[37.397221,101.412209],[37.396179,101.412369],[37.394939,101.412666],[37.394131,101.413139],[37.39407,101.413162],[37.393711,101.413223],[37.393089,101.412956],[37.391979,101.412209],[37.390869,101.411697],[37.389389,101.411148],[37.38903,101.410583],[37.38913,101.40995],[37.389179,101.409843],[37.389591,101.409142],[37.38966,101.408524],[37.389408,101.408096],[37.38839,101.406822],[37.387348,101.405571],[37.387112,101.405411],[37.386189,101.405357],[37.38554,101.40522],[37.384762,101.404449],[37.38401,101.403732],[37.38353,101.403618],[37.3825,101.403793],[37.38203,101.403572],[37.381908,101.40332],[37.38184,101.40303],[37.38163,101.401863],[37.381161,101.400917],[37.38028,101.399353],[37.379539,101.398064],[37.37907,101.397758],[37.378651,101.397919],[37.378529,101.398209],[37.378262,101.399963],[37.378239,101.400597],[37.378601,101.401222],[37.37904,101.401627],[37.37915,101.401901],[37.379169,101.402367],[37.37854,101.403183],[37.378342,101.40345],[37.378269,101.404053],[37.378471,101.404953],[37.378979,101.406151],[37.37957,101.407173],[37.379631,101.407341],[37.37973,101.407913],[37.379639,101.409309],[37.379372,101.409698],[37.378639,101.41011],[37.378429,101.410233],[37.378311,101.410339],[37.377861,101.411201],[37.377651,101.411713],[37.377571,101.411819],[37.376991,101.412308],[37.376259,101.412827],[37.374969,101.413727],[37.374741,101.413841],[37.373779,101.413933],[37.37265,101.414131],[37.372059,101.41494],[37.371849,101.415283],[37.37146,101.415459],[37.371319,101.415199],[37.37151,101.41481],[37.37159,101.414726],[37.37183,101.41449],[37.372509,101.413429],[37.373138,101.413017],[37.37431,101.412582],[37.37439,101.412537],[37.37524,101.411491],[37.376221,101.41021],[37.376579,101.409309],[37.37677,101.408707],[37.376801,101.407959],[37.376671,101.407494],[37.376549,101.407181],[37.375622,101.406151],[37.37534,101.405891],[37.374939,101.405739],[37.37405,101.405937],[37.372532,101.406487],[37.37244,101.406502],[37.371429,101.406052],[37.370049,101.405357],[37.369881,101.40464],[37.36993,101.404381],[37.370461,101.402924],[37.370449,101.402229],[37.370121,101.401772],[37.369801,101.401688],[37.368721,101.401741],[37.36731,101.401833],[37.36607,101.402046],[37.36491,101.402313],[37.363361,101.402893],[37.362251,101.403313],[37.36216,101.403671],[37.362228,101.403793],[37.362572,101.403816],[37.362751,101.403793],[37.36301,101.403664],[37.364571,101.40313],[37.364681,101.403091],[37.36499,101.403091],[37.365139,101.40345],[37.36483,101.403687],[37.364071,101.403687],[37.36314,101.404083],[37.362671,101.404282],[37.361889,101.404373],[37.361141,101.404373],[37.361,101.404381],[37.360821,101.404442],[37.360691,101.404716],[37.36097,101.405006],[37.362041,101.40477],[37.362999,101.404846],[37.363091,101.404861],[37.364029,101.404579],[37.364319,101.404488],[37.364849,101.404587],[37.36517,101.404739],[37.365719,101.40477],[37.366051,101.404442],[37.366531,101.404007],[37.366619,101.404022],[37.36742,101.404083],[37.367668,101.404312],[37.36755,101.404663],[37.36747,101.404694],[37.36647,101.404694],[37.366249,101.404793],[37.365921,101.405167],[37.365761,101.405357],[37.36499,101.405739],[37.363918,101.405998],[37.362591,101.406319],[37.36179,101.406464],[37.361012,101.406601],[37.360149,101.406754],[37.35891,101.406799],[37.358398,101.406807],[37.357201,101.407204],[37.356079,101.407928],[37.356022,101.407967],[37.35553,101.408157],[37.354881,101.407799],[37.353771,101.406982],[37.35355,101.40683],[37.337841,101.397949],[37.335972,101.398239],[37.33374,101.398643],[37.333111,101.398743],[37.33165,101.399529],[37.3283,101.401382],[37.327991,101.401611],[37.327702,101.402107],[37.327591,101.40287],[37.327621,101.403572],[37.32711,101.4048],[37.325871,101.406174],[37.32552,101.40638],[37.325272,101.406433],[37.324612,101.406219],[37.323872,101.405457],[37.32349,101.405167],[37.32299,101.405228],[37.321861,101.406189],[37.32111,101.407578],[37.32032,101.409317],[37.320179,101.40947],[37.319901,101.409416],[37.319881,101.408897],[37.319931,101.408813],[37.320728,101.407356],[37.321331,101.406303],[37.322369,101.404823],[37.322861,101.404213],[37.323071,101.403961],[37.323219,101.403831],[37.32349,101.40377],[37.324001,101.403893],[37.324501,101.403793],[37.3246,101.403587],[37.324551,101.402191],[37.324982,101.401337],[37.326141,101.400253],[37.326759,101.399658],[37.326931,101.399437],[37.326889,101.399101],[37.326778,101.398987],[37.326469,101.399132],[37.325409,101.400177],[37.32468,101.400787],[37.32391,101.401749],[37.323589,101.402153],[37.322632,101.40284],[37.32106,101.404533],[37.32021,101.405121],[37.31958,101.40609],[37.3195,101.406197],[37.31847,101.407379],[37.316929,101.409149],[37.31678,101.409607],[37.317039,101.412064],[37.317181,101.412399],[37.31757,101.412689],[37.318748,101.412956],[37.31889,101.412971],[37.319851,101.412727],[37.32058,101.412491],[37.32103,101.412643],[37.322189,101.413002],[37.32336,101.413361],[37.324661,101.413834],[37.324821,101.413918],[37.325069,101.414093],[37.325199,101.414383],[37.325119,101.414848],[37.324951,101.415009],[37.322498,101.415657],[37.322071,101.415771],[37.320229,101.415787],[37.31879,101.416527],[37.31702,101.417488],[37.314079,101.41925],[37.312801,101.420464],[37.31229,101.420959],[37.311039,101.421883],[37.308819,101.423248],[37.308151,101.423737],[37.307831,101.424103],[37.30756,101.424423],[37.307129,101.424561],[37.3064,101.424431],[37.306149,101.424408],[37.305901,101.424454],[37.305309,101.424759],[37.304619,101.42485],[37.303761,101.424797],[37.303371,101.424927],[37.302719,101.425468],[37.302361,101.425636],[37.302189,101.425346],[37.30238,101.425018],[37.303379,101.424522],[37.304871,101.424004],[37.306099,101.422768],[37.307281,101.422249],[37.307781,101.422028],[37.307709,101.421837],[37.306499,101.422058],[37.305401,101.42244],[37.30378,101.423218],[37.30299,101.423508],[37.30265,101.423378],[37.301788,101.422119],[37.299229,101.4188],[37.29887,101.418297],[37.297771,101.417084],[37.296501,101.415581],[37.295761,101.414757],[37.294979,101.414841],[37.29454,101.41497],[37.293732,101.414757],[37.292919,101.414383],[37.292629,101.414322],[37.290932,101.414398],[37.288929,101.414543],[37.287491,101.414978],[37.286819,101.415253],[37.285591,101.415314],[37.285339,101.415314],[37.284981,101.415489],[37.28487,101.416031],[37.284981,101.4161],[37.286949,101.415756],[37.287498,101.415688],[37.28775,101.415672],[37.28846,101.415657],[37.288528,101.415657],[37.288681,101.415703],[37.288731,101.415993],[37.288582,101.416199],[37.28772,101.416443],[37.28672,101.41655],[37.28492,101.416656],[37.282841,101.416847],[37.280769,101.416542],[37.277889,101.416054],[37.275749,101.415771],[37.273762,101.416153],[37.272942,101.416183],[37.272301,101.415916],[37.271969,101.415771],[37.270729,101.415771],[37.2687,101.416069],[37.26685,101.416168],[37.263821,101.41597],[37.2612,101.415314],[37.25959,101.41494],[37.25724,101.414398],[37.25568,101.41433],[37.253761,101.414413],[37.253609,101.414429],[37.251259,101.414558],[37.250561,101.415009],[37.24929,101.416481],[37.248531,101.417526],[37.244671,101.429771],[37.243301,101.435257],[37.242859,101.437271],[37.242939,101.438911],[37.24342,101.442207],[37.2449,101.44738],[37.245338,101.450417],[37.245529,101.452568],[37.245449,101.454262],[37.24464,101.464493],[37.24445,101.466148],[37.24437,101.466454],[37.244041,101.466988],[37.243401,101.467506],[37.243069,101.467857],[37.242939,101.468613],[37.243969,101.471687],[37.244919,101.472878],[37.245079,101.473251],[37.24514,101.475067],[37.243679,101.483513],[37.243172,101.48555],[37.242458,101.486748],[37.241989,101.487427],[37.24176,101.488922],[37.241661,101.490196],[37.24086,101.491463],[37.238831,101.495354],[37.238529,101.500031],[37.237782,101.50103],[37.236099,101.501312],[37.2356,101.501694],[37.2346,101.503036],[37.23447,101.503258],[37.234409,101.503517],[37.234539,101.504219],[37.235321,101.506203],[37.235191,101.507553],[37.235222,101.507881],[37.236031,101.509827],[37.235661,101.512444],[37.235168,101.516289],[37.23476,101.517311],[37.233669,101.518204],[37.233139,101.520264],[37.2327,101.520737],[37.23246,101.520737],[37.230881,101.520073],[37.230061,101.520126],[37.22958,101.520447],[37.229382,101.520668],[37.22855,101.521217],[37.228031,101.521927],[37.227242,101.522346],[37.226849,101.522469],[37.225948,101.523193],[37.224831,101.524261],[37.223831,101.526154],[37.222679,101.528816],[37.222561,101.528976],[37.22216,101.529846],[37.221958,101.530083],[37.221588,101.530113],[37.221241,101.529846],[37.22076,101.529358],[37.220341,101.529297],[37.219872,101.5298],[37.21909,101.531013],[37.218342,101.531342],[37.218159,101.531631],[37.218189,101.532112],[37.218819,101.534027],[37.219021,101.535423],[37.219009,101.535713],[37.21862,101.536133],[37.218182,101.53595],[37.216209,101.532883],[37.215919,101.532661],[37.215542,101.53273],[37.212608,101.537086],[37.21244,101.53727],[37.20805,101.53756],[37.207062,101.537064],[37.206692,101.537086],[37.206261,101.537643],[37.206009,101.537888],[37.20583,101.537933],[37.205631,101.537872],[37.20414,101.536377],[37.20364,101.536217],[37.203091,101.537331],[37.202221,101.538544],[37.20163,101.539177],[37.199741,101.539398],[37.199051,101.539177],[37.199131,101.539062],[37.200741,101.539124],[37.201439,101.538971],[37.20163,101.538849],[37.201561,101.538239],[37.200771,101.538116],[37.19978,101.538231],[37.19849,101.538254],[37.197311,101.538109],[37.19585,101.537376],[37.19503,101.537163],[37.19453,101.537262],[37.192909,101.538673],[37.18969,101.541893],[37.1894,101.542267],[37.18771,101.543747],[37.187351,101.544594],[37.18652,101.54702],[37.185921,101.547348],[37.18494,101.54747],[37.184078,101.547211],[37.182579,101.546593],[37.179371,101.547737],[37.177158,101.54882],[37.175419,101.549004],[37.174992,101.54911],[37.173851,101.550056],[37.171951,101.551811],[37.16856,101.555199],[37.16573,101.557533],[37.165051,101.558037],[37.1646,101.558212],[37.16185,101.558594],[37.150612,101.56044],[37.149799,101.560539],[37.148972,101.561523],[37.14526,101.565498],[37.145012,101.565239],[37.144112,101.564613],[37.142639,101.563789],[37.141941,101.563713],[37.141781,101.563766],[37.141171,101.564651],[37.140381,101.568283],[37.140129,101.569633],[37.139511,101.570518],[37.139111,101.570717],[37.13829,101.570168],[37.136162,101.569733],[37.127941,101.568977],[37.120708,101.566162],[37.115791,101.566833],[37.11084,101.566566],[37.11071,101.566589],[37.110439,101.566727],[37.110569,101.566597],[37.110451,101.56649],[37.10928,101.566307],[37.106831,101.565643],[37.10585,101.565697],[37.102749,101.566742],[37.100529,101.56694],[37.10001,101.56694],[37.09763,101.566391],[37.08778,101.565727],[37.084541,101.565201],[37.081539,101.566353],[37.078499,101.568489],[37.076111,101.570312],[37.07375,101.571854],[37.068119,101.575279],[37.06662,101.573463],[37.057621,101.568863],[37.054428,101.567383],[37.04855,101.566383],[37.045929,101.566063],[37.039959,101.569397],[37.038471,101.569267],[37.036831,101.568779],[37.031479,101.56675],[37.030899,101.566673],[37.0303,101.566719],[37.025002,101.56855],[37.023991,101.569206],[37.023399,101.569893],[37.021519,101.573753],[37.020229,101.57666],[37.01791,101.581337],[37.009121,101.59391],[37.005348,101.598343],[37.004761,101.600288],[37.00333,101.606148],[37.001411,101.615402],[37.001499,101.617416],[37.001041,101.619637],[36.99847,101.625504],[36.998131,101.625938],[36.996529,101.62748],[36.988991,101.633797],[36.98806,101.634453],[36.974491,101.64325],[36.96608,101.653717],[36.96159,101.659042],[36.96096,101.659973],[36.950859,101.667549],[36.948372,101.669502],[36.946701,101.670937],[36.943699,101.673103],[36.940811,101.675346],[36.938049,101.677582],[36.934719,101.680923],[36.927681,101.686798],[36.92522,101.689323],[36.92408,101.691132],[36.922691,101.694366],[36.921761,101.6968],[36.919979,101.702789],[36.919071,101.704964],[36.918449,101.706131],[36.916691,101.708611],[36.916679,101.708733],[36.91671,101.708809],[36.916759,101.70887],[36.917049,101.709122],[36.917431,101.709488],[36.91782,101.71003],[36.918171,101.710632],[36.918308,101.711243],[36.918079,101.711983],[36.91766,101.712891],[36.917179,101.713943],[36.916649,101.714989],[36.91605,101.716057],[36.915352,101.717194],[36.914558,101.718353],[36.9137,101.719528],[36.912769,101.720703],[36.911789,101.72187],[36.910728,101.723038],[36.909641,101.724213],[36.908501,101.725403],[36.907349,101.726593],[36.9062,101.727783],[36.905048,101.728996],[36.903889,101.730202],[36.902481,101.731659],[36.901321,101.732872],[36.900169,101.734077],[36.89901,101.735283],[36.89492,101.739517],[36.893959,101.740387],[36.892769,101.741287],[36.89156,101.742027],[36.89032,101.74263],[36.889,101.743149],[36.88768,101.743683],[36.886391,101.744308],[36.885139,101.745033],[36.88385,101.745789],[36.88253,101.746559],[36.88118,101.74736],[36.879841,101.748154],[36.87849,101.748947],[36.87714,101.749786],[36.87339,101.75248],[36.868092,101.756477],[36.866772,101.757263],[36.86541,101.758003],[36.864021,101.758713],[36.85524,101.761681],[36.85376,101.762123],[36.85231,101.762558],[36.850849,101.762993],[36.849369,101.763443],[36.832531,101.766273],[36.821499,101.769531],[36.812901,101.772072],[36.81139,101.772331],[36.758228,101.771317],[36.756771,101.770851],[36.755322,101.770401],[36.753849,101.769951],[36.75116,101.769203],[36.74971,101.768867],[36.748341,101.7686],[36.746971,101.768387],[36.745579,101.768204],[36.744171,101.768021],[36.742722,101.767822],[36.684299,101.766548],[36.68285,101.766586],[36.6814,101.766693],[36.67997,101.7668],[36.6786,101.76696],[36.67728,101.767159],[36.676041,101.767357],[36.6749,101.767563],[36.67384,101.767769],[36.672791,101.767982],[36.671791,101.768181],[36.670921,101.768356],[36.670441,101.768448],[36.670219,101.768509],[36.669899,101.76857],[36.66946,101.768646],[36.6689,101.768784],[36.668201,101.768944],[36.667488,101.769127],[36.66687,101.769287],[36.66642,101.769417],[36.666119,101.769524],[36.665741,101.769691],[36.66518,101.769867],[36.66449,101.770111],[36.663719,101.770401],[36.662949,101.770714],[36.662121,101.771027],[36.661228,101.771378],[36.66024,101.771767],[36.659199,101.772171],[36.658131,101.772583],[36.657089,101.772987],[36.656109,101.773369],[36.655209,101.773781],[36.654449,101.774147],[36.653919,101.774353],[36.653351,101.774567],[36.653011,101.774696],[36.652409,101.774918],[36.651878,101.775124],[36.65136,101.775291],[36.65062,101.775543],[36.6497,101.775574],[36.648708,101.775352],[36.648239,101.774963],[36.648102,101.774643],[36.647961,101.774147],[36.647781,101.773842],[36.647572,101.773697],[36.647209,101.773727],[36.646111,101.774017],[36.644958,101.774422],[36.64172,101.776169],[36.64053,101.776848],[36.640259,101.777359],[36.64035,101.777939],[36.640629,101.778648],[36.640591,101.779846],[36.640331,101.78064],[36.63974,101.782043],[36.639099,101.783524],[36.63863,101.784576],[36.638149,101.785751],[36.637661,101.787308],[36.636921,101.790131],[36.636768,101.790733],[36.636501,101.791649],[36.63623,101.792412],[36.63588,101.793198],[36.635471,101.793922],[36.634838,101.794792],[36.634369,101.795288],[36.63266,101.796669],[36.631969,101.797287],[36.63147,101.797859],[36.630901,101.798683],[36.630348,101.799767],[36.63007,101.800583],[36.629768,101.801903],[36.629539,101.80378],[36.62936,101.804733],[36.629009,101.805862],[36.628529,101.806923],[36.62804,101.807693],[36.627628,101.808243],[36.623409,101.813072],[36.622681,101.814003],[36.622162,101.814781],[36.621712,101.815613],[36.62014,101.818932],[36.619671,101.819687],[36.61898,101.820557],[36.618038,101.82151],[36.616959,101.822289],[36.612671,101.824448],[36.611801,101.824959],[36.610989,101.825569],[36.61042,101.826103],[36.609501,101.82708],[36.605671,101.831581],[36.60498,101.832253],[36.604431,101.832687],[36.603031,101.833603],[36.596249,101.837624],[36.595249,101.838371],[36.594379,101.839287],[36.5938,101.840103],[36.59309,101.841537],[36.592079,101.844223],[36.591572,101.845154],[36.590981,101.845978],[36.58989,101.846977],[36.588341,101.847977],[36.58757,101.848618],[36.58704,101.849213],[36.586411,101.850014],[36.58567,101.851311],[36.583961,101.855827],[36.58371,101.856491],[36.583389,101.857323],[36.582649,101.85907],[36.582081,101.860291],[36.581921,101.860588],[36.581089,101.862213],[36.580181,101.863838],[36.57859,101.866623],[36.578281,101.867188],[36.576771,101.869682],[36.575649,101.871872],[36.57513,101.873138],[36.57481,101.874153],[36.573139,101.879433],[36.572811,101.880302],[36.572319,101.881653],[36.572071,101.882149],[36.571621,101.882858],[36.571098,101.883499],[36.569538,101.885063],[36.568748,101.886147],[36.56823,101.887062],[36.568001,101.887573],[36.56741,101.889587],[36.567242,101.893753],[36.56715,101.89492],[36.566921,101.896339],[36.56657,101.897942],[36.565361,101.90155],[36.565159,101.90213],[36.56501,101.902573],[36.5648,101.903381],[36.564171,101.906937],[36.563869,101.909027],[36.563831,101.90934],[36.563728,101.910263],[36.563499,101.91169],[36.562759,101.915443],[36.562241,101.917618],[36.56118,101.921127],[36.560188,101.923721],[36.559429,101.925407],[36.55801,101.928009],[36.55735,101.929329],[36.556789,101.930763],[36.556438,101.932068],[36.55624,101.933167],[36.556141,101.934288],[36.55595,101.940407],[36.555901,101.941208],[36.555679,101.942772],[36.555401,101.944077],[36.5532,101.952919],[36.552898,101.954018],[36.552471,101.955353],[36.552071,101.956352],[36.551609,101.957291],[36.550812,101.958611],[36.548988,101.960968],[36.5485,101.961594],[36.54364,101.967583],[36.542759,101.968826],[36.54158,101.970863],[36.540878,101.972298],[36.539371,101.975861],[36.538769,101.977127],[36.53796,101.9786],[36.536041,101.981743],[36.535351,101.982986],[36.53484,101.984047],[36.533951,101.986221],[36.532661,101.989998],[36.531658,101.992554],[36.529919,101.9963],[36.527691,102.000778],[36.525009,102.006371],[36.524189,102.008232],[36.52359,102.009804],[36.523079,102.011726],[36.522671,102.013718],[36.522041,102.01722],[36.521339,102.021637],[36.520679,102.025291],[36.520351,102.026657],[36.520031,102.027733],[36.5186,102.031937],[36.51833,102.033043],[36.518169,102.033867],[36.518051,102.034721],[36.517971,102.035873],[36.517879,102.039383],[36.51767,102.041382],[36.51725,102.04335],[36.51638,102.04631],[36.5159,102.048157],[36.515629,102.049507],[36.51543,102.050903],[36.515289,102.052628],[36.51524,102.054077],[36.5154,102.058456],[36.51535,102.060219],[36.515121,102.062248],[36.5144,102.066704],[36.51424,102.067497],[36.514011,102.068283],[36.51366,102.069122],[36.51329,102.069763],[36.512821,102.070381],[36.51405,102.069],[36.514992,102.067719],[36.51535,102.066994],[36.515541,102.066483],[36.515732,102.065666],[36.51582,102.064537],[36.515701,102.062073],[36.51564,102.061752],[36.515499,102.059753],[36.515388,102.061218],[36.515121,102.062866],[36.514889,102.064522],[36.51487,102.066162],[36.515049,102.06778],[36.515442,102.06929],[36.51601,102.070717],[36.51664,102.072037],[36.5172,102.073357],[36.517639,102.074722],[36.517929,102.076103],[36.518059,102.07756],[36.518009,102.079102],[36.517689,102.080673],[36.517288,102.082336],[36.517052,102.084053],[36.51693,102.085716],[36.516819,102.087341],[36.516708,102.088913],[36.516579,102.090446],[36.51646,102.091858],[36.51635,102.093132],[36.516201,102.094276],[36.515961,102.095322],[36.515678,102.096283],[36.515369,102.097137],[36.515072,102.097809],[36.514832,102.098297],[36.514339,102.099182],[36.513672,102.100212],[36.51292,102.10144],[36.5121,102.102783],[36.51125,102.104141],[36.51041,102.105492],[36.50956,102.106888],[36.508709,102.108208],[36.50795,102.109558],[36.507332,102.110977],[36.506771,102.112473],[36.506302,102.113983],[36.505932,102.115494],[36.50565,102.116966],[36.505459,102.118408],[36.505341,102.119873],[36.505291,102.121384],[36.505291,102.122963],[36.505291,102.124634],[36.505291,102.12635],[36.50528,102.128067],[36.505291,102.129753],[36.505291,102.131401],[36.50531,102.133011],[36.505291,102.134583],[36.505219,102.136162],[36.5051,102.137733],[36.504951,102.139252],[36.504768,102.140717],[36.504539,102.142174],[36.504269,102.143677],[36.503948,102.145271],[36.503571,102.146896],[36.503159,102.148529],[36.502682,102.150146],[36.502178,102.151779],[36.50169,102.153442],[36.50119,102.155128],[36.500721,102.156883],[36.50029,102.158699],[36.499939,102.160583],[36.499569,102.162857],[36.499088,102.165863],[36.49881,102.167648],[36.498482,102.16935],[36.498081,102.171013],[36.497581,102.172569],[36.49699,102.174057],[36.4963,102.175423],[36.495522,102.17672],[36.494671,102.178017],[36.493801,102.179337],[36.492939,102.180656],[36.492069,102.181938],[36.491199,102.183212],[36.490349,102.184479],[36.48954,102.185707],[36.488831,102.186958],[36.48822,102.188217],[36.48764,102.189484],[36.487148,102.190773],[36.486759,102.192101],[36.48645,102.193459],[36.486191,102.194839],[36.486019,102.196243],[36.485859,102.197617],[36.485649,102.199074],[36.485439,102.200699],[36.48521,102.202408],[36.485001,102.204178],[36.484791,102.20594],[36.484558,102.207703],[36.484329,102.209351],[36.48407,102.210953],[36.483749,102.212486],[36.483391,102.214043],[36.483021,102.215584],[36.482571,102.21711],[36.482151,102.21859],[36.481731,102.220016],[36.481258,102.221397],[36.480751,102.222717],[36.48024,102.224037],[36.47971,102.225327],[36.47921,102.226562],[36.47876,102.22773],[36.478329,102.228928],[36.478088,102.230209],[36.477921,102.231552],[36.477879,102.232903],[36.477989,102.234261],[36.478088,102.235641],[36.478168,102.237137],[36.47826,102.23877],[36.47839,102.240379],[36.478519,102.241943],[36.47868,102.243439],[36.478882,102.244881],[36.47913,102.246277],[36.479408,102.247627],[36.479759,102.248993],[36.480141,102.25042],[36.480499,102.251892],[36.480862,102.253357],[36.48122,102.254807],[36.481579,102.256302],[36.481979,102.25782],[36.482441,102.259323],[36.48296,102.260757],[36.483471,102.262192],[36.48407,102.263641],[36.484718,102.265106],[36.48539,102.266541],[36.486012,102.267982],[36.48658,102.269432],[36.487011,102.270943],[36.48732,102.272476],[36.48745,102.274063],[36.487461,102.275627],[36.487289,102.277168],[36.486992,102.278641],[36.486599,102.28009],[36.486149,102.281517],[36.48563,102.282944],[36.485119,102.284378],[36.484581,102.285851],[36.4841,102.287376],[36.483749,102.28891],[36.48354,102.290466],[36.483398,102.292061],[36.483471,102.293587],[36.48362,102.29512],[36.48381,102.296677],[36.483978,102.298286],[36.484161,102.299919],[36.484341,102.301567],[36.48452,102.303177],[36.48465,102.304802],[36.484718,102.306412],[36.484749,102.307991],[36.484741,102.309563],[36.484699,102.311142],[36.484612,102.312683],[36.484482,102.314201],[36.484291,102.315689],[36.484081,102.317146],[36.483829,102.31855],[36.483559,102.319923],[36.483261,102.321312],[36.48291,102.322769],[36.482632,102.324226],[36.482399,102.325684],[36.482201,102.327171],[36.482059,102.328697],[36.48196,102.330231],[36.48185,102.331787],[36.48175,102.333397],[36.481651,102.33503],[36.481541,102.336693],[36.481441,102.338341],[36.4813,102.339897],[36.481152,102.341423],[36.48093,102.342857],[36.480652,102.344177],[36.480251,102.345413],[36.47982,102.346573],[36.479279,102.347778],[36.478661,102.348984],[36.477901,102.350281],[36.477112,102.351631],[36.476299,102.352989],[36.475491,102.354332],[36.47472,102.355698],[36.474079,102.357162],[36.473549,102.358688],[36.473122,102.360329],[36.472778,102.361992],[36.472519,102.363678],[36.47226,102.365356],[36.472,102.367058],[36.471741,102.368736],[36.471489,102.370407],[36.471241,102.372093],[36.471001,102.373756],[36.470749,102.375412],[36.47049,102.377068],[36.47023,102.378731],[36.46999,102.380379],[36.46973,102.382027],[36.469398,102.383659],[36.469101,102.385353],[36.468819,102.387062],[36.468571,102.388809],[36.468391,102.390533],[36.468281,102.392227],[36.468201,102.393929],[36.46817,102.395607],[36.46822,102.397293],[36.468311,102.398956],[36.468418,102.400627],[36.46854,102.402298],[36.46867,102.403969],[36.4688,102.405609],[36.468929,102.40728],[36.469059,102.409012],[36.46917,102.410759],[36.46925,102.412483],[36.469299,102.414177],[36.46928,102.415909],[36.469231,102.417641],[36.46909,102.419342],[36.468929,102.421013],[36.468739,102.422737],[36.468529,102.424477],[36.468342,102.426208],[36.468151,102.427872],[36.46796,102.429443],[36.467758,102.430946],[36.467579,102.432426],[36.467388,102.433937],[36.467171,102.435501],[36.466999,102.43705],[36.466881,102.438629],[36.466801,102.440239],[36.466751,102.441872],[36.46674,102.443466],[36.46677,102.445053],[36.466801,102.446579],[36.466801,102.448067],[36.46674,102.449516],[36.466549,102.450996],[36.466309,102.452454],[36.4659,102.453903],[36.465401,102.455292],[36.464828,102.456596],[36.464211,102.457817],[36.463581,102.459007],[36.46294,102.460167],[36.462299,102.461288],[36.461739,102.462334],[36.461151,102.463387],[36.460579,102.464439],[36.45993,102.465591],[36.45916,102.467003],[36.458431,102.468513],[36.457821,102.470093],[36.457352,102.471764],[36.457008,102.473488],[36.456791,102.475258],[36.4566,102.477028],[36.45644,102.47876],[36.456329,102.480461],[36.456181,102.482147],[36.456032,102.483803],[36.455952,102.485474],[36.455891,102.48716],[36.45591,102.488869],[36.455978,102.490601],[36.4561,102.492317],[36.45628,102.494019],[36.456459,102.495728],[36.456589,102.497452],[36.45657,102.499168],[36.456371,102.500893],[36.45607,102.502541],[36.455582,102.504173],[36.45496,102.50576],[36.45438,102.507317],[36.453819,102.508827],[36.453251,102.510307],[36.45274,102.511742],[36.452179,102.513206],[36.451561,102.514618],[36.45089,102.516006],[36.45015,102.517303],[36.44923,102.51857],[36.448299,102.519783],[36.447399,102.520927],[36.446529,102.522049],[36.445629,102.523178],[36.444729,102.524338],[36.443859,102.525436],[36.443008,102.526543],[36.442249,102.52755],[36.44162,102.528481],[36.441051,102.529404],[36.440578,102.530243],[36.440128,102.531029],[36.43969,102.532089],[36.439209,102.533524],[36.438808,102.53508],[36.43853,102.536713],[36.4384,102.53833],[36.438389,102.539978],[36.438499,102.541557],[36.438751,102.543022],[36.439079,102.544373],[36.439468,102.545677],[36.439899,102.546959],[36.44035,102.548233],[36.440811,102.549522],[36.441269,102.550812],[36.441669,102.552162],[36.442009,102.553596],[36.442211,102.555061],[36.442242,102.55658],[36.442051,102.558067],[36.44173,102.559517],[36.441269,102.56089],[36.440651,102.562233],[36.43996,102.563477],[36.439201,102.564728],[36.438412,102.565933],[36.43763,102.567123],[36.43684,102.568329],[36.43605,102.569527],[36.43528,102.570717],[36.43449,102.57193],[36.433681,102.573174],[36.43288,102.574402],[36.432121,102.575684],[36.431419,102.576973],[36.430759,102.578323],[36.430141,102.579697],[36.429531,102.5811],[36.42897,102.582497],[36.428459,102.583946],[36.427971,102.585457],[36.42757,102.587013],[36.4272,102.588516],[36.42683,102.590019],[36.426521,102.591553],[36.426239,102.593063],[36.4259,102.594582],[36.42551,102.596077],[36.425091,102.597572],[36.424599,102.599121],[36.424049,102.60067],[36.423489,102.602203],[36.422932,102.603737],[36.422352,102.605301],[36.42178,102.606827],[36.42123,102.60833],[36.420719,102.609802],[36.420238,102.611267],[36.419849,102.612663],[36.419529,102.614037],[36.419258,102.615433],[36.41898,102.616821],[36.41869,102.618233],[36.418468,102.619659],[36.418301,102.621063],[36.41819,102.622437],[36.41806,102.623863],[36.417931,102.625282],[36.417809,102.626678],[36.41769,102.628036],[36.417568,102.629356],[36.41745,102.630707],[36.417339,102.632027],[36.417221,102.633324],[36.41711,102.63459],[36.417,102.635918],[36.416828,102.637367],[36.416611,102.638893],[36.416279,102.640312],[36.415859,102.641762],[36.415352,102.643158],[36.414768,102.644478],[36.414131,102.645714],[36.413441,102.646812],[36.412739,102.64785],[36.411991,102.648811],[36.411201,102.649727],[36.410412,102.650673],[36.40955,102.651558],[36.40871,102.652481],[36.407871,102.653397],[36.407082,102.65432],[36.406368,102.655373],[36.405788,102.656548],[36.405411,102.657738],[36.405239,102.658928],[36.40517,102.660103],[36.405258,102.661217],[36.405491,102.662277],[36.4058,102.663422],[36.406132,102.664673],[36.406269,102.666008],[36.40617,102.667488],[36.405979,102.668938],[36.405548,102.670311],[36.40501,102.6716],[36.404251,102.672897],[36.4034,102.674133],[36.402451,102.675148],[36.401409,102.675972],[36.400311,102.676628],[36.399181,102.677101],[36.398029,102.677467],[36.396889,102.677834],[36.395802,102.678284],[36.364868,102.688026],[36.36396,102.688309],[36.362999,102.688637],[36.362,102.68911],[36.361,102.689774],[36.3601,102.690628],[36.35936,102.691597],[36.358742,102.692703],[36.358269,102.693863],[36.357868,102.695084],[36.357529,102.696289],[36.357231,102.69751],[36.356941,102.698799],[36.35667,102.700218],[36.356491,102.701668],[36.356461,102.703102],[36.35659,102.704483],[36.356838,102.70578],[36.357239,102.707047],[36.357792,102.708229],[36.358471,102.709267],[36.35918,102.710274],[36.35981,102.711349],[36.360279,102.71257],[36.360569,102.713837],[36.36071,102.715134],[36.360661,102.716423],[36.360439,102.717644],[36.360062,102.718781],[36.35965,102.720009],[36.3591,102.721207],[36.35844,102.722366],[36.357651,102.723473],[36.356758,102.724503],[36.355801,102.725403],[36.354801,102.726173],[36.35376,102.726898],[36.35268,102.727661],[36.351768,102.728653],[36.351051,102.729797],[36.350521,102.731071],[36.350109,102.732437],[36.349739,102.73391],[36.349369,102.735382],[36.348991,102.736839],[36.348671,102.738258],[36.348381,102.739609],[36.347988,102.741013],[36.34753,102.742332],[36.34005,102.754784],[36.339161,102.755432],[36.338169,102.756142],[36.33712,102.75695],[36.33596,102.757759],[36.334949,102.758667],[36.334141,102.75975],[36.33358,102.760887],[36.33321,102.76194],[36.332981,102.762993],[36.332859,102.764],[36.332878,102.765083],[36.333118,102.766228],[36.333401,102.767479],[36.333641,102.76873],[36.333832,102.77002],[36.33387,102.771461],[36.333691,102.773102],[36.333351,102.774803],[36.333031,102.776466],[36.33279,102.778137],[36.332611,102.779831],[36.33255,102.781532],[36.332619,102.783272],[36.332779,102.784943],[36.333,102.786591],[36.333241,102.788223],[36.333469,102.789871],[36.33371,102.791519],[36.333961,102.793167],[36.334221,102.794807],[36.334469,102.796463],[36.334751,102.798119],[36.335018,102.799782],[36.33527,102.80146],[36.335522,102.803047],[36.335701,102.804604],[36.335709,102.806122],[36.335571,102.80764],[36.33527,102.809128],[36.334789,102.810516],[36.33424,102.811836],[36.333691,102.813164],[36.333199,102.814468],[36.332821,102.815819],[36.33255,102.817177],[36.332378,102.818512],[36.332352,102.819801],[36.332409,102.821037],[36.332481,102.82225],[36.332569,102.823647],[36.33268,102.825363],[36.332802,102.827103],[36.33292,102.828842],[36.333038,102.830582],[36.33316,102.832314],[36.333271,102.834053],[36.333302,102.83577],[36.333069,102.837486],[36.332649,102.839211],[36.332062,102.840851],[36.331589,102.842529],[36.331371,102.844269],[36.33147,102.846001],[36.331718,102.847679],[36.332001,102.849373],[36.33226,102.851051],[36.332458,102.852707],[36.332451,102.854446],[36.33223,102.856232],[36.331841,102.85791],[36.331322,102.859482],[36.330509,102.860924],[36.32962,102.862282],[36.328651,102.863586],[36.327679,102.864929],[36.326698,102.866257],[36.325729,102.867592],[36.32476,102.868896],[36.323879,102.87027],[36.323071,102.871727],[36.322418,102.873322],[36.321899,102.874947],[36.321522,102.87661],[36.32122,102.878304],[36.32093,102.879982],[36.32061,102.881683],[36.32021,102.883362],[36.319729,102.885094],[36.31918,102.886726],[36.318581,102.888237],[36.31789,102.889702],[36.31715,102.891113],[36.31636,102.892509],[36.31546,102.893852],[36.31448,102.895157],[36.313461,102.896408],[36.312439,102.897636],[36.311409,102.898888],[36.310379,102.900078],[36.309341,102.901283],[36.308311,102.902496],[36.30732,102.903763],[36.3064,102.905037],[36.305618,102.906418],[36.304939,102.907898],[36.304379,102.90947],[36.30394,102.91111],[36.303631,102.912811],[36.303459,102.914543],[36.303349,102.916283],[36.303249,102.918022],[36.303169,102.919777],[36.303082,102.921577],[36.30299,102.923393],[36.302891,102.925148],[36.302811,102.926842],[36.302719,102.928467],[36.30275,102.930069],[36.302879,102.931648],[36.30307,102.933121],[36.303219,102.934509],[36.303249,102.935883],[36.303261,102.937149],[36.303242,102.938301],[36.303188,102.939346],[36.30312,102.940231],[36.302509,102.94854],[36.302429,102.949707],[36.302299,102.951012],[36.302052,102.952461],[36.30167,102.954018],[36.301109,102.95565],[36.300381,102.957191],[36.29958,102.958641],[36.298752,102.96006],[36.297901,102.961487],[36.297039,102.962936],[36.296181,102.964371],[36.29533,102.96582],[36.29446,102.967308],[36.293629,102.968842],[36.292938,102.970451],[36.292339,102.972061],[36.291771,102.973679],[36.291199,102.975304],[36.290668,102.976952],[36.290089,102.978577],[36.289429,102.980171],[36.288651,102.981689],[36.287769,102.983124],[36.286812,102.984482],[36.285789,102.985733],[36.284691,102.986877],[36.283539,102.987923],[36.282318,102.988853],[36.281071,102.989723],[36.279819,102.990578],[36.278629,102.991524],[36.2775,102.992592],[36.276402,102.993752],[36.275372,102.994957],[36.274429,102.99633],[36.273571,102.99781],[36.272812,102.999336],[36.27206,103.000877],[36.271278,103.002441],[36.2705,103.004028],[36.26984,103.0056],[36.269218,103.007156],[36.268581,103.008713],[36.267792,103.010246],[36.267071,103.011818],[36.266232,103.013313],[36.265228,103.014641],[36.264111,103.015762],[36.262798,103.016663],[36.26141,103.017357],[36.26004,103.017838],[36.258659,103.018257],[36.257309,103.018677],[36.255932,103.019127],[36.25457,103.019524],[36.25322,103.019897],[36.251839,103.020363],[36.250542,103.02108],[36.249359,103.022057],[36.248291,103.023262],[36.247379,103.024658],[36.24667,103.026222],[36.245949,103.027779],[36.245079,103.029182],[36.24408,103.030457],[36.243038,103.031708],[36.241989,103.032951],[36.240891,103.034233],[36.23983,103.035477],[36.23877,103.03672],[36.237789,103.037971],[36.236752,103.039223],[36.23576,103.040527],[36.234989,103.04203],[36.234489,103.043694],[36.234299,103.045448],[36.23436,103.047256],[36.234612,103.049057],[36.234859,103.050789],[36.234909,103.052551],[36.234669,103.054314],[36.23418,103.055977],[36.233521,103.057579],[36.232681,103.059013],[36.2318,103.060432],[36.230919,103.061852],[36.230049,103.063278],[36.229179,103.064713],[36.228291,103.066116],[36.227409,103.067543],[36.226589,103.068893],[36.225819,103.070343],[36.225121,103.071907],[36.224529,103.073502],[36.223999,103.075157],[36.22348,103.076859],[36.223,103.07856],[36.222569,103.080292],[36.22208,103.081963],[36.2215,103.083603],[36.22084,103.085167],[36.220119,103.08667],[36.219379,103.088173],[36.218639,103.089668],[36.217918,103.091179],[36.21722,103.092697],[36.21656,103.094208],[36.215981,103.095863],[36.2155,103.09758],[36.215191,103.099319],[36.214958,103.101059],[36.21476,103.102783],[36.214439,103.104477],[36.213909,103.106148],[36.21312,103.107712],[36.21209,103.1091],[36.211048,103.11039],[36.210018,103.111679],[36.20903,103.112991],[36.208172,103.114464],[36.207531,103.116043],[36.207211,103.117798],[36.207008,103.119583],[36.206829,103.121361],[36.206631,103.123161],[36.206459,103.124924],[36.20628,103.126694],[36.2061,103.128464],[36.205921,103.130234],[36.205811,103.132004],[36.20578,103.133774],[36.205841,103.135551],[36.205971,103.137329],[36.20612,103.139122],[36.206249,103.140907],[36.206322,103.142693],[36.206268,103.144447],[36.206039,103.146172],[36.205601,103.147781],[36.205009,103.1493],[36.204239,103.150772],[36.20332,103.152107],[36.202358,103.153252],[36.201359,103.154373],[36.200371,103.155518],[36.199459,103.156754],[36.198689,103.158157],[36.198021,103.159721],[36.19754,103.161339],[36.197262,103.163033],[36.197151,103.164787],[36.19722,103.166573],[36.197369,103.168312],[36.19754,103.170013],[36.197659,103.171692],[36.197681,103.173317],[36.19746,103.174927],[36.197029,103.176422],[36.196381,103.177856],[36.19553,103.179077],[36.194611,103.180206],[36.193699,103.18132],[36.192829,103.182426],[36.191952,103.183563],[36.191071,103.184753],[36.190231,103.185966],[36.189449,103.187233],[36.188648,103.188507],[36.187698,103.189781],[36.186691,103.190971],[36.18565,103.192047],[36.184521,103.193123],[36.18338,103.194138],[36.18224,103.195129],[36.18108,103.196098],[36.180031,103.197189],[36.17907,103.198433],[36.17823,103.199791],[36.177589,103.201393],[36.17709,103.203041],[36.176739,103.204681],[36.176399,103.206306],[36.17598,103.207893],[36.17548,103.209412],[36.174858,103.210854],[36.174191,103.212288],[36.173538,103.213852],[36.172989,103.2155],[36.172649,103.217247],[36.172531,103.219101],[36.172668,103.221329],[36.172939,103.22316],[36.173222,103.224876],[36.1735,103.226547],[36.173752,103.228127],[36.173939,103.229721],[36.174179,103.231247],[36.174438,103.232758],[36.174648,103.234306],[36.174759,103.235893],[36.17474,103.237457],[36.17469,103.239113],[36.174622,103.240784],[36.1745,103.242447],[36.174511,103.244179],[36.174648,103.245949],[36.17495,103.247719],[36.175381,103.249428],[36.175941,103.251106],[36.176579,103.252762],[36.177219,103.254372],[36.177799,103.255951],[36.178169,103.257561],[36.178371,103.259117],[36.178391,103.260643],[36.178268,103.262154],[36.178009,103.263657],[36.177662,103.26506],[36.177181,103.266342],[36.176559,103.267609],[36.175961,103.268806],[36.175381,103.269981],[36.17482,103.271133],[36.174301,103.27227],[36.17384,103.273376],[36.17345,103.274384],[36.173161,103.275284],[36.172939,103.27607],[36.172798,103.276749],[36.17268,103.277298],[36.172619,103.277718],[36.172619,103.278023],[36.17255,103.278267],[36.172482,103.278526],[36.172138,103.279694],[36.172081,103.279877],[36.171959,103.280159],[36.171791,103.280441],[36.17173,103.280579],[36.171711,103.280663],[36.171661,103.280769],[36.171638,103.280807],[36.1716,103.280853],[36.171551,103.280937],[36.171391,103.281303],[36.17112,103.282066],[36.170689,103.283333],[36.170292,103.284767],[36.170071,103.286293],[36.169991,103.287849],[36.170078,103.289436],[36.1702,103.291023],[36.170231,103.29258],[36.170151,103.293983],[36.169941,103.295372],[36.169571,103.296951],[36.16851,103.305054],[36.168419,103.306953],[36.16827,103.308723],[36.16785,103.310417],[36.167179,103.311996],[36.166271,103.313431],[36.16523,103.314774],[36.1642,103.316132],[36.163361,103.317711],[36.163029,103.31881],[36.162781,103.320084],[36.162498,103.325623],[36.162251,103.328667],[36.161888,103.330269],[36.161179,103.332024],[36.16016,103.333656],[36.157082,103.338173],[36.155689,103.340042],[36.154961,103.340767],[36.153721,103.341583],[36.148899,103.343163],[36.148109,103.343552],[36.1474,103.344063],[36.14653,103.344963],[36.142269,103.350891],[36.141861,103.351784],[36.141548,103.352837],[36.141392,103.353622],[36.141312,103.354942],[36.141312,103.356323],[36.141521,103.3582],[36.142639,103.366814],[36.14333,103.372566],[36.14349,103.37439],[36.143551,103.378151],[36.14362,103.380043],[36.143951,103.382278],[36.144451,103.38401],[36.145111,103.385612],[36.15411,103.398842],[36.155128,103.400093],[36.15612,103.401283],[36.157051,103.402473],[36.15781,103.403847],[36.158379,103.405357],[36.158821,103.406967],[36.159088,103.408684],[36.159321,103.410454],[36.159531,103.412643],[36.159882,103.414429],[36.16058,103.416023],[36.161499,103.417427],[36.16264,103.418617],[36.163952,103.419487],[36.165371,103.420067],[36.166809,103.420593],[36.168251,103.421089],[36.169708,103.421608],[36.17115,103.422272],[36.172501,103.423119],[36.173721,103.424263],[36.174858,103.425537],[36.175659,103.427223],[36.176361,103.429291],[36.176991,103.431534],[36.177189,103.432838],[36.177212,103.434021],[36.17717,103.434967],[36.17688,103.436829],[36.17598,103.441719],[36.175621,103.44455],[36.175591,103.446701],[36.176281,103.450691],[36.176701,103.452438],[36.177071,103.454086],[36.177361,103.455711],[36.17746,103.457237],[36.177158,103.456787],[36.176998,103.456589],[36.1768,103.456467],[36.176449,103.456459],[36.176331,103.456612],[36.17625,103.456818],[36.176201,103.457039],[36.176231,103.457268],[36.176331,103.457474],[36.176491,103.457603],[36.176689,103.457733],[36.17691,103.457787],[36.177349,103.458008],[36.177731,103.458298],[36.17804,103.458687],[36.178211,103.459213],[36.178299,103.459747],[36.178322,103.460243],[36.17831,103.460457],[36.178242,103.460709],[36.178249,103.46109],[36.177689,103.462067],[36.177311,103.462547],[36.1772,103.462738],[36.177109,103.462982],[36.17701,103.463928],[36.176899,103.464378],[36.1768,103.4645],[36.175251,103.465729],[36.174911,103.467194],[36.17487,103.467773],[36.174591,103.469757],[36.174309,103.470833],[36.174229,103.471077],[36.173988,103.471497],[36.173538,103.471733],[36.174229,103.471489],[36.17416,103.471832],[36.173969,103.472],[36.173069,103.475014],[36.171669,103.478172],[36.171021,103.480209],[36.170811,103.482384],[36.170441,103.482681],[36.169361,103.482674],[36.168732,103.482658],[36.167721,103.482674],[36.167332,103.482841],[36.16708,103.483437],[36.16634,103.486961],[36.165279,103.491341],[36.164589,103.493446],[36.163799,103.494377],[36.162411,103.495079],[36.155079,103.497543],[36.15213,103.498734],[36.151791,103.49884],[36.14447,103.500648],[36.14299,103.501266],[36.142841,103.501373],[36.141708,103.502586],[36.14072,103.503593],[36.14006,103.504601],[36.138741,103.508942],[36.138149,103.511543],[36.137932,103.513313],[36.138039,103.518738],[36.138,103.522591],[36.137661,103.524048],[36.136459,103.526466],[36.136051,103.526978],[36.13266,103.529221],[36.12867,103.530296],[36.123032,103.531723],[36.122059,103.532089],[36.11982,103.533241],[36.116169,103.535553],[36.115021,103.53627],[36.11412,103.537117],[36.11311,103.538673],[36.11042,103.545486],[36.109219,103.548241],[36.1087,103.550247],[36.108509,103.552002],[36.108749,103.556358],[36.108971,103.55764],[36.109459,103.559082],[36.1115,103.562927],[36.11195,103.564087],[36.111801,103.564117],[36.11142,103.564163],[36.11076,103.564323],[36.109909,103.56456],[36.109112,103.56485],[36.10836,103.565163],[36.10775,103.56543],[36.10733,103.565666],[36.10696,103.566017],[36.10664,103.566307],[36.10622,103.566803],[36.105869,103.566978],[36.105518,103.566887],[36.105099,103.56665],[36.104721,103.566406],[36.104382,103.566269],[36.104061,103.566223],[36.10379,103.566322],[36.1035,103.566559],[36.103199,103.566811],[36.10268,103.567261],[36.101822,103.567711],[36.100868,103.568237],[36.10009,103.569122],[36.09935,103.569992],[36.09861,103.57077],[36.098011,103.571213],[36.097469,103.571411],[36.096951,103.571587],[36.096409,103.571777],[36.095909,103.57196],[36.09539,103.572144],[36.09481,103.572159],[36.0942,103.572037],[36.09362,103.571877],[36.093029,103.571693],[36.092361,103.571571],[36.091492,103.57151],[36.09053,103.571442],[36.089512,103.571136],[36.088509,103.570709],[36.08754,103.570297],[36.086658,103.569923],[36.085831,103.569489],[36.085011,103.568947],[36.08429,103.568451],[36.08358,103.568001],[36.08279,103.567543],[36.081951,103.567322],[36.08112,103.567436],[36.080292,103.567734],[36.07943,103.567833],[36.078571,103.567574],[36.077759,103.567329],[36.077,103.567253],[36.076241,103.567482],[36.075581,103.568031],[36.074841,103.568703],[36.074081,103.569122],[36.07338,103.569473],[36.07267,103.569794],[36.071899,103.57016],[36.071281,103.570473],[36.07069,103.570763],[36.070011,103.570992],[36.069382,103.570869],[36.06881,103.570473],[36.06813,103.569923],[36.067268,103.569206],[36.06641,103.56852],[36.065659,103.56781],[36.065121,103.567162],[36.06464,103.566566],[36.064171,103.566093],[36.063671,103.565788],[36.06316,103.565529],[36.062641,103.565269],[36.062092,103.564987],[36.06168,103.564552],[36.061611,103.563751],[36.061699,103.562576],[36.061779,103.561279],[36.061821,103.56012],[36.06144,103.559196],[36.060928,103.558563],[36.060329,103.558067],[36.05983,103.557602],[36.059681,103.556778],[36.05991,103.555649],[36.060169,103.55442],[36.06041,103.553177],[36.060741,103.552063],[36.061352,103.55098],[36.061878,103.549911],[36.062229,103.54892],[36.062469,103.547882],[36.062538,103.546783],[36.062408,103.54567],[36.062168,103.544594],[36.061852,103.543556],[36.061321,103.54274],[36.060532,103.542427],[36.0597,103.542511],[36.058929,103.542641],[36.05827,103.542763],[36.057571,103.542877],[36.05674,103.54303],[36.055882,103.543091],[36.054989,103.543007],[36.054211,103.543007],[36.053532,103.54306],[36.05267,103.54364],[36.05183,103.544357],[36.051189,103.544891],[36.050709,103.545082],[36.050079,103.544983],[36.04929,103.544731],[36.048359,103.544601],[36.047379,103.544884],[36.04657,103.545647],[36.04586,103.546608],[36.045101,103.547447],[36.044239,103.547958],[36.043221,103.548027],[36.04221,103.547821],[36.041279,103.547829],[36.04044,103.548058],[36.039669,103.548241],[36.039051,103.548279],[36.03828,103.548019],[36.037239,103.548073],[36.036171,103.548233],[36.035,103.548187],[36.03418,103.548042],[36.033569,103.547798],[36.033138,103.547546],[36.03281,103.547379],[36.032139,103.547073],[36.0313,103.546738],[36.03046,103.546089],[36.029499,103.545258],[36.028412,103.544601],[36.027321,103.544006],[36.02631,103.543457],[36.02544,103.543007],[36.0247,103.543068],[36.024109,103.543259],[36.023312,103.542931],[36.0224,103.542397],[36.021481,103.541931],[36.02066,103.541771],[36.01923,103.541351],[36.01841,103.540916],[36.017712,103.540497],[36.01722,103.540237],[36.01685,103.53994],[36.016548,103.539543],[36.0163,103.538963],[36.01622,103.538322],[36.016319,103.537514],[36.016602,103.536491],[36.016899,103.535431],[36.017239,103.534363],[36.01749,103.533386],[36.01749,103.532539],[36.017208,103.531807],[36.0168,103.531281],[36.016399,103.530853],[36.016022,103.53038],[36.015701,103.529823],[36.015511,103.529167],[36.015419,103.528473],[36.015541,103.527573],[36.015862,103.526611],[36.01627,103.525742],[36.01672,103.524986],[36.0172,103.524429],[36.01767,103.52401],[36.01828,103.523903],[36.019169,103.524139],[36.020119,103.524406],[36.02108,103.524277],[36.0219,103.523712],[36.02269,103.523102],[36.023571,103.522758],[36.02457,103.522697],[36.025539,103.52256],[36.026371,103.522072],[36.027069,103.521233],[36.027729,103.520287],[36.028469,103.519417],[36.02932,103.518646],[36.03019,103.517883],[36.031052,103.517113],[36.031799,103.516441],[36.032398,103.515793],[36.032879,103.514977],[36.033272,103.514061],[36.033539,103.513077],[36.033741,103.512009],[36.034111,103.510986],[36.034561,103.509987],[36.03484,103.508858],[36.034859,103.507698],[36.034721,103.506607],[36.034519,103.505722],[36.03434,103.504883],[36.03421,103.503868],[36.034302,103.502808],[36.034489,103.501747],[36.034618,103.500687],[36.034512,103.499649],[36.034328,103.498642],[36.034161,103.49765],[36.03397,103.496681],[36.033791,103.495697],[36.033691,103.494698],[36.033852,103.493683],[36.0341,103.492653],[36.034271,103.491653],[36.034851,103.490936],[36.03537,103.490097],[36.0355,103.489067],[36.035511,103.488098],[36.035259,103.487198],[36.03503,103.486282],[36.035271,103.48539],[36.035851,103.48455],[36.03611,103.483437],[36.036289,103.482193],[36.036461,103.480927],[36.03656,103.479729],[36.036449,103.478622],[36.036308,103.477608],[36.036549,103.476707],[36.037239,103.476028],[36.03809,103.475502],[36.0438,103.472023],[36.044491,103.471581],[36.044979,103.47113],[36.04533,103.470642],[36.045639,103.469948],[36.045769,103.469147],[36.045811,103.468369],[36.04591,103.467506],[36.046101,103.466667],[36.046398,103.46582],[36.046768,103.464973],[36.047211,103.464149],[36.04768,103.463463],[36.048019,103.462967],[36.048401,103.462517],[36.048851,103.461937],[36.04937,103.461304],[36.04995,103.460564],[36.050499,103.459877],[36.051048,103.45919],[36.05164,103.458443],[36.052231,103.457718],[36.052872,103.456917],[36.053539,103.455994],[36.05407,103.454971],[36.054401,103.45388],[36.054588,103.452766],[36.054691,103.451637],[36.054779,103.450531],[36.054981,103.449379],[36.055248,103.44809],[36.055519,103.446823],[36.055759,103.445663],[36.055969,103.444656],[36.055969,103.443802],[36.05571,103.442848],[36.055401,103.441811],[36.05508,103.44072],[36.05476,103.439629],[36.05444,103.438599],[36.054131,103.437607],[36.053871,103.436653],[36.053699,103.435631],[36.0536,103.434662],[36.053501,103.4338],[36.053391,103.43293],[36.053249,103.431831],[36.053051,103.43071],[36.052872,103.429764],[36.052731,103.428963],[36.052608,103.428207],[36.052471,103.427383],[36.052349,103.426514],[36.052189,103.425667],[36.051991,103.424957],[36.0518,103.424332],[36.051609,103.42366],[36.051411,103.422951],[36.051151,103.422188],[36.05072,103.421577],[36.05019,103.42115],[36.049648,103.420738],[36.04911,103.420326],[36.048531,103.419884],[36.047852,103.419342],[36.047081,103.418777],[36.046211,103.418312],[36.04528,103.417999],[36.044319,103.417847],[36.043331,103.41774],[36.042358,103.417633],[36.041401,103.417557],[36.040531,103.417473],[36.039688,103.417389],[36.038879,103.417313],[36.038071,103.417229],[36.037331,103.417152],[36.036671,103.417038],[36.03606,103.416924],[36.03553,103.416801],[36.03513,103.416687],[36.034931,103.416634],[36.034752,103.416557],[36.033508,103.416237],[36.032879,103.416054],[36.032101,103.415817],[36.031219,103.415558],[36.030369,103.41526],[36.029572,103.414803],[36.028801,103.414139],[36.028091,103.413544],[36.02739,103.413071],[36.026649,103.412933],[36.02597,103.413177],[36.02533,103.41362],[36.0247,103.41407],[36.02409,103.414139],[36.02359,103.41378],[36.02317,103.413292],[36.02272,103.41275],[36.022209,103.412132],[36.02158,103.411392],[36.020859,103.410553],[36.020149,103.409683],[36.01939,103.40892],[36.01857,103.408272],[36.0177,103.407707],[36.016781,103.407303],[36.01585,103.406937],[36.014961,103.406616],[36.01416,103.406326],[36.013451,103.405968],[36.012798,103.40535],[36.012291,103.404457],[36.01181,103.40332],[36.011269,103.402077],[36.010719,103.400902],[36.010208,103.39978],[36.00972,103.398743],[36.009071,103.397873],[36.008339,103.397087],[36.007671,103.396378],[36.00716,103.395576],[36.006851,103.394493],[36.00663,103.393227],[36.006371,103.391907],[36.005951,103.390648],[36.005299,103.389511],[36.004532,103.388588],[36.003651,103.387939],[36.002659,103.387642],[36.00169,103.387741],[36.000679,103.387947],[35.99968,103.388184],[35.99876,103.388367],[35.99791,103.388344],[35.997021,103.387993],[35.996109,103.387543],[35.995152,103.387077],[35.994228,103.386673],[35.99342,103.386421],[35.99268,103.38665],[35.992088,103.38726],[35.99144,103.387802],[35.990589,103.388161],[35.989651,103.388153],[35.98872,103.387917],[35.98782,103.38755],[35.98695,103.387047],[35.986061,103.386543],[35.985241,103.386017],[35.984661,103.385193],[35.984119,103.384323],[35.983421,103.383781],[35.982712,103.383301],[35.982182,103.382423],[35.981739,103.38134],[35.981319,103.380302],[35.980881,103.379242],[35.98045,103.378166],[35.98003,103.377159],[35.979622,103.376213],[35.979359,103.375229],[35.979252,103.374123],[35.978951,103.373123],[35.97839,103.372238],[35.977871,103.371323],[35.977631,103.370201],[35.977291,103.369133],[35.9767,103.36837],[35.9762,103.367844],[35.975719,103.367332],[35.975201,103.366882],[35.974529,103.366463],[35.973789,103.365952],[35.97324,103.365128],[35.97274,103.364227],[35.97226,103.363327],[35.971748,103.362427],[35.970909,103.361908],[35.96991,103.361443],[35.968899,103.360977],[35.967949,103.360443],[35.96703,103.359848],[35.966141,103.359261],[35.96529,103.358704],[35.964481,103.358124],[35.963871,103.357224],[35.963322,103.35611],[35.962742,103.355072],[35.96204,103.354179],[35.96133,103.353317],[35.96072,103.352547],[35.960159,103.351891],[35.959671,103.351433],[35.959,103.350822],[35.958199,103.350197],[35.957401,103.349541],[35.9566,103.3489],[35.955761,103.34832],[35.954899,103.347893],[35.95401,103.347527],[35.953079,103.347183],[35.952209,103.346848],[35.951519,103.346367],[35.951019,103.345596],[35.95052,103.344849],[35.949871,103.344421],[35.94907,103.344223],[35.948292,103.344101],[35.947639,103.344002],[35.946999,103.343887],[35.946301,103.343773],[35.945591,103.343651],[35.944809,103.343529],[35.944,103.343323],[35.943291,103.342857],[35.942692,103.342148],[35.942131,103.341408],[35.94154,103.340843],[35.940899,103.340607],[35.94035,103.340424],[35.93993,103.34037],[35.939491,103.340332],[35.938862,103.340317],[35.938301,103.340363],[35.937832,103.340408],[35.937439,103.340424],[35.93705,103.340431],[35.936581,103.340317],[35.936211,103.339737],[35.93605,103.339012],[35.93589,103.338287],[35.935741,103.337608],[35.935551,103.336746],[35.93536,103.335999],[35.935181,103.33535],[35.93491,103.334801],[35.934639,103.334183],[35.934662,103.333519],[35.93483,103.332878],[35.934952,103.332329],[35.93502,103.331711],[35.934879,103.331123],[35.934502,103.330612],[35.934231,103.330093],[35.934292,103.329514],[35.934471,103.328979],[35.934689,103.328453],[35.934959,103.327942],[35.93523,103.327438],[35.935558,103.326881],[35.935928,103.326302],[35.936329,103.325996],[35.93676,103.325882],[35.937099,103.325798],[35.93716,103.325638],[35.93689,103.325508],[35.9366,103.325447],[35.936371,103.325523],[35.936001,103.325783],[35.935661,103.326157],[35.93544,103.326553],[35.93528,103.326714],[35.935001,103.326576],[35.934631,103.32637],[35.934261,103.326149],[35.934132,103.325859],[35.93417,103.32534],[35.93425,103.324707],[35.93433,103.324173],[35.934429,103.323708],[35.934502,103.323181],[35.93457,103.322563],[35.934631,103.321854],[35.934711,103.32106],[35.934811,103.320267],[35.934879,103.319504],[35.934971,103.318771],[35.934929,103.318176],[35.934952,103.317688],[35.934898,103.317123],[35.934818,103.316391],[35.934792,103.315918],[35.934799,103.315819],[35.93449,103.315529],[35.934021,103.3153],[35.933731,103.315079],[35.9333,103.314484],[35.932991,103.314209],[35.93206,103.31369],[35.931179,103.313438],[35.93055,103.31308],[35.93045,103.312927],[35.930561,103.31279],[35.931301,103.312927],[35.931931,103.312729],[35.932541,103.312851],[35.93264,103.312767],[35.932671,103.312683],[35.93259,103.312553],[35.932251,103.312363],[35.93095,103.312019],[35.93042,103.3116],[35.93021,103.311493],[35.93,103.311501],[35.929619,103.311707],[35.92934,103.311974],[35.929199,103.31218],[35.929001,103.312714],[35.92902,103.312897],[35.929161,103.313431],[35.929131,103.313599],[35.92905,103.31369],[35.92836,103.313927],[35.928131,103.313873],[35.92802,103.313766],[35.927731,103.313408],[35.92757,103.313408],[35.927471,103.313507],[35.927441,103.313728],[35.92749,103.313828],[35.92778,103.314056],[35.92786,103.31427],[35.927811,103.3144],[35.927441,103.314796],[35.927219,103.315201],[35.92659,103.316589],[35.92635,103.317291],[35.92606,103.31871],[35.925869,103.31913],[35.925659,103.319351],[35.921909,103.322456],[35.921421,103.322708],[35.921211,103.322723],[35.920971,103.322647],[35.9207,103.322456],[35.92025,103.321831],[35.91988,103.321548],[35.919651,103.321533],[35.9193,103.3218],[35.91909,103.3218],[35.918961,103.321693],[35.918789,103.321426],[35.91853,103.320938],[35.91827,103.320763],[35.918091,103.320763],[35.917961,103.320847],[35.917641,103.321823],[35.917561,103.321907],[35.917419,103.321968],[35.917191,103.321877],[35.91679,103.321487],[35.916691,103.321449],[35.916561,103.321487],[35.916161,103.3218],[35.915901,103.321831],[35.914989,103.321136],[35.914841,103.321091],[35.914459,103.321136],[35.913651,103.321487],[35.913311,103.321579],[35.912979,103.321579],[35.912811,103.321503],[35.912701,103.321327],[35.912571,103.320686],[35.912449,103.320587],[35.91235,103.320618],[35.912251,103.320877],[35.912121,103.321709],[35.91201,103.322006],[35.911621,103.322807],[35.911381,103.32312],[35.911091,103.323288],[35.910511,103.323349],[35.90971,103.323288],[35.909481,103.32338],[35.909069,103.323914],[35.90884,103.324318],[35.908539,103.325203],[35.908451,103.325363],[35.907921,103.325851],[35.907841,103.326057],[35.907871,103.326271],[35.908291,103.327103],[35.908451,103.327797],[35.90844,103.328041],[35.90834,103.328178],[35.90797,103.328407],[35.9076,103.328377],[35.90731,103.328247],[35.907181,103.32814],[35.906361,103.327087],[35.906281,103.326759],[35.90596,103.326157],[35.905769,103.326073],[35.904621,103.32605],[35.90448,103.325974],[35.90419,103.325638],[35.904121,103.32547],[35.903931,103.323669],[35.90382,103.323341],[35.9034,103.322639],[35.903271,103.322327],[35.903221,103.322166],[35.903141,103.321648],[35.903191,103.321518],[35.90332,103.321419],[35.903751,103.321373],[35.90398,103.32122],[35.90406,103.321098],[35.904079,103.320961],[35.904041,103.320587],[35.903931,103.320419],[35.903801,103.320358],[35.90366,103.320343],[35.90303,103.320427],[35.902809,103.320297],[35.90266,103.32],[35.90202,103.318047],[35.90184,103.317719],[35.9016,103.317497],[35.899841,103.318741],[35.89954,103.320923],[35.899841,103.321854],[35.899891,103.322159],[35.899761,103.32328],[35.899811,103.323608],[35.900421,103.324417],[35.900829,103.325241],[35.90099,103.325394],[35.901291,103.325539],[35.901581,103.325768],[35.902,103.326828],[35.902531,103.327347],[35.90313,103.328468],[35.903351,103.329033],[35.903721,103.329483],[35.90395,103.330208],[35.903961,103.330566],[35.903881,103.330856],[35.903931,103.331078],[35.90419,103.331284],[35.90443,103.33165],[35.904701,103.331947],[35.905319,103.332397],[35.905491,103.332619],[35.905651,103.333023],[35.90554,103.333847],[35.905609,103.334068],[35.90588,103.334503],[35.9062,103.334747],[35.907101,103.335007],[35.907181,103.335159],[35.907181,103.335693],[35.907219,103.335777],[35.907341,103.335876],[35.90757,103.335876],[35.90773,103.335777],[35.907879,103.335617],[35.908119,103.33519],[35.908291,103.335121],[35.90839,103.335159],[35.908779,103.33548],[35.909451,103.335854],[35.90955,103.335991],[35.90955,103.336067],[35.90942,103.336571],[35.90942,103.336723],[35.909931,103.337753],[35.90995,103.338097],[35.90974,103.338676],[35.909679,103.33876],[35.90918,103.339058],[35.908791,103.339523],[35.908291,103.339897],[35.9081,103.339897],[35.907909,103.339653],[35.90773,103.339607],[35.9076,103.339737],[35.907501,103.340157],[35.907391,103.340317],[35.906929,103.340553],[35.90678,103.3405],[35.90641,103.34005],[35.906231,103.340027],[35.905979,103.340157],[35.90591,103.340218],[35.90575,103.340828],[35.9053,103.341309],[35.905121,103.341347],[35.904881,103.341309],[35.904751,103.3414],[35.904411,103.342293],[35.9039,103.343323],[35.903801,103.343407],[35.903419,103.343559],[35.902191,103.343681],[35.90147,103.343674],[35.901081,103.343536],[35.90065,103.343536],[35.89859,103.343857],[35.89846,103.343979],[35.89817,103.344414],[35.897621,103.344704],[35.897129,103.345703],[35.896881,103.34639],[35.896431,103.34671],[35.895969,103.346939],[35.89587,103.347069],[35.895691,103.347488],[35.89558,103.347527],[35.89534,103.347504],[35.89521,103.347527],[35.89476,103.348007],[35.89463,103.348091],[35.89418,103.348106],[35.893681,103.348648],[35.893181,103.349037],[35.892849,103.34922],[35.89254,103.349564],[35.89238,103.349663],[35.891979,103.3498],[35.890751,103.349899],[35.890461,103.349991],[35.890411,103.350182],[35.89043,103.350258],[35.890511,103.350327],[35.89156,103.35038],[35.892181,103.350471],[35.893009,103.350128],[35.893799,103.349693],[35.89444,103.349716],[35.894539,103.349617],[35.894619,103.349274],[35.894699,103.349159],[35.89558,103.349037],[35.896191,103.348778],[35.896641,103.34893],[35.897041,103.34993],[35.89719,103.350098],[35.897339,103.350098],[35.89772,103.349899],[35.8978,103.349777],[35.8978,103.349579],[35.89764,103.349007],[35.8978,103.348557],[35.897709,103.348099],[35.8978,103.347931],[35.898121,103.347954],[35.89872,103.348198],[35.899151,103.348503],[35.89925,103.348503],[35.899361,103.34832],[35.89933,103.347771],[35.89941,103.34761],[35.89954,103.347588],[35.90036,103.347977],[35.900539,103.348007],[35.90073,103.347939],[35.90081,103.347816],[35.900829,103.347687],[35.90081,103.347557],[35.90065,103.347237],[35.900631,103.347099],[35.900749,103.346939],[35.900909,103.346909],[35.90134,103.347023],[35.901581,103.347237],[35.901871,103.347633],[35.902,103.347656],[35.90229,103.347557],[35.902451,103.347679],[35.902481,103.347763],[35.902481,103.347893],[35.90239,103.34819],[35.902279,103.348427],[35.902161,103.348557],[35.901821,103.34874],[35.901421,103.349083],[35.90097,103.349548],[35.900539,103.349586],[35.900391,103.34967],[35.8992,103.351128],[35.898899,103.35125],[35.89851,103.351738],[35.897949,103.352081],[35.897701,103.352127],[35.89711,103.351883],[35.89674,103.351799],[35.89637,103.351517],[35.896191,103.351509],[35.895741,103.352219],[35.895531,103.352287],[35.895241,103.35228],[35.895111,103.352341],[35.895081,103.352386],[35.89502,103.352798],[35.89492,103.353027],[35.89476,103.353088],[35.89397,103.353027],[35.893871,103.353111],[35.893799,103.353317],[35.893951,103.354019],[35.89389,103.354156],[35.8937,103.354309],[35.893311,103.354301],[35.89315,103.354233],[35.89241,103.353683],[35.892151,103.353607],[35.892021,103.353699],[35.892021,103.35376],[35.89212,103.353859],[35.892509,103.353973],[35.89323,103.354584],[35.893391,103.35466],[35.89381,103.354607],[35.893921,103.35466],[35.89402,103.35479],[35.89415,103.355057],[35.894161,103.35524],[35.89365,103.356293],[35.893379,103.357338],[35.89333,103.357857],[35.89352,103.358528],[35.893539,103.358757],[35.89328,103.359581],[35.893101,103.36042],[35.892891,103.36097],[35.892601,103.361397],[35.892479,103.361679],[35.892399,103.362267],[35.89225,103.362717],[35.891689,103.363441],[35.891701,103.363586],[35.89183,103.36393],[35.89188,103.364227],[35.891739,103.364799],[35.891239,103.365868],[35.89119,103.366417],[35.89098,103.366737],[35.89064,103.367073],[35.890411,103.367378],[35.890461,103.367554],[35.8909,103.367996],[35.890999,103.368294],[35.890999,103.368591],[35.890789,103.369034],[35.89082,103.36924],[35.891251,103.369507],[35.89138,103.369766],[35.89138,103.370003],[35.8913,103.370537],[35.89101,103.371597],[35.890831,103.371979],[35.89056,103.372147],[35.89024,103.372467],[35.890041,103.372566],[35.88974,103.372597],[35.88937,103.372917],[35.88903,103.373154],[35.88842,103.374519],[35.888161,103.374847],[35.886051,103.37606],[35.886009,103.37616],[35.88596,103.376633],[35.885849,103.376869],[35.88541,103.377274],[35.884781,103.377457],[35.884541,103.377586],[35.88446,103.377731],[35.884411,103.378151],[35.8843,103.378258],[35.883511,103.378441],[35.88298,103.378433],[35.882721,103.378593],[35.88261,103.378754],[35.882599,103.37886],[35.882771,103.379341],[35.882801,103.379578],[35.882759,103.379761],[35.882641,103.37989],[35.881191,103.380547],[35.880939,103.38073],[35.880829,103.380997],[35.880619,103.382156],[35.880322,103.382767],[35.880291,103.38385],[35.880409,103.384117],[35.880939,103.38459],[35.881069,103.384758],[35.88121,103.385139],[35.88121,103.385368],[35.881161,103.385468],[35.880951,103.385757],[35.88076,103.385887],[35.879971,103.386147],[35.879841,103.386299],[35.879841,103.386543],[35.88002,103.386917],[35.879921,103.387154],[35.879681,103.387321],[35.87952,103.387543],[35.879551,103.387688],[35.879791,103.388077],[35.879791,103.388206],[35.879631,103.38842],[35.879021,103.388748],[35.87709,103.389458],[35.876881,103.389587],[35.87672,103.389809],[35.87672,103.389977],[35.876801,103.39016],[35.878311,103.3909],[35.878521,103.391068],[35.878559,103.39119],[35.878521,103.391258],[35.878349,103.391243],[35.87804,103.390953],[35.877689,103.39077],[35.87616,103.39035],[35.876011,103.390266],[35.875931,103.390129],[35.87603,103.389709],[35.87619,103.389503],[35.87701,103.388939],[35.878201,103.388283],[35.87825,103.388153],[35.878231,103.388077],[35.87812,103.388031],[35.877522,103.388428],[35.875599,103.389351],[35.875351,103.389648],[35.87513,103.390297],[35.875111,103.390511],[35.87524,103.390678],[35.87656,103.391373],[35.87661,103.391434],[35.876629,103.391602],[35.876541,103.391769],[35.876339,103.39193],[35.875771,103.392357],[35.875191,103.392609],[35.874691,103.392929],[35.874081,103.393051],[35.87344,103.393417],[35.871861,103.39402],[35.87075,103.394524],[35.87011,103.394608],[35.869961,103.394691],[35.86961,103.395073],[35.868111,103.395668],[35.867321,103.396179],[35.867111,103.39637],[35.867069,103.396553],[35.867081,103.396683],[35.867199,103.396843],[35.86832,103.39743],[35.869591,103.398453],[35.87022,103.398804],[35.87038,103.399048],[35.870361,103.399178],[35.870201,103.399361],[35.869431,103.399841],[35.869091,103.399986],[35.86861,103.400093],[35.868141,103.400467],[35.86787,103.400551],[35.867661,103.400681],[35.867149,103.401268],[35.867119,103.401443],[35.867149,103.401558],[35.86763,103.402008],[35.867649,103.402283],[35.867481,103.402573],[35.867161,103.402901],[35.866291,103.403427],[35.86607,103.403679],[35.865761,103.404739],[35.865841,103.406013],[35.865971,103.40625],[35.86607,103.406303],[35.866211,103.406273],[35.867451,103.405586],[35.867729,103.40551],[35.867889,103.405602],[35.86832,103.406197],[35.868839,103.406593],[35.868931,103.406731],[35.86898,103.406891],[35.868931,103.407028],[35.868771,103.407204],[35.867191,103.407806],[35.866859,103.407967],[35.866791,103.408081],[35.866791,103.408257],[35.866909,103.408417],[35.867561,103.408813],[35.867691,103.408951],[35.86776,103.409119],[35.86768,103.409271],[35.867569,103.40934],[35.86515,103.410027],[35.864929,103.410172],[35.864769,103.410393],[35.864689,103.410759],[35.864761,103.411324],[35.864731,103.411621],[35.864109,103.412628],[35.86393,103.413116],[35.863892,103.414146],[35.86396,103.414627],[35.86388,103.414917],[35.863529,103.415466],[35.863441,103.415733],[35.863411,103.416649],[35.863491,103.416946],[35.863731,103.417427],[35.86372,103.417908],[35.863781,103.418327],[35.864071,103.418747],[35.864521,103.420151],[35.864891,103.42057],[35.86499,103.420769],[35.86499,103.421059],[35.864799,103.421509],[35.86478,103.421677],[35.865089,103.422218],[35.865089,103.422607],[35.86515,103.422897],[35.865471,103.423698],[35.865509,103.424347],[35.866211,103.425583],[35.866371,103.425957],[35.866501,103.426392],[35.866631,103.427513],[35.866611,103.427803],[35.866501,103.428108],[35.866081,103.428947],[35.866081,103.429131],[35.866161,103.429199],[35.866261,103.429161],[35.86668,103.428268],[35.86694,103.427948],[35.86705,103.427917],[35.867531,103.428108],[35.867661,103.428101],[35.86779,103.428017],[35.868309,103.427551],[35.86842,103.427544],[35.868481,103.427681],[35.868301,103.427917],[35.867771,103.428368],[35.867661,103.428436],[35.867161,103.42852],[35.867001,103.428658],[35.866699,103.429367],[35.866699,103.429558],[35.866791,103.429817],[35.866791,103.430061],[35.866631,103.430191],[35.866371,103.430267],[35.86623,103.430397],[35.866119,103.430641],[35.86594,103.431297],[35.86578,103.431534],[35.865601,103.431633],[35.86512,103.431763],[35.86441,103.432266],[35.864201,103.432281],[35.863701,103.432137],[35.86356,103.432137],[35.86343,103.432259],[35.86338,103.43248],[35.863491,103.433296],[35.864361,103.435059],[35.864361,103.435333],[35.864269,103.435577],[35.864109,103.435791],[35.863621,103.436157],[35.863491,103.436699],[35.863361,103.436943],[35.862949,103.437317],[35.86245,103.437477],[35.862171,103.437668],[35.861931,103.437866],[35.861752,103.438148],[35.86166,103.438637],[35.86132,103.439491],[35.861229,103.440849],[35.86158,103.441933],[35.861771,103.44236],[35.862122,103.442917],[35.862141,103.443161],[35.862011,103.443298],[35.86132,103.443497],[35.861111,103.443932],[35.861012,103.444],[35.86031,103.444054],[35.8601,103.444153],[35.860031,103.444237],[35.860031,103.444519],[35.86034,103.444893],[35.860371,103.445053],[35.860321,103.445221],[35.86005,103.445541],[35.859909,103.445587],[35.859699,103.445587],[35.858891,103.445396],[35.85844,103.445396],[35.856571,103.445953],[35.8563,103.446091],[35.855801,103.44648],[35.855221,103.446709],[35.85482,103.446999],[35.854191,103.447113],[35.85363,103.447479],[35.852451,103.447937],[35.851891,103.448051],[35.85046,103.447929],[35.850182,103.44796],[35.84903,103.448624],[35.847549,103.449226],[35.8456,103.450958],[35.8447,103.45121],[35.844551,103.451347],[35.844379,103.451988],[35.84417,103.452217],[35.841621,103.453018],[35.84103,103.4533],[35.840721,103.453308],[35.839741,103.453018],[35.839409,103.45269],[35.839081,103.452217],[35.838791,103.451988],[35.837379,103.45195],[35.836552,103.45182],[35.836411,103.451714],[35.836281,103.4515],[35.83577,103.44986],[35.835541,103.449448],[35.834641,103.449051],[35.8339,103.448349],[35.833389,103.448067],[35.831711,103.446968],[35.831539,103.446907],[35.831089,103.446907],[35.83028,103.446663],[35.829361,103.446587],[35.82859,103.446327],[35.828239,103.44632],[35.826759,103.446579],[35.825489,103.446587],[35.823792,103.446289],[35.822731,103.446251],[35.822109,103.445961],[35.82196,103.445953],[35.821239,103.446121],[35.82066,103.446564],[35.820499,103.446617],[35.819111,103.446938],[35.816921,103.447937],[35.816559,103.448021],[35.81599,103.447937],[35.814091,103.44809],[35.81358,103.448036],[35.812801,103.448151],[35.8125,103.448067],[35.81221,103.447906],[35.812111,103.447777],[35.81205,103.447578],[35.81213,103.446388],[35.812031,103.445686],[35.812229,103.444946],[35.812241,103.444763],[35.812191,103.44458],[35.811161,103.443619],[35.810452,103.442787],[35.809799,103.442299],[35.809681,103.442131],[35.808922,103.440361],[35.808731,103.440071],[35.80843,103.439758],[35.808281,103.439697],[35.807869,103.439728],[35.807449,103.439537],[35.806911,103.439407],[35.805611,103.438591],[35.804291,103.438309],[35.80405,103.438179],[35.803631,103.43782],[35.802731,103.437592],[35.802341,103.437393],[35.801941,103.437286],[35.80056,103.437141],[35.7995,103.437111],[35.798691,103.437286],[35.798481,103.43721],[35.798012,103.436867],[35.797791,103.436821],[35.795181,103.43663],[35.793781,103.436768],[35.792801,103.436974],[35.79229,103.43692],[35.79073,103.436157],[35.78941,103.435959],[35.788971,103.435799],[35.787891,103.434837],[35.787312,103.434486],[35.786201,103.434097],[35.785431,103.434029],[35.783321,103.432663],[35.78191,103.431961],[35.780861,103.431618],[35.780449,103.431396],[35.779381,103.431396],[35.77903,103.431473],[35.778332,103.431137],[35.777512,103.431],[35.77626,103.430901],[35.77512,103.430588],[35.774719,103.430557],[35.77388,103.430611],[35.77367,103.430557],[35.773472,103.430397],[35.773041,103.429649],[35.772831,103.429337],[35.771561,103.428581],[35.770069,103.427193],[35.769489,103.427048],[35.768162,103.42617],[35.767551,103.426033],[35.767231,103.425774],[35.76545,103.424019],[35.764339,103.423241],[35.763401,103.42289],[35.762741,103.422348],[35.762371,103.421913],[35.76136,103.420219],[35.761292,103.419991],[35.761238,103.419327],[35.76086,103.418114],[35.760712,103.417877],[35.76012,103.417557],[35.759979,103.417381],[35.759651,103.41674],[35.759491,103.41655],[35.758671,103.415916],[35.757431,103.415581],[35.757252,103.415482],[35.757038,103.415268],[35.756512,103.414574],[35.75589,103.414101],[35.755531,103.413559],[35.755131,103.413231],[35.75449,103.41291],[35.7537,103.412727],[35.753029,103.412468],[35.751961,103.4123],[35.751732,103.412338],[35.75153,103.412437],[35.750721,103.413139],[35.750191,103.413361],[35.748661,103.414337],[35.747501,103.415573],[35.747021,103.416161],[35.746319,103.416679],[35.74596,103.417007],[35.74577,103.417267],[35.745159,103.417717],[35.744869,103.418159],[35.74469,103.418793],[35.74456,103.418877],[35.744171,103.418907],[35.743889,103.419144],[35.74361,103.419609],[35.743511,103.41996],[35.743462,103.420349],[35.74345,103.420807],[35.743721,103.421707],[35.743698,103.42186],[35.743629,103.421928],[35.743401,103.421959],[35.742809,103.421829],[35.7416,103.421478],[35.741199,103.42128],[35.74094,103.421227],[35.74065,103.42131],[35.74012,103.421638],[35.739811,103.421738],[35.738621,103.421799],[35.737419,103.422371],[35.736851,103.422546],[35.736271,103.423141],[35.735371,103.423576],[35.734909,103.424309],[35.73457,103.42469],[35.733471,103.425323],[35.732941,103.425507],[35.732761,103.425659],[35.73243,103.426041],[35.731781,103.426521],[35.731392,103.426888],[35.73093,103.427017],[35.73019,103.427361],[35.729591,103.427727],[35.728901,103.427887],[35.727501,103.428978],[35.72707,103.429199],[35.726212,103.429367],[35.72541,103.430107],[35.725182,103.43026],[35.72477,103.430443],[35.723,103.431],[35.722721,103.430969],[35.72171,103.430527],[35.72142,103.430519],[35.720909,103.43058],[35.720711,103.430641],[35.719101,103.431473],[35.718399,103.43222],[35.718151,103.432373],[35.717541,103.432457],[35.717239,103.432411],[35.716431,103.432129],[35.716171,103.432137],[35.7155,103.432327],[35.714588,103.43293],[35.713051,103.43364],[35.71278,103.433823],[35.71246,103.434158],[35.712231,103.434334],[35.71172,103.434471],[35.711391,103.434441],[35.710972,103.434128],[35.710869,103.43399],[35.710831,103.433823],[35.71093,103.431198],[35.71101,103.430946],[35.7113,103.430458],[35.711399,103.430191],[35.711391,103.429947],[35.711239,103.429314],[35.711208,103.428047],[35.711151,103.427719],[35.710819,103.427368],[35.710091,103.426849],[35.70953,103.42601],[35.708981,103.425728],[35.708778,103.425507],[35.70842,103.424606],[35.708229,103.423592],[35.70797,103.42308],[35.707722,103.422737],[35.706871,103.422058],[35.706322,103.421387],[35.70499,103.419319],[35.7048,103.418739],[35.704361,103.416847],[35.703651,103.415848],[35.70327,103.41497],[35.703098,103.414879],[35.70266,103.414818],[35.702049,103.414467],[35.701721,103.414383],[35.701271,103.414291],[35.70076,103.414337],[35.700081,103.414261],[35.69939,103.413971],[35.69849,103.413681],[35.697868,103.413673],[35.697472,103.413559],[35.696949,103.413498],[35.696659,103.413551],[35.696331,103.413689],[35.696159,103.413696],[35.695,103.413429],[35.69334,103.41317],[35.692032,103.41304],[35.69128,103.41317],[35.690941,103.413109],[35.69067,103.412949],[35.690331,103.412468],[35.690182,103.412369],[35.687698,103.411743],[35.687191,103.411568],[35.68639,103.411217],[35.685081,103.41053],[35.684212,103.410477],[35.682892,103.410057],[35.68222,103.410103],[35.681419,103.41024],[35.680771,103.410057],[35.680248,103.410011],[35.67989,103.409798],[35.679691,103.409737],[35.679241,103.409889],[35.678841,103.41011],[35.678001,103.41021],[35.67762,103.410141],[35.676731,103.40963],[35.676571,103.409576],[35.6759,103.40979],[35.675289,103.410103],[35.675011,103.410103],[35.674641,103.410011],[35.674511,103.40992],[35.674179,103.409286],[35.67355,103.408478],[35.673241,103.407913],[35.672878,103.406868],[35.67276,103.406113],[35.672611,103.405769],[35.67205,103.40509],[35.671398,103.40477],[35.671242,103.40461],[35.67078,103.403748],[35.670349,103.403191],[35.669762,103.402283],[35.66938,103.401527],[35.667961,103.39978],[35.667419,103.399017],[35.666729,103.397881],[35.666481,103.397179],[35.666401,103.3964],[35.666401,103.396027],[35.6665,103.39534],[35.66684,103.394257],[35.666851,103.39389],[35.6661,103.392097],[35.665989,103.391739],[35.665932,103.391281],[35.66592,103.390427],[35.666031,103.389999],[35.66695,103.388039],[35.666988,103.387772],[35.666931,103.386757],[35.666962,103.386276],[35.667122,103.385788],[35.667679,103.38459],[35.667751,103.384331],[35.667721,103.384216],[35.667549,103.384087],[35.66613,103.383667],[35.665871,103.38353],[35.66489,103.382767],[35.664322,103.381897],[35.664261,103.381706],[35.664249,103.381287],[35.6642,103.381027],[35.664322,103.38092],[35.665871,103.378578],[35.666142,103.378319],[35.66671,103.378059],[35.666851,103.377937],[35.666889,103.377823],[35.66687,103.377693],[35.666512,103.37719],[35.666351,103.376846],[35.666328,103.376404],[35.666401,103.375977],[35.666561,103.375519],[35.66674,103.375221],[35.666988,103.374947],[35.66732,103.374748],[35.668049,103.374527],[35.668598,103.37394],[35.66864,103.373871],[35.66864,103.373657],[35.668331,103.373161],[35.668308,103.37291],[35.668442,103.372383],[35.668991,103.370827],[35.669281,103.370537],[35.669781,103.370399],[35.669899,103.370308],[35.67017,103.369781],[35.670681,103.369217],[35.670738,103.369003],[35.67075,103.368317],[35.671169,103.366959],[35.67131,103.366699],[35.67149,103.366508],[35.67197,103.366348],[35.672138,103.366158],[35.67226,103.365868],[35.672588,103.365303],[35.672779,103.364464],[35.673592,103.362717],[35.67384,103.362488],[35.674469,103.362373],[35.67466,103.362167],[35.674641,103.361969],[35.67429,103.361183],[35.674179,103.360779],[35.674141,103.360336],[35.674179,103.35997],[35.674278,103.35952],[35.6744,103.3592],[35.675159,103.357887],[35.675381,103.357407],[35.675671,103.356628],[35.67572,103.356117],[35.675522,103.354897],[35.675228,103.354187],[35.67519,103.353928],[35.67511,103.352631],[35.67495,103.351517],[35.674931,103.350708],[35.67498,103.349876],[35.675152,103.349289],[35.676109,103.348091],[35.676201,103.347801],[35.676189,103.347366],[35.67625,103.347],[35.67664,103.346359],[35.676708,103.346169],[35.676651,103.34594],[35.676479,103.345848],[35.67622,103.345863],[35.675591,103.346001],[35.675369,103.345947],[35.674358,103.34494],[35.674191,103.344566],[35.673908,103.343567],[35.673439,103.342529],[35.672691,103.341347],[35.672001,103.339569],[35.67157,103.338913],[35.67141,103.338219],[35.671101,103.337196],[35.671089,103.336029],[35.671391,103.335098],[35.67144,103.33448],[35.671391,103.334053],[35.671181,103.333214],[35.671169,103.332649],[35.671379,103.33062],[35.671589,103.32991],[35.671638,103.329498],[35.671589,103.329224],[35.670971,103.327377],[35.67094,103.326408],[35.671162,103.324913],[35.67104,103.323448],[35.670731,103.322311],[35.670158,103.321243],[35.670052,103.320953],[35.669651,103.319107],[35.669701,103.318359],[35.66983,103.317574],[35.670078,103.317001],[35.670559,103.316399],[35.671478,103.316109],[35.672039,103.315468],[35.672112,103.315041],[35.672001,103.314247],[35.672031,103.313904],[35.672371,103.312859],[35.672649,103.312218],[35.672852,103.31192],[35.673111,103.311699],[35.673901,103.31144],[35.674511,103.31105],[35.674591,103.310944],[35.674629,103.310707],[35.674511,103.310501],[35.674358,103.310379],[35.673752,103.310043],[35.673439,103.309769],[35.673,103.30909],[35.672859,103.308746],[35.672291,103.306664],[35.672249,103.30632],[35.672241,103.305237],[35.672031,103.30368],[35.67181,103.303261],[35.671211,103.302803],[35.671021,103.302429],[35.670952,103.302147],[35.670959,103.301697],[35.671268,103.30024],[35.671268,103.299927],[35.6712,103.299637],[35.67104,103.2994],[35.670189,103.298431],[35.669708,103.297737],[35.66906,103.29705],[35.668468,103.295937],[35.66814,103.295647],[35.667011,103.29483],[35.666752,103.294487],[35.66613,103.293007],[35.665619,103.291512],[35.665421,103.290428],[35.66547,103.289299],[35.66563,103.289001],[35.6661,103.288353],[35.666439,103.287956],[35.667191,103.287514],[35.667252,103.287369],[35.66721,103.287209],[35.666969,103.287086],[35.665951,103.287117],[35.66523,103.287567],[35.665001,103.287628],[35.664711,103.28759],[35.66431,103.287376],[35.664001,103.287308],[35.663181,103.287369],[35.662651,103.287308],[35.662441,103.287209],[35.662392,103.287086],[35.66243,103.286957],[35.662498,103.286911],[35.66312,103.287117],[35.663261,103.287079],[35.663288,103.286957],[35.663158,103.286827],[35.662258,103.286507],[35.661449,103.286011],[35.661442,103.285828],[35.661579,103.285767],[35.662231,103.286209],[35.662338,103.286217],[35.662361,103.286171],[35.662338,103.286049],[35.66177,103.285568],[35.661541,103.285301],[35.661201,103.284683],[35.66111,103.28434],[35.660938,103.282738],[35.6609,103.2826],[35.660751,103.282387],[35.660568,103.282318],[35.65966,103.282188],[35.659149,103.281898],[35.65765,103.281517],[35.65723,103.281487],[35.657101,103.281387],[35.65707,103.281288],[35.657101,103.281197],[35.65723,103.281128],[35.658131,103.281342],[35.658291,103.281258],[35.65831,103.281151],[35.658291,103.281067],[35.65818,103.281013],[35.65773,103.280991],[35.657372,103.280891],[35.656239,103.280273],[35.654949,103.279778],[35.654598,103.279572],[35.65456,103.279449],[35.654621,103.27935],[35.655392,103.279572],[35.65596,103.27951],[35.65641,103.279533],[35.65654,103.27948],[35.656582,103.279373],[35.656528,103.279259],[35.656471,103.279228],[35.655281,103.279137],[35.65514,103.279053],[35.65514,103.278923],[35.655182,103.278839],[35.655331,103.278748],[35.656681,103.278648],[35.656792,103.278557],[35.656761,103.278397],[35.656651,103.278313],[35.655998,103.278236],[35.655331,103.278297],[35.655258,103.278229],[35.655251,103.278137],[35.6553,103.278038],[35.65546,103.277946],[35.65675,103.27771],[35.65683,103.277557],[35.656811,103.277481],[35.6567,103.277397],[35.655861,103.277428],[35.65443,103.277191],[35.65427,103.277077],[35.654251,103.276917],[35.65448,103.276817],[35.65659,103.276543],[35.656731,103.276367],[35.656731,103.276268],[35.656681,103.276176],[35.656528,103.276077],[35.655151,103.27552],[35.65369,103.275146],[35.653419,103.275131],[35.653278,103.275177],[35.652969,103.275414],[35.652748,103.275414],[35.65258,103.275169],[35.652451,103.274719],[35.652321,103.27446],[35.651939,103.274063],[35.651451,103.273788],[35.651291,103.273598],[35.651299,103.27343],[35.65136,103.273361],[35.651501,103.273323],[35.651642,103.273369],[35.652271,103.273804],[35.65239,103.273811],[35.652481,103.273743],[35.6525,103.273628],[35.652458,103.273483],[35.65226,103.273148],[35.6521,103.272957],[35.651661,103.272659],[35.651211,103.272621],[35.65004,103.272881],[35.649658,103.273033],[35.649212,103.273361],[35.649109,103.273376],[35.648979,103.273323],[35.64819,103.272118],[35.646919,103.271004],[35.646561,103.270851],[35.64571,103.270798],[35.645481,103.270714],[35.64291,103.267601],[35.642479,103.267113],[35.641449,103.266518],[35.640148,103.265381],[35.639851,103.26535],[35.639332,103.26561],[35.638561,103.265511],[35.638519,103.265419],[35.638618,103.265297],[35.639278,103.265327],[35.639462,103.265289],[35.640018,103.264847],[35.64048,103.264709],[35.64053,103.264664],[35.640541,103.264526],[35.640461,103.264488],[35.640331,103.264511],[35.639488,103.264816],[35.639141,103.264877],[35.63884,103.264847],[35.637539,103.264397],[35.63736,103.26413],[35.636978,103.262703],[35.636829,103.262299],[35.63596,103.260696],[35.634201,103.25956],[35.633709,103.259323],[35.633259,103.259193],[35.633369,103.258347],[35.633419,103.257973],[35.63335,103.25753],[35.632938,103.256683],[35.631889,103.254807],[35.631321,103.253601],[35.630329,103.252037],[35.629211,103.251122],[35.627739,103.249153],[35.62553,103.245537],[35.62373,103.242867],[35.622391,103.240761],[35.620541,103.236931],[35.620201,103.236359],[35.618198,103.23378],[35.617821,103.233383],[35.616402,103.232117],[35.614368,103.230057],[35.612492,103.228554],[35.61097,103.227501],[35.61018,103.22702],[35.60989,103.226784],[35.60968,103.226479],[35.609032,103.225113],[35.608459,103.223633],[35.606361,103.217888],[35.60556,103.215599],[35.605331,103.214813],[35.605228,103.214073],[35.604889,103.211906],[35.604721,103.210388],[35.60458,103.209633],[35.604149,103.206146],[35.60376,103.203613],[35.6036,103.202927],[35.603359,103.202293],[35.603119,103.201691],[35.602638,103.200798],[35.601089,103.198578],[35.600658,103.198082],[35.599781,103.197357],[35.598999,103.196541],[35.597111,103.195717],[35.596088,103.194817],[35.59544,103.194504],[35.595081,103.19426],[35.59306,103.192612],[35.592621,103.192284],[35.59185,103.191849],[35.59042,103.190697],[35.590179,103.190697],[35.58989,103.19088],[35.588188,103.19265],[35.58741,103.193542],[35.584061,103.197113],[35.582069,103.199463],[35.58186,103.199707],[35.581558,103.199982],[35.575211,103.207153],[35.57468,103.207718],[35.57449,103.207787],[35.57439,103.207703],[35.5728,103.204857],[35.57233,103.203918],[35.571621,103.201767],[35.571049,103.200562],[35.567841,103.195183],[35.566792,103.19313],[35.56625,103.191948],[35.564529,103.187828],[35.56329,103.185181],[35.562019,103.182838],[35.56052,103.180397],[35.55962,103.179077],[35.556969,103.175499],[35.55489,103.17289],[35.550018,103.166527],[35.548321,103.164391],[35.5476,103.163391],[35.546902,103.162338],[35.545528,103.16008],[35.543041,103.15567],[35.54232,103.15464],[35.541561,103.153687],[35.54073,103.152809],[35.539799,103.152023],[35.538818,103.151321],[35.535782,103.149399],[35.534851,103.148666],[35.533989,103.147789],[35.533211,103.146782],[35.532539,103.145638],[35.53196,103.14431],[35.530941,103.141441],[35.530281,103.140083],[35.529461,103.138878],[35.526112,103.134903],[35.5242,103.13282],[35.523232,103.132057],[35.521309,103.13089],[35.520531,103.130219],[35.51989,103.129433],[35.519241,103.128273],[35.51741,103.124367],[35.516689,103.1231],[35.514229,103.119591],[35.5135,103.118378],[35.512829,103.117073],[35.511581,103.114212],[35.510941,103.1129],[35.510281,103.111717],[35.509041,103.109848],[35.505951,103.106201],[35.505112,103.104973],[35.50441,103.103653],[35.50386,103.102333],[35.50346,103.101013],[35.503189,103.099716],[35.502399,103.094597],[35.502201,103.093712],[35.501808,103.092293],[35.501389,103.090981],[35.50058,103.08902],[35.499882,103.087723],[35.495811,103.081123],[35.48962,103.071373],[35.488949,103.070259],[35.488369,103.069061],[35.487919,103.067871],[35.487572,103.066711],[35.48708,103.064552],[35.486481,103.062363],[35.486,103.060966],[35.485378,103.059608],[35.484631,103.058342],[35.483799,103.05722],[35.478809,103.051376],[35.47821,103.050323],[35.477829,103.049171],[35.47768,103.047943],[35.477772,103.045326],[35.47773,103.043961],[35.47747,103.042709],[35.477051,103.041588],[35.476521,103.040527],[35.47591,103.03965],[35.47348,103.036369],[35.473091,103.035751],[35.472778,103.035004],[35.472481,103.034416],[35.47213,103.033684],[35.471741,103.03286],[35.471352,103.031998],[35.470959,103.03112],[35.47057,103.030228],[35.4702,103.029404],[35.469872,103.028671],[35.469601,103.028069],[35.469429,103.02774],[35.469158,103.027458],[35.46896,103.027069],[35.468651,103.026581],[35.46825,103.025993],[35.467819,103.025383],[35.467369,103.024727],[35.4669,103.023933],[35.466431,103.022949],[35.465912,103.021828],[35.465328,103.020729],[35.46468,103.019623],[35.464008,103.018539],[35.463291,103.017517],[35.462559,103.016533],[35.461849,103.015556],[35.46114,103.014618],[35.46048,103.013733],[35.459919,103.012947],[35.45927,103.012123],[35.458549,103.011261],[35.457821,103.010536],[35.457119,103.009933],[35.456459,103.009354],[35.45591,103.008858],[35.455589,103.008537],[35.455299,103.008209],[35.45509,103.00795],[35.454781,103.007591],[35.454411,103.007004],[35.45396,103.00631],[35.45343,103.005493],[35.452881,103.004639],[35.45229,103.003723],[35.45166,103.002747],[35.450989,103.001732],[35.450352,103.000763],[35.449749,102.999847],[35.449181,102.99894],[35.448589,102.998016],[35.448009,102.997017],[35.44743,102.995979],[35.44685,102.994904],[35.446331,102.993752],[35.44582,102.992622],[35.44537,102.991463],[35.44492,102.990227],[35.444489,102.988983],[35.44408,102.987747],[35.44368,102.986572],[35.443291,102.985443],[35.442909,102.984306],[35.442478,102.983147],[35.442039,102.982018],[35.441681,102.981148],[35.44136,102.980476],[35.440971,102.97966],[35.440491,102.978683],[35.439949,102.977654],[35.439381,102.976646],[35.43877,102.975662],[35.438099,102.97467],[35.43742,102.97364],[35.436722,102.97261],[35.436008,102.971558],[35.435322,102.970543],[35.43462,102.969528],[35.433941,102.968452],[35.4333,102.967262],[35.43269,102.966011],[35.43211,102.964684],[35.43158,102.963417],[35.431,102.962303],[35.430302,102.961357],[35.429562,102.960564],[35.428768,102.959732],[35.427952,102.958832],[35.42709,102.957909],[35.426281,102.956879],[35.425621,102.955727],[35.425098,102.954536],[35.424549,102.953484],[35.423809,102.952728],[35.422932,102.952316],[35.422001,102.952164],[35.421009,102.951927],[35.420071,102.951408],[35.419189,102.950607],[35.418491,102.94957],[35.418018,102.94838],[35.417789,102.947189],[35.417782,102.946098],[35.41782,102.945053],[35.4179,102.944054],[35.417839,102.943031],[35.417629,102.941994],[35.417309,102.94101],[35.41695,102.940071],[35.416561,102.939163],[35.416069,102.938316],[35.415401,102.937714],[35.414631,102.937431],[35.41383,102.937317],[35.413139,102.937134],[35.412491,102.936829],[35.411789,102.936691],[35.4114,102.936707],[35.411301,102.936707],[35.411072,102.93676],[35.41066,102.936859],[35.409988,102.937027],[35.409199,102.937218],[35.408352,102.937424],[35.407452,102.937622],[35.406528,102.937851],[35.405682,102.938026],[35.404869,102.937973],[35.404079,102.937561],[35.403461,102.93679],[35.403118,102.935806],[35.403011,102.934837],[35.403049,102.933891],[35.40324,102.932953],[35.403542,102.932159],[35.40387,102.931419],[35.40424,102.930603],[35.40443,102.929657],[35.404491,102.928612],[35.404388,102.927582],[35.404121,102.926682],[35.403759,102.925926],[35.403309,102.925323],[35.402802,102.92482],[35.40226,102.924454],[35.401581,102.924118],[35.400791,102.923843],[35.399948,102.923599],[35.399151,102.9235],[35.39827,102.923492],[35.39735,102.923553],[35.396461,102.923607],[35.39558,102.923599],[35.394718,102.923477],[35.39389,102.923233],[35.39307,102.922943],[35.392231,102.922623],[35.39143,102.92234],[35.39061,102.921997],[35.389771,102.921677],[35.388908,102.921349],[35.388069,102.921028],[35.387199,102.9207],[35.386341,102.920349],[35.385529,102.919762],[35.38496,102.918961],[35.384529,102.918007],[35.384071,102.917122],[35.3834,102.916473],[35.382599,102.916077],[35.38166,102.915848],[35.380772,102.915627],[35.37994,102.915367],[35.379131,102.915009],[35.378422,102.914597],[35.377838,102.914192],[35.37468,102.90918],[35.374611,102.908829],[35.374439,102.908287],[35.374298,102.907402],[35.374321,102.906273],[35.374531,102.905228],[35.37495,102.904221],[35.375511,102.903107],[35.3759,102.90184],[35.375999,102.900543],[35.375912,102.899307],[35.375759,102.898193],[35.37561,102.897133],[35.375469,102.89608],[35.375301,102.894974],[35.374969,102.893929],[35.374378,102.89315],[35.37368,102.892708],[35.372768,102.892517],[35.371868,102.892357],[35.370911,102.892181],[35.36985,102.891998],[35.368778,102.891777],[35.367809,102.891579],[35.366951,102.891083],[35.366268,102.890213],[35.365891,102.889053],[35.365669,102.888008],[35.36544,102.887177],[35.36515,102.886414],[35.36488,102.885513],[35.36478,102.884354],[35.364731,102.883034],[35.364552,102.88176],[35.364288,102.880661],[35.364029,102.879623],[35.363899,102.878464],[35.364021,102.877327],[35.364441,102.876213],[35.364979,102.875038],[35.365551,102.873749],[35.366169,102.872398],[35.366798,102.870979],[35.36742,102.869614],[35.368019,102.868248],[35.368549,102.866814],[35.368858,102.865257],[35.368961,102.86364],[35.368801,102.862106],[35.368431,102.860733],[35.368,102.859467],[35.367599,102.858261],[35.36639,102.854156],[35.365791,102.853081],[35.364971,102.852219],[35.363811,102.851501],[35.363041,102.850388],[35.362431,102.84906],[35.362061,102.847656],[35.36227,102.846184],[35.362411,102.844818],[35.36026,102.837929],[35.359489,102.837067],[35.35873,102.836166],[35.35833,102.834877],[35.358231,102.833473],[35.35804,102.83223],[35.357498,102.831139],[35.35677,102.830231],[35.35622,102.829117],[35.355942,102.827766],[35.355701,102.826424],[35.35524,102.825127],[35.35461,102.823883],[35.35376,102.822739],[35.352798,102.821808],[35.35183,102.821068],[35.35104,102.820137],[35.350651,102.81884],[35.350788,102.81739],[35.35146,102.816071],[35.352291,102.814774],[35.352989,102.813347],[35.353378,102.811852],[35.353401,102.810509],[35.353149,102.809212],[35.35268,102.807991],[35.35199,102.806923],[35.351181,102.805923],[35.35033,102.804901],[35.349461,102.803833],[35.348579,102.802696],[35.347729,102.801422],[35.346909,102.800049],[35.346119,102.798599],[35.34531,102.797157],[35.344509,102.795769],[35.34375,102.794441],[35.342979,102.793121],[35.342239,102.791832],[35.341431,102.790657],[35.34045,102.789818],[35.339298,102.789383],[35.3381,102.789253],[35.336971,102.789108],[35.33593,102.788727],[35.334961,102.787979],[35.334099,102.786957],[35.333279,102.785858],[35.332409,102.784927],[35.331421,102.784317],[35.330471,102.784027],[35.329521,102.783981],[35.32848,102.783913],[35.3274,102.783783],[35.326351,102.783684],[35.325291,102.783577],[35.32428,102.783379],[35.32341,102.782951],[35.322651,102.782417],[35.321892,102.781883],[35.32111,102.781273],[35.320259,102.780647],[35.319302,102.779938],[35.318272,102.779167],[35.317268,102.778442],[35.316319,102.777733],[35.31538,102.777039],[35.314579,102.776443],[35.313789,102.775848],[35.313019,102.775261],[35.31218,102.774643],[35.311279,102.773972],[35.310329,102.773247],[35.309299,102.772476],[35.308281,102.771721],[35.30727,102.770973],[35.306221,102.770241],[35.305149,102.76963],[35.303982,102.769386],[35.302799,102.769669],[35.301762,102.770378],[35.300961,102.771469],[35.300449,102.772797],[35.300171,102.774277],[35.29998,102.775772],[35.29966,102.777222],[35.299042,102.778503],[35.298061,102.779442],[35.29686,102.779953],[35.29562,102.780006],[35.294418,102.77993],[35.293289,102.779846],[35.292091,102.779808],[35.290871,102.780098],[35.289761,102.780853],[35.288792,102.781937],[35.287811,102.783127],[35.286819,102.784317],[35.285671,102.785278],[35.284519,102.785851],[35.283691,102.786346],[35.282909,102.786987],[35.28215,102.787903],[35.281509,102.789078],[35.28088,102.790298],[35.27998,102.791092],[35.279041,102.791397],[35.278191,102.791832],[35.277489,102.792702],[35.276871,102.793739],[35.27599,102.794518],[35.275082,102.795197],[35.274281,102.796066],[35.273659,102.797142],[35.27285,102.797981],[35.271969,102.798538],[35.27113,102.799278],[35.270439,102.800369],[35.27002,102.801697],[35.269691,102.803078],[35.269009,102.804176],[35.26833,102.80526],[35.267719,102.806412],[35.267151,102.807663],[35.26646,102.808907],[35.265461,102.809837],[35.26432,102.810318],[35.263149,102.810349],[35.262001,102.810471],[35.260948,102.810944],[35.260021,102.811798],[35.259159,102.813004],[35.258171,102.814133],[35.256962,102.81472],[35.255711,102.814743],[35.254459,102.814583],[35.253288,102.814636],[35.252251,102.815086],[35.251461,102.81588],[35.250809,102.81662],[35.25013,102.817413],[35.24934,102.818222],[35.248451,102.819069],[35.247459,102.819939],[35.246399,102.820847],[35.2453,102.821823],[35.24419,102.822777],[35.243111,102.823723],[35.24213,102.824547],[35.241241,102.825233],[35.240318,102.825447],[35.23938,102.825203],[35.238338,102.824837],[35.237228,102.824516],[35.23616,102.824661],[35.235271,102.82534],[35.23457,102.826111],[35.23394,102.826828],[35.23325,102.827423],[35.232368,102.827667],[35.23151,102.827499],[35.230751,102.826981],[35.22998,102.826317],[35.229229,102.825653],[35.2285,102.825111],[35.227921,102.824867],[35.227428,102.824753],[35.226891,102.824638],[35.226311,102.824516],[35.225788,102.824364],[35.2253,102.824142],[35.224899,102.823929],[35.224579,102.823761],[35.224289,102.823593],[35.223721,102.823593],[35.223019,102.824867],[35.22028,102.823959],[35.219189,102.82222],[35.219341,102.820396],[35.217682,102.819847],[35.216991,102.819962],[35.216461,102.820084],[35.216099,102.820137],[35.21553,102.820168],[35.214588,102.82019],[35.212101,102.820183],[35.211349,102.820267],[35.210251,102.820648],[35.209091,102.821487],[35.20895,102.821457],[35.20776,102.822563],[35.207409,102.822762],[35.206841,102.82299],[35.20562,102.823189],[35.205009,102.823189],[35.203999,102.823151],[35.20266,102.82312],[35.20145,102.822144],[35.19294,102.825737],[35.191181,102.825211],[35.18959,102.824623],[35.18874,102.823799],[35.187778,102.822731],[35.187222,102.822189],[35.186218,102.821831],[35.18605,102.821823],[35.185322,102.821877],[35.184959,102.821877],[35.184441,102.821777],[35.18425,102.821716],[35.182701,102.820602],[35.182388,102.82045],[35.181721,102.820358],[35.180901,102.820633],[35.180462,102.820976],[35.180199,102.821297],[35.17981,102.822037],[35.179729,102.822243],[35.179531,102.822861],[35.17952,102.824043],[35.177551,102.824539],[35.176521,102.824928],[35.169189,102.832947],[35.168301,102.831947],[35.167881,102.832352],[35.16703,102.833344],[35.166321,102.834084],[35.165489,102.834763],[35.164631,102.835503],[35.16338,102.836906],[35.162361,102.838348],[35.16256,102.839882],[35.156368,102.845108],[35.15435,102.845139],[35.153439,102.845741],[35.152439,102.846649],[35.15229,102.846764],[35.151039,102.847153],[35.14999,102.847733],[35.148682,102.84922],[35.144951,102.850227],[35.143131,102.848869],[35.142151,102.848541],[35.140621,102.848083],[35.1395,102.847763],[35.138168,102.847656],[35.137821,102.847679],[35.136589,102.847939],[35.13625,102.848083],[35.134949,102.848778],[35.13311,102.849907],[35.130322,102.850929],[35.12952,102.851608],[35.128719,102.85257],[35.127361,102.853859],[35.126019,102.855324],[35.114201,102.858513],[35.114029,102.860222],[35.113811,102.860641],[35.11343,102.861794],[35.11274,102.863426],[35.111851,102.86483],[35.110458,102.866867],[35.110008,102.867348],[35.108829,102.868202],[35.106941,102.869392],[35.1059,102.870377],[35.105209,102.871582],[35.104801,102.872726],[35.10276,102.878822],[35.101971,102.881264],[35.101219,102.882874],[35.100349,102.884193],[35.09911,102.886208],[35.09874,102.887062],[35.098228,102.888268],[35.097759,102.889137],[35.09724,102.889877],[35.096531,102.890739],[35.09597,102.891609],[35.095181,102.893143],[35.094181,102.894974],[35.093029,102.896812],[35.09185,102.898552],[35.091179,102.899857],[35.09074,102.90136],[35.09066,102.902786],[35.090691,102.903732],[35.090698,102.904198],[35.090401,102.905327],[35.090199,102.905724],[35.089939,102.906036],[35.089359,102.906487],[35.088699,102.906723],[35.088348,102.906731],[35.08746,102.906471],[35.086861,102.906021],[35.085949,102.905281],[35.085789,102.905167],[35.084629,102.90464],[35.084122,102.904533],[35.083241,102.904503],[35.08252,102.904678],[35.082439,102.905113],[35.080551,102.905243],[35.080002,102.905342],[35.07943,102.905388],[35.078529,102.905533],[35.077862,102.905724],[35.07674,102.906197],[35.076092,102.906303],[35.075779,102.906281],[35.075321,102.906151],[35.074951,102.905998],[35.074261,102.905907],[35.073589,102.905968],[35.073021,102.906273],[35.0728,102.906464],[35.07222,102.907021],[35.07185,102.907333],[35.070881,102.907707],[35.07037,102.90773],[35.069679,102.907471],[35.069519,102.907372],[35.06921,102.907112],[35.06815,102.905968],[35.067699,102.905647],[35.066841,102.905418],[35.066139,102.905472],[35.065319,102.905853],[35.06353,102.906998],[35.060638,102.908791],[35.059471,102.909378],[35.05872,102.909523],[35.057129,102.909554],[35.05666,102.909569],[35.055828,102.909561],[35.055069,102.909683],[35.05476,102.909767],[35.054298,102.909988],[35.053692,102.910393],[35.053219,102.910629],[35.052132,102.911293],[35.05164,102.911552],[35.051029,102.911957],[35.050388,102.9123],[35.049751,102.912727],[35.049061,102.913116],[35.0485,102.913307],[35.047729,102.91349],[35.04673,102.913612],[35.045731,102.913612],[35.045341,102.913628],[35.04422,102.91391],[35.043549,102.914284],[35.043388,102.914413],[35.042709,102.915176],[35.042332,102.915733],[35.041721,102.916733],[35.04084,102.918243],[35.040649,102.918663],[35.04018,102.919487],[35.03981,102.920067],[35.039669,102.920258],[35.038979,102.920837],[35.034828,102.92321],[35.034069,102.923576],[35.033489,102.923683],[35.032349,102.923714],[35.031311,102.924141],[35.03067,102.924637],[35.030319,102.92485],[35.029362,102.925087],[35.028751,102.925011],[35.027981,102.924629],[35.02702,102.924057],[35.02623,102.923759],[35.025589,102.923683],[35.025311,102.923691],[35.02446,102.924072],[35.023602,102.924522],[35.023251,102.924591],[35.022881,102.924622],[35.022148,102.924583],[35.021389,102.924629],[35.020828,102.924843],[35.020691,102.924896],[35.020302,102.925171],[35.019508,102.925797],[35.018921,102.926018],[35.017399,102.926132],[35.017029,102.926201],[35.01582,102.92659],[35.015659,102.926613],[35.014999,102.926613],[35.0144,102.926361],[35.01395,102.926071],[35.013599,102.925758],[35.01334,102.925507],[35.01223,102.924316],[35.011372,102.923477],[35.010792,102.922783],[35.010441,102.922287],[35.01025,102.921921],[35.01001,102.921494],[35.00967,102.9207],[35.008801,102.918907],[35.008308,102.917824],[35.007332,102.915756],[35.005859,102.912498],[35.00528,102.91127],[35.004841,102.910263],[35.004608,102.909851],[35.00452,102.909607],[35.00441,102.909309],[35.004002,102.908371],[35.003311,102.906532],[35.002911,102.905418],[35.00272,102.904968],[35.002331,102.904541],[35.00214,102.904472],[35.001499,102.904503],[35.000359,102.904617],[34.999981,102.904694],[34.998661,102.905273],[34.99477,102.905273],[34.993271,102.904968],[34.993111,102.906036],[34.993172,102.906326],[34.993172,102.906883],[34.993061,102.907677],[34.992901,102.9077],[34.992901,102.907707],[34.99292,102.907784],[34.992962,102.908218],[34.993011,102.908371],[34.99297,102.908592],[34.992722,102.908707],[34.99202,102.90873],[34.990101,102.908607],[34.989811,102.908546],[34.98624,102.908333],[34.97057,102.907372],[34.970188,102.907257],[34.96883,102.907173],[34.968571,102.907097],[34.968449,102.906738],[34.968349,102.906082],[34.96822,102.905457],[34.967999,102.904533],[34.967899,102.904167],[34.967709,102.903862],[34.967522,102.903618],[34.967319,102.90345],[34.966942,102.903412],[34.96677,102.903374],[34.966469,102.903259],[34.966099,102.903061],[34.965698,102.902763],[34.96529,102.902351],[34.965,102.90197],[34.964722,102.90155],[34.96365,102.899529],[34.96339,102.899071],[34.96312,102.898552],[34.962379,102.897202],[34.961761,102.896187],[34.961559,102.895844],[34.961151,102.895271],[34.960979,102.894951],[34.96072,102.894524],[34.960529,102.894287],[34.960339,102.893967],[34.958981,102.892014],[34.958031,102.890839],[34.957039,102.889557],[34.956711,102.889183],[34.954849,102.886749],[34.954552,102.886398],[34.95417,102.885887],[34.953442,102.884987],[34.95295,102.884338],[34.95298,102.884361],[34.952621,102.883888],[34.95232,102.883553],[34.950809,102.881683],[34.949909,102.880409],[34.949902,102.880363],[34.949459,102.879562],[34.949249,102.879082],[34.948891,102.878151],[34.94838,102.876427],[34.94825,102.875931],[34.94809,102.875397],[34.947899,102.874863],[34.947491,102.873863],[34.94685,102.872551],[34.946629,102.872147],[34.945992,102.871132],[34.945702,102.870758],[34.945068,102.870163],[34.944729,102.869919],[34.944359,102.869698],[34.94392,102.869476],[34.943031,102.869164],[34.9426,102.86898],[34.94141,102.868584],[34.940441,102.868263],[34.940182,102.868202],[34.94017,102.868172],[34.93821,102.867638],[34.92548,102.864548],[34.924671,102.864166],[34.924419,102.864082],[34.924049,102.864014],[34.923771,102.863907],[34.921612,102.863007],[34.920521,102.862503],[34.919701,102.862137],[34.919361,102.862007],[34.919041,102.861908],[34.91869,102.861847],[34.917961,102.861893],[34.917591,102.861954],[34.91721,102.862061],[34.916382,102.862396],[34.915192,102.862839],[34.91394,102.863182],[34.90559,102.863182],[34.905281,102.86306],[34.90493,102.862877],[34.904579,102.86264],[34.904289,102.862381],[34.90379,102.861794],[34.903591,102.861473],[34.903091,102.860428],[34.902969,102.860107],[34.902748,102.859421],[34.90255,102.858582],[34.902401,102.857788],[34.90229,102.856934],[34.90226,102.855743],[34.902302,102.854851],[34.902699,102.843513],[34.902748,102.843033],[34.902802,102.842773],[34.902882,102.842484],[34.902969,102.842239],[34.903091,102.841988],[34.903259,102.841743],[34.90345,102.841476],[34.903641,102.841309],[34.903839,102.841148],[34.90427,102.840889],[34.90451,102.840767],[34.904919,102.840477],[34.90519,102.840347],[34.90554,102.840111],[34.905949,102.839867],[34.9062,102.839684],[34.906399,102.8395],[34.906651,102.839073],[34.90675,102.838837],[34.906841,102.838516],[34.906841,102.838203],[34.906799,102.837883],[34.906731,102.837639],[34.906609,102.837341],[34.906422,102.837128],[34.9062,102.836983],[34.905891,102.836929],[34.905659,102.837013],[34.905479,102.837128],[34.905289,102.837334],[34.904961,102.837769],[34.9048,102.837929],[34.90456,102.838112],[34.904369,102.838158],[34.90416,102.838158],[34.90387,102.838058],[34.903702,102.837914],[34.903561,102.8377],[34.90345,102.83744],[34.9034,102.837181],[34.903358,102.8367],[34.903389,102.834],[34.90337,102.833641],[34.903309,102.833313],[34.90316,102.833023],[34.902889,102.832733],[34.902481,102.832588],[34.902111,102.83255],[34.901699,102.832443],[34.90139,102.832268],[34.901291,102.832199],[34.90126,102.832207],[34.900959,102.832062],[34.90073,102.831909],[34.900188,102.831413],[34.899799,102.830994],[34.899551,102.830391],[34.89954,102.829742],[34.89975,102.828796],[34.900291,102.826729],[34.900459,102.826141],[34.900791,102.825249],[34.901192,102.824402],[34.901939,102.823067],[34.902519,102.821953],[34.902809,102.820869],[34.902828,102.820053],[34.90266,102.818581],[34.90242,102.817253],[34.902142,102.816521],[34.90155,102.816017],[34.901119,102.815987],[34.90094,102.816032],[34.900219,102.81646],[34.89735,102.818604],[34.89658,102.819038],[34.896309,102.81913],[34.895592,102.81926],[34.89455,102.81913],[34.894299,102.819038],[34.894279,102.819054],[34.893848,102.818817],[34.891331,102.817307],[34.890549,102.816818],[34.88974,102.816223],[34.889099,102.81562],[34.88662,102.813263],[34.885929,102.812698],[34.885239,102.812553],[34.883179,102.812737],[34.882179,102.812881],[34.881531,102.813217],[34.880081,102.814484],[34.879219,102.815117],[34.87833,102.815407],[34.876251,102.815826],[34.87524,102.816177],[34.87442,102.816704],[34.8736,102.817513],[34.871979,102.819473],[34.871269,102.820374],[34.87011,102.822029],[34.868389,102.825363],[34.8675,102.827492],[34.867031,102.82843],[34.866348,102.829491],[34.865631,102.830368],[34.86274,102.833412],[34.862671,102.833473],[34.862171,102.833946],[34.861832,102.834343],[34.86105,102.835129],[34.8605,102.835587],[34.859859,102.836037],[34.859131,102.836388],[34.85902,102.836411],[34.85841,102.836441],[34.856838,102.836319],[34.85606,102.836372],[34.855518,102.83654],[34.854542,102.836899],[34.85199,102.837784],[34.851212,102.838028],[34.850399,102.838058],[34.849541,102.837807],[34.847771,102.83709],[34.846642,102.836693],[34.845551,102.836502],[34.84444,102.836479],[34.84346,102.836617],[34.842529,102.836884],[34.838779,102.838303],[34.837971,102.838623],[34.836941,102.838989],[34.836239,102.839203],[34.835381,102.839401],[34.834461,102.839531],[34.83366,102.839577],[34.832821,102.839577],[34.83197,102.8395],[34.831059,102.839348],[34.830219,102.839012],[34.82938,102.838501],[34.8284,102.837921],[34.827801,102.837502],[34.828339,102.837227],[34.8283,102.836708],[34.827179,102.836128],[34.827049,102.835678],[34.826839,102.834747],[34.826328,102.83239],[34.82626,102.831909],[34.826221,102.831367],[34.825481,102.809509],[34.82452,102.804512],[34.824749,102.800652],[34.82336,102.796608],[34.823029,102.794762],[34.822659,102.792732],[34.82222,102.790337],[34.82225,102.789932],[34.82235,102.789238],[34.822399,102.788689],[34.822479,102.788254],[34.822819,102.78569],[34.82291,102.78476],[34.822922,102.784363],[34.822948,102.783829],[34.82283,102.782516],[34.822781,102.782173],[34.822762,102.781914],[34.822659,102.781242],[34.822479,102.78022],[34.822361,102.77935],[34.822289,102.778992],[34.822231,102.77858],[34.8218,102.77594],[34.82169,102.775124],[34.82148,102.773903],[34.821281,102.772614],[34.821251,102.772308],[34.821159,102.771797],[34.82077,102.769218],[34.820641,102.768478],[34.820499,102.767776],[34.82032,102.767067],[34.82,102.766113],[34.81992,102.765938],[34.81881,102.76329],[34.817699,102.760696],[34.817261,102.759697],[34.816891,102.758812],[34.816559,102.758057],[34.816399,102.757668],[34.816101,102.757004],[34.815361,102.755127],[34.81501,102.754242],[34.814602,102.753212],[34.814301,102.752411],[34.81414,102.752022],[34.814011,102.751694],[34.813309,102.749931],[34.812111,102.746841],[34.81181,102.746033],[34.811581,102.745331],[34.811359,102.744476],[34.811249,102.743782],[34.811211,102.743439],[34.811161,102.743103],[34.811131,102.742279],[34.81115,102.741661],[34.811211,102.740913],[34.81134,102.740082],[34.81142,102.739647],[34.811649,102.738876],[34.811939,102.738121],[34.812569,102.736847],[34.812939,102.736191],[34.813702,102.734894],[34.81395,102.734512],[34.814281,102.73394],[34.814442,102.733627],[34.814701,102.733047],[34.814831,102.732674],[34.814941,102.732277],[34.815048,102.731667],[34.815029,102.731659],[34.815189,102.730492],[34.81522,102.730164],[34.815319,102.729599],[34.815411,102.728943],[34.81546,102.72863],[34.815491,102.728317],[34.815609,102.727676],[34.815632,102.727371],[34.815681,102.727142],[34.815811,102.726151],[34.81591,102.725548],[34.815979,102.724693],[34.815971,102.723831],[34.815922,102.723358],[34.81583,102.722801],[34.815731,102.722366],[34.81546,102.72139],[34.813671,102.702057],[34.813679,102.701981],[34.813641,102.701767],[34.813622,102.701439],[34.81358,102.701263],[34.81353,102.700867],[34.81329,102.699417],[34.813221,102.699097],[34.813171,102.698761],[34.812931,102.697617],[34.812698,102.696899],[34.81258,102.696678],[34.81245,102.696259],[34.811798,102.69503],[34.810711,102.6931],[34.80978,102.691353],[34.80933,102.69059],[34.808609,102.689217],[34.807819,102.687881],[34.807301,102.687149],[34.806492,102.686287],[34.806389,102.68618],[34.805779,102.685753],[34.804722,102.685097],[34.80024,102.682579],[34.798962,102.681671],[34.798031,102.68074],[34.797771,102.68045],[34.796791,102.679237],[34.795681,102.677917],[34.794701,102.676682],[34.793739,102.675369],[34.792339,102.673683],[34.79084,102.672112],[34.790329,102.671608],[34.789688,102.671013],[34.78886,102.67012],[34.7882,102.669006],[34.787392,102.667397],[34.786709,102.666054],[34.786228,102.665031],[34.785648,102.663887],[34.785099,102.662712],[34.784191,102.660843],[34.783691,102.659462],[34.783642,102.659241],[34.783249,102.657211],[34.783051,102.656487],[34.782711,102.65522],[34.782429,102.653969],[34.781731,102.651283],[34.781391,102.649628],[34.78133,102.647057],[34.7812,102.644676],[34.781181,102.643707],[34.781181,102.641258],[34.78093,102.639847],[34.780602,102.638451],[34.78027,102.637558],[34.779869,102.636703],[34.77692,102.631866],[34.77594,102.630173],[34.775299,102.629143],[34.774818,102.628311],[34.774311,102.627243],[34.773731,102.625763],[34.773201,102.624527],[34.77282,102.623756],[34.77142,102.62188],[34.77108,102.621521],[34.770821,102.621147],[34.77055,102.620667],[34.770279,102.620064],[34.769798,102.619324],[34.769329,102.618683],[34.767971,102.617058],[34.767368,102.616386],[34.766109,102.615143],[34.765209,102.614143],[34.764912,102.613869],[34.764641,102.613586],[34.763229,102.611977],[34.762489,102.611],[34.76207,102.610291],[34.761742,102.609581],[34.76152,102.6092],[34.760941,102.608047],[34.759949,102.60598],[34.75972,102.605438],[34.75909,102.604111],[34.75845,102.603073],[34.75753,102.601501],[34.756649,102.600288],[34.75621,102.599533],[34.75499,102.597313],[34.75415,102.595909],[34.753601,102.594887],[34.753201,102.593872],[34.753159,102.593674],[34.75293,102.591904],[34.752861,102.590759],[34.752949,102.589401],[34.753078,102.588303],[34.75351,102.586922],[34.75565,102.579758],[34.75584,102.578217],[34.755981,102.576653],[34.756039,102.576088],[34.75629,102.574623],[34.7565,102.57196],[34.756531,102.571327],[34.75676,102.568359],[34.756779,102.567932],[34.75708,102.564949],[34.757191,102.564148],[34.757309,102.563568],[34.75753,102.56205],[34.757702,102.560501],[34.757729,102.559914],[34.75769,102.55909],[34.757641,102.558891],[34.75716,102.557549],[34.756889,102.557037],[34.75618,102.556236],[34.755322,102.55571],[34.754429,102.555428],[34.753979,102.555321],[34.752979,102.555206],[34.750229,102.554993],[34.749149,102.554863],[34.74852,102.554703],[34.747108,102.554283],[34.746811,102.554123],[34.746132,102.55365],[34.745998,102.553543],[34.745251,102.552658],[34.74506,102.55217],[34.744949,102.55172],[34.744862,102.551529],[34.74464,102.550888],[34.744049,102.549103],[34.743271,102.547394],[34.742561,102.546082],[34.74268,102.54583],[34.74239,102.545258],[34.742222,102.544983],[34.741859,102.544289],[34.741718,102.543991],[34.74144,102.54348],[34.740608,102.541634],[34.740349,102.540916],[34.739979,102.539757],[34.739399,102.537689],[34.73888,102.535637],[34.73838,102.533928],[34.738071,102.532784],[34.73782,102.531952],[34.737358,102.530571],[34.73682,102.529381],[34.73637,102.52861],[34.736069,102.528183],[34.73502,102.526894],[34.73431,102.526207],[34.733829,102.525833],[34.73296,102.525223],[34.732029,102.524673],[34.731319,102.524223],[34.726311,102.521217],[34.723518,102.519577],[34.722172,102.518883],[34.72105,102.518623],[34.719391,102.51841],[34.717651,102.518143],[34.717461,102.518097],[34.71558,102.517487],[34.71307,102.51667],[34.709629,102.515488],[34.708309,102.515083],[34.707741,102.514877],[34.70652,102.51416],[34.705318,102.513],[34.704071,102.511543],[34.703339,102.510597],[34.70274,102.509758],[34.702259,102.508583],[34.70203,102.507317],[34.70182,102.505287],[34.701599,102.502953],[34.70126,102.500847],[34.700729,102.498833],[34.700359,102.49704],[34.700291,102.49659],[34.700001,102.494347],[34.699799,102.493042],[34.69915,102.491188],[34.698078,102.490112],[34.696999,102.489166],[34.695801,102.488373],[34.69511,102.488029],[34.694759,102.4879],[34.69408,102.487679],[34.692692,102.487457],[34.690979,102.487511],[34.689369,102.487808],[34.68774,102.488319],[34.685471,102.489143],[34.683971,102.489433],[34.68269,102.489357],[34.682259,102.489273],[34.68082,102.488647],[34.679729,102.487808],[34.678478,102.486389],[34.67598,102.483437],[34.674229,102.4813],[34.67318,102.479584],[34.672508,102.4786],[34.67181,102.478119],[34.671429,102.477966],[34.671051,102.477898],[34.668739,102.477768],[34.667679,102.477547],[34.667271,102.477371],[34.665409,102.476357],[34.664761,102.476143],[34.662941,102.475693],[34.66077,102.475197],[34.659939,102.474907],[34.659328,102.474617],[34.65836,102.47403],[34.657051,102.473282],[34.65633,102.472839],[34.655609,102.472458],[34.654861,102.472214],[34.65448,102.472153],[34.654079,102.47213],[34.653461,102.472183],[34.651669,102.47242],[34.650768,102.472382],[34.6492,102.472054],[34.648781,102.471931],[34.647369,102.471687],[34.646561,102.471687],[34.64637,102.471703],[34.64497,102.472054],[34.64394,102.472504],[34.642288,102.473297],[34.640911,102.473801],[34.640308,102.473846],[34.63929,102.473633],[34.638321,102.473129],[34.636902,102.472618],[34.635311,102.472473],[34.633961,102.472221],[34.633759,102.472153],[34.63192,102.471359],[34.629452,102.470207],[34.628571,102.469833],[34.627731,102.469353],[34.626911,102.468842],[34.626579,102.468613],[34.624931,102.467598],[34.62447,102.467377],[34.623749,102.467003],[34.620998,102.465317],[34.619572,102.464363],[34.617699,102.462662],[34.617031,102.462303],[34.6161,102.461952],[34.61515,102.461853],[34.61438,102.461983],[34.61335,102.46241],[34.612289,102.463211],[34.611771,102.463799],[34.611141,102.464928],[34.610661,102.466003],[34.610538,102.466187],[34.610062,102.46682],[34.609459,102.467216],[34.608841,102.467323],[34.608318,102.467293],[34.607849,102.467133],[34.607441,102.466827],[34.606098,102.465607],[34.605228,102.464577],[34.60186,102.460617],[34.601051,102.459717],[34.59996,102.458519],[34.597759,102.456078],[34.597462,102.455803],[34.59639,102.455307],[34.595989,102.455292],[34.595409,102.455429],[34.594521,102.455887],[34.594219,102.456169],[34.593861,102.456657],[34.59367,102.45694],[34.593369,102.457336],[34.593029,102.45787],[34.591129,102.46077],[34.588699,102.464363],[34.58794,102.46537],[34.58733,102.46595],[34.586712,102.466316],[34.58577,102.46666],[34.584919,102.466667],[34.584469,102.466583],[34.583969,102.466507],[34.582829,102.466202],[34.582531,102.466187],[34.582298,102.466118],[34.58157,102.466019],[34.578449,102.46534],[34.577202,102.464851],[34.575939,102.464088],[34.574711,102.463013],[34.573879,102.461967],[34.573132,102.460823],[34.570789,102.456993],[34.56992,102.455521],[34.568779,102.454231],[34.567451,102.453133],[34.56498,102.451134],[34.563641,102.449997],[34.56292,102.44928],[34.56282,102.449142],[34.56234,102.448418],[34.560749,102.445572],[34.55888,102.442146],[34.558361,102.441238],[34.556309,102.437523],[34.555641,102.436447],[34.55505,102.435829],[34.554169,102.435059],[34.553329,102.434258],[34.552429,102.432999],[34.55085,102.430573],[34.549931,102.429123],[34.549271,102.428207],[34.548389,102.427467],[34.547298,102.426773],[34.546532,102.425888],[34.546001,102.424759],[34.54562,102.423302],[34.545071,102.421654],[34.544369,102.420593],[34.54319,102.419388],[34.542789,102.418854],[34.542461,102.418289],[34.542191,102.417671],[34.541901,102.41658],[34.54158,102.414993],[34.541168,102.413979],[34.540581,102.413132],[34.53854,102.410606],[34.537159,102.408981],[34.536518,102.408287],[34.53492,102.407066],[34.53458,102.406693],[34.53373,102.405434],[34.53315,102.404007],[34.532421,102.40184],[34.531719,102.400589],[34.53067,102.399391],[34.52882,102.397598],[34.52821,102.396782],[34.526871,102.394547],[34.525902,102.39312],[34.525051,102.392174],[34.523788,102.390823],[34.522869,102.389793],[34.521931,102.388527],[34.52145,102.38765],[34.520679,102.386192],[34.519939,102.384987],[34.519279,102.384018],[34.518421,102.382797],[34.517941,102.38208],[34.516659,102.380219],[34.515621,102.378754],[34.514771,102.376633],[34.50613,102.368523],[34.505322,102.366173],[34.5037,102.363876],[34.501049,102.359802],[34.500092,102.358276],[34.49889,102.3563],[34.497841,102.354683],[34.496971,102.353416],[34.495789,102.352112],[34.494671,102.351784],[34.48978,102.338341],[34.490662,102.336861],[34.490559,102.335258],[34.490429,102.333649],[34.490398,102.333054],[34.490261,102.331688],[34.490219,102.330711],[34.490131,102.329948],[34.489769,102.328743],[34.4893,102.32785],[34.488739,102.327042],[34.487259,102.325104],[34.48687,102.324623],[34.486191,102.323677],[34.485748,102.322968],[34.485409,102.32235],[34.485249,102.322037],[34.48457,102.320282],[34.483841,102.318626],[34.480789,102.313278],[34.479919,102.311729],[34.478199,102.308777],[34.477699,102.308037],[34.477131,102.307373],[34.47683,102.307083],[34.476021,102.306396],[34.472462,102.303352],[34.471939,102.302994],[34.47176,102.302872],[34.470989,102.302498],[34.470181,102.302277],[34.469139,102.302208],[34.468719,102.302254],[34.46809,102.302391],[34.467178,102.303284],[34.466572,102.302879],[34.465462,102.303436],[34.464691,102.303574],[34.46426,102.303612],[34.463089,102.303551],[34.462589,102.303452],[34.461342,102.302994],[34.460819,102.30275],[34.455811,102.300583],[34.45499,102.30027],[34.45414,102.300056],[34.453041,102.299957],[34.450451,102.300034],[34.44627,102.300171],[34.445278,102.300171],[34.44389,102.299896],[34.441971,102.299477],[34.439621,102.298927],[34.431759,102.297218],[34.429379,102.296806],[34.426949,102.296707],[34.426071,102.296623],[34.425629,102.296516],[34.424591,102.296173],[34.42358,102.295723],[34.42215,102.295219],[34.421108,102.295021],[34.419628,102.294083],[34.41708,102.29528],[34.413521,102.295677],[34.410141,102.296028],[34.40892,102.29612],[34.398399,102.297173],[34.394421,102.297592],[34.393822,102.297684],[34.392269,102.298111],[34.38921,102.299088],[34.38755,102.299583],[34.38662,102.299812],[34.382931,102.300613],[34.380459,102.301064],[34.379219,102.301178],[34.378189,102.301247],[34.37674,102.301529],[34.372559,102.302727],[34.370708,102.303192],[34.369881,102.303368],[34.364689,102.304161],[34.363022,102.304207],[34.359451,102.303726],[34.358231,102.303619],[34.357208,102.303612],[34.353741,102.303864],[34.352852,102.303909],[34.35051,102.304108],[34.350021,102.304199],[34.349758,102.304291],[34.348721,102.304733],[34.347759,102.305511],[34.346939,102.306488],[34.34655,102.307022],[34.346069,102.307747],[34.345402,102.308563],[34.344791,102.309082],[34.344631,102.309189],[34.34396,102.309593],[34.343269,102.309853],[34.34251,102.310028],[34.341579,102.310066],[34.338428,102.3097],[34.33593,102.309433],[34.33326,102.309067],[34.33086,102.308769],[34.32967,102.30835],[34.329151,102.307983],[34.328819,102.307709],[34.32795,102.306801],[34.327499,102.306381],[34.326248,102.305489],[34.325771,102.305237],[34.325089,102.304947],[34.32362,102.304588],[34.32235,102.30468],[34.321461,102.304947],[34.319901,102.305779],[34.318371,102.30661],[34.31649,102.307579],[34.31612,102.307793],[34.315159,102.308479],[34.313511,102.309837],[34.310379,102.312492],[34.308121,102.314293],[34.305241,102.316673],[34.303188,102.318352],[34.301781,102.319527],[34.297661,102.322906],[34.296581,102.323822],[34.29166,102.327873],[34.291111,102.328346],[34.289768,102.329712],[34.288582,102.331207],[34.280128,102.343491],[34.27388,102.352661],[34.27211,102.355057],[34.270851,102.356216],[34.268822,102.357643],[34.266102,102.359451],[34.262959,102.361519],[34.26181,102.362518],[34.260311,102.364166],[34.257961,102.366676],[34.248569,102.377083],[34.247108,102.378723],[34.24577,102.38015],[34.244541,102.381317],[34.24242,102.383034],[34.23119,102.391983],[34.222839,102.39859],[34.221378,102.399857],[34.220169,102.401161],[34.218891,102.402946],[34.215382,102.408546],[34.213509,102.411499],[34.20911,102.417763],[34.20789,102.418282],[34.207649,102.419868],[34.205429,102.422913],[34.204109,102.424973],[34.203629,102.426666],[34.203098,102.428757],[34.20248,102.432091],[34.20042,102.442657],[34.197849,102.456253],[34.1973,102.459023],[34.19706,102.460426],[34.196369,102.464111],[34.196129,102.466629],[34.195629,102.474739],[34.195271,102.477531],[34.193829,102.483788],[34.1926,102.486267],[34.19241,102.489609],[34.191132,102.493523],[34.189491,102.497711],[34.189571,102.501793],[34.188831,102.504898],[34.188229,102.508217],[34.18763,102.509987],[34.186218,102.515877],[34.185211,102.520317],[34.183899,102.525864],[34.183189,102.528763],[34.182529,102.531616],[34.181938,102.534042],[34.181278,102.536423],[34.180641,102.538559],[34.179699,102.541634],[34.17907,102.5439],[34.178169,102.546806],[34.177151,102.550217],[34.176739,102.55175],[34.176121,102.553719],[34.175461,102.555748],[34.17477,102.557159],[34.17395,102.558182],[34.17289,102.558884],[34.171749,102.559273],[34.170589,102.559387],[34.168159,102.559578],[34.16251,102.560081],[34.160141,102.560318],[34.15765,102.560509],[34.15731,102.560608],[34.157009,102.560783],[34.15667,102.561234],[34.155861,102.562752],[34.154591,102.564873],[34.154411,102.565613],[34.154419,102.565758],[34.154598,102.566277],[34.154881,102.566757],[34.155289,102.567383],[34.155651,102.567993],[34.155701,102.568123],[34.15572,102.568939],[34.155331,102.569717],[34.1549,102.570488],[34.154251,102.571564],[34.154091,102.571739],[34.15382,102.571907],[34.15242,102.572319],[34.151798,102.572937],[34.151661,102.573471],[34.151508,102.574753],[34.151279,102.577316],[34.150928,102.580673],[34.150951,102.581352],[34.151138,102.583923],[34.15094,102.584732],[34.150742,102.584976],[34.15062,102.585083],[34.15036,102.585197],[34.148972,102.585426],[34.146721,102.585762],[34.146019,102.585907],[34.145489,102.586121],[34.14447,102.586723],[34.14291,102.587181],[34.1423,102.58741],[34.141529,102.58786],[34.14101,102.588257],[34.140419,102.588898],[34.139992,102.589684],[34.137878,102.594872],[34.137569,102.595581],[34.137058,102.596458],[34.136478,102.597252],[34.136108,102.597794],[34.135769,102.598373],[34.135502,102.59919],[34.135269,102.599823],[34.134621,102.600739],[34.13414,102.601173],[34.133541,102.601761],[34.132969,102.602966],[34.13279,102.603416],[34.132259,102.604134],[34.131371,102.605133],[34.130749,102.605881],[34.130569,102.606178],[34.13039,102.606453],[34.129902,102.607567],[34.129478,102.608711],[34.129021,102.609818],[34.128429,102.610817],[34.128059,102.611389],[34.125,102.616364],[34.123699,102.618591],[34.12326,102.619942],[34.123058,102.621437],[34.123169,102.623863],[34.12286,102.62487],[34.122269,102.625343],[34.121922,102.625443],[34.120152,102.62561],[34.11916,102.629173],[34.117748,102.629852],[34.11734,102.630692],[34.11689,102.631721],[34.116718,102.632317],[34.11668,102.632736],[34.116741,102.633392],[34.117569,102.634941],[34.117119,102.636574],[34.117851,102.637733],[34.117489,102.639999],[34.11742,102.640556],[34.11742,102.640762],[34.117611,102.641777],[34.117809,102.642403],[34.118019,102.64315],[34.118118,102.64357],[34.118328,102.644272],[34.118549,102.645073],[34.118622,102.645287],[34.11869,102.6455],[34.118961,102.646332],[34.119091,102.646553],[34.119579,102.646988],[34.12048,102.647331],[34.120602,102.647346],[34.120838,102.647476],[34.121189,102.647629],[34.121571,102.647881],[34.12178,102.648064],[34.122101,102.648453],[34.122299,102.648804],[34.122421,102.649071],[34.12252,102.649559],[34.12254,102.650414],[34.12241,102.651123],[34.12159,102.654167],[34.12141,102.654877],[34.120789,102.657181],[34.120602,102.657951],[34.119202,102.663193],[34.11874,102.664993],[34.117939,102.667877],[34.117481,102.669327],[34.117271,102.669952],[34.116741,102.671371],[34.116451,102.672081],[34.11586,102.673431],[34.115139,102.674973],[34.114189,102.67688],[34.113899,102.67749],[34.113861,102.677513],[34.113602,102.678078],[34.11298,102.679298],[34.111851,102.681679],[34.11161,102.682251],[34.111301,102.683113],[34.110828,102.684723],[34.110661,102.68541],[34.11026,102.686928],[34.10931,102.690353],[34.108589,102.693024],[34.108318,102.694092],[34.107891,102.695663],[34.107639,102.696693],[34.10741,102.697479],[34.107201,102.698318],[34.106979,102.699112],[34.1068,102.699806],[34.106602,102.700508],[34.10611,102.702332],[34.105911,102.703239],[34.10569,102.704292],[34.105518,102.705276],[34.10527,102.70755],[34.105209,102.708504],[34.10516,102.709648],[34.105122,102.711617],[34.105061,102.712791],[34.104931,102.713821],[34.104752,102.714607],[34.104321,102.715973],[34.104279,102.716187],[34.104019,102.716766],[34.10371,102.71772],[34.103432,102.71846],[34.103142,102.71933],[34.102959,102.720306],[34.10294,102.720757],[34.103001,102.72171],[34.10358,102.725479],[34.10368,102.726471],[34.10368,102.727333],[34.103619,102.727814],[34.103371,102.728653],[34.102989,102.729439],[34.102558,102.730049],[34.102509,102.730164],[34.10207,102.730568],[34.10099,102.731247],[34.100201,102.731697],[34.098301,102.732727],[34.09761,102.733131],[34.09655,102.733688],[34.095421,102.734306],[34.094818,102.734612],[34.094059,102.734802],[34.093418,102.734848],[34.092781,102.734718],[34.092171,102.734459],[34.091621,102.734123],[34.090931,102.733582],[34.090691,102.733414],[34.087151,102.730698],[34.086498,102.730301],[34.086021,102.730087],[34.085419,102.729973],[34.084221,102.729912],[34.08215,102.729851],[34.081181,102.729134],[34.07951,102.730637],[34.07851,102.729851],[34.077999,102.729927],[34.078018,102.729927],[34.077862,102.72998],[34.077381,102.730087],[34.07605,102.730476],[34.0742,102.730957],[34.073021,102.731308],[34.072559,102.731361],[34.072121,102.731377],[34.071659,102.731323],[34.071259,102.731216],[34.069962,102.730743],[34.0695,102.730553],[34.067268,102.729713],[34.06567,102.729057],[34.064571,102.728554],[34.062561,102.727524],[34.062019,102.727226],[34.05949,102.725906],[34.059021,102.725723],[34.058472,102.725548],[34.05484,102.724602],[34.054459,102.724518],[34.05402,102.724388],[34.053341,102.724113],[34.052719,102.723793],[34.04837,102.721077],[34.048031,102.720886],[34.04689,102.720177],[34.04665,102.720039],[34.04604,102.719757],[34.045361,102.719566],[34.044289,102.719398],[34.0443,102.719414],[34.044189,102.719414],[34.043919,102.71936],[34.043369,102.719299],[34.042461,102.719162],[34.042141,102.719139],[34.04137,102.719017],[34.04052,102.718941],[34.040279,102.71888],[34.039242,102.718773],[34.038658,102.718681],[34.038349,102.718658],[34.037701,102.718559],[34.036789,102.718437],[34.036201,102.718437],[34.03595,102.718483],[34.035679,102.718536],[34.035469,102.71862],[34.035061,102.718903],[34.034851,102.719101],[34.034481,102.719582],[34.034019,102.720261],[34.032318,102.722923],[34.032169,102.723129],[34.031799,102.723518],[34.031601,102.723686],[34.03141,102.723824],[34.03117,102.723953],[34.03093,102.724037],[34.030689,102.724113],[34.03043,102.724152],[34.03019,102.724136],[34.029148,102.72406],[34.028519,102.723984],[34.028259,102.723991],[34.027969,102.723953],[34.02771,102.723953],[34.027409,102.723999],[34.027111,102.724083],[34.026871,102.724167],[34.026611,102.724319],[34.026119,102.724693],[34.025501,102.725212],[34.025318,102.725319],[34.02512,102.725502],[34.024391,102.726021],[34.023659,102.726501],[34.023232,102.726753],[34.023048,102.726883],[34.022831,102.726997],[34.021309,102.72789],[34.021019,102.728081],[34.020611,102.728416],[34.020409,102.72863],[34.019951,102.729271],[34.019691,102.729782],[34.018902,102.731781],[34.018452,102.732986],[34.018139,102.733757],[34.017879,102.734299],[34.01767,102.734619],[34.017479,102.734863],[34.01725,102.735107],[34.017052,102.735359],[34.016781,102.735641],[34.013119,102.738113],[34.008789,102.741043],[34.00354,102.74456],[34.002659,102.745171],[34.002548,102.745232],[34.001911,102.745667],[34.001431,102.745911],[34.000221,102.746902],[33.99966,102.747452],[33.999161,102.748161],[33.998959,102.74855],[33.998829,102.748894],[33.998611,102.749763],[33.99855,102.750549],[33.998581,102.751427],[33.998661,102.752113],[33.99894,102.753883],[33.998981,102.754433],[33.99905,102.754868],[33.999142,102.755241],[33.999321,102.756371],[33.999962,102.760437],[34.00042,102.763367],[34.00053,102.764191],[34.00061,102.765053],[34.00058,102.765778],[34.00045,102.766693],[34.000111,102.767281],[33.99979,102.767883],[33.997421,102.771591],[33.997379,102.77169],[33.997211,102.771896],[33.9944,102.77623],[33.991291,102.781052],[33.990311,102.782539],[33.988289,102.785713],[33.98724,102.787323],[33.985649,102.789726],[33.984509,102.791489],[33.983978,102.792351],[33.982471,102.794647],[33.980518,102.797699],[33.980141,102.798248],[33.979351,102.799507],[33.978889,102.800194],[33.97575,102.805038],[33.97533,102.805717],[33.974899,102.806343],[33.97456,102.806892],[33.97398,102.807747],[33.97361,102.808327],[33.973179,102.808983],[33.97274,102.809677],[33.97234,102.81028],[33.971889,102.810997],[33.967892,102.817139],[33.966999,102.818527],[33.966179,102.819763],[33.965462,102.820877],[33.96508,102.821442],[33.96019,102.828987],[33.95985,102.829529],[33.956089,102.83532],[33.955639,102.836037],[33.955219,102.836662],[33.954239,102.838188],[33.953659,102.83905],[33.953629,102.839073],[33.953621,102.839127],[33.953159,102.839882],[33.950729,102.843613],[33.950432,102.844116],[33.949982,102.844757],[33.943562,102.854668],[33.941631,102.857613],[33.937241,102.864418],[33.936729,102.865189],[33.936131,102.865997],[33.935501,102.866768],[33.93491,102.867416],[33.934181,102.868118],[33.930019,102.871872],[33.929482,102.872414],[33.928982,102.873016],[33.928581,102.873756],[33.928459,102.874039],[33.928261,102.874702],[33.927151,102.879211],[33.926868,102.880211],[33.92659,102.880882],[33.926262,102.881554],[33.92585,102.882187],[33.925751,102.882309],[33.92522,102.882874],[33.924709,102.883324],[33.92411,102.883743],[33.921749,102.8853],[33.912102,102.891747],[33.909801,102.893257],[33.908459,102.894173],[33.90493,102.896492],[33.90419,102.897003],[33.902908,102.897842],[33.900631,102.899384],[33.894958,102.903137],[33.894371,102.903549],[33.88932,102.906891],[33.88871,102.907333],[33.888161,102.907669],[33.885799,102.909233],[33.885151,102.909683],[33.88385,102.910522],[33.880421,102.912827],[33.872849,102.917847],[33.871632,102.918694],[33.871029,102.91906],[33.861191,102.925621],[33.84753,102.934692],[33.843861,102.937149],[33.8433,102.937508],[33.839359,102.94014],[33.838619,102.940613],[33.837799,102.94117],[33.83699,102.941803],[33.83633,102.942436],[33.835701,102.943169],[33.83033,102.950912],[33.830059,102.951248],[33.82962,102.951691],[33.829041,102.952103],[33.828609,102.952293],[33.828289,102.952393],[33.827839,102.952477],[33.825901,102.952759],[33.825291,102.952873],[33.824951,102.952972],[33.82473,102.953056],[33.82378,102.95359],[33.82267,102.954277],[33.822578,102.954353],[33.821991,102.954712],[33.821289,102.955017],[33.82061,102.9552],[33.817371,102.955978],[33.815041,102.95649],[33.814362,102.956612],[33.813492,102.95665],[33.812759,102.956581],[33.811111,102.95649],[33.809631,102.956383],[33.808189,102.956322],[33.80751,102.956383],[33.806839,102.956612],[33.806271,102.956963],[33.80566,102.957474],[33.803619,102.959358],[33.802921,102.959923],[33.802151,102.96032],[33.801472,102.960487],[33.800758,102.96051],[33.800201,102.960388],[33.799492,102.960083],[33.798309,102.959412],[33.797821,102.959167],[33.797161,102.958946],[33.796391,102.958923],[33.79549,102.959068],[33.795151,102.959137],[33.794991,102.959137],[33.79488,102.95919],[33.789989,102.960152],[33.788921,102.960342],[33.788219,102.960487],[33.787189,102.960617],[33.786499,102.960617],[33.78574,102.960587],[33.784649,102.96048],[33.783852,102.960327],[33.781792,102.96003],[33.781132,102.959969],[33.78038,102.959976],[33.779659,102.960052],[33.778271,102.960243],[33.777191,102.960342],[33.775761,102.960533],[33.77491,102.960587],[33.77422,102.960609],[33.773399,102.960564],[33.772469,102.960442],[33.771858,102.960327],[33.7701,102.959953],[33.767799,102.959488],[33.763859,102.958656],[33.76247,102.958344],[33.760979,102.957939],[33.759571,102.957527],[33.758968,102.957336],[33.75602,102.956253],[33.75528,102.955994],[33.74733,102.953102],[33.746521,102.952003],[33.739429,102.953453],[33.73904,102.95488],[33.738609,102.955276],[33.738121,102.955704],[33.737041,102.956688],[33.73307,102.960243],[33.732578,102.960716],[33.731289,102.961899],[33.730652,102.962433],[33.72995,102.962967],[33.729382,102.963333],[33.72916,102.963417],[33.728291,102.963753],[33.72757,102.963913],[33.726791,102.963966],[33.720871,102.964233],[33.71986,102.964287],[33.719379,102.964302],[33.717449,102.964409],[33.711418,102.964668],[33.706329,102.964928],[33.704552,102.964989],[33.703678,102.964943],[33.7029,102.96479],[33.700619,102.964142],[33.699989,102.963997],[33.699162,102.963982],[33.69836,102.964157],[33.696911,102.964821],[33.6945,102.966003],[33.68998,102.968147],[33.689308,102.968353],[33.68885,102.96843],[33.68819,102.968384],[33.687592,102.968231],[33.687099,102.967987],[33.686779,102.967796],[33.686111,102.967247],[33.685181,102.966362],[33.684639,102.965912],[33.684299,102.965668],[33.683739,102.965393],[33.683189,102.965149],[33.682461,102.964928],[33.681049,102.964546],[33.68066,102.96447],[33.67968,102.964203],[33.679169,102.964073],[33.678822,102.963959],[33.677391,102.9636],[33.677269,102.963593],[33.676781,102.963371],[33.676491,102.963211],[33.67598,102.962837],[33.675831,102.962708],[33.674549,102.961243],[33.674171,102.960907],[33.673759,102.960617],[33.673061,102.96032],[33.67297,102.960274],[33.672691,102.960243],[33.672081,102.96022],[33.672058,102.960243],[33.671799,102.960251],[33.67091,102.960327],[33.669979,102.960426],[33.668468,102.960564],[33.667591,102.960587],[33.666801,102.96048],[33.66629,102.960281],[33.66592,102.960052],[33.66552,102.959747],[33.66534,102.959587],[33.665039,102.959244],[33.66473,102.958801],[33.663448,102.956543],[33.662201,102.954262],[33.66201,102.953957],[33.66161,102.953217],[33.661018,102.952362],[33.66029,102.951698],[33.659512,102.951286],[33.659019,102.951157],[33.65802,102.950996],[33.653961,102.950623],[33.65266,102.95047],[33.651711,102.950119],[33.65136,102.949898],[33.650639,102.949242],[33.649712,102.94828],[33.648491,102.946968],[33.64846,102.946907],[33.647911,102.946327],[33.647621,102.946083],[33.6474,102.945847],[33.647099,102.945572],[33.646801,102.945328],[33.64645,102.945084],[33.646141,102.944893],[33.645821,102.944748],[33.64521,102.944527],[33.644489,102.944389],[33.643711,102.944397],[33.64344,102.944443],[33.64278,102.944603],[33.64246,102.94471],[33.641861,102.945023],[33.641541,102.945221],[33.641239,102.945457],[33.640751,102.945892],[33.640251,102.946373],[33.63728,102.9496],[33.63625,102.950737],[33.635609,102.951401],[33.635101,102.951851],[33.634411,102.95224],[33.634312,102.952278],[33.633221,102.95253],[33.631989,102.952599],[33.631111,102.952782],[33.630299,102.953247],[33.62973,102.953773],[33.628448,102.955116],[33.627991,102.955566],[33.627449,102.955917],[33.626678,102.956131],[33.625938,102.956017],[33.625351,102.955704],[33.624329,102.954811],[33.624031,102.954567],[33.623772,102.954407],[33.623371,102.954208],[33.623089,102.954109],[33.622799,102.954048],[33.622501,102.95401],[33.622181,102.954018],[33.620621,102.954269],[33.620171,102.954308],[33.619781,102.954308],[33.61916,102.954224],[33.618759,102.954086],[33.618351,102.953903],[33.618019,102.95369],[33.617241,102.95314],[33.616989,102.952904],[33.616562,102.95256],[33.615978,102.952049],[33.615711,102.951843],[33.615139,102.951447],[33.614639,102.951218],[33.614071,102.951111],[33.613449,102.951157],[33.61269,102.951347],[33.612331,102.951462],[33.611542,102.95166],[33.61105,102.951683],[33.610149,102.951462],[33.609959,102.951347],[33.609249,102.950798],[33.609169,102.950706],[33.60878,102.950104],[33.607841,102.947853],[33.607712,102.94751],[33.607029,102.945877],[33.60688,102.945473],[33.606258,102.944077],[33.605999,102.943443],[33.606239,102.942429],[33.605961,102.942207],[33.605289,102.941772],[33.603168,102.941093],[33.602612,102.939697],[33.598629,102.938179],[33.598061,102.937988],[33.597691,102.937843],[33.597599,102.937843],[33.596951,102.937767],[33.59639,102.937759],[33.595661,102.93869],[33.594891,102.938461],[33.59399,102.938477],[33.59269,102.940697],[33.592319,102.940483],[33.592289,102.940483],[33.59235,102.940598],[33.592289,102.940742],[33.59235,102.941292],[33.59026,102.944901],[33.588982,102.944992],[33.588531,102.945557],[33.588219,102.94593],[33.58786,102.946457],[33.586781,102.947868],[33.586369,102.948547],[33.58622,102.948624],[33.58601,102.948837],[33.585121,102.949966],[33.584629,102.950562],[33.584221,102.950989],[33.583839,102.951408],[33.582951,102.952339],[33.582539,102.952797],[33.580509,102.954964],[33.579029,102.956596],[33.57869,102.95694],[33.577942,102.957771],[33.577641,102.958038],[33.57756,102.958092],[33.577511,102.958138],[33.577469,102.958168],[33.57653,102.961349],[33.576649,102.961388],[33.576839,102.9618],[33.577148,102.962677],[33.577599,102.964157],[33.577709,102.964577],[33.578209,102.965652],[33.577011,102.967728],[33.562309,102.992767],[33.56229,102.995613],[33.56152,102.997063],[33.560551,102.998123],[33.558681,102.998947],[33.55827,103.000237],[33.558331,103.003082],[33.55722,103.005333],[33.556961,103.007217],[33.556789,103.008347],[33.55669,103.00946],[33.55669,103.016533],[33.556629,103.018227],[33.556561,103.018593],[33.556301,103.019386],[33.556061,103.019974],[33.55497,103.022774],[33.554691,103.023613],[33.554531,103.024307],[33.554489,103.024986],[33.554611,103.025681],[33.554852,103.026299],[33.555038,103.026611],[33.55547,103.027077],[33.556049,103.027412],[33.556301,103.027473],[33.558159,103.027588],[33.558571,103.027443],[33.560741,103.027687],[33.562149,103.02787],[33.564812,103.028107],[33.56588,103.028259],[33.566101,103.028313],[33.566521,103.02845],[33.567268,103.028893],[33.568119,103.029701],[33.568401,103.03009],[33.568619,103.030518],[33.569099,103.031937],[33.56929,103.032692],[33.570278,103.03598],[33.570869,103.037613],[33.571529,103.038567],[33.571819,103.038918],[33.572639,103.039703],[33.57436,103.041023],[33.576141,103.042473],[33.577438,103.043503],[33.578541,103.044456],[33.57946,103.045403],[33.58009,103.046387],[33.580711,103.047668],[33.581051,103.048508],[33.581772,103.050163],[33.582081,103.050926],[33.582359,103.051498],[33.583759,103.054657],[33.584389,103.05619],[33.5853,103.058311],[33.585911,103.059708],[33.58717,103.062637],[33.587841,103.064102],[33.588612,103.066017],[33.589489,103.067993],[33.590069,103.069412],[33.59116,103.072006],[33.592331,103.0737],[33.592239,103.076012],[33.591888,103.077469],[33.588421,103.091187],[33.58823,103.093384],[33.587769,103.099693],[33.586311,103.101318],[33.58577,103.102692],[33.58519,103.103661],[33.584728,103.104362],[33.584541,103.104553],[33.583931,103.10508],[33.583511,103.105438],[33.582981,103.105759],[33.581848,103.106354],[33.576511,103.108421],[33.56625,103.112213],[33.562092,103.113823],[33.560051,103.114532],[33.557999,103.115288],[33.556381,103.115921],[33.554642,103.116798],[33.55278,103.118057],[33.540932,103.12635],[33.540051,103.126831],[33.53867,103.127197],[33.536831,103.127403],[33.534981,103.127831],[33.533508,103.128571],[33.532131,103.129562],[33.530449,103.130882],[33.528648,103.132103],[33.52784,103.132584],[33.526031,103.13372],[33.525089,103.134483],[33.523491,103.136093],[33.52187,103.137619],[33.520359,103.138779],[33.518581,103.139954],[33.51659,103.141243],[33.51403,103.142937],[33.512081,103.144287],[33.510559,103.145508],[33.5093,103.146713],[33.508282,103.147774],[33.506821,103.149513],[33.505219,103.151497],[33.503681,103.153297],[33.502419,103.154572],[33.501141,103.155182],[33.498909,103.156174],[33.49741,103.157066],[33.496059,103.158203],[33.494041,103.160233],[33.490829,103.163582],[33.4893,103.164886],[33.488022,103.165588],[33.48666,103.165993],[33.482281,103.167053],[33.48,103.167587],[33.47776,103.167923],[33.47578,103.167976],[33.47366,103.167992],[33.473042,103.168053],[33.472118,103.168411],[33.471451,103.168877],[33.46891,103.171303],[33.46743,103.172752],[33.466019,103.173973],[33.465092,103.174339],[33.464039,103.174347],[33.463402,103.17424],[33.460442,103.17347],[33.459129,103.173553],[33.458099,103.17395],[33.456661,103.174797],[33.452709,103.177162],[33.451981,103.177551],[33.450802,103.177933],[33.448799,103.178253],[33.4459,103.178673],[33.444172,103.178818],[33.442329,103.178841],[33.440689,103.178886],[33.43597,103.178757],[33.43486,103.178963],[33.434509,103.179077],[33.43354,103.179619],[33.432861,103.180191],[33.432621,103.180367],[33.428909,103.183418],[33.427761,103.184303],[33.426731,103.185028],[33.426079,103.185371],[33.424889,103.185768],[33.423561,103.186249],[33.42234,103.186783],[33.42144,103.187538],[33.420849,103.188568],[33.41993,103.190323],[33.419071,103.191368],[33.41795,103.1922],[33.416611,103.192886],[33.41518,103.193527],[33.414162,103.193932],[33.412579,103.19426],[33.411289,103.194458],[33.409969,103.194748],[33.409081,103.195297],[33.408409,103.195999],[33.407421,103.197197],[33.40657,103.198158],[33.40559,103.198967],[33.40443,103.199654],[33.403301,103.200119],[33.402142,103.200333],[33.400848,103.200493],[33.3992,103.20047],[33.39814,103.200737],[33.397228,103.201271],[33.395699,103.202797],[33.39473,103.20369],[33.393841,103.204552],[33.393452,103.204903],[33.39249,103.205544],[33.391548,103.20594],[33.39053,103.205963],[33.38789,103.205322],[33.3843,103.204483],[33.38155,103.203796],[33.380268,103.203644],[33.380119,103.203667],[33.37936,103.20401],[33.378689,103.204781],[33.377628,103.206673],[33.377392,103.20694],[33.376301,103.207603],[33.37542,103.207771],[33.375221,103.207787],[33.373589,103.207779],[33.371601,103.207703],[33.369869,103.20768],[33.368271,103.207527],[33.364609,103.206711],[33.363331,103.206749],[33.362511,103.206848],[33.35915,103.207161],[33.35651,103.207298],[33.354771,103.207253],[33.352612,103.206963],[33.350712,103.206741],[33.350052,103.206711],[33.348801,103.20694],[33.34761,103.207336],[33.346218,103.207764],[33.344971,103.207817],[33.34351,103.207718],[33.340851,103.207443],[33.339149,103.207283],[33.337589,103.207191],[33.33651,103.207367],[33.335629,103.207718],[33.335289,103.207893],[33.33448,103.208481],[33.33342,103.209343],[33.332958,103.209671],[33.331921,103.210167],[33.33073,103.210426],[33.328442,103.210587],[33.326839,103.21067],[33.32542,103.210709],[33.324169,103.210793],[33.322571,103.210983],[33.32114,103.211067],[33.31963,103.21125],[33.318501,103.211456],[33.318321,103.211517],[33.317341,103.212067],[33.317051,103.212341],[33.31641,103.213173],[33.315929,103.214523],[33.315769,103.215584],[33.315392,103.217644],[33.315022,103.218781],[33.31493,103.218964],[33.314308,103.219673],[33.31403,103.219887],[33.31282,103.220322],[33.310768,103.220886],[33.309471,103.221313],[33.308739,103.221474],[33.307789,103.221581],[33.307049,103.221519],[33.304871,103.221161],[33.30373,103.221107],[33.30304,103.221283],[33.301949,103.221893],[33.30154,103.222267],[33.3009,103.223007],[33.300018,103.223831],[33.29895,103.224327],[33.297581,103.224564],[33.296982,103.22464],[33.295471,103.22496],[33.294319,103.225349],[33.292728,103.226143],[33.291061,103.226891],[33.288261,103.227432],[33.286781,103.227943],[33.282139,103.229927],[33.280621,103.230652],[33.276501,103.233047],[33.274921,103.234009],[33.273731,103.234467],[33.27227,103.234741],[33.271271,103.23468],[33.270931,103.234619],[33.27002,103.234413],[33.26836,103.233803],[33.26722,103.233566],[33.266048,103.233704],[33.264832,103.233948],[33.261791,103.23468],[33.26038,103.234917],[33.25914,103.235062],[33.257462,103.235161],[33.253731,103.235443],[33.25238,103.235397],[33.25106,103.235001],[33.249592,103.234207],[33.245819,103.232117],[33.244678,103.231339],[33.24382,103.230408],[33.240059,103.225594],[33.238972,103.224113],[33.23819,103.223106],[33.23785,103.22274],[33.23695,103.222267],[33.236149,103.22216],[33.235329,103.222282],[33.233398,103.222618],[33.231781,103.22258],[33.231091,103.222488],[33.22718,103.221893],[33.225471,103.221657],[33.224178,103.221687],[33.223011,103.22187],[33.221619,103.222328],[33.219818,103.223061],[33.218491,103.223648],[33.21571,103.2248],[33.214199,103.225372],[33.212749,103.225952],[33.20895,103.227547],[33.202869,103.230019],[33.201542,103.230637],[33.199081,103.23204],[33.197811,103.23259],[33.19664,103.232933],[33.19558,103.233063],[33.194279,103.233063],[33.192841,103.23288],[33.191399,103.232643],[33.18642,103.231979],[33.185291,103.231842],[33.183811,103.231827],[33.18346,103.231873],[33.182259,103.232147],[33.180988,103.232643],[33.179909,103.233147],[33.178261,103.233887],[33.176609,103.234703],[33.1754,103.23526],[33.17424,103.235748],[33.173161,103.236099],[33.171631,103.236526],[33.168621,103.23732],[33.167042,103.237823],[33.16547,103.238548],[33.164291,103.239281],[33.160252,103.242126],[33.15736,103.244202],[33.155819,103.245247],[33.15461,103.245842],[33.15316,103.246277],[33.15181,103.246437],[33.14666,103.246887],[33.145031,103.24704],[33.1436,103.247307],[33.142368,103.247726],[33.14098,103.248497],[33.139992,103.249237],[33.134682,103.253471],[33.13332,103.254578],[33.132111,103.255623],[33.13126,103.256447],[33.130001,103.257912],[33.128738,103.259537],[33.127579,103.261253],[33.126831,103.262512],[33.12627,103.263611],[33.124859,103.266617],[33.124149,103.268204],[33.123569,103.269531],[33.12236,103.272102],[33.12175,103.273468],[33.121052,103.274872],[33.1194,103.278381],[33.118641,103.280159],[33.118469,103.281509],[33.118641,103.284523],[33.118599,103.285828],[33.118481,103.286583],[33.11805,103.287819],[33.116661,103.290291],[33.11607,103.291298],[33.114521,103.294037],[33.113831,103.295357],[33.110771,103.300713],[33.108799,103.30423],[33.10693,103.307663],[33.10585,103.309563],[33.10474,103.311562],[33.10376,103.313301],[33.10342,103.313927],[33.10157,103.317261],[33.100632,103.318848],[33.099758,103.320091],[33.096821,103.323883],[33.096001,103.324966],[33.095161,103.326042],[33.094471,103.327003],[33.093639,103.328377],[33.092258,103.331177],[33.091648,103.332573],[33.091042,103.333832],[33.090149,103.335831],[33.089481,103.337082],[33.088829,103.338371],[33.08831,103.339577],[33.087849,103.340714],[33.087318,103.342339],[33.087101,103.343529],[33.086899,103.345703],[33.086929,103.347954],[33.08675,103.349571],[33.0863,103.350693],[33.08556,103.351624],[33.084641,103.352303],[33.078941,103.355186],[33.078522,103.35537],[33.077671,103.355667],[33.076359,103.355904],[33.075459,103.355949],[33.0746,103.355873],[33.07333,103.355553],[33.07206,103.355103],[33.071529,103.354889],[33.069302,103.35408],[33.06802,103.353828],[33.066929,103.353844],[33.06506,103.35424],[33.063622,103.354446],[33.062641,103.354362],[33.061691,103.354103],[33.060921,103.353767],[33.060162,103.353394],[33.05899,103.352783],[33.056351,103.351448],[33.055248,103.350853],[33.05402,103.350143],[33.052711,103.349342],[33.051449,103.348427],[33.050282,103.347649],[33.049179,103.347076],[33.048111,103.346832],[33.046661,103.346809],[33.04493,103.347054],[33.043259,103.347359],[33.04216,103.347313],[33.040951,103.347214],[33.039921,103.347031],[33.038059,103.346832],[33.037102,103.347107],[33.029449,103.349022],[33.028889,103.349289],[33.02813,103.349907],[33.027081,103.351288],[33.026409,103.352318],[33.025848,103.353027],[33.024971,103.353699],[33.023991,103.354027],[33.021801,103.354317],[33.020592,103.354553],[33.019341,103.354713],[33.017941,103.354828],[33.016911,103.35479],[33.016479,103.354752],[33.01535,103.354446],[33.01424,103.354088],[33.013458,103.353592],[33.01091,103.352257],[33.0103,103.351982],[33.008732,103.351624],[33.005501,103.351112],[33.004581,103.3507],[33.003799,103.350021],[33.003651,103.349854],[33.003201,103.349083],[33.002541,103.347862],[33.001862,103.346657],[33.001579,103.346313],[33.00087,103.345573],[32.999931,103.345062],[32.998878,103.344803],[32.992008,103.343224],[32.990391,103.343048],[32.989071,103.34304],[32.987709,103.343117],[32.986309,103.343323],[32.984741,103.343651],[32.979359,103.344963],[32.977219,103.345512],[32.974861,103.346077],[32.970989,103.347076],[32.96925,103.347572],[32.967682,103.348213],[32.966331,103.348824],[32.965172,103.349152],[32.964169,103.349197],[32.963829,103.349136],[32.962742,103.348732],[32.960621,103.347633],[32.959702,103.347198],[32.95908,103.347054],[32.95863,103.347038],[32.958031,103.347107],[32.957119,103.347351],[32.955151,103.347977],[32.952831,103.348663],[32.952141,103.3489],[32.951641,103.349167],[32.95116,103.349442],[32.949409,103.350571],[32.94825,103.351273],[32.94762,103.351593],[32.947079,103.351791],[32.945309,103.35257],[32.944351,103.3526],[32.943501,103.352821],[32.943272,103.352859],[32.941738,103.353241],[32.940842,103.353378],[32.940022,103.353416],[32.93951,103.353409],[32.938541,103.353279],[32.937328,103.352989],[32.936821,103.352829],[32.935581,103.352386],[32.93502,103.352127],[32.93438,103.35173],[32.92968,103.348557],[32.928959,103.348389],[32.92881,103.348389],[32.927872,103.348579],[32.927238,103.348923],[32.926979,103.349167],[32.926231,103.350121],[32.92588,103.350883],[32.92561,103.351929],[32.925621,103.353188],[32.926079,103.354408],[32.92646,103.355003],[32.926689,103.355247],[32.926819,103.35537],[32.927231,103.355652],[32.92894,103.356537],[32.92939,103.356903],[32.92963,103.357208],[32.929829,103.357567],[32.929981,103.358223],[32.930019,103.358673],[32.93,103.359138],[32.929909,103.3601],[32.930092,103.361542],[32.93021,103.362022],[32.93042,103.36274],[32.930618,103.364227],[32.930641,103.364723],[32.930511,103.366203],[32.93037,103.366928],[32.929901,103.370033],[32.929829,103.370567],[32.92918,103.373558],[32.928799,103.375076],[32.928452,103.376228],[32.928242,103.377434],[32.928139,103.378677],[32.928169,103.3797],[32.928249,103.38044],[32.928341,103.380913],[32.928692,103.382339],[32.928909,103.382988],[32.929192,103.383743],[32.929409,103.384277],[32.929859,103.385559],[32.930119,103.386688],[32.93008,103.38781],[32.929829,103.388687],[32.92976,103.388863],[32.929501,103.389328],[32.929329,103.389587],[32.928612,103.390182],[32.927959,103.390533],[32.92667,103.391029],[32.9259,103.391296],[32.924332,103.391922],[32.924019,103.392059],[32.921459,103.393173],[32.92033,103.393883],[32.918991,103.394997],[32.91835,103.397507],[32.918289,103.399567],[32.918541,103.402367],[32.918579,103.403191],[32.918869,103.404228],[32.91993,103.406593],[32.920429,103.408546],[32.9212,103.410851],[32.921989,103.412651],[32.922771,103.414688],[32.92392,103.417473],[32.9244,103.418663],[32.92532,103.420891],[32.92561,103.421631],[32.925999,103.422462],[32.926659,103.423683],[32.927441,103.424919],[32.928329,103.426208],[32.928848,103.427254],[32.928989,103.427818],[32.92905,103.429153],[32.928909,103.430054],[32.928532,103.431862],[32.928421,103.432999],[32.928551,103.434288],[32.928719,103.435532],[32.928741,103.436203],[32.92852,103.437347],[32.92844,103.437569],[32.927872,103.438599],[32.926811,103.440201],[32.92614,103.441238],[32.925838,103.441612],[32.92487,103.442177],[32.924221,103.442284],[32.923759,103.442238],[32.92308,103.442139],[32.92284,103.442032],[32.922298,103.441994],[32.921169,103.441811],[32.919289,103.441727],[32.917931,103.441872],[32.917221,103.442162],[32.916569,103.442596],[32.914398,103.444443],[32.913891,103.444946],[32.912571,103.446381],[32.911499,103.447723],[32.91016,103.449493],[32.90984,103.449928],[32.909279,103.450684],[32.90884,103.451134],[32.907711,103.452148],[32.90715,103.452873],[32.906818,103.453522],[32.90646,103.454453],[32.906151,103.455406],[32.905731,103.456581],[32.905121,103.457428],[32.904419,103.458252],[32.90411,103.458588],[32.903252,103.459747],[32.903019,103.460037],[32.90263,103.460426],[32.90176,103.461113],[32.901588,103.461182],[32.901039,103.461357],[32.900089,103.461479],[32.89872,103.461533],[32.897171,103.46167],[32.896172,103.461678],[32.894901,103.461601],[32.89386,103.461304],[32.893242,103.461021],[32.892818,103.460808],[32.88744,103.45845],[32.885921,103.458076],[32.884232,103.45826],[32.88364,103.458801],[32.88335,103.459244],[32.883228,103.460114],[32.883331,103.461067],[32.883701,103.462151],[32.884941,103.464317],[32.885361,103.465477],[32.88559,103.466217],[32.885941,103.46756],[32.886768,103.471481],[32.88702,103.472878],[32.88702,103.473999],[32.886959,103.474541],[32.8867,103.475273],[32.886589,103.475487],[32.886299,103.475929],[32.885639,103.476753],[32.885151,103.477409],[32.884171,103.4786],[32.883739,103.479172],[32.883289,103.480072],[32.883289,103.481178],[32.88422,103.483498],[32.884609,103.484032],[32.885479,103.484833],[32.885681,103.485199],[32.885921,103.486977],[32.886101,103.48748],[32.88789,103.488998],[32.88847,103.489853],[32.889359,103.490211],[32.88966,103.490784],[32.89048,103.491524],[32.890678,103.491867],[32.890888,103.492531],[32.89201,103.494492],[32.89254,103.495956],[32.8932,103.496986],[32.893539,103.497864],[32.894569,103.499237],[32.894711,103.499672],[32.894741,103.500282],[32.895451,103.501518],[32.89576,103.503227],[32.895981,103.503563],[32.896961,103.504143],[32.898571,103.505417],[32.898788,103.505783],[32.89922,103.506897],[32.89954,103.508629],[32.899872,103.509567],[32.901138,103.512047],[32.9021,103.513329],[32.90271,103.514191],[32.90337,103.515282],[32.903599,103.5159],[32.90369,103.51725],[32.903641,103.5177],[32.903542,103.51815],[32.9034,103.51857],[32.903118,103.51918],[32.90287,103.519539],[32.901981,103.52021],[32.89875,103.521294],[32.897659,103.521713],[32.896591,103.52224],[32.895561,103.522926],[32.89481,103.523613],[32.89386,103.524544],[32.892632,103.525681],[32.89151,103.526657],[32.889999,103.528061],[32.88969,103.528328],[32.887032,103.530907],[32.88538,103.532829],[32.88414,103.534088],[32.883041,103.535133],[32.88232,103.535957],[32.88184,103.536827],[32.881329,103.538147],[32.880569,103.539284],[32.880119,103.539719],[32.87899,103.540367],[32.878181,103.540756],[32.876961,103.541527],[32.87677,103.541687],[32.875542,103.542923],[32.87439,103.544113],[32.87344,103.544777],[32.87281,103.54496],[32.872379,103.544991],[32.871529,103.544769],[32.869991,103.543968],[32.868919,103.543694],[32.86871,103.543694],[32.86792,103.543907],[32.865631,103.545013],[32.864841,103.545326],[32.863529,103.546043],[32.863209,103.546341],[32.862499,103.547562],[32.862141,103.548943],[32.861809,103.550858],[32.86142,103.552467],[32.86134,103.552696],[32.860748,103.55394],[32.860229,103.554649],[32.859379,103.555748],[32.858181,103.55687],[32.857422,103.557388],[32.855759,103.558571],[32.854111,103.559631],[32.852581,103.560661],[32.85178,103.56115],[32.850929,103.561546],[32.84938,103.560806],[32.847279,103.562027],[32.846119,103.561127],[32.844318,103.560806],[32.842979,103.560966],[32.83886,103.561691],[32.836922,103.561974],[32.835239,103.562263],[32.835041,103.562317],[32.833969,103.562889],[32.832489,103.56398],[32.832199,103.56424],[32.830921,103.565247],[32.829681,103.565933],[32.828079,103.566483],[32.826851,103.566849],[32.826199,103.566994],[32.825119,103.566849],[32.82309,103.565964],[32.82196,103.56604],[32.821091,103.566437],[32.819809,103.567093],[32.81958,103.567169],[32.818661,103.567421],[32.816849,103.567734],[32.81509,103.567963],[32.813641,103.568352],[32.81329,103.568604],[32.81266,103.569221],[32.81216,103.570007],[32.811611,103.570801],[32.810741,103.571503],[32.80975,103.571831],[32.80854,103.571991],[32.806389,103.572197],[32.80484,103.572342],[32.801029,103.572723],[32.800159,103.572884],[32.79948,103.573219],[32.79895,103.573669],[32.79842,103.574249],[32.79784,103.575233],[32.79734,103.576553],[32.79668,103.578011],[32.796631,103.578827],[32.796841,103.581757],[32.796799,103.582779],[32.796261,103.583809],[32.795582,103.584511],[32.793018,103.585953],[32.792259,103.586868],[32.79192,103.587959],[32.79147,103.592941],[32.79113,103.595108],[32.79044,103.596313],[32.789612,103.596863],[32.78825,103.597397],[32.788052,103.597458],[32.787029,103.597878],[32.786579,103.598267],[32.786301,103.598579],[32.78574,103.599663],[32.78553,103.60096],[32.78524,103.603996],[32.785069,103.605637],[32.785721,103.607887],[32.785721,103.608856],[32.785389,103.609711],[32.784641,103.610893],[32.78352,103.612663],[32.782211,103.614609],[32.78183,103.615097],[32.780869,103.616226],[32.78072,103.616257],[32.780609,103.61631],[32.780491,103.616371],[32.780258,103.616623],[32.779961,103.616898],[32.778049,103.618217],[32.776642,103.619171],[32.775639,103.619743],[32.774971,103.619812],[32.774311,103.619583],[32.773739,103.619347],[32.773289,103.619118],[32.772671,103.618927],[32.771999,103.618568],[32.771679,103.618523],[32.771259,103.618523],[32.770809,103.618294],[32.770481,103.618217],[32.770248,103.61824],[32.7701,103.618294],[32.769852,103.618462],[32.769402,103.618912],[32.769089,103.619797],[32.768589,103.620064],[32.76759,103.620682],[32.767712,103.618896],[32.767509,103.618248],[32.767559,103.617279],[32.767399,103.616951],[32.767208,103.616699],[32.766899,103.61644],[32.766251,103.616249],[32.76609,103.616226],[32.765862,103.616249],[32.765579,103.616241],[32.765041,103.616058],[32.76498,103.616013],[32.764648,103.615883],[32.76403,103.615891],[32.763828,103.615959],[32.763561,103.616081],[32.762581,103.616364],[32.76236,103.616409],[32.76173,103.616272],[32.76059,103.615753],[32.756771,103.614197],[32.755939,103.613922],[32.754959,103.613441],[32.754341,103.613152],[32.754169,103.613091],[32.753738,103.61306],[32.753349,103.613052],[32.75243,103.612778],[32.751999,103.612778],[32.751919,103.612762],[32.751499,103.612793],[32.750641,103.612663],[32.750401,103.61261],[32.749691,103.612511],[32.748161,103.612556],[32.747429,103.612289],[32.746552,103.611816],[32.745739,103.611656],[32.74556,103.611679],[32.745361,103.611656],[32.744301,103.611977],[32.74408,103.612099],[32.7439,103.612099],[32.743488,103.611992],[32.743408,103.611992],[32.743271,103.612053],[32.742981,103.61232],[32.742882,103.612396],[32.74255,103.61274],[32.742531,103.61274],[32.742401,103.612938],[32.74218,103.613113],[32.741951,103.613312],[32.74173,103.613472],[32.741379,103.613831],[32.741161,103.613983],[32.74057,103.614433],[32.740231,103.614548],[32.740028,103.614571],[32.739491,103.614548],[32.738289,103.614304],[32.737469,103.614227],[32.736851,103.614113],[32.736641,103.614113],[32.736401,103.614021],[32.736271,103.614014],[32.73555,103.613983],[32.734982,103.613892],[32.73439,103.614037],[32.73407,103.614166],[32.73391,103.614182],[32.73341,103.614281],[32.733051,103.614441],[32.73288,103.614662],[32.731121,103.615913],[32.733009,103.614578],[32.731171,103.616257],[32.728809,103.614731],[32.72821,103.614487],[32.72781,103.61451],[32.7276,103.614601],[32.727131,103.615219],[32.7267,103.615868],[32.726521,103.616058],[32.726341,103.616112],[32.725739,103.616089],[32.724991,103.615448],[32.723011,103.613426],[32.722759,103.613197],[32.722198,103.612961],[32.72105,103.612663],[32.720032,103.612297],[32.71991,103.612244],[32.719711,103.612053],[32.719181,103.611343],[32.718578,103.610367],[32.718201,103.60994],[32.717861,103.609596],[32.7174,103.609222],[32.716751,103.608887],[32.71611,103.608681],[32.714588,103.608047],[32.71349,103.607727],[32.712181,103.607422],[32.711411,103.607193],[32.71056,103.607246],[32.710251,103.607239],[32.709042,103.606903],[32.70776,103.606293],[32.707481,103.606216],[32.707062,103.606163],[32.706421,103.606087],[32.70546,103.605927],[32.704552,103.605583],[32.703732,103.605598],[32.70332,103.605667],[32.703072,103.605698],[32.702839,103.605667],[32.70211,103.605438],[32.701931,103.605408],[32.701771,103.605408],[32.701271,103.605263],[32.700932,103.605141],[32.700531,103.604874],[32.699711,103.604362],[32.699169,103.604118],[32.698891,103.604088],[32.698589,103.604118],[32.698139,103.604012],[32.6973,103.603699],[32.69627,103.6036],[32.695469,103.603432],[32.695122,103.60334],[32.694538,103.603218],[32.693939,103.603157],[32.69331,103.602837],[32.69286,103.602531],[32.692181,103.602127],[32.69138,103.602203],[32.690689,103.60231],[32.68866,103.601852],[32.687641,103.601738],[32.68716,103.601822],[32.686211,103.602089],[32.686081,103.602112],[32.684361,103.601738],[32.682961,103.601402],[32.682331,103.601341],[32.681709,103.601334],[32.680939,103.601372],[32.68008,103.601387],[32.679352,103.601357],[32.67865,103.60128],[32.67775,103.60128],[32.67635,103.601967],[32.67564,103.60199],[32.6745,103.601768],[32.673389,103.60173],[32.671902,103.601349],[32.671082,103.601578],[32.670502,103.601852],[32.669762,103.602242],[32.66906,103.602257],[32.667542,103.602127],[32.666489,103.602188],[32.665051,103.602013],[32.663712,103.601898],[32.661572,103.601799],[32.660351,103.601608],[32.659389,103.601212],[32.658588,103.60099],[32.657459,103.600868],[32.657021,103.600853],[32.655869,103.600868],[32.654869,103.600761],[32.652618,103.600151],[32.65189,103.599792],[32.651279,103.599457],[32.650551,103.598969],[32.650131,103.598763],[32.64856,103.59819],[32.64624,103.597343],[32.64613,103.597282],[32.646099,103.597252],[32.644691,103.596863],[32.64436,103.596947],[32.644329,103.59697],[32.64418,103.597214],[32.643421,103.598312],[32.643139,103.598549],[32.64296,103.598618],[32.64146,103.598503],[32.640888,103.598488],[32.638309,103.598106],[32.637669,103.597969],[32.637081,103.597794],[32.63623,103.597557],[32.635571,103.597229],[32.634159,103.59642],[32.633621,103.595932],[32.633099,103.595192],[32.63298,103.595062],[32.630989,103.593307],[32.630871,103.593224],[32.63018,103.593033],[32.62859,103.592728],[32.627861,103.592484],[32.627331,103.592087],[32.626701,103.591553],[32.626431,103.591339],[32.625969,103.591042],[32.625401,103.590927],[32.624741,103.590843],[32.623569,103.590637],[32.62336,103.590607],[32.620441,103.590843],[32.61964,103.590919],[32.618912,103.591141],[32.618301,103.591522],[32.617229,103.592491],[32.61618,103.593407],[32.613911,103.59549],[32.612141,103.597343],[32.60939,103.600151],[32.60881,103.600609],[32.60812,103.600983],[32.607559,103.601189],[32.60487,103.602074],[32.60397,103.601501],[32.599178,103.605614],[32.598019,103.605003],[32.597408,103.605362],[32.597099,103.605637],[32.596779,103.605873],[32.5961,103.606407],[32.59581,103.607697],[32.58968,103.610817],[32.588779,103.609818],[32.587219,103.609459],[32.58707,103.609444],[32.586552,103.60965],[32.58593,103.61013],[32.585361,103.610619],[32.585091,103.61097],[32.584961,103.611092],[32.58469,103.611214],[32.584171,103.611511],[32.58358,103.612038],[32.583382,103.613289],[32.573071,103.617027],[32.572479,103.61599],[32.572121,103.61599],[32.57011,103.616623],[32.56966,103.616882],[32.569519,103.617027],[32.569351,103.617126],[32.56926,103.617233],[32.568729,103.617599],[32.56815,103.617767],[32.567829,103.61776],[32.567451,103.617661],[32.566639,103.617523],[32.566261,103.61763],[32.565498,103.618553],[32.565231,103.618668],[32.561069,103.620064],[32.560051,103.620728],[32.560001,103.62178],[32.54961,103.625549],[32.546169,103.626801],[32.544022,103.627579],[32.5396,103.629181],[32.539082,103.628212],[32.530869,103.630623],[32.528111,103.630257],[32.527721,103.630333],[32.526001,103.631042],[32.52544,103.631203],[32.52467,103.631088],[32.523991,103.630859],[32.523708,103.630859],[32.522869,103.631157],[32.52224,103.631233],[32.521599,103.631126],[32.520771,103.631111],[32.520168,103.631279],[32.519741,103.6315],[32.519482,103.631683],[32.519119,103.632027],[32.518742,103.632233],[32.51857,103.632362],[32.518261,103.632889],[32.518059,103.633118],[32.517811,103.633324],[32.517342,103.633774],[32.516441,103.634323],[32.5159,103.634613],[32.515598,103.634857],[32.515469,103.635094],[32.515301,103.636017],[32.515099,103.636948],[32.514881,103.637337],[32.514751,103.63868],[32.510632,103.641068],[32.509769,103.639954],[32.509331,103.639832],[32.508751,103.63958],[32.508579,103.639526],[32.508289,103.639519],[32.507221,103.639709],[32.506599,103.639847],[32.505138,103.64035],[32.504871,103.640373],[32.504539,103.640282],[32.504421,103.640213],[32.504131,103.639923],[32.504051,103.639793],[32.502449,103.639282],[32.502102,103.639664],[32.501961,103.639877],[32.501869,103.640083],[32.50156,103.641472],[32.501389,103.642082],[32.500481,103.644814],[32.4991,103.645393],[32.498219,103.645126],[32.49791,103.645111],[32.49778,103.645119],[32.49712,103.645409],[32.496429,103.645859],[32.493111,103.648804],[32.492649,103.648972],[32.49192,103.649017],[32.49152,103.648979],[32.491261,103.648872],[32.491058,103.648666],[32.49078,103.648216],[32.490429,103.647552],[32.490261,103.647293],[32.48975,103.646797],[32.489422,103.646507],[32.488869,103.646133],[32.488708,103.646088],[32.488609,103.646103],[32.488419,103.646156],[32.488251,103.646294],[32.487968,103.646683],[32.487228,103.647362],[32.4869,103.647827],[32.486591,103.648651],[32.486309,103.649246],[32.485149,103.651466],[32.484699,103.652138],[32.484268,103.652397],[32.483719,103.652641],[32.482811,103.652809],[32.481812,103.653061],[32.481209,103.653191],[32.480999,103.653259],[32.48045,103.653709],[32.480061,103.654411],[32.479839,103.655159],[32.479599,103.656219],[32.479561,103.656441],[32.479481,103.657791],[32.47961,103.659042],[32.475731,103.661293],[32.474949,103.660133],[32.474339,103.660072],[32.47393,103.660149],[32.472481,103.660339],[32.47221,103.660408],[32.469349,103.661484],[32.468899,103.662041],[32.46833,103.662727],[32.467201,103.664032],[32.466019,103.66507],[32.464512,103.666359],[32.464039,103.666801],[32.463879,103.66703],[32.463669,103.667793],[32.463581,103.668404],[32.463928,103.669243],[32.455311,103.675484],[32.44862,103.680344],[32.443989,103.683693],[32.438961,103.687317],[32.43782,103.686546],[32.43652,103.686813],[32.436062,103.686958],[32.435749,103.687141],[32.43425,103.688454],[32.433849,103.688766],[32.43364,103.688881],[32.43288,103.689041],[32.432201,103.689087],[32.431709,103.689262],[32.43148,103.689537],[32.431221,103.689781],[32.430901,103.690392],[32.430779,103.690521],[32.430569,103.690689],[32.430302,103.691002],[32.43005,103.691017],[32.429619,103.691109],[32.429199,103.691223],[32.428699,103.691429],[32.4282,103.691597],[32.427891,103.691879],[32.427719,103.692093],[32.427269,103.692978],[32.42688,103.693932],[32.426559,103.694733],[32.426208,103.695396],[32.425591,103.695999],[32.42511,103.6968],[32.424549,103.697533],[32.423981,103.698036],[32.42355,103.69838],[32.42337,103.698738],[32.423248,103.699593],[32.42337,103.700943],[32.42247,103.701736],[32.42268,103.703369],[32.422531,103.703758],[32.421791,103.704437],[32.42112,103.705002],[32.420502,103.705597],[32.419819,103.70636],[32.41909,103.707314],[32.41893,103.707489],[32.4179,103.709068],[32.41293,103.713463],[32.411888,103.713661],[32.410511,103.71376],[32.409721,103.713173],[32.4021,103.720001],[32.401299,103.720428],[32.387909,103.726318],[32.387878,103.727661],[32.387779,103.727737],[32.387428,103.728081],[32.387211,103.728348],[32.386478,103.728844],[32.38607,103.728958],[32.385349,103.728912],[32.384682,103.728897],[32.383949,103.728867],[32.38303,103.727943],[32.37851,103.728539],[32.378052,103.729881],[32.377319,103.730423],[32.377121,103.730499],[32.37574,103.730873],[32.374809,103.731003],[32.374081,103.731056],[32.373859,103.73111],[32.373112,103.73143],[32.37228,103.731667],[32.371811,103.73175],[32.371632,103.731697],[32.37093,103.731216],[32.369781,103.730347],[32.369221,103.729057],[32.365871,103.728638],[32.36549,103.726868],[32.365139,103.726471],[32.364941,103.726196],[32.364769,103.726021],[32.3647,103.725861],[32.36459,103.725563],[32.364441,103.724899],[32.364208,103.724403],[32.363659,103.723984],[32.36335,103.723862],[32.36224,103.723877],[32.361752,103.723869],[32.361462,103.723907],[32.3605,103.724121],[32.360321,103.724121],[32.35928,103.723869],[32.358891,103.724007],[32.358719,103.724167],[32.358139,103.725037],[32.35788,103.725449],[32.357471,103.726189],[32.35717,103.72718],[32.357121,103.727638],[32.357059,103.727814],[32.356861,103.727661],[32.35606,103.728683],[32.356659,103.730026],[32.356579,103.730827],[32.356449,103.731697],[32.356121,103.733276],[32.355782,103.735153],[32.355492,103.735832],[32.35524,103.736168],[32.35519,103.736282],[32.35503,103.736519],[32.35458,103.736748],[32.353859,103.736992],[32.3536,103.73703],[32.35339,103.73703],[32.352219,103.736847],[32.350929,103.736702],[32.350719,103.736748],[32.350319,103.736893],[32.350101,103.736282],[32.34993,103.737289],[32.34943,103.737503],[32.348598,103.737381],[32.348,103.737122],[32.347729,103.736923],[32.347641,103.735962],[32.34623,103.735779],[32.345821,103.734337],[32.34568,103.7342],[32.345551,103.734009],[32.345379,103.733856],[32.340771,103.727203],[32.34053,103.726822],[32.340481,103.726677],[32.340439,103.726479],[32.34045,103.726242],[32.3405,103.726082],[32.34066,103.72567],[32.340672,103.725456],[32.340439,103.724876],[32.340099,103.724167],[32.340019,103.723389],[32.340031,103.72316],[32.340111,103.7229],[32.340462,103.722481],[32.340611,103.722221],[32.340599,103.721718],[32.340519,103.721527],[32.340092,103.720932],[32.339809,103.720772],[32.33762,103.72052],[32.33683,103.72049],[32.336369,103.720421],[32.335609,103.720207],[32.33519,103.720032],[32.334728,103.719711],[32.334259,103.71933],[32.333832,103.719162],[32.333599,103.719109],[32.332722,103.718712],[32.33234,103.718613],[32.331558,103.71875],[32.330231,103.719467],[32.329472,103.719803],[32.329041,103.719841],[32.328621,103.719849],[32.32827,103.71981],[32.327869,103.719887],[32.327389,103.719841],[32.327122,103.719658],[32.327019,103.719437],[32.32682,103.718987],[32.32658,103.718788],[32.32629,103.718719],[32.326061,103.718613],[32.325771,103.718536],[32.325531,103.71859],[32.325089,103.718727],[32.324959,103.718803],[32.32428,103.719032],[32.32365,103.719139],[32.323429,103.719193],[32.3232,103.719276],[32.323051,103.71936],[32.322319,103.719917],[32.321701,103.720268],[32.320808,103.72068],[32.320461,103.720589],[32.32016,103.720291],[32.319981,103.7202],[32.31926,103.720177],[32.319061,103.7202],[32.318741,103.720169],[32.318642,103.720329],[32.318451,103.720284],[32.31786,103.720062],[32.317741,103.720062],[32.317532,103.720154],[32.317039,103.720467],[32.316441,103.721413],[32.316071,103.721367],[32.315369,103.72123],[32.314651,103.720978],[32.313961,103.720818],[32.313251,103.720802],[32.312721,103.720818],[32.312141,103.720993],[32.31142,103.721336],[32.31131,103.721367],[32.310471,103.721367],[32.310162,103.721313],[32.30938,103.720802],[32.30904,103.72068],[32.308788,103.720657],[32.30843,103.720863],[32.308201,103.7211],[32.307041,103.721878],[32.30603,103.722488],[32.30579,103.722588],[32.305161,103.723068],[32.304489,103.723373],[32.30444,103.723373],[32.303829,103.723457],[32.303188,103.72361],[32.302551,103.723793],[32.301521,103.723824],[32.300659,103.723892],[32.300339,103.723938],[32.29982,103.724121],[32.299648,103.724281],[32.299541,103.724426],[32.29929,103.725037],[32.299129,103.725609],[32.299,103.726334],[32.29895,103.726807],[32.29908,103.72802],[32.28278,103.735847],[32.282139,103.734863],[32.281811,103.734901],[32.281319,103.734909],[32.280991,103.734932],[32.280048,103.735046],[32.279228,103.734962],[32.27861,103.735107],[32.278561,103.73513],[32.2784,103.735298],[32.277771,103.736427],[32.277031,103.737267],[32.276718,103.737709],[32.27663,103.7388],[32.27467,103.739754],[32.274441,103.741219],[32.273811,103.741577],[32.27319,103.741737],[32.272499,103.741997],[32.271721,103.742462],[32.27121,103.742844],[32.270771,103.743271],[32.27013,103.743736],[32.269711,103.743942],[32.26902,103.744179],[32.26878,103.744217],[32.268242,103.7444],[32.267399,103.744713],[32.266949,103.745033],[32.266449,103.745407],[32.266289,103.745499],[32.26561,103.745697],[32.264511,103.745117],[32.26244,103.74675],[32.26263,103.748032],[32.262428,103.748466],[32.26202,103.748802],[32.261749,103.748993],[32.26149,103.749092],[32.261181,103.749313],[32.260849,103.749634],[32.260441,103.749863],[32.259892,103.749931],[32.259129,103.749352],[32.255508,103.75219],[32.255661,103.75383],[32.25523,103.755402],[32.2547,103.756187],[32.254581,103.756477],[32.25425,103.756783],[32.25404,103.757088],[32.253658,103.757812],[32.253181,103.758797],[32.252628,103.759499],[32.252041,103.759956],[32.251362,103.76017],[32.250881,103.760178],[32.250431,103.760246],[32.250271,103.760193],[32.250019,103.760139],[32.24942,103.760101],[32.24892,103.760193],[32.24855,103.760353],[32.248371,103.760628],[32.24818,103.760788],[32.247921,103.76078],[32.247719,103.760857],[32.247601,103.760986],[32.24733,103.761414],[32.24699,103.761803],[32.24659,103.762108],[32.246311,103.762253],[32.24559,103.762543],[32.24535,103.762657],[32.24522,103.762688],[32.244541,103.762772],[32.24379,103.762787],[32.243359,103.762917],[32.243111,103.763077],[32.242298,103.764],[32.24152,103.764717],[32.240849,103.765167],[32.2402,103.76545],[32.239552,103.765663],[32.238811,103.765701],[32.23835,103.765701],[32.23772,103.765602],[32.237068,103.765427],[32.236561,103.76516],[32.236031,103.764816],[32.23555,103.764458],[32.234901,103.763496],[32.233509,103.764069],[32.23288,103.764282],[32.224331,103.765762],[32.220219,103.766548],[32.219711,103.765091],[32.219559,103.764893],[32.219341,103.764732],[32.219231,103.764687],[32.21899,103.764641],[32.218861,103.764603],[32.217991,103.764503],[32.216721,103.764427],[32.21656,103.764503],[32.21627,103.76458],[32.215931,103.764526],[32.215691,103.764557],[32.215611,103.764603],[32.215092,103.7649],[32.21487,103.765068],[32.214329,103.765556],[32.213848,103.765984],[32.21368,103.766083],[32.213299,103.766129],[32.21262,103.765923],[32.212448,103.765938],[32.212139,103.765953],[32.21146,103.766144],[32.211151,103.766167],[32.210129,103.766037],[32.20974,103.765907],[32.208851,103.765282],[32.20853,103.765259],[32.20784,103.765244],[32.207291,103.765198],[32.206909,103.765213],[32.205502,103.765457],[32.20406,103.765137],[32.20266,103.764061],[32.202389,103.763924],[32.202091,103.763809],[32.201061,103.763603],[32.200821,103.763321],[32.200741,103.762932],[32.200588,103.762619],[32.200359,103.762421],[32.200008,103.762177],[32.199879,103.762032],[32.199371,103.762123],[32.19912,103.762032],[32.197449,103.761223],[32.19677,103.760948],[32.19651,103.760857],[32.19553,103.760399],[32.195431,103.760384],[32.194851,103.760391],[32.19352,103.760483],[32.193169,103.76049],[32.192711,103.760437],[32.19249,103.760361],[32.192451,103.760384],[32.19223,103.760292],[32.191719,103.760223],[32.19112,103.760071],[32.190578,103.759804],[32.190128,103.759468],[32.189541,103.758987],[32.189251,103.758774],[32.189072,103.758713],[32.1884,103.758659],[32.18734,103.75856],[32.186588,103.758537],[32.18642,103.758507],[32.185841,103.758492],[32.185539,103.758423],[32.18528,103.758179],[32.185169,103.757729],[32.184952,103.757149],[32.184818,103.756958],[32.184601,103.756721],[32.183971,103.756264],[32.182529,103.755493],[32.18235,103.755463],[32.180672,103.755501],[32.18037,103.755623],[32.180271,103.755722],[32.179218,103.756973],[32.17902,103.757111],[32.178589,103.757187],[32.178162,103.757187],[32.17794,103.757133],[32.1782,103.757179],[32.177479,103.756889],[32.176491,103.756157],[32.175869,103.755608],[32.17561,103.755188],[32.175282,103.754471],[32.17485,103.753616],[32.174622,103.752991],[32.174191,103.751953],[32.174129,103.751694],[32.173981,103.75135],[32.173321,103.750267],[32.172981,103.749519],[32.172749,103.748756],[32.17263,103.748497],[32.17244,103.748177],[32.171909,103.747513],[32.171791,103.747299],[32.171471,103.746872],[32.171249,103.746223],[32.171101,103.745667],[32.171001,103.745117],[32.171021,103.744598],[32.171059,103.744263],[32.17112,103.743896],[32.171131,103.743523],[32.171082,103.743179],[32.170929,103.742683],[32.1707,103.742149],[32.17046,103.741623],[32.170261,103.741432],[32.170029,103.74147],[32.169788,103.741653],[32.169571,103.741737],[32.16925,103.741951],[32.168861,103.742126],[32.168369,103.742264],[32.167759,103.742081],[32.167648,103.741997],[32.16708,103.741257],[32.166809,103.741043],[32.16544,103.740593],[32.164761,103.740387],[32.164242,103.740181],[32.163879,103.739899],[32.163651,103.739647],[32.163429,103.739227],[32.16325,103.738724],[32.163109,103.738358],[32.162701,103.737907],[32.162079,103.737297],[32.16188,103.737061],[32.161549,103.736763],[32.161449,103.736633],[32.161121,103.73629],[32.16048,103.735924],[32.159801,103.735672],[32.158619,103.735321],[32.158321,103.735168],[32.157829,103.734978],[32.157619,103.734871],[32.157261,103.734863],[32.15641,103.734749],[32.156132,103.734734],[32.155869,103.734741],[32.15556,103.734787],[32.15498,103.734978],[32.154881,103.734993],[32.15456,103.734863],[32.154018,103.734497],[32.153561,103.734306],[32.153309,103.734123],[32.153069,103.733887],[32.15284,103.73362],[32.152649,103.733353],[32.152611,103.7332],[32.152512,103.733101],[32.152302,103.732964],[32.152199,103.732933],[32.151611,103.732811],[32.150921,103.732643],[32.150028,103.73246],[32.149891,103.732407],[32.14967,103.732384],[32.149471,103.732323],[32.149132,103.732269],[32.148769,103.732162],[32.148399,103.732109],[32.148102,103.732147],[32.147652,103.732246],[32.147018,103.732269],[32.146889,103.732231],[32.146309,103.731903],[32.146118,103.731773],[32.145882,103.731682],[32.145241,103.731667],[32.14481,103.731697],[32.144581,103.731773],[32.143681,103.732109],[32.14352,103.732193],[32.14336,103.732239],[32.143082,103.732399],[32.142429,103.732674],[32.142059,103.732903],[32.14172,103.7332],[32.141521,103.733467],[32.14122,103.733803],[32.140888,103.733917],[32.14045,103.733757],[32.140251,103.733597],[32.139679,103.733017],[32.13945,103.732826],[32.138981,103.732613],[32.138741,103.732536],[32.138519,103.732513],[32.138199,103.732567],[32.137489,103.732903],[32.13707,103.733231],[32.136742,103.733437],[32.136459,103.733528],[32.136021,103.73365],[32.135731,103.733757],[32.13538,103.733849],[32.135151,103.733849],[32.134472,103.733772],[32.134109,103.733658],[32.1339,103.733612],[32.133678,103.733719],[32.13327,103.734016],[32.132912,103.734138],[32.132721,103.734177],[32.132309,103.734451],[32.13208,103.734528],[32.131302,103.734627],[32.130322,103.734642],[32.129959,103.734703],[32.129459,103.734818],[32.128342,103.734962],[32.12801,103.734932],[32.12796,103.734947],[32.127811,103.734932],[32.127411,103.734818],[32.127129,103.734779],[32.126709,103.734642],[32.126419,103.734444],[32.12624,103.734329],[32.12587,103.733849],[32.125641,103.733711],[32.125179,103.733582],[32.124821,103.733543],[32.123871,103.733559],[32.12331,103.733521],[32.122761,103.733383],[32.12159,103.732971],[32.12088,103.732597],[32.120209,103.732147],[32.119419,103.731651],[32.118851,103.731148],[32.118061,103.73037],[32.11755,103.729736],[32.117001,103.728928],[32.11657,103.728508],[32.116482,103.728447],[32.11618,103.728317],[32.115959,103.728271],[32.115841,103.728233],[32.11515,103.728073],[32.114681,103.727882],[32.114521,103.727791],[32.11412,103.727226],[32.11396,103.727127],[32.1138,103.726967],[32.113609,103.726753],[32.11338,103.726562],[32.112801,103.726143],[32.11261,103.726112],[32.112209,103.726151],[32.112041,103.726128],[32.111629,103.725693],[32.111462,103.725578],[32.111382,103.725487],[32.11079,103.725159],[32.110691,103.725189],[32.110519,103.725319],[32.110249,103.725563],[32.11005,103.725731],[32.109749,103.725662],[32.109631,103.725563],[32.109341,103.725449],[32.108501,103.725731],[32.108212,103.725983],[32.107979,103.726227],[32.107899,103.726288],[32.107689,103.726372],[32.107262,103.726448],[32.107059,103.726433],[32.106621,103.726227],[32.1064,103.725937],[32.106468,103.725822],[32.10664,103.725662],[32.106419,103.725403],[32.106838,103.724632],[32.106541,103.724342],[32.106781,103.723579],[32.10656,103.723412],[32.106461,103.723213],[32.105831,103.723534],[32.10561,103.723511],[32.105389,103.723541],[32.103531,103.725349],[32.103321,103.725487],[32.103142,103.725563],[32.102829,103.725723],[32.102638,103.725754],[32.102261,103.725891],[32.102081,103.725922],[32.1017,103.725937],[32.100639,103.725937],[32.100368,103.725883],[32.100151,103.725639],[32.099911,103.725288],[32.099491,103.724838],[32.0994,103.724709],[32.09919,103.724068],[32.09903,103.723351],[32.09874,103.722366],[32.09869,103.722183],[32.098431,103.721733],[32.098091,103.721329],[32.098011,103.721268],[32.097778,103.72123],[32.09734,103.721336],[32.096729,103.721321],[32.096039,103.721069],[32.095852,103.72084],[32.095718,103.720329],[32.095692,103.720032],[32.095558,103.719658],[32.095242,103.71949],[32.094551,103.719528],[32.093971,103.719597],[32.093029,103.719841],[32.092461,103.720016],[32.092072,103.719994],[32.09169,103.720093],[32.09132,103.720222],[32.090988,103.720383],[32.090691,103.720467],[32.09034,103.720451],[32.090019,103.72039],[32.08976,103.720177],[32.089458,103.719994],[32.089298,103.719978],[32.08894,103.719887],[32.088661,103.71965],[32.088459,103.719582],[32.08799,103.719368],[32.0877,103.71917],[32.087158,103.718628],[32.086891,103.718407],[32.08662,103.718384],[32.08622,103.718437],[32.085991,103.718513],[32.085491,103.718719],[32.085121,103.718826],[32.08485,103.718964],[32.08456,103.719177],[32.084278,103.719513],[32.083988,103.719597],[32.083691,103.719414],[32.08334,103.719078],[32.083149,103.71891],[32.082939,103.718788],[32.082661,103.718811],[32.082359,103.718948],[32.081539,103.719131],[32.081551,103.719147],[32.08149,103.719147],[32.081402,103.719177],[32.081322,103.719177],[32.081108,103.719292],[32.0807,103.719437],[32.080441,103.719467],[32.079571,103.719292],[32.079418,103.7192],[32.079071,103.718903],[32.078289,103.718468],[32.077709,103.71804],[32.07732,103.717697],[32.077068,103.717644],[32.076691,103.717667],[32.07597,103.71785],[32.075291,103.717949],[32.074791,103.717903],[32.07415,103.717781],[32.073978,103.71769],[32.073811,103.717697],[32.073521,103.71759],[32.073269,103.71756],[32.073101,103.717461],[32.072868,103.717392],[32.072659,103.7173],[32.072201,103.717331],[32.071869,103.717308],[32.071651,103.717239],[32.071442,103.717163],[32.071369,103.717056],[32.071178,103.716927],[32.070919,103.716942],[32.070351,103.717209],[32.069969,103.717339],[32.069939,103.717133],[32.069771,103.716927],[32.071201,103.716042],[32.07135,103.715736],[32.07127,103.715477],[32.070969,103.715363],[32.070621,103.715279],[32.070332,103.715103],[32.070061,103.714867],[32.06992,103.714828],[32.06934,103.714539],[32.06897,103.714447],[32.068741,103.714417],[32.068489,103.714371],[32.068489,103.714256],[32.068359,103.714127],[32.068241,103.71376],[32.068069,103.71347],[32.067909,103.713387],[32.067501,103.713242],[32.06707,103.713173],[32.066971,103.713188],[32.06673,103.713463],[32.066639,103.713783],[32.06649,103.71405],[32.065781,103.714432],[32.065659,103.714233],[32.065651,103.713913],[32.06575,103.71283],[32.065701,103.712608],[32.065639,103.712532],[32.065121,103.71212],[32.065071,103.711838],[32.065239,103.711227],[32.065262,103.710899],[32.06509,103.710602],[32.064751,103.710327],[32.064442,103.710121],[32.064159,103.710213],[32.063801,103.71051],[32.063591,103.710823],[32.06345,103.711143],[32.063278,103.711411],[32.063019,103.711502],[32.06271,103.711517],[32.062469,103.71138],[32.062168,103.711082],[32.06192,103.710777],[32.06189,103.710609],[32.061798,103.710243],[32.061611,103.709633],[32.06134,103.709129],[32.0611,103.708908],[32.06097,103.70874],[32.06094,103.708641],[32.060879,103.708618],[32.060692,103.708397],[32.060551,103.708183],[32.06041,103.707863],[32.06041,103.707817],[32.060459,103.707581],[32.060478,103.707321],[32.06041,103.707062],[32.060181,103.706543],[32.06015,103.70636],[32.060181,103.705681],[32.05999,103.705177],[32.059761,103.704674],[32.05954,103.704399],[32.059391,103.704086],[32.05901,103.703987],[32.058632,103.703957],[32.05806,103.703819],[32.057991,103.703613],[32.05806,103.703194],[32.057499,103.703552],[32.057331,103.703819],[32.05698,103.704231],[32.05648,103.704903],[32.05624,103.705261],[32.056068,103.705452],[32.055962,103.705627],[32.055691,103.705872],[32.0555,103.705994],[32.05529,103.70607],[32.055061,103.7062],[32.054859,103.706284],[32.0546,103.706306],[32.054409,103.705971],[32.0541,103.705528],[32.05405,103.705307],[32.053959,103.705109],[32.053959,103.704964],[32.054081,103.704842],[32.054539,103.704552],[32.054741,103.704468],[32.054859,103.704231],[32.05481,103.703911],[32.054722,103.703659],[32.0546,103.703461],[32.054501,103.703247],[32.054451,103.703056],[32.054619,103.702797],[32.05455,103.702911],[32.056252,103.701553],[32.056499,103.701393],[32.056709,103.70118],[32.056801,103.701027],[32.057209,103.700912],[32.057961,103.700989],[32.058311,103.700768],[32.058529,103.700684],[32.058811,103.700706],[32.059181,103.700844],[32.0592,103.700867],[32.059509,103.701019],[32.059669,103.701073],[32.060009,103.700996],[32.060581,103.700813],[32.06073,103.700661],[32.06078,103.700417],[32.06076,103.700233],[32.06057,103.699951],[32.060429,103.699837],[32.060169,103.699677],[32.058109,103.698669],[32.057529,103.698318],[32.057381,103.698257],[32.057308,103.69825],[32.057011,103.698143],[32.056919,103.69809],[32.05685,103.698013],[32.056671,103.697723],[32.056561,103.697388],[32.056461,103.696854],[32.0564,103.696701],[32.055801,103.695648],[32.055531,103.695229],[32.055012,103.694649],[32.054909,103.69442],[32.05484,103.693748],[32.054829,103.693298],[32.054821,103.693039],[32.05484,103.69265],[32.054699,103.692177],[32.05471,103.692101],[32.054562,103.691803],[32.053829,103.690521],[32.053612,103.690224],[32.053162,103.689713],[32.052589,103.688713],[32.052509,103.688606],[32.05228,103.688454],[32.051979,103.688316],[32.051769,103.688171],[32.05154,103.687897],[32.05138,103.687752],[32.051041,103.687187],[32.05088,103.687027],[32.050549,103.687027],[32.04998,103.687103],[32.049671,103.686989],[32.04921,103.686707],[32.04884,103.68615],[32.048988,103.685677],[32.048859,103.684868],[32.048698,103.684334],[32.04834,103.6828],[32.048092,103.681953],[32.048038,103.681664],[32.048149,103.68132],[32.04829,103.681358],[32.048149,103.681213],[32.047981,103.680946],[32.047791,103.680733],[32.04731,103.680023],[32.046822,103.679764],[32.046478,103.679703],[32.046249,103.679611],[32.046211,103.679604],[32.0462,103.679619],[32.045959,103.679878],[32.045879,103.680122],[32.045681,103.680962],[32.045631,103.681129],[32.045521,103.681473],[32.045311,103.682533],[32.045219,103.682877],[32.04509,103.683601],[32.044991,103.683937],[32.044788,103.684158],[32.044609,103.684196],[32.043598,103.68428],[32.042339,103.684319],[32.04211,103.684349],[32.04179,103.684509],[32.041679,103.684669],[32.0415,103.684883],[32.04113,103.684967],[32.041069,103.684937],[32.040691,103.684624],[32.04034,103.68454],[32.03973,103.684624],[32.039589,103.684593],[32.039341,103.684464],[32.038689,103.683983],[32.038311,103.68383],[32.0382,103.683769],[32.038101,103.683678],[32.037682,103.683083],[32.037521,103.682961],[32.037281,103.682922],[32.037289,103.682953],[32.037029,103.683006],[32.03677,103.68309],[32.036461,103.683273],[32.036072,103.683601],[32.036011,103.683693],[32.035789,103.684303],[32.035461,103.684898],[32.035381,103.686089],[32.033588,103.686653],[32.03339,103.687881],[32.033291,103.688087],[32.033081,103.688461],[32.032982,103.68856],[32.032951,103.688622],[32.03281,103.688744],[32.032391,103.689171],[32.032379,103.689217],[32.03233,103.689247],[32.031929,103.689728],[32.031879,103.689758],[32.0317,103.689934],[32.031361,103.69017],[32.031109,103.690269],[32.030891,103.690323],[32.030621,103.690323],[32.030411,103.690247],[32.029942,103.690117],[32.029812,103.690063],[32.029789,103.690041],[32.029701,103.69001],[32.02953,103.689987],[32.02906,103.689789],[32.02874,103.689713],[32.028679,103.689682],[32.02832,103.689552],[32.027969,103.689598],[32.02779,103.689713],[32.02774,103.689789],[32.027599,103.689911],[32.02747,103.690048],[32.02689,103.690582],[32.026562,103.690826],[32.025902,103.691238],[32.025791,103.691353],[32.02533,103.691628],[32.025211,103.691757],[32.025082,103.691963],[32.02504,103.692108],[32.025021,103.692329],[32.025021,103.692688],[32.02504,103.69278],[32.025021,103.693359],[32.024921,103.693649],[32.024811,103.69381],[32.024632,103.693947],[32.02438,103.694],[32.024231,103.693916],[32.023949,103.693527],[32.02346,103.693108],[32.023392,103.693024],[32.023048,103.692467],[32.0228,103.692017],[32.022049,103.690773],[32.02161,103.68985],[32.02132,103.68856],[32.021198,103.68856],[32.018799,103.687172],[32.018398,103.687973],[32.017841,103.688713],[32.017681,103.688873],[32.01749,103.688988],[32.017269,103.689072],[32.016529,103.689171],[32.01627,103.689232],[32.016109,103.68924],[32.015911,103.689194],[32.015789,103.689087],[32.015659,103.688873],[32.015282,103.688042],[32.01524,103.687988],[32.015141,103.687767],[32.01498,103.6875],[32.014832,103.687309],[32.014671,103.687241],[32.014599,103.687248],[32.014469,103.687302],[32.014351,103.687393],[32.01403,103.687553],[32.013962,103.68763],[32.013512,103.687889],[32.013248,103.687958],[32.013031,103.687897],[32.012581,103.687714],[32.012291,103.687553],[32.01202,103.687332],[32.01173,103.686836],[32.01165,103.686684],[32.011608,103.686623],[32.01152,103.686417],[32.0112,103.685883],[32.01107,103.685593],[32.010941,103.68515],[32.010891,103.684738],[32.010761,103.683968],[32.010681,103.683746],[32.01062,103.683708],[32.010551,103.683678],[32.01012,103.683777],[32.00996,103.683853],[32.009838,103.683937],[32.00935,103.684143],[32.0093,103.684174],[32.009121,103.684242],[32.00806,103.684708],[32.00771,103.684776],[32.006889,103.684822],[32.005989,103.684822],[32.005859,103.684799],[32.00555,103.684593],[32.005421,103.684341],[32.005329,103.684013],[32.00515,103.683601],[32.005001,103.683434],[32.004749,103.683296],[32.004169,103.683273],[32.003941,103.68338],[32.00388,103.68364],[32.00391,103.684212],[32.004059,103.68502],[32.004089,103.685089],[32.004139,103.685707],[32.004219,103.686089],[32.00441,103.686531],[32.004959,103.687462],[32.005562,103.688522],[32.005859,103.689491],[32.005871,103.69001],[32.00568,103.690758],[32.00552,103.691643],[32.004871,103.693199],[32.004799,103.693359],[32.0047,103.693489],[32.00449,103.693489],[32.004379,103.69326],[32.00444,103.692886],[32.004509,103.692108],[32.00449,103.691849],[32.00444,103.691673],[32.004009,103.690979],[32.00378,103.690742],[32.003441,103.690742],[32.003101,103.690804],[32.00272,103.690826],[32.002499,103.690697],[32.002419,103.690392],[32.0023,103.689796],[32.002209,103.689667],[32.00145,103.688766],[32.00124,103.688393],[32.00082,103.687828],[32.000992,103.687607],[32.000961,103.687553],[32.00106,103.687531],[32.001209,103.687347],[32.00016,103.685837],[31.99964,103.685143],[31.99942,103.684769],[31.999229,103.684349],[31.99905,103.683792],[31.998989,103.683434],[31.998949,103.683281],[31.998859,103.683098],[31.998819,103.68306],[31.998409,103.682907],[31.998079,103.682671],[31.997959,103.682503],[31.997829,103.682228],[31.997499,103.682091],[31.997,103.682266],[31.996469,103.682426],[31.99605,103.682426],[31.99486,103.682411],[31.994129,103.681923],[31.99395,103.681549],[31.99382,103.680733],[31.99361,103.680489],[31.993389,103.680641],[31.992479,103.681931],[31.992331,103.682098],[31.99192,103.682259],[31.991211,103.682198],[31.990641,103.682121],[31.989719,103.681847],[31.98885,103.681557],[31.98814,103.681267],[31.98777,103.681091],[31.98768,103.680992],[31.987761,103.680817],[31.987921,103.680878],[31.988609,103.681297],[31.990959,103.681488],[31.991449,103.681488],[31.991989,103.68116],[31.9921,103.680992],[31.99231,103.680511],[31.99242,103.680313],[31.99271,103.680031],[31.992861,103.679916],[31.99299,103.679764],[31.993219,103.67907],[31.9935,103.678726],[31.993641,103.67865],[31.993731,103.678436],[31.99354,103.678329],[31.993441,103.678413],[31.99317,103.678703],[31.99308,103.678848],[31.992929,103.67939],[31.992689,103.67968],[31.992359,103.679787],[31.99194,103.680229],[31.99155,103.680397],[31.99077,103.680252],[31.990499,103.680153],[31.99,103.679901],[31.989771,103.679802],[31.98945,103.679733],[31.98896,103.679604],[31.988859,103.679558],[31.98881,103.679497],[31.988251,103.679222],[31.987749,103.679077],[31.98703,103.679077],[31.98654,103.679153],[31.98535,103.679413],[31.98514,103.67942],[31.984949,103.67939],[31.98477,103.679337],[31.98423,103.678902],[31.98399,103.678673],[31.98382,103.678413],[31.98365,103.677872],[31.983561,103.67691],[31.983561,103.676697],[31.983521,103.676399],[31.983509,103.676422],[31.983419,103.6763],[31.98321,103.676147],[31.983049,103.676079],[31.982861,103.676041],[31.9825,103.676003],[31.982321,103.676003],[31.98192,103.675957],[31.98172,103.675972],[31.981541,103.676003],[31.981211,103.676132],[31.98065,103.67646],[31.98004,103.676773],[31.979469,103.677017],[31.978901,103.677094],[31.97864,103.677101],[31.978121,103.677193],[31.97716,103.677322],[31.97678,103.677353],[31.97662,103.677361],[31.976391,103.677406],[31.975889,103.677467],[31.97518,103.677452],[31.97434,103.677452],[31.972851,103.677422],[31.972481,103.677498],[31.972269,103.677597],[31.972019,103.677711],[31.97098,103.678223],[31.970699,103.678268],[31.97035,103.67823],[31.970209,103.678169],[31.9692,103.677452],[31.969009,103.677406],[31.968861,103.677422],[31.968651,103.677467],[31.968149,103.677643],[31.96809,103.677628],[31.96797,103.677681],[31.96767,103.677963],[31.96734,103.678337],[31.96706,103.678772],[31.96677,103.679108],[31.96656,103.679268],[31.96627,103.679611],[31.96604,103.680023],[31.965691,103.680557],[31.9653,103.680649],[31.964319,103.680389],[31.963421,103.680183],[31.96328,103.679947],[31.96348,103.679878],[31.963539,103.679893],[31.96409,103.680153],[31.96434,103.680191],[31.96452,103.680191],[31.964701,103.680153],[31.96505,103.679962],[31.96534,103.679703],[31.96578,103.679398],[31.966209,103.678726],[31.966619,103.67791],[31.966999,103.677277],[31.96771,103.676239],[31.967979,103.675949],[31.96834,103.675743],[31.96888,103.675522],[31.96911,103.675323],[31.969009,103.675201],[31.96888,103.675278],[31.968691,103.675461],[31.968349,103.675697],[31.96773,103.67601],[31.96744,103.676178],[31.967239,103.676422],[31.96682,103.67717],[31.96637,103.677567],[31.965931,103.677887],[31.965731,103.677994],[31.96524,103.678032],[31.964569,103.677971],[31.96418,103.678108],[31.96356,103.678459],[31.963341,103.678352],[31.963449,103.678131],[31.964211,103.677711],[31.96497,103.677437],[31.96604,103.677391],[31.966471,103.677063],[31.96681,103.676117],[31.967119,103.675697],[31.96789,103.675049],[31.968349,103.674713],[31.968861,103.674477],[31.968941,103.674232],[31.968691,103.674118],[31.968611,103.674133],[31.968361,103.674217],[31.96801,103.674431],[31.96714,103.675072],[31.96664,103.67527],[31.966471,103.675247],[31.966181,103.675323],[31.96574,103.675484],[31.965521,103.675537],[31.96493,103.675636],[31.963949,103.675972],[31.96307,103.676208],[31.96254,103.67617],[31.96192,103.675827],[31.960951,103.675194],[31.960871,103.675133],[31.960739,103.674927],[31.96084,103.67482],[31.961069,103.674911],[31.96154,103.675346],[31.962179,103.675468],[31.962669,103.675468],[31.962879,103.67543],[31.96319,103.675293],[31.96376,103.674843],[31.96398,103.674622],[31.964001,103.674301],[31.963751,103.674339],[31.963039,103.674927],[31.962721,103.675018],[31.962061,103.674911],[31.96166,103.674683],[31.96077,103.673447],[31.96077,103.673424],[31.95982,103.672707],[31.95936,103.672493],[31.95837,103.672241],[31.95751,103.672234],[31.9566,103.672363],[31.95599,103.67218],[31.95553,103.671944],[31.95491,103.671677],[31.953979,103.671417],[31.953461,103.671089],[31.95289,103.67086],[31.95249,103.670731],[31.95084,103.670067],[31.950411,103.670029],[31.950081,103.670082],[31.94912,103.670319],[31.94894,103.670326],[31.948771,103.670303],[31.948521,103.670303],[31.94829,103.670341],[31.948021,103.670441],[31.94791,103.670509],[31.947599,103.670509],[31.94602,103.67038],[31.945841,103.670433],[31.94503,103.670418],[31.94383,103.670372],[31.943661,103.670387],[31.943171,103.670403],[31.942419,103.670448],[31.941509,103.67067],[31.941351,103.670692],[31.941111,103.670776],[31.940821,103.670929],[31.94002,103.671257],[31.93902,103.671547],[31.93849,103.671623],[31.93815,103.671692],[31.937639,103.671738],[31.937469,103.671783],[31.93697,103.671852],[31.93646,103.672043],[31.93585,103.672333],[31.934759,103.672752],[31.93413,103.672867],[31.933599,103.673019],[31.93354,103.673058],[31.932859,103.673279],[31.93256,103.67334],[31.931919,103.673264],[31.931589,103.673149],[31.931379,103.673042],[31.93117,103.672859],[31.930771,103.67276],[31.930531,103.67276],[31.93025,103.672691],[31.929951,103.672691],[31.92959,103.672623],[31.929331,103.672401],[31.929041,103.672379],[31.92865,103.672188],[31.92831,103.672058],[31.92807,103.672012],[31.927919,103.671783],[31.92782,103.671547],[31.92782,103.671547],[31.927719,103.671501],[31.92771,103.671417],[31.92749,103.671432],[31.926901,103.671623],[31.92679,103.671707],[31.926661,103.671753],[31.926371,103.671883],[31.92581,103.672043],[31.925119,103.672096],[31.9249,103.67215],[31.92481,103.672127],[31.92453,103.671997],[31.92415,103.671989],[31.923849,103.672096],[31.92359,103.67215],[31.922529,103.672409],[31.922079,103.672539],[31.921459,103.672783],[31.92091,103.673141],[31.920349,103.673569],[31.919979,103.67379],[31.919319,103.674133],[31.918659,103.674423],[31.91729,103.675049],[31.91678,103.675262],[31.91613,103.675682],[31.91539,103.676239],[31.915359,103.676582],[31.914511,103.677742],[31.914009,103.678291],[31.913601,103.678833],[31.91308,103.678993],[31.912729,103.679131],[31.9121,103.679466],[31.911579,103.679718],[31.91099,103.679832],[31.910271,103.679893],[31.90967,103.679993],[31.9091,103.68026],[31.907619,103.681168],[31.907049,103.681503],[31.906269,103.681839],[31.90589,103.681938],[31.904499,103.682213],[31.904249,103.682297],[31.90403,103.682281],[31.904119,103.682426],[31.903959,103.68248],[31.903431,103.682518],[31.90321,103.682602],[31.901991,103.683411],[31.90144,103.683746],[31.90024,103.684357],[31.899611,103.684769],[31.898359,103.685959],[31.897631,103.686348],[31.89703,103.686691],[31.896799,103.68679],[31.896139,103.686897],[31.89554,103.68692],[31.89493,103.686859],[31.894199,103.68663],[31.89382,103.686569],[31.893709,103.686577],[31.89315,103.686852],[31.89258,103.687492],[31.892191,103.68811],[31.891279,103.689301],[31.890841,103.689812],[31.89011,103.690804],[31.889391,103.691223],[31.889191,103.691292],[31.888929,103.691277],[31.888611,103.691231],[31.88792,103.690979],[31.887289,103.690666],[31.88656,103.690437],[31.886129,103.690376],[31.88599,103.690407],[31.885361,103.690712],[31.885,103.690567],[31.884661,103.690491],[31.884489,103.690613],[31.88435,103.690804],[31.884199,103.691093],[31.88397,103.691597],[31.883671,103.692062],[31.88357,103.692192],[31.88382,103.692307],[31.88278,103.69278],[31.882139,103.69313],[31.88139,103.693382],[31.87995,103.693489],[31.879089,103.693687],[31.87871,103.693871],[31.87858,103.693947],[31.878481,103.693916],[31.878059,103.694077],[31.87727,103.694649],[31.8771,103.694809],[31.876459,103.695236],[31.876011,103.69548],[31.87565,103.695534],[31.875521,103.695457],[31.874981,103.695259],[31.874701,103.695236],[31.874319,103.695343],[31.873831,103.695557],[31.87311,103.695923],[31.872299,103.696114],[31.871611,103.696136],[31.87063,103.696083],[31.87023,103.696098],[31.86994,103.696152],[31.869049,103.696487],[31.86899,103.696548],[31.86886,103.696854],[31.868799,103.697189],[31.86879,103.697708],[31.86862,103.698029],[31.868509,103.698059],[31.86772,103.698013],[31.867599,103.69796],[31.86746,103.69796],[31.867069,103.697998],[31.866871,103.697891],[31.86672,103.69767],[31.866501,103.697449],[31.866051,103.697197],[31.865761,103.696892],[31.865219,103.696541],[31.864599,103.696083],[31.864519,103.695999],[31.86438,103.695717],[31.863899,103.69545],[31.86322,103.695358],[31.862711,103.695427],[31.86134,103.695557],[31.861099,103.695442],[31.86097,103.695412],[31.860649,103.695374],[31.860359,103.695358],[31.860029,103.695427],[31.859529,103.695686],[31.85914,103.695938],[31.858879,103.695969],[31.85874,103.69603],[31.85832,103.696037],[31.858009,103.696136],[31.85664,103.696747],[31.856409,103.696793],[31.856199,103.696777],[31.8557,103.696693],[31.855379,103.696671],[31.85475,103.696823],[31.853951,103.69706],[31.853689,103.69709],[31.853081,103.697052],[31.852369,103.696953],[31.85146,103.696747],[31.850861,103.696648],[31.849831,103.696602],[31.849291,103.696671],[31.848949,103.696671],[31.8487,103.696831],[31.848021,103.696877],[31.847349,103.696777],[31.84696,103.696739],[31.8466,103.696617],[31.8458,103.695999],[31.845579,103.695717],[31.845369,103.695389],[31.845169,103.694893],[31.844761,103.694054],[31.844509,103.693748],[31.84387,103.693314],[31.8437,103.693169],[31.843361,103.693047],[31.84314,103.693153],[31.843069,103.693283],[31.843031,103.693367],[31.842939,103.693893],[31.842859,103.694023],[31.84277,103.694077],[31.841921,103.694344],[31.841619,103.694389],[31.841511,103.694489],[31.841459,103.694504],[31.84137,103.694862],[31.841339,103.695251],[31.84124,103.695763],[31.841061,103.696518],[31.84091,103.696716],[31.8407,103.696854],[31.840509,103.697037],[31.84016,103.697861],[31.839609,103.698853],[31.839121,103.699532],[31.83886,103.70108],[31.838499,103.701141],[31.838421,103.701653],[31.838369,103.702339],[31.838329,103.702591],[31.838249,103.702843],[31.83782,103.703659],[31.836781,103.704193],[31.836821,103.705048],[31.83672,103.705704],[31.83482,103.710823],[31.835489,103.71196],[31.83531,103.712517],[31.835011,103.713013],[31.83404,103.712936],[31.832781,103.716331],[31.83177,103.715919],[31.831129,103.716087],[31.830839,103.716331],[31.83029,103.716728],[31.83008,103.716957],[31.829781,103.717499],[31.829479,103.71814],[31.829161,103.718758],[31.82902,103.718933],[31.828711,103.719254],[31.82844,103.719498],[31.82836,103.719704],[31.828369,103.71981],[31.82831,103.719887],[31.828291,103.719978],[31.82782,103.720734],[31.826111,103.721161],[31.823009,103.724838],[31.822451,103.725182],[31.821369,103.725723],[31.820841,103.726112],[31.82028,103.72644],[31.820021,103.726547],[31.81946,103.726852],[31.819099,103.727173],[31.81893,103.727631],[31.818899,103.727852],[31.818899,103.727951],[31.81883,103.728271],[31.8188,103.728691],[31.81778,103.728409],[31.81743,103.7286],[31.81723,103.728737],[31.81683,103.728958],[31.81637,103.729111],[31.81601,103.729378],[31.815741,103.729462],[31.815371,103.729492],[31.81517,103.729584],[31.814989,103.729752],[31.814989,103.729897],[31.815599,103.730919],[31.81551,103.731392],[31.81539,103.731552],[31.81481,103.731583],[31.813641,103.731087],[31.813419,103.73127],[31.813231,103.731483],[31.81304,103.731712],[31.81291,103.73201],[31.812599,103.732117],[31.81226,103.732399],[31.81201,103.732559],[31.81159,103.732712],[31.81119,103.732674],[31.811069,103.732788],[31.81065,103.732727],[31.81044,103.732819],[31.81044,103.732948],[31.8099,103.732964],[31.809681,103.732986],[31.809259,103.733231],[31.809,103.73333],[31.808741,103.733383],[31.808281,103.733231],[31.8078,103.733177],[31.80777,103.733208],[31.80809,103.734016],[31.80801,103.734131],[31.80776,103.734138],[31.80702,103.733963],[31.806049,103.73391],[31.80595,103.734001],[31.80534,103.734131],[31.805201,103.734467],[31.805201,103.735077],[31.805111,103.735077],[31.805019,103.735962],[31.804911,103.736061],[31.80488,103.736153],[31.804291,103.735771],[31.803391,103.735138],[31.802799,103.734863],[31.802441,103.734749],[31.80213,103.73468],[31.801661,103.734596],[31.801189,103.734482],[31.80093,103.734444],[31.80147,103.733681],[31.80092,103.733597],[31.800369,103.733429],[31.79858,103.732971],[31.7983,103.732933],[31.797649,103.732811],[31.79673,103.732826],[31.796431,103.732918],[31.79594,103.733017],[31.79587,103.73307],[31.795811,103.73317],[31.79587,103.733437],[31.796009,103.733582],[31.795839,103.733742],[31.79594,103.73407],[31.79627,103.734894],[31.795931,103.735298],[31.79587,103.735443],[31.79578,103.735764],[31.795811,103.735786],[31.795839,103.735947],[31.795971,103.73629],[31.796049,103.736839],[31.796089,103.737083],[31.796089,103.737518],[31.79598,103.738052],[31.795971,103.738373],[31.795919,103.738823],[31.795839,103.739319],[31.79579,103.739769],[31.79587,103.740547],[31.796141,103.742592],[31.79608,103.742622],[31.79587,103.742081],[31.79582,103.742561],[31.79558,103.742851],[31.79524,103.743011],[31.79487,103.743393],[31.791531,103.753731],[31.790319,103.753754],[31.78965,103.754066],[31.789061,103.754578],[31.7887,103.755051],[31.78842,103.7556],[31.78825,103.755981],[31.787979,103.756798],[31.787901,103.756958],[31.787571,103.757446],[31.787069,103.758057],[31.78665,103.758438],[31.78623,103.758682],[31.786051,103.758743],[31.784121,103.759537],[31.783621,103.759697],[31.78343,103.759697],[31.783079,103.759857],[31.78252,103.760017],[31.78229,103.760429],[31.781969,103.760643],[31.781691,103.760643],[31.781321,103.760651],[31.78089,103.760803],[31.780479,103.760918],[31.78023,103.761017],[31.780081,103.761139],[31.77957,103.761681],[31.77924,103.762138],[31.7792,103.762253],[31.779119,103.762688],[31.77916,103.763138],[31.77915,103.763344],[31.77903,103.763603],[31.778959,103.763962],[31.77894,103.764267],[31.77887,103.764503],[31.77846,103.765358],[31.778111,103.765938],[31.777809,103.766518],[31.777611,103.766853],[31.777361,103.767357],[31.777241,103.767723],[31.77718,103.768112],[31.777109,103.76886],[31.7771,103.769501],[31.777121,103.769859],[31.77721,103.770309],[31.777361,103.771294],[31.77734,103.771584],[31.777189,103.77227],[31.7771,103.773232],[31.77759,103.774353],[31.776859,103.776382],[31.77779,103.777153],[31.777719,103.777412],[31.777571,103.777603],[31.77737,103.777733],[31.776951,103.777908],[31.77623,103.778259],[31.776159,103.778313],[31.77593,103.778969],[31.774679,103.778999],[31.774561,103.779083],[31.774309,103.779404],[31.77387,103.780411],[31.77351,103.781342],[31.773149,103.782097],[31.773479,103.78299],[31.76511,103.789299],[31.76424,103.788803],[31.764059,103.788918],[31.76396,103.789017],[31.76359,103.78933],[31.763201,103.789612],[31.76284,103.790092],[31.76256,103.790787],[31.76247,103.791367],[31.762871,103.792313],[31.7623,103.793083],[31.763201,103.794403],[31.76347,103.794762],[31.764099,103.795464],[31.764521,103.796158],[31.765039,103.797447],[31.765289,103.798141],[31.765409,103.798553],[31.765511,103.799088],[31.76552,103.799751],[31.765471,103.800423],[31.76553,103.801903],[31.765551,103.802116],[31.76556,103.802422],[31.76553,103.80323],[31.765539,103.805206],[31.76553,103.805862],[31.765511,103.805923],[31.765459,103.807419],[31.765499,103.807999],[31.76549,103.808167],[31.765591,103.808479],[31.765671,103.808777],[31.765909,103.809509],[31.766029,103.809807],[31.7661,103.810127],[31.76622,103.810516],[31.766491,103.81205],[31.76668,103.812691],[31.767071,103.813316],[31.76815,103.814392],[31.768391,103.814743],[31.76856,103.815079],[31.76861,103.815353],[31.76865,103.815804],[31.768539,103.816299],[31.76837,103.816772],[31.76803,103.817413],[31.767691,103.817787],[31.76757,103.817833],[31.76709,103.818169],[31.766491,103.818489],[31.765921,103.818359],[31.765209,103.818123],[31.76478,103.818001],[31.76436,103.817917],[31.764151,103.81794],[31.76396,103.818024],[31.7638,103.818176],[31.762899,103.818771],[31.762751,103.818893],[31.762119,103.819878],[31.761869,103.820221],[31.761511,103.820778],[31.761311,103.821159],[31.760889,103.821877],[31.760509,103.822403],[31.760389,103.822533],[31.76022,103.822693],[31.76004,103.822823],[31.75967,103.822952],[31.759541,103.822952],[31.75906,103.822998],[31.758619,103.823097],[31.75794,103.823311],[31.757521,103.823471],[31.75667,103.823486],[31.751591,103.831108],[31.75139,103.831291],[31.75066,103.831802],[31.75094,103.833023],[31.750351,103.833847],[31.750219,103.833977],[31.750019,103.834091],[31.749229,103.834328],[31.74898,103.834503],[31.748501,103.835091],[31.748199,103.835854],[31.748199,103.835838],[31.747869,103.836678],[31.747589,103.837143],[31.747339,103.83744],[31.74721,103.837669],[31.74711,103.837692],[31.74708,103.837738],[31.746849,103.837769],[31.7467,103.837723],[31.746651,103.837738],[31.74621,103.837601],[31.745951,103.837608],[31.74544,103.837784],[31.74523,103.83783],[31.744459,103.83783],[31.74403,103.837967],[31.74374,103.838074],[31.743549,103.838203],[31.74305,103.838676],[31.74268,103.839233],[31.74264,103.839241],[31.74234,103.839577],[31.74229,103.839592],[31.74169,103.840752],[31.741409,103.841141],[31.741159,103.841011],[31.74094,103.841164],[31.740669,103.841454],[31.738171,103.843643],[31.737659,103.844048],[31.737391,103.844177],[31.737169,103.844238],[31.7369,103.844383],[31.73649,103.84449],[31.73601,103.844513],[31.734369,103.844421],[31.734011,103.844353],[31.73353,103.843582],[31.73074,103.845497],[31.722481,103.851181],[31.721781,103.850327],[31.72146,103.850388],[31.721239,103.850449],[31.7208,103.850632],[31.720289,103.850891],[31.719749,103.851257],[31.71924,103.851646],[31.718679,103.852013],[31.71838,103.852097],[31.71792,103.852119],[31.717039,103.852493],[31.7167,103.8526],[31.716,103.853142],[31.71582,103.853348],[31.7155,103.852966],[31.71513,103.853149],[31.714649,103.853256],[31.714319,103.853317],[31.713989,103.853409],[31.713329,103.853523],[31.712799,103.853447],[31.71246,103.853416],[31.71192,103.853363],[31.711491,103.853279],[31.711149,103.853256],[31.710831,103.853287],[31.710279,103.853523],[31.710039,103.853561],[31.709749,103.853569],[31.709419,103.8535],[31.70919,103.853378],[31.709021,103.853363],[31.70867,103.853432],[31.70829,103.853592],[31.707581,103.85379],[31.707319,103.853844],[31.706829,103.853851],[31.70647,103.853882],[31.706051,103.853889],[31.705891,103.853859],[31.704599,103.853119],[31.704229,103.852859],[31.703501,103.851593],[31.70344,103.851463],[31.70225,103.850548],[31.701151,103.84977],[31.7006,103.849579],[31.700199,103.850067],[31.699499,103.850227],[31.69916,103.850357],[31.697941,103.850883],[31.697689,103.850838],[31.697639,103.850853],[31.698191,103.850487],[31.697781,103.850502],[31.697229,103.850662],[31.696899,103.850662],[31.69673,103.850693],[31.696581,103.850632],[31.696159,103.850243],[31.695869,103.849747],[31.69516,103.848351],[31.69486,103.847588],[31.69433,103.846321],[31.69418,103.845993],[31.69404,103.845657],[31.693939,103.845467],[31.69384,103.845367],[31.69348,103.845093],[31.69335,103.844971],[31.69327,103.844948],[31.69294,103.844727],[31.69268,103.844513],[31.69241,103.844414],[31.692181,103.844368],[31.69173,103.844383],[31.691389,103.844437],[31.69006,103.844933],[31.68998,103.844948],[31.689449,103.844887],[31.68928,103.844833],[31.68854,103.844673],[31.686399,103.844727],[31.685869,103.844772],[31.68545,103.844772],[31.68499,103.84481],[31.6845,103.844833],[31.684099,103.844887],[31.68379,103.84491],[31.68375,103.844948],[31.683599,103.844994],[31.68347,103.844978],[31.683081,103.844879],[31.682541,103.844589],[31.682091,103.844261],[31.681471,103.843887],[31.68079,103.84359],[31.67959,103.84343],[31.6793,103.843353],[31.67861,103.842819],[31.677931,103.842216],[31.677271,103.841614],[31.676781,103.841202],[31.67572,103.84024],[31.67477,103.83934],[31.67441,103.83905],[31.67417,103.838814],[31.673901,103.838577],[31.673281,103.83799],[31.67313,103.837891],[31.672689,103.837433],[31.67164,103.836563],[31.6712,103.836143],[31.669941,103.834976],[31.669479,103.834534],[31.66906,103.834213],[31.66855,103.833969],[31.6682,103.833893],[31.66783,103.833763],[31.667379,103.833633],[31.66733,103.833656],[31.666821,103.833366],[31.66638,103.833031],[31.66555,103.832458],[31.664881,103.831863],[31.663839,103.830544],[31.663401,103.829941],[31.662809,103.829079],[31.662411,103.8284],[31.662041,103.827629],[31.66198,103.827469],[31.661921,103.827377],[31.661631,103.826813],[31.66135,103.826134],[31.66128,103.825989],[31.66123,103.825844],[31.661119,103.82563],[31.66086,103.824982],[31.66082,103.824669],[31.660879,103.824387],[31.661119,103.824112],[31.6614,103.8237],[31.66165,103.823158],[31.66206,103.822563],[31.66206,103.822166],[31.66115,103.82093],[31.6605,103.819977],[31.66037,103.819511],[31.6604,103.819298],[31.66054,103.819008],[31.661131,103.818253],[31.662029,103.817177],[31.66238,103.816566],[31.66254,103.816109],[31.66251,103.816078],[31.662821,103.815193],[31.662979,103.814796],[31.663099,103.814362],[31.66312,103.813957],[31.663,103.813606],[31.662861,103.813271],[31.662609,103.812897],[31.662161,103.812553],[31.661501,103.812119],[31.661381,103.812057],[31.66119,103.811897],[31.66066,103.811737],[31.657261,103.811653],[31.656969,103.811607],[31.656799,103.811607],[31.65591,103.811508],[31.65435,103.811256],[31.65407,103.81115],[31.65349,103.810959],[31.65291,103.810699],[31.65218,103.810318],[31.65169,103.810028],[31.651421,103.809837],[31.65086,103.809486],[31.650181,103.809013],[31.64917,103.80835],[31.64901,103.808273],[31.648069,103.80764],[31.64772,103.807457],[31.64661,103.806664],[31.646,103.806282],[31.645321,103.805817],[31.64521,103.805771],[31.644779,103.805473],[31.64201,103.803658],[31.64163,103.803429],[31.641411,103.803261],[31.640711,103.802788],[31.640459,103.80265],[31.640051,103.802353],[31.63879,103.801537],[31.638399,103.801224],[31.63818,103.800911],[31.637899,103.800056],[31.637699,103.799606],[31.63752,103.79937],[31.637421,103.799309],[31.637091,103.799179],[31.636299,103.798683],[31.63612,103.798439],[31.636049,103.79818],[31.63599,103.797836],[31.63596,103.797417],[31.63578,103.796913],[31.63439,103.795692],[31.633631,103.79509],[31.633011,103.794724],[31.63138,103.793823],[31.630911,103.793266],[31.63064,103.792877],[31.630251,103.792221],[31.628441,103.789413],[31.627769,103.788399],[31.62665,103.786667],[31.626141,103.786324],[31.625351,103.786057],[31.624701,103.785873],[31.62455,103.785858],[31.623051,103.786079],[31.62244,103.785873],[31.622271,103.78569],[31.621571,103.784348],[31.620819,103.782867],[31.62027,103.781723],[31.620211,103.781509],[31.62023,103.780823],[31.620359,103.779968],[31.620359,103.779022],[31.62023,103.776962],[31.62007,103.77623],[31.619789,103.775642],[31.61961,103.775467],[31.619471,103.775192],[31.619471,103.775131],[31.61939,103.775017],[31.61923,103.774712],[31.618891,103.77417],[31.618549,103.773529],[31.6182,103.772949],[31.617941,103.772743],[31.6178,103.772667],[31.617611,103.772621],[31.615549,103.772438],[31.615431,103.772453],[31.61515,103.772438],[31.61446,103.772339],[31.6124,103.772141],[31.611521,103.771957],[31.611401,103.771889],[31.61091,103.771347],[31.610479,103.770729],[31.609631,103.769333],[31.609159,103.768631],[31.608749,103.767776],[31.60873,103.767029],[31.60874,103.766586],[31.60874,103.766281],[31.608841,103.765717],[31.60885,103.765213],[31.608801,103.764809],[31.60874,103.764587],[31.6085,103.763832],[31.608351,103.763412],[31.608299,103.763184],[31.60766,103.7612],[31.607519,103.760681],[31.60745,103.760246],[31.60742,103.759247],[31.60746,103.758263],[31.607491,103.758011],[31.607479,103.757538],[31.60751,103.755051],[31.60742,103.754303],[31.60717,103.753563],[31.6071,103.753403],[31.606939,103.753181],[31.606911,103.753014],[31.606859,103.752869],[31.60623,103.751663],[31.606039,103.751427],[31.605419,103.750862],[31.60511,103.750618],[31.604509,103.750183],[31.603661,103.749817],[31.60322,103.749542],[31.602449,103.749207],[31.60186,103.749046],[31.60113,103.748894],[31.600531,103.748779],[31.600149,103.748749],[31.599739,103.74881],[31.599489,103.748947],[31.599791,103.750053],[31.59976,103.750511],[31.59939,103.750511],[31.598949,103.750381],[31.598301,103.749687],[31.597931,103.749947],[31.59779,103.750061],[31.59738,103.750267],[31.597139,103.750298],[31.596889,103.750267],[31.59667,103.750229],[31.595501,103.750107],[31.595249,103.750107],[31.594379,103.750031],[31.593941,103.749969],[31.593651,103.749893],[31.59326,103.749657],[31.59285,103.749336],[31.591949,103.748558],[31.59079,103.74762],[31.589581,103.74659],[31.58902,103.746071],[31.58843,103.745483],[31.587721,103.744789],[31.586809,103.743843],[31.585581,103.742828],[31.585119,103.742523],[31.58432,103.741852],[31.584089,103.741547],[31.583691,103.740662],[31.5835,103.740356],[31.58338,103.74012],[31.583389,103.739594],[31.58337,103.739517],[31.583269,103.73941],[31.58316,103.739052],[31.58317,103.738792],[31.583099,103.738708],[31.582979,103.738319],[31.582911,103.738052],[31.58285,103.737244],[31.583099,103.735764],[31.58333,103.734688],[31.583441,103.733932],[31.583599,103.73304],[31.58354,103.732521],[31.583509,103.732407],[31.583321,103.732109],[31.583139,103.731934],[31.582781,103.731773],[31.58251,103.731468],[31.582439,103.731194],[31.582399,103.730988],[31.58235,103.730873],[31.582319,103.730713],[31.58205,103.730408],[31.581869,103.730232],[31.58148,103.729797],[31.581249,103.729568],[31.57992,103.728477],[31.579309,103.728127],[31.578699,103.727837],[31.57826,103.727676],[31.577909,103.727654],[31.57765,103.727661],[31.577391,103.727859],[31.57725,103.728027],[31.577181,103.728218],[31.577049,103.728989],[31.57687,103.729736],[31.57692,103.729759],[31.576811,103.730118],[31.576521,103.73053],[31.57486,103.731537],[31.574511,103.731621],[31.57411,103.731613],[31.572451,103.731178],[31.572081,103.731049],[31.57181,103.730904],[31.571581,103.730659],[31.57115,103.730003],[31.57091,103.729698],[31.570841,103.729446],[31.570551,103.728958],[31.570419,103.728668],[31.570259,103.727829],[31.570221,103.727303],[31.570259,103.726196],[31.570601,103.725067],[31.571039,103.723846],[31.571091,103.723778],[31.571409,103.723427],[31.571951,103.723061],[31.572781,103.72226],[31.572981,103.721764],[31.573111,103.720444],[31.57321,103.719803],[31.57345,103.717644],[31.57349,103.717079],[31.57333,103.716583],[31.572769,103.715477],[31.57268,103.715317],[31.57251,103.714951],[31.572399,103.714767],[31.572121,103.714607],[31.570459,103.714119],[31.57028,103.714073],[31.56971,103.714188],[31.569071,103.714523],[31.56881,103.71463],[31.56859,103.714638],[31.56839,103.714592],[31.56753,103.714233],[31.567221,103.71405],[31.566891,103.713669],[31.56612,103.712608],[31.56591,103.712273],[31.56567,103.711967],[31.565531,103.7117],[31.565269,103.710907],[31.565241,103.710709],[31.56505,103.708588],[31.564871,103.707779],[31.56448,103.70652],[31.56403,103.7052],[31.563551,103.704109],[31.56237,103.701767],[31.56175,103.70079],[31.561319,103.700592],[31.56106,103.700706],[31.560499,103.701073],[31.560169,103.700996],[31.559509,103.700127],[31.55743,103.697662],[31.557249,103.697479],[31.55703,103.697067],[31.556971,103.696693],[31.556971,103.696404],[31.55706,103.695908],[31.5571,103.695534],[31.55711,103.695259],[31.557211,103.694489],[31.557289,103.693314],[31.55723,103.692993],[31.55699,103.692467],[31.556499,103.691849],[31.555901,103.691437],[31.555229,103.691093],[31.554729,103.690727],[31.553869,103.690033],[31.55308,103.689453],[31.55245,103.689293],[31.55179,103.689331],[31.5515,103.689194],[31.551279,103.688927],[31.551201,103.68882],[31.551069,103.68856],[31.550911,103.688332],[31.55088,103.688263],[31.550791,103.688141],[31.55068,103.687943],[31.550501,103.687691],[31.55039,103.687492],[31.550249,103.687332],[31.550039,103.686989],[31.549721,103.686569],[31.549561,103.686401],[31.54932,103.686073],[31.549061,103.685806],[31.548849,103.685654],[31.548201,103.685471],[31.546721,103.685173],[31.54623,103.685043],[31.545071,103.684883],[31.544661,103.684914],[31.54361,103.685059],[31.542259,103.685219],[31.541861,103.685226],[31.54143,103.68512],[31.54108,103.684959],[31.540331,103.684486],[31.539591,103.684113],[31.539339,103.683937],[31.538879,103.683456],[31.53878,103.683273],[31.538549,103.682693],[31.53841,103.682228],[31.538349,103.682083],[31.53797,103.681633],[31.537781,103.681549],[31.53731,103.681503],[31.536909,103.681633],[31.536739,103.681793],[31.53632,103.682243],[31.535919,103.682571],[31.53581,103.682632],[31.53521,103.682831],[31.5347,103.682961],[31.534069,103.683067],[31.533119,103.683151],[31.532459,103.683151],[31.532169,103.682983],[31.531931,103.682549],[31.53187,103.682388],[31.531691,103.682007],[31.531469,103.681419],[31.531269,103.681068],[31.53096,103.680771],[31.53055,103.680618],[31.53031,103.680397],[31.53005,103.680122],[31.52984,103.679527],[31.529831,103.679237],[31.52985,103.678467],[31.529909,103.678139],[31.529831,103.677742],[31.529591,103.677254],[31.529289,103.676773],[31.52895,103.676277],[31.52866,103.675941],[31.528271,103.675453],[31.527849,103.675003],[31.526911,103.674347],[31.525351,103.67337],[31.5249,103.673058],[31.524019,103.672531],[31.523661,103.672401],[31.52273,103.672012],[31.522129,103.671738],[31.521561,103.671509],[31.521231,103.67131],[31.52075,103.670868],[31.52038,103.670471],[31.520069,103.670227],[31.519911,103.670128],[31.51977,103.670013],[31.518841,103.669434],[31.518539,103.669327],[31.5182,103.669296],[31.516991,103.669312],[31.516451,103.669228],[31.516319,103.669167],[31.51606,103.668999],[31.515751,103.668556],[31.51548,103.668114],[31.515421,103.667801],[31.5154,103.667542],[31.515381,103.666924],[31.515329,103.666283],[31.515261,103.665817],[31.51515,103.665497],[31.51512,103.664787],[31.51515,103.664192],[31.51516,103.66349],[31.51511,103.66272],[31.5149,103.662178],[31.514629,103.661797],[31.514311,103.66124],[31.51392,103.660606],[31.513571,103.660072],[31.51343,103.65992],[31.51298,103.659317],[31.51251,103.658638],[31.512381,103.658386],[31.5123,103.658096],[31.51219,103.657417],[31.5121,103.656967],[31.512091,103.65657],[31.5121,103.656174],[31.51206,103.655632],[31.51227,103.654694],[31.51231,103.653923],[31.51231,103.653488],[31.512251,103.653],[31.51214,103.652657],[31.51195,103.652367],[31.511379,103.651993],[31.51108,103.651909],[31.51009,103.651833],[31.509399,103.651611],[31.509001,103.65139],[31.50861,103.651253],[31.508169,103.651001],[31.50762,103.650551],[31.507179,103.650223],[31.506929,103.650146],[31.506809,103.650017],[31.50654,103.649467],[31.506161,103.648819],[31.505791,103.648247],[31.505501,103.647942],[31.50522,103.647743],[31.50474,103.64743],[31.5044,103.647377],[31.503639,103.647423],[31.50312,103.647408],[31.50276,103.647362],[31.50252,103.647293],[31.502279,103.647186],[31.50178,103.647293],[31.50156,103.647324],[31.501129,103.647163],[31.50087,103.647011],[31.499599,103.646423],[31.499189,103.64592],[31.49877,103.64518],[31.49864,103.644798],[31.498529,103.644257],[31.49844,103.643959],[31.498249,103.643623],[31.49818,103.643509],[31.49803,103.643204],[31.49761,103.642769],[31.49737,103.64241],[31.497351,103.642281],[31.496889,103.641319],[31.49667,103.640373],[31.49663,103.640022],[31.49654,103.639511],[31.49651,103.639214],[31.496559,103.638962],[31.496651,103.638741],[31.496771,103.638527],[31.496889,103.638321],[31.49692,103.638],[31.496679,103.637642],[31.496361,103.637306],[31.49608,103.637123],[31.495819,103.637016],[31.495211,103.636902],[31.495001,103.636887],[31.4946,103.636818],[31.49444,103.636742],[31.49408,103.636436],[31.493879,103.636208],[31.49338,103.635498],[31.493259,103.635101],[31.49325,103.63456],[31.493299,103.634087],[31.49329,103.634064],[31.49328,103.633797],[31.493179,103.633537],[31.49304,103.633362],[31.49292,103.63311],[31.49287,103.632629],[31.492889,103.632347],[31.49287,103.632141],[31.49279,103.631889],[31.49268,103.631683],[31.492519,103.631279],[31.49246,103.631027],[31.49229,103.630524],[31.492279,103.630211],[31.49213,103.629646],[31.49206,103.629494],[31.492041,103.629478],[31.49194,103.629204],[31.49168,103.628479],[31.491529,103.627823],[31.491541,103.627007],[31.491779,103.625931],[31.49194,103.625412],[31.49206,103.625076],[31.49214,103.624893],[31.492161,103.624718],[31.49226,103.624557],[31.49284,103.624184],[31.493641,103.623482],[31.494209,103.622757],[31.49416,103.622543],[31.493589,103.621727],[31.493231,103.621323],[31.492849,103.621063],[31.49229,103.620827],[31.49198,103.62072],[31.491289,103.620644],[31.4911,103.620537],[31.490971,103.62043],[31.49082,103.62014],[31.490959,103.619667],[31.491131,103.619537],[31.49202,103.619431],[31.49262,103.619301],[31.492849,103.619164],[31.493589,103.618568],[31.493971,103.618217],[31.49407,103.618088],[31.49424,103.617722],[31.494249,103.617439],[31.494209,103.61702],[31.49416,103.616814],[31.49394,103.616463],[31.493799,103.616333],[31.49304,103.615288],[31.49287,103.614967],[31.49275,103.614693],[31.49246,103.61438],[31.49251,103.614326],[31.492359,103.614159],[31.4921,103.613907],[31.492029,103.613792],[31.491261,103.612923],[31.49037,103.611641],[31.489941,103.611397],[31.48942,103.611343],[31.489161,103.611237],[31.488001,103.611008],[31.48781,103.611],[31.48749,103.610901],[31.48715,103.610863],[31.48699,103.610863],[31.48642,103.610641],[31.485809,103.610527],[31.485399,103.610321],[31.48514,103.610168],[31.4848,103.609711],[31.48461,103.609352],[31.484529,103.609108],[31.48443,103.608566],[31.484421,103.608223],[31.484249,103.60759],[31.484171,103.60746],[31.484011,103.607246],[31.48378,103.60685],[31.483641,103.606483],[31.48325,103.605629],[31.48311,103.605347],[31.48307,103.605148],[31.48288,103.604584],[31.48271,103.604187],[31.482441,103.603287],[31.482109,103.602463],[31.481991,103.602074],[31.48176,103.601486],[31.481529,103.601044],[31.48126,103.600342],[31.48111,103.60006],[31.480829,103.599457],[31.48035,103.598396],[31.479919,103.597481],[31.479851,103.597382],[31.479401,103.596352],[31.47921,103.596039],[31.47884,103.59549],[31.478701,103.595261],[31.47863,103.59478],[31.478609,103.594254],[31.47863,103.59391],[31.478939,103.591682],[31.47924,103.590721],[31.47921,103.590088],[31.47917,103.589813],[31.479179,103.589661],[31.47929,103.588966],[31.47933,103.588593],[31.479521,103.587677],[31.479679,103.586761],[31.479891,103.585663],[31.47998,103.584953],[31.48003,103.584641],[31.480061,103.584351],[31.480089,103.584023],[31.47991,103.583214],[31.47979,103.58284],[31.47925,103.581673],[31.479031,103.581337],[31.478769,103.580887],[31.478291,103.580223],[31.47813,103.579971],[31.47789,103.579399],[31.477711,103.578911],[31.477579,103.578613],[31.47744,103.57827],[31.477369,103.578049],[31.477171,103.577744],[31.47682,103.577278],[31.476589,103.577057],[31.47645,103.576981],[31.47596,103.576874],[31.475651,103.576843],[31.47522,103.576736],[31.474939,103.576721],[31.474701,103.576691],[31.474701,103.576538],[31.47485,103.57589],[31.47493,103.575394],[31.474899,103.575012],[31.47488,103.574982],[31.474701,103.574913],[31.47438,103.574913],[31.4736,103.574699],[31.47336,103.574677],[31.47287,103.574707],[31.472691,103.574692],[31.472071,103.573463],[31.47057,103.572227],[31.469021,103.570557],[31.467991,103.569771],[31.467079,103.569771],[31.46619,103.570038],[31.46537,103.570297],[31.464979,103.570297],[31.46344,103.569809],[31.46101,103.568909],[31.460279,103.568176],[31.459869,103.566643],[31.459511,103.564423],[31.45912,103.562363],[31.45895,103.561737],[31.45866,103.561172],[31.457279,103.558601],[31.456921,103.557899],[31.45583,103.555847],[31.45546,103.555267],[31.45499,103.554581],[31.454519,103.55394],[31.454309,103.553558],[31.454201,103.552887],[31.454559,103.551971],[31.454941,103.551086],[31.45583,103.549187],[31.45603,103.548561],[31.456051,103.547821],[31.455839,103.54734],[31.45536,103.546867],[31.45483,103.546669],[31.454321,103.546539],[31.45405,103.54644],[31.45322,103.545769],[31.452959,103.545502],[31.45269,103.545273],[31.452419,103.545273],[31.45207,103.545097],[31.45167,103.544968],[31.4515,103.544937],[31.45006,103.544777],[31.449619,103.544678],[31.448759,103.544289],[31.447929,103.543854],[31.446199,103.542969],[31.445761,103.542709],[31.445221,103.542221],[31.44474,103.541649],[31.444201,103.5411],[31.44396,103.540993],[31.44367,103.540916],[31.44301,103.54097],[31.439659,103.541473],[31.43886,103.541656],[31.43778,103.542038],[31.43689,103.542381],[31.436449,103.542473],[31.4356,103.542572],[31.43504,103.542603],[31.43441,103.542709],[31.43392,103.542732],[31.43346,103.542732],[31.433439,103.542702],[31.43302,103.542763],[31.43259,103.542961],[31.42981,103.544456],[31.429331,103.544563],[31.429131,103.54454],[31.428671,103.544243],[31.42819,103.543793],[31.42675,103.542313],[31.42621,103.541862],[31.425631,103.541344],[31.4251,103.540894],[31.42322,103.539574],[31.42255,103.539131],[31.420071,103.537849],[31.419399,103.537537],[31.418791,103.537178],[31.41828,103.536774],[31.41699,103.535599],[31.41613,103.534889],[31.415621,103.534599],[31.415159,103.534439],[31.414471,103.534264],[31.4142,103.534172],[31.4135,103.533989],[31.41247,103.533699],[31.41194,103.533478],[31.4118,103.533379],[31.411671,103.533257],[31.41148,103.533012],[31.411209,103.532547],[31.41111,103.53241],[31.410629,103.531464],[31.41045,103.531174],[31.410061,103.530838],[31.409889,103.530731],[31.40934,103.530617],[31.409149,103.530602],[31.40756,103.530182],[31.405861,103.52977],[31.405149,103.529556],[31.404869,103.529404],[31.40461,103.529167],[31.404289,103.528397],[31.4041,103.527321],[31.403919,103.526123],[31.403549,103.523849],[31.403299,103.523109],[31.403049,103.522797],[31.402411,103.522438],[31.401699,103.522278],[31.4014,103.522232],[31.399179,103.521721],[31.398439,103.52153],[31.39542,103.520851],[31.39481,103.520683],[31.394239,103.520287],[31.39345,103.5196],[31.39155,103.517853],[31.39131,103.517677],[31.38913,103.515678],[31.389139,103.515663],[31.389111,103.515671],[31.38839,103.515022],[31.38792,103.514572],[31.3871,103.513901],[31.386959,103.513748],[31.372419,103.509407],[31.372141,103.509369],[31.37159,103.509079],[31.371031,103.508568],[31.370649,103.508171],[31.370449,103.507912],[31.36974,103.507149],[31.369089,103.506401],[31.36894,103.506187],[31.36865,103.505577],[31.36833,103.5047],[31.36797,103.503563],[31.36692,103.500427],[31.36664,103.499542],[31.366489,103.499138],[31.366409,103.498779],[31.366329,103.49865],[31.366199,103.498291],[31.36598,103.49752],[31.365681,103.49704],[31.364771,103.496407],[31.36245,103.494919],[31.36208,103.494667],[31.361071,103.494041],[31.359541,103.493042],[31.35741,103.491707],[31.35729,103.491661],[31.35708,103.491631],[31.3564,103.4916],[31.355619,103.491638],[31.355021,103.491547],[31.35438,103.491257],[31.35321,103.490623],[31.35268,103.490349],[31.352221,103.490082],[31.35165,103.489799],[31.35129,103.489647],[31.350531,103.489464],[31.34993,103.489326],[31.34919,103.489143],[31.34828,103.488937],[31.347219,103.488564],[31.346821,103.488358],[31.346279,103.488037],[31.34433,103.486763],[31.34374,103.486504],[31.343491,103.486443],[31.342831,103.486427],[31.342421,103.486519],[31.342251,103.486572],[31.34177,103.486649],[31.340799,103.486862],[31.340321,103.486931],[31.339331,103.487167],[31.339029,103.48719],[31.338591,103.487122],[31.33721,103.486099],[31.336519,103.485413],[31.33604,103.484711],[31.33556,103.483917],[31.335421,103.483276],[31.33383,103.480087],[31.333611,103.479721],[31.333361,103.479378],[31.333019,103.479057],[31.332359,103.478569],[31.33135,103.477859],[31.330931,103.477432],[31.33073,103.477013],[31.32996,103.47448],[31.329849,103.474258],[31.32967,103.47403],[31.32946,103.473862],[31.32926,103.473793],[31.328569,103.473801],[31.32366,103.474693],[31.322969,103.474777],[31.322241,103.474907],[31.321489,103.474937],[31.320959,103.47477],[31.320721,103.474617],[31.32004,103.474167],[31.31922,103.473587],[31.31871,103.473312],[31.31826,103.473183],[31.3176,103.473129],[31.31675,103.473099],[31.314791,103.473061],[31.314131,103.472977],[31.313431,103.472839],[31.31291,103.472748],[31.311569,103.472473],[31.31142,103.47245],[31.310841,103.47229],[31.310711,103.472237],[31.31061,103.472168],[31.310511,103.472069],[31.310221,103.471672],[31.30938,103.470322],[31.30928,103.470108],[31.30896,103.469612],[31.30871,103.469307],[31.308189,103.468964],[31.30788,103.468842],[31.30744,103.468697],[31.306231,103.468193],[31.30521,103.467827],[31.303169,103.466942],[31.302691,103.466766],[31.302429,103.46669],[31.301991,103.466507],[31.3016,103.466209],[31.301519,103.466164],[31.3015,103.466057],[31.301161,103.465897],[31.30098,103.465851],[31.300831,103.465759],[31.30061,103.465729],[31.300011,103.465698],[31.299561,103.465477],[31.2994,103.465157],[31.299179,103.464828],[31.29841,103.464378],[31.29821,103.464104],[31.298149,103.463753],[31.29805,103.463463],[31.29759,103.463226],[31.297171,103.462921],[31.295549,103.462402],[31.289801,103.460899],[31.28867,103.461166],[31.280279,103.469017],[31.27939,103.469353],[31.27865,103.470039],[31.277781,103.471283],[31.27607,103.474007],[31.274839,103.474609],[31.273741,103.474922],[31.27346,103.474907],[31.27326,103.474876],[31.273069,103.474823],[31.272539,103.474747],[31.27182,103.475014],[31.271271,103.475098],[31.27033,103.475189],[31.269159,103.475159],[31.26734,103.475319],[31.26685,103.475456],[31.26601,103.475906],[31.26573,103.476089],[31.264391,103.477097],[31.26379,103.477753],[31.26339,103.478279],[31.263041,103.479218],[31.26285,103.479637],[31.26289,103.480217],[31.26284,103.480522],[31.262449,103.481049],[31.261801,103.481667],[31.26133,103.482147],[31.260521,103.482559],[31.25906,103.480049],[31.257441,103.480988],[31.250851,103.486687],[31.249491,103.488113],[31.24909,103.488403],[31.24823,103.488411],[31.2472,103.487907],[31.24691,103.487778],[31.24605,103.487694],[31.231581,103.492683],[31.22551,103.486893],[31.20331,103.497948],[31.17948,103.496834],[31.160801,103.494209],[31.156799,103.491173],[31.148029,103.488243],[31.140209,103.48967],[31.13055,103.494873],[31.122959,103.496063],[31.118771,103.494431],[31.11475,103.489479],[31.11301,103.485519],[31.11005,103.483063],[31.107821,103.481087],[31.10568,103.479523],[31.1042,103.478653],[31.102659,103.478302],[31.1021,103.478157],[31.101521,103.478127],[31.1012,103.478233],[31.10042,103.478691],[31.09967,103.478943],[31.098499,103.479149],[31.098141,103.479118],[31.097481,103.479111],[31.097071,103.479134],[31.096581,103.479263],[31.0959,103.479858],[31.09536,103.480507],[31.09507,103.481194],[31.09473,103.482063],[31.094601,103.482246],[31.09396,103.483131],[31.09333,103.483788],[31.092581,103.484711],[31.091961,103.485336],[31.09182,103.485428],[31.091551,103.485481],[31.09111,103.485313],[31.0909,103.48513],[31.090441,103.484558],[31.09029,103.484444],[31.089769,103.484253],[31.089439,103.484322],[31.089211,103.484489],[31.088739,103.484894],[31.08844,103.485107],[31.08814,103.48526],[31.08798,103.485313],[31.087151,103.485283],[31.08099,103.485023],[31.08004,103.484787],[31.07909,103.484596],[31.07826,103.484528],[31.07803,103.484528],[31.076891,103.484703],[31.076639,103.484787],[31.07621,103.484901],[31.07493,103.485321],[31.07374,103.486191],[31.07304,103.486572],[31.072531,103.4869],[31.072001,103.487381],[31.07168,103.487602],[31.071199,103.487823],[31.07078,103.488029],[31.070181,103.488373],[31.06941,103.488876],[31.06925,103.489197],[31.068439,103.489433],[31.06757,103.489807],[31.06679,103.490547],[31.066259,103.490631],[31.065491,103.490921],[31.06476,103.491257],[31.064449,103.491547],[31.06436,103.491722],[31.064289,103.491898],[31.0641,103.492142],[31.063959,103.492287],[31.06378,103.492561],[31.06341,103.493294],[31.063021,103.494453],[31.04641,103.526978],[31.045561,103.528099],[31.045469,103.528198],[31.044621,103.52887],[31.04331,103.529427],[31.04154,103.529877],[31.03215,103.534622],[31.031231,103.535057],[31.02936,103.535568],[31.028521,103.535843],[31.028061,103.536072],[31.02762,103.536369],[31.0271,103.536819],[31.026369,103.537727],[31.02529,103.539307],[31.024401,103.540733],[31.02223,103.543907],[31.0205,103.546577],[31.01989,103.547508],[31.019421,103.548233],[31.018761,103.549217],[31.01827,103.550056],[31.016239,103.554207],[31,103.586853],[30.998091,103.59005],[30.997681,103.590523],[30.997181,103.590973],[30.996849,103.591232],[30.99613,103.591728],[30.994261,103.592941],[30.99297,103.593803],[30.99185,103.594482],[30.989941,103.594841],[30.988621,103.594322],[30.987591,103.59417],[30.986259,103.593773],[30.98485,103.593773],[30.98218,103.594559],[30.98111,103.594566],[30.979811,103.594269],[30.977461,103.59359],[30.976021,103.5933],[30.975691,103.593277],[30.974489,103.5933],[30.968679,103.594116],[30.964621,103.594727],[30.964001,103.594841],[30.96237,103.595337],[30.96122,103.596024],[30.960211,103.59697],[30.959351,103.598152],[30.958561,103.599762],[30.956551,103.604424],[30.955151,103.607269],[30.95435,103.608627],[30.95089,103.613831],[30.95076,103.614052],[30.950279,103.614952],[30.94981,103.615753],[30.95084,103.615593],[30.95225,103.615532],[30.953581,103.61544],[30.95606,103.615318],[30.95643,103.615288],[30.956989,103.615211],[30.957359,103.615143],[30.957899,103.614998],[30.958441,103.614822],[30.959141,103.614571],[30.959829,103.614304],[30.96102,103.613876],[30.96183,103.613579],[30.962391,103.613373],[30.9631,103.614807],[30.96336,103.615799],[30.963539,103.616302],[30.96368,103.616631],[30.96384,103.616966],[30.965599,103.620323],[30.96623,103.621567],[30.967489,103.624222],[30.9722,103.633148],[30.977289,103.642822],[30.979099,103.645447],[30.978251,103.646347],[30.976589,103.647888],[30.974079,103.650269],[30.97238,103.65197],[30.970909,103.653526],[30.969839,103.654716],[30.968639,103.656143],[30.96751,103.657547],[30.96689,103.658363],[30.96583,103.65979],[30.964109,103.662231],[30.96328,103.663368],[30.962151,103.664833],[30.96097,103.66626],[30.960381,103.667],[30.96023,103.667236],[30.960091,103.667473],[30.95998,103.667747],[30.959789,103.667877],[30.95978,103.667747],[30.959209,103.668411],[30.9589,103.668793],[30.958099,103.669853],[30.957161,103.671143],[30.95595,103.672943],[30.955231,103.674072],[30.952909,103.677902],[30.95179,103.679703],[30.95059,103.681709],[30.949539,103.683418],[30.948919,103.684387],[30.948441,103.685112],[30.946659,103.687637],[30.945499,103.689217],[30.944401,103.690613],[30.94367,103.691513],[30.941299,103.694313],[30.93787,103.698303],[30.9366,103.69986],[30.935209,103.701637],[30.933901,103.703407],[30.933069,103.704597],[30.932249,103.705803],[30.93026,103.708878],[30.92915,103.710564],[30.928301,103.711777],[30.92745,103.712952],[30.926741,103.713837],[30.926001,103.714722],[30.92543,103.715347],[30.924641,103.716148],[30.923651,103.717117],[30.922649,103.718063],[30.92116,103.71936],[30.919451,103.720932],[30.918831,103.721542],[30.91785,103.722572],[30.917471,103.722992],[30.91674,103.723831],[30.91588,103.724892],[30.91522,103.725761],[30.914129,103.727333],[30.913691,103.728027],[30.913139,103.728973],[30.9126,103.729927],[30.912069,103.730949],[30.91169,103.731743],[30.911209,103.732803],[30.91054,103.734383],[30.910151,103.735451],[30.90979,103.736519],[30.907459,103.744202],[30.90659,103.746933],[30.906219,103.747978],[30.90593,103.748749],[30.90542,103.749992],[30.904989,103.750977],[30.904369,103.752274],[30.90366,103.753609],[30.902901,103.754898],[30.902121,103.756119],[30.901489,103.757042],[30.900669,103.758133],[30.900181,103.758751],[30.899691,103.759354],[30.89871,103.760468],[30.897711,103.76152],[30.8972,103.762016],[30.896469,103.762703],[30.895241,103.763748],[30.894569,103.764267],[30.89386,103.764793],[30.892929,103.765442],[30.89245,103.765747],[30.89105,103.766602],[30.888321,103.768097],[30.887011,103.768806],[30.885719,103.769524],[30.884649,103.770149],[30.88401,103.770561],[30.88294,103.771317],[30.88183,103.772202],[30.88139,103.772591],[30.880751,103.773193],[30.87995,103.773979],[30.879379,103.774582],[30.87867,103.775398],[30.87817,103.776016],[30.87768,103.776649],[30.877211,103.777298],[30.87676,103.777946],[30.876011,103.779152],[30.875561,103.779938],[30.875271,103.780487],[30.87471,103.781616],[30.873949,103.783363],[30.873369,103.784813],[30.872669,103.786507],[30.87229,103.787331],[30.871759,103.788399],[30.871731,103.78846],[30.871059,103.789703],[30.87076,103.790207],[30.8703,103.790939],[30.86948,103.792137],[30.869141,103.792603],[30.86861,103.793266],[30.867701,103.794357],[30.867149,103.794991],[30.86639,103.795761],[30.86561,103.796501],[30.864811,103.797203],[30.861601,103.799957],[30.859289,103.80191],[30.858471,103.802628],[30.85726,103.803719],[30.856291,103.804657],[30.85533,103.805634],[30.854509,103.806503],[30.8498,103.811783],[30.848881,103.812798],[30.84778,103.813957],[30.846491,103.815239],[30.84572,103.815941],[30.844299,103.817162],[30.84318,103.818062],[30.842051,103.818932],[30.84137,103.819427],[30.840231,103.820213],[30.8391,103.820953],[30.8354,103.823181],[30.83396,103.824097],[30.833031,103.824722],[30.832359,103.825211],[30.83148,103.825867],[30.83041,103.826736],[30.82938,103.827629],[30.82819,103.828728],[30.8272,103.829712],[30.82618,103.830788],[30.82559,103.831444],[30.824631,103.832573],[30.82229,103.835541],[30.821581,103.836411],[30.82119,103.836853],[30.820379,103.83773],[30.819759,103.838371],[30.81912,103.838989],[30.818251,103.839783],[30.817591,103.840332],[30.81691,103.840874],[30.816,103.841553],[30.81461,103.842506],[30.810249,103.84536],[30.809401,103.845963],[30.808769,103.84642],[30.80835,103.846733],[30.807949,103.847061],[30.807341,103.84758],[30.806721,103.848129],[30.80587,103.848938],[30.80525,103.849564],[30.804661,103.850189],[30.8039,103.851044],[30.80353,103.851471],[30.80266,103.852547],[30.802,103.853439],[30.80117,103.854637],[30.80069,103.8554],[30.79991,103.856697],[30.7966,103.862488],[30.795549,103.864281],[30.79442,103.866318],[30.79245,103.869789],[30.790501,103.873192],[30.78861,103.876472],[30.78834,103.876984],[30.78797,103.877747],[30.7875,103.878838],[30.787291,103.879433],[30.78709,103.88002],[30.786909,103.880638],[30.786751,103.881271],[30.78661,103.881897],[30.786501,103.882553],[30.786409,103.883186],[30.786341,103.883827],[30.786289,103.88446],[30.786261,103.885094],[30.786261,103.886047],[30.78632,103.887306],[30.78647,103.889542],[30.78635,103.891296],[30.78624,103.892967],[30.785839,103.895668],[30.78549,103.897171],[30.78499,103.898582],[30.784599,103.899689],[30.78377,103.901466],[30.783159,103.902473],[30.78298,103.902771],[30.782511,103.903587],[30.78203,103.904282],[30.78134,103.905197],[30.77743,103.910294],[30.773211,103.915771],[30.772129,103.91713],[30.77091,103.91864],[30.769369,103.920647],[30.7686,103.921638],[30.766121,103.924881],[30.7631,103.929024],[30.76078,103.93219],[30.75775,103.936234],[30.757311,103.936577],[30.7565,103.93766],[30.75602,103.938057],[30.755301,103.938583],[30.754761,103.938843],[30.7542,103.939056],[30.75358,103.939201],[30.752729,103.939293],[30.7521,103.939232],[30.75139,103.939072],[30.750839,103.938889],[30.75004,103.938591],[30.748631,103.937691],[30.746429,103.936737],[30.74535,103.936371],[30.74428,103.93605],[30.7437,103.935883],[30.739031,103.934921],[30.736521,103.934418],[30.736271,103.934357],[30.734831,103.934059],[30.73411,103.933907],[30.73082,103.933296],[30.72954,103.933067],[30.729179,103.933006],[30.725719,103.93264],[30.725229,103.932571],[30.72271,103.932442],[30.719419,103.932381],[30.715771,103.932343],[30.712839,103.932167],[30.71044,103.931961],[30.70717,103.931511],[30.702971,103.930763],[30.70075,103.930359],[30.698931,103.930107],[30.6966,103.929947],[30.693951,103.929916],[30.69375,103.929916],[30.69273,103.929947],[30.69128,103.930038],[30.6903,103.930122],[30.685061,103.930573],[30.682341,103.930847],[30.67981,103.931221],[30.676941,103.931831],[30.674351,103.932541],[30.67045,103.93396],[30.66506,103.935852],[30.663919,103.936203],[30.66292,103.936432],[30.66181,103.936653],[30.660431,103.936867],[30.65892,103.936996],[30.65756,103.937042],[30.65484,103.937103],[30.650579,103.93708],[30.648371,103.93718],[30.64661,103.937378],[30.64509,103.937637],[30.64365,103.938019],[30.64196,103.938469],[30.63983,103.939247],[30.63492,103.941093],[30.633631,103.941528],[30.63224,103.941971],[30.630779,103.94239],[30.629311,103.942734],[30.627041,103.943169],[30.62483,103.943512],[30.619511,103.944397],[30.61833,103.944679],[30.616791,103.945107],[30.615311,103.945686],[30.61389,103.946373],[30.61227,103.947456],[30.61113,103.94841],[30.60972,103.949783],[30.60885,103.950798],[30.607639,103.952438],[30.606489,103.954514],[30.605459,103.956711],[30.60393,103.960114],[30.601891,103.964783],[30.60046,103.96785],[30.599171,103.970444],[30.597589,103.973083],[30.59609,103.975372],[30.59486,103.977203],[30.592131,103.981133],[30.591129,103.982712],[30.589991,103.985039],[30.589319,103.986877],[30.58885,103.988724],[30.58856,103.990677],[30.588461,103.992706],[30.58849,103.994728],[30.58868,104.002876],[30.58857,104.005081],[30.588181,104.007187],[30.58745,104.009308],[30.5863,104.011383],[30.584311,104.014137],[30.58374,104.014938],[30.58132,104.018349],[30.5807,104.019234],[30.579081,104.022034],[30.57872,104.02272],[30.578449,104.023232],[30.57793,104.023956],[30.577459,104.024513],[30.57682,104.024979],[30.576241,104.025208],[30.57585,104.025307],[30.575529,104.025391],[30.57468,104.025391],[30.57391,104.025269],[30.57362,104.025162],[30.571671,104.024368],[30.570181,104.023758],[30.56801,104.022743],[30.56468,104.020882],[30.554741,104.014908],[30.55094,104.012497],[30.548651,104.010696],[30.54603,104.008163],[30.54306,104.004494],[30.54019,103.999863],[30.538441,103.997513],[30.536329,103.995216],[30.528799,103.987923],[30.525129,103.984543],[30.522129,103.982224],[30.51981,103.980797],[30.51687,103.979141],[30.51384,103.977158],[30.51082,103.974457],[30.50326,103.967072],[30.50028,103.964706],[30.497601,103.96299],[30.48823,103.958504],[30.482201,103.955002],[30.476259,103.950844],[30.47337,103.948822],[30.470671,103.947304],[30.46776,103.94593],[30.45928,103.942421],[30.455521,103.940567],[30.452351,103.938187],[30.450029,103.935883],[30.44676,103.931976],[30.443501,103.928284],[30.43807,103.92318],[30.42778,103.913887],[30.424299,103.910683],[30.42137,103.908173],[30.418739,103.906342],[30.415751,103.904572],[30.409611,103.900833],[30.408791,103.900307],[30.40811,103.899879],[30.40642,103.89872],[30.406269,103.898613],[30.406139,103.898514],[30.405199,103.897797],[30.404831,103.897507],[30.404539,103.897301],[30.4027,103.895752],[30.402639,103.895714],[30.400829,103.894089],[30.395901,103.889481],[30.38553,103.878517],[30.38382,103.876129],[30.382191,103.873322],[30.381121,103.870064],[30.380699,103.86879],[30.38039,103.867699],[30.379641,103.864769],[30.378071,103.858124],[30.37772,103.856689],[30.376881,103.85466],[30.375919,103.852417],[30.374901,103.850273],[30.3745,103.849602],[30.373409,103.848267],[30.37274,103.847504],[30.371759,103.846527],[30.37007,103.845253],[30.37002,103.845222],[30.36821,103.844131],[30.36706,103.843628],[30.364889,103.842949],[30.362579,103.842438],[30.359209,103.841759],[30.35545,103.841057],[30.351959,103.840683],[30.349331,103.83992],[30.34514,103.838531],[30.342319,103.83725],[30.339621,103.836571],[30.336281,103.835983],[30.332951,103.835632],[30.32992,103.835281],[30.32859,103.835083],[30.3276,103.834839],[30.32691,103.834572],[30.326309,103.834229],[30.325581,103.833733],[30.32482,103.833267],[30.32445,103.833092],[30.324329,103.833061],[30.323629,103.832787],[30.32313,103.832687],[30.322559,103.832611],[30.32193,103.832611],[30.3211,103.83271],[30.32037,103.832901],[30.319811,103.833107],[30.319309,103.833397],[30.318569,103.8339],[30.318041,103.834328],[30.317631,103.834663],[30.31662,103.835457],[30.31559,103.835968],[30.3148,103.836304],[30.31304,103.83699],[30.311819,103.837433],[30.305599,103.839798],[30.303049,103.840767],[30.302441,103.841011],[30.301571,103.841316],[30.300711,103.841667],[30.300541,103.841743],[30.29854,103.842484],[30.29718,103.842903],[30.29463,103.843719],[30.293159,103.843903],[30.29126,103.844063],[30.28908,103.844002],[30.28517,103.843407],[30.279461,103.842461],[30.274309,103.84182],[30.272249,103.841682],[30.26882,103.841507],[30.263081,103.841637],[30.260481,103.841827],[30.25771,103.842117],[30.254551,103.842537],[30.252159,103.842957],[30.244909,103.844063],[30.238979,103.844971],[30.2346,103.845627],[30.228121,103.846626],[30.223459,103.847366],[30.21862,103.847878],[30.21557,103.848358],[30.21253,103.848862],[30.21196,103.848938],[30.21122,103.849037],[30.211149,103.849052],[30.21056,103.849129],[30.20863,103.849457],[30.206671,103.849739],[30.206619,103.849747],[30.20463,103.850037],[30.20118,103.850723],[30.19952,103.850739],[30.19763,103.850632],[30.195299,103.850273],[30.193661,103.849907],[30.192101,103.849403],[30.18655,103.847427],[30.18231,103.845909],[30.17621,103.843719],[30.170601,103.841721],[30.166719,103.840317],[30.161591,103.838501],[30.156549,103.83667],[30.15312,103.835442],[30.149229,103.83403],[30.14525,103.832611],[30.142139,103.831398],[30.139771,103.83033],[30.134809,103.827782],[30.13142,103.825974],[30.12595,103.82296],[30.12237,103.821037],[30.12002,103.819763],[30.11664,103.817947],[30.11326,103.816017],[30.111601,103.815163],[30.10816,103.813248],[30.1056,103.811852],[30.102711,103.810066],[30.099331,103.808411],[30.095301,103.806702],[30.09252,103.805687],[30.086599,103.80368],[30.08601,103.803482],[30.085569,103.803329],[30.08502,103.803139],[30.08182,103.80204],[30.081141,103.801811],[30.079639,103.8013],[30.07716,103.800453],[30.07605,103.800056],[30.074249,103.799438],[30.07411,103.799393],[30.07151,103.798538],[30.06843,103.797859],[30.06653,103.797302],[30.06459,103.796806],[30.062309,103.796303],[30.055731,103.795067],[30.050871,103.794098],[30.04826,103.793358],[30.046261,103.792587],[30.0441,103.791458],[30.042601,103.790527],[30.036551,103.786591],[30.03101,103.782967],[30.029051,103.781616],[30.024891,103.778503],[30.021879,103.775917],[30.0187,103.77298],[30.01498,103.769363],[30.013029,103.767441],[30.011021,103.765747],[30.009581,103.764793],[30.00824,103.764023],[30.00703,103.763443],[30.00528,103.762733],[30.004009,103.762444],[30.0023,103.762123],[30.00091,103.762047],[29.99885,103.762077],[29.996031,103.762238],[29.98945,103.762657],[29.98629,103.762863],[29.985081,103.762993],[29.983101,103.763489],[29.98243,103.763687],[29.9806,103.764481],[29.977921,103.765984],[29.97703,103.766487],[29.97328,103.768593],[29.97217,103.769096],[29.969801,103.769981],[29.969139,103.770142],[29.968201,103.770332],[29.965611,103.770554],[29.96287,103.770348],[29.96159,103.770027],[29.9582,103.769203],[29.956301,103.768723],[29.95241,103.767761],[29.94582,103.766167],[29.941891,103.764954],[29.938259,103.763428],[29.93232,103.760307],[29.9265,103.757187],[29.92123,103.754211],[29.9186,103.752403],[29.916189,103.75061],[29.9119,103.747131],[29.90592,103.742203],[29.90304,103.740356],[29.902201,103.739906],[29.90093,103.739372],[29.89822,103.738579],[29.89192,103.737061],[29.888399,103.735947],[29.886129,103.735092],[29.884081,103.734154],[29.88076,103.732521],[29.877239,103.730759],[29.87343,103.729156],[29.872789,103.728912],[29.86729,103.727081],[29.861521,103.725227],[29.8587,103.724289],[29.856159,103.723618],[29.854139,103.723183],[29.847811,103.72216],[29.84544,103.721687],[29.843941,103.72123],[29.842291,103.720627],[29.841141,103.720047],[29.839939,103.719368],[29.83886,103.718597],[29.834391,103.714973],[29.82803,103.709839],[29.824579,103.706779],[29.82353,103.705704],[29.818701,103.700737],[29.816549,103.699013],[29.81579,103.698471],[29.81492,103.69799],[29.81385,103.697479],[29.81284,103.697067],[29.81114,103.696518],[29.804569,103.694901],[29.801861,103.694099],[29.800591,103.693657],[29.79631,103.691856],[29.79286,103.690376],[29.78804,103.688293],[29.78281,103.686028],[29.7794,103.684883],[29.77482,103.683647],[29.771151,103.68325],[29.76623,103.682564],[29.7612,103.681862],[29.75733,103.680702],[29.752661,103.678726],[29.741501,103.673637],[29.735689,103.670433],[29.730261,103.667122],[29.728109,103.665894],[29.725889,103.665009],[29.723049,103.664223],[29.719179,103.663467],[29.71279,103.661957],[29.70635,103.660027],[29.70294,103.659363],[29.70014,103.659142],[29.68815,103.659363],[29.68462,103.659538],[29.68202,103.660202],[29.67861,103.661789],[29.669941,103.667168],[29.667179,103.669067],[29.66548,103.670013],[29.66226,103.671219],[29.65731,103.672684],[29.654421,103.673882],[29.651899,103.675377],[29.64912,103.677238],[29.64385,103.680489],[29.639219,103.682854],[29.63732,103.683731],[29.63269,103.685913],[29.629339,103.687523],[29.626249,103.68943],[29.62406,103.690987],[29.618151,103.695602],[29.61622,103.696747],[29.61463,103.697456],[29.61256,103.69812],[29.611,103.698418],[29.60833,103.698517],[29.59409,103.697853],[29.59317,103.697777],[29.59227,103.697708],[29.590639,103.697578],[29.589661,103.697533],[29.588791,103.697472],[29.588249,103.697449],[29.57856,103.697304],[29.5669,103.703148],[29.545259,103.705719],[29.533911,103.709663],[29.5194,103.710701],[29.50877,103.719643],[29.49684,103.726669],[29.47427,103.734573],[29.463039,103.741623],[29.456329,103.746758],[29.44392,103.752083],[29.435089,103.758949],[29.42598,103.763763],[29.41267,103.773537],[29.407921,103.7761],[29.388491,103.777473],[29.381571,103.779373],[29.375561,103.784538],[29.367929,103.790733],[29.359091,103.80069],[29.352209,103.809097],[29.335911,103.826767],[29.318411,103.840843],[29.305571,103.847687],[29.294029,103.850273],[29.289061,103.853722],[29.285049,103.858421],[29.28236,103.861847],[29.278641,103.865082],[29.27508,103.866959],[29.27075,103.867813],[29.266239,103.869019],[29.262159,103.871269],[29.25914,103.875252],[29.256281,103.880081],[29.254311,103.88562],[29.25462,103.892014],[29.25462,103.896103],[29.25388,103.89949],[29.25211,103.902519],[29.24992,103.903862],[29.24637,103.904198],[29.239189,103.902817],[29.2363,103.903],[29.2334,103.904572],[29.22904,103.90992],[29.22484,103.915077],[29.22064,103.922813],[29.217951,103.927429],[29.21423,103.930832],[29.210199,103.933403],[29.20557,103.936142],[29.201851,103.936989],[29.19854,103.937851],[29.19643,103.938721],[29.192829,103.940613],[29.18956,103.942139],[29.18597,103.942307],[29.18281,103.943001],[29.178619,103.944717],[29.171591,103.945229],[29.16573,103.945923],[29.161699,103.947372],[29.160009,103.947983],[29.158831,103.948608],[29.15626,103.949867],[29.152901,103.951424],[29.149111,103.953827],[29.1474,103.955566],[29.146151,103.957626],[29.145109,103.960457],[29.142111,103.970154],[29.14106,103.973381],[29.139879,103.975868],[29.13899,103.976921],[29.136841,103.97908],[29.134291,103.981583],[29.13253,103.984039],[29.13093,103.986557],[29.12966,103.987846],[29.12866,103.988503],[29.127199,103.98938],[29.125521,103.990341],[29.124041,103.991127],[29.119749,103.993317],[29.11607,103.995277],[29.11408,103.996292],[29.112249,103.997368],[29.11076,103.998611],[29.10943,104.000572],[29.108459,104.002899],[29.107861,104.005363],[29.107149,104.009163],[29.106421,104.012009],[29.10582,104.014008],[29.104271,104.017776],[29.103621,104.019836],[29.10293,104.023308],[29.102461,104.025742],[29.10177,104.027687],[29.100349,104.030693],[29.099409,104.032883],[29.098749,104.034416],[29.09796,104.036942],[29.097639,104.038231],[29.097269,104.039864],[29.09687,104.041733],[29.096081,104.043922],[29.09543,104.044937],[29.094481,104.04641],[29.093491,104.047684],[29.092251,104.049271],[29.09111,104.051208],[29.090521,104.053123],[29.09025,104.054497],[29.090191,104.055412],[29.09095,104.06636],[29.08976,104.070282],[29.086451,104.075089],[29.084789,104.082336],[29.08194,104.09523],[29.08194,104.100754],[29.083441,104.1138],[29.083441,104.123207],[29.08194,104.130234],[29.081051,104.137589],[29.078979,104.141144],[29.074051,104.144547],[29.07147,104.146637],[29.069349,104.150803],[29.0674,104.15818],[29.06502,104.162086],[29.06082,104.166382],[29.057659,104.171707],[29.053459,104.177032],[29.050289,104.182549],[29.04789,104.189774],[29.044889,104.195938],[29.042179,104.201973],[29.03993,104.212639],[29.03933,104.220207],[29.03903,104.228256],[29.03784,104.231812],[29.03484,104.236618],[29.028379,104.253113],[29.026449,104.257019],[29.021049,104.261993],[29.01655,104.268517],[29.01055,104.274857],[29.00544,104.280022],[29.00108,104.287064],[28.99402,104.295143],[28.98967,104.302856],[28.98292,104.309708],[28.97978,104.313469],[28.970779,104.318787],[28.95965,104.328072],[28.95751,104.330688],[28.9533,104.345627],[28.949699,104.352333],[28.94536,104.363281],[28.933331,104.374786],[28.93166,104.380173],[28.93046,104.396652],[28.928961,104.401611],[28.92506,104.414322],[28.92205,104.426697],[28.92115,104.433708],[28.91231,104.449966],[28.905689,104.457191],[28.902519,104.467171],[28.89502,104.482246],[28.8881,104.49015],[28.88599,104.496696],[28.88163,104.504936],[28.88027,104.513527],[28.873369,104.529999],[28.870211,104.537712],[28.86569,104.545631],[28.864491,104.554916],[28.860729,104.567627],[28.859831,104.576729],[28.857719,104.585152],[28.85787,104.598732],[28.857719,104.609558],[28.859831,104.621941],[28.861771,104.631523],[28.86043,104.638496],[28.857889,104.644302],[28.85685,104.64566],[28.856409,104.645889],[28.855829,104.645912],[28.85532,104.645851],[28.8547,104.645592],[28.854259,104.645401],[28.85355,104.644783],[28.85206,104.6436],[28.85038,104.642418],[28.84877,104.641296],[28.847361,104.64032],[28.84576,104.639198],[28.84403,104.637993],[28.84247,104.636917],[28.84119,104.636147],[28.839411,104.63517],[28.838369,104.634666],[28.83795,104.634483],[28.83754,104.634277],[28.83667,104.633926],[28.836451,104.633842],[28.83535,104.6334],[28.83428,104.63295],[28.833019,104.632332],[28.832069,104.631706],[28.83111,104.630867],[28.830311,104.629936],[28.830179,104.629784],[28.829399,104.628593],[28.82859,104.627098],[28.82773,104.625526],[28.82724,104.624779],[28.826429,104.623734],[28.82542,104.622673],[28.823549,104.621033],[28.82159,104.619324],[28.820299,104.618202],[28.81879,104.61689],[28.8176,104.615837],[28.816589,104.61496],[28.81525,104.6138],[28.81423,104.612862],[28.81304,104.611588],[28.811781,104.610023],[28.81085,104.608841],[28.809839,104.607529],[28.80899,104.606438],[28.80829,104.605591],[28.80397,104.599716],[28.79163,104.60006],[28.77869,104.590103],[28.768459,104.583923],[28.764999,104.582039],[28.75341,104.570534],[28.7498,104.564194],[28.741831,104.551826],[28.73023,104.546158],[28.723009,104.535347],[28.71352,104.533112],[28.71097,104.53157],[28.70705,104.521606],[28.703291,104.519379],[28.69832,104.519897],[28.68597,104.524361],[28.68507,104.523331],[28.682211,104.520752],[28.672421,104.509598],[28.66684,104.501183],[28.664129,104.500328],[28.65494,104.501701],[28.651779,104.500839],[28.63928,104.496384],[28.635811,104.493629],[28.62888,104.483849],[28.62285,104.476982],[28.61788,104.467537],[28.608089,104.457916],[28.599489,104.44368],[28.599649,104.435951],[28.59844,104.429077],[28.600401,104.421021],[28.601,104.411232],[28.603109,104.394073],[28.603109,104.384453],[28.59889,104.372437],[28.587891,104.364723],[28.56769,104.354424],[28.563009,104.348747],[28.56241,104.339653],[28.564819,104.332947],[28.564671,104.32798],[28.558189,104.323517],[28.549589,104.320587],[28.543711,104.312363],[28.544621,104.305489],[28.544769,104.295532],[28.53949,104.285919],[28.53919,104.276817],[28.542509,104.26532],[28.551399,104.260002],[28.55744,104.260857],[28.561199,104.257263],[28.563009,104.246437],[28.562111,104.240433],[28.555321,104.22876],[28.55216,104.226868],[28.5511,104.22155],[28.54492,104.213654],[28.54055,104.20919],[28.536169,104.200607],[28.536631,104.192368],[28.532709,104.189102],[28.52652,104.187729],[28.523661,104.184471],[28.51038,104.181381],[28.502541,104.186867],[28.49575,104.186363],[28.49379,104.184471],[28.491529,104.186012],[28.48896,104.190483],[28.484739,104.192879],[28.48217,104.192368],[28.47765,104.190987],[28.472059,104.191681],[28.46904,104.193222],[28.46467,104.192879],[28.45742,104.191849],[28.45561,104.192711],[28.45335,104.195969],[28.44837,104.196136],[28.446711,104.195107],[28.45335,104.187393],[28.45471,104.190132],[28.45335,104.192543],[28.451691,104.194427],[28.449881,104.194427],[28.44656,104.192711],[28.445049,104.187393],[28.44293,104.185837],[28.438709,104.184982],[28.436899,104.183441],[28.435989,104.179657],[28.43478,104.178802],[28.43207,104.179657],[28.430401,104.178978],[28.429199,104.177429],[28.427691,104.176743],[28.42573,104.176918],[28.41984,104.175369],[28.39855,104.157013],[28.39492,104.150993],[28.3916,104.147049],[28.38798,104.147217],[28.384649,104.147392],[28.38254,104.149452],[28.37635,104.150139],[28.372419,104.15168],[28.36698,104.152367],[28.35928,104.149803],[28.35656,104.14756],[28.350519,104.14035],[28.34553,104.13829],[28.340851,104.133324],[28.33481,104.132797],[28.328911,104.13623],[28.323021,104.135033],[28.318029,104.135536],[28.31501,104.134506],[28.3067,104.136063],[28.30216,104.138474],[28.298389,104.13726],[28.2943,104.138809],[28.2875,104.144302],[28.27949,104.143784],[28.27541,104.145683],[28.268,104.153397],[28.26059,104.152367],[28.254551,104.144989],[28.24925,104.141899],[28.24729,104.140869],[28.244869,104.137444],[28.228689,104.140869],[28.205839,104.139839],[28.204781,104.134506],[28.201611,104.131599],[28.202209,104.124557],[28.200399,104.118378],[28.19994,104.111],[28.188601,104.103104],[28.184361,104.1007],[28.17906,104.096581],[28.17725,104.092461],[28.17165,104.093658],[28.165291,104.094002],[28.16151,104.092796],[28.15213,104.084389],[28.14592,104.083191],[28.141991,104.082672],[28.13608,104.072548],[28.132151,104.072723],[28.1273,104.073227],[28.1273,104.079758],[28.1273,104.082848],[28.12488,104.083878],[28.119579,104.080788],[28.11731,104.081642],[28.114429,104.086792],[28.11458,104.090569],[28.09354,104.131943],[28.09066,104.134003],[28.08672,104.133141],[28.0846,104.133827],[28.074301,104.141899],[28.06855,104.141899],[28.063551,104.144989],[28.05961,104.144653],[28.053101,104.145844],[28.046881,104.143784],[28.04492,104.142593],[28.040979,104.132111],[28.03643,104.125237],[28.03734,104.121811],[28.03931,104.119408],[28.04492,104.104134],[28.04295,104.097778],[28.039459,104.089882],[28.036131,104.079582],[28.027639,104.075638],[28.023701,104.076317],[28.01643,104.066193],[28.01552,104.052979],[28.01749,104.047653],[28.02037,104.036842],[28.01128,104.010918],[28.00491,104.006973],[28.00279,104.00251],[27.992331,103.988777],[27.99157,103.974182],[27.97747,103.962509],[27.97505,103.953934],[27.966101,103.948952],[27.96595,103.941223],[27.963221,103.935913],[27.95549,103.935043],[27.94791,103.919937],[27.93684,103.917374],[27.928499,103.916679],[27.916361,103.915131],[27.904831,103.913254],[27.89315,103.909286],[27.89012,103.912041],[27.884649,103.910843],[27.874941,103.906197],[27.86569,103.89917],[27.861441,103.897621],[27.854151,103.889557],[27.85294,103.88784],[27.853701,103.88475],[27.8496,103.876343],[27.846411,103.875481],[27.84565,103.873253],[27.843229,103.872223],[27.840639,103.867073],[27.83503,103.867409],[27.831989,103.864151],[27.828501,103.863121],[27.824551,103.857109],[27.821369,103.855049],[27.817869,103.855217],[27.81332,103.856941],[27.81135,103.859512],[27.80846,103.858139],[27.804661,103.861923],[27.799959,103.863289],[27.797831,103.864838],[27.79814,103.868271],[27.787661,103.878403],[27.7869,103.880966],[27.77627,103.880287],[27.7749,103.883202],[27.7708,103.883202],[27.76852,103.88681],[27.75865,103.886978],[27.7547,103.88475],[27.749531,103.884918],[27.74634,103.887154],[27.74361,103.887321],[27.73844,103.891273],[27.73601,103.89299],[27.73358,103.895218],[27.732059,103.89196],[27.72872,103.892303],[27.725531,103.896927],[27.715651,103.891441],[27.712761,103.89196],[27.70896,103.889214],[27.703951,103.88681],[27.701361,103.887497],[27.698931,103.886467],[27.696199,103.886292],[27.69376,103.884918],[27.689659,103.884064],[27.686621,103.880463],[27.684799,103.879768],[27.682671,103.877876],[27.680389,103.877022],[27.67902,103.875481],[27.67598,103.874786],[27.67066,103.866722],[27.667311,103.865181],[27.66564,103.856598],[27.66412,103.852303],[27.65789,103.848183],[27.652719,103.846123],[27.65028,103.843552],[27.64694,103.843552],[27.64283,103.842857],[27.63949,103.839943],[27.63797,103.837029],[27.631729,103.83239],[27.628229,103.831017],[27.626101,103.827583],[27.623819,103.826393],[27.623671,103.82209],[27.621849,103.820717],[27.62261,103.816772],[27.61956,103.815567],[27.618191,103.811279],[27.61515,103.806824],[27.61059,103.80407],[27.605419,103.801147],[27.59964,103.800461],[27.59507,103.800461],[27.593861,103.801491],[27.592939,103.803207],[27.590811,103.804916],[27.588989,103.808357],[27.587311,103.807671],[27.588989,103.805267],[27.59005,103.80304],[27.59157,103.801826],[27.59157,103.798576],[27.592939,103.798576],[27.5931,103.795998],[27.587009,103.785873],[27.586399,103.783813],[27.58518,103.783813],[27.58518,103.781921],[27.582291,103.777107],[27.580311,103.774544],[27.57818,103.773682],[27.57773,103.771797],[27.57362,103.770416],[27.573931,103.768883],[27.57469,103.768021],[27.57453,103.765099],[27.57453,103.763039],[27.57469,103.761841],[27.57316,103.759781],[27.57073,103.758583],[27.56982,103.756172],[27.566931,103.756172],[27.56312,103.753937],[27.56053,103.754967],[27.55475,103.754112],[27.54973,103.752571],[27.54668,103.752739],[27.53923,103.748962],[27.53344,103.747589],[27.530701,103.746902],[27.52355,103.739182],[27.51639,103.736778],[27.51137,103.739182],[27.506189,103.740211],[27.50436,103.739349],[27.50071,103.734718],[27.49873,103.730423],[27.495081,103.729393],[27.494619,103.726646],[27.493549,103.726822],[27.491421,103.728203],[27.476191,103.728706],[27.454559,103.719437],[27.44207,103.725273],[27.41617,103.733856],[27.3988,103.720993],[27.38965,103.717033],[27.36128,103.693459],[27.35232,103.692528],[27.351521,103.692436],[27.34355,103.691467],[27.31587,103.685341],[27.29833,103.681534],[27.29615,103.68148],[27.294399,103.681831],[27.28997,103.683388],[27.2887,103.683456],[27.28771,103.683289],[27.269011,103.676178],[27.268061,103.67598],[27.25794,103.676392],[27.25091,103.676598],[27.24836,103.676224],[27.217649,103.667976],[27.210899,103.667221],[27.20487,103.667038],[27.200251,103.666199],[27.196159,103.664726],[27.19311,103.663017],[27.191919,103.662132],[27.182261,103.651466],[27.179991,103.649803],[27.1779,103.648628],[27.175831,103.647827],[27.17329,103.647232],[27.17054,103.647072],[27.167339,103.647293],[27.164,103.647942],[27.15872,103.649628],[27.154169,103.651733],[27.152031,103.652283],[27.147369,103.652802],[27.143101,103.653908],[27.14143,103.653961],[27.14053,103.65387],[27.131121,103.650887],[27.129351,103.650627],[27.127211,103.650993],[27.12598,103.651718],[27.125299,103.65181],[27.124319,103.651947],[27.12398,103.651947],[27.12299,103.651672],[27.12096,103.651001],[27.113211,103.649933],[27.11253,103.649673],[27.110041,103.648109],[27.10898,103.647667],[27.108009,103.647499],[27.104919,103.647614],[27.103239,103.647346],[27.10194,103.646919],[27.09943,103.645592],[27.09831,103.645218],[27.09693,103.645073],[27.095551,103.645157],[27.09359,103.64563],[27.091999,103.646187],[27.088079,103.647491],[27.08704,103.647629],[27.086451,103.647598],[27.08568,103.647453],[27.084551,103.646973],[27.083851,103.6465],[27.083,103.645699],[27.08264,103.645157],[27.082161,103.644569],[27.080271,103.641853],[27.07803,103.639061],[27.07766,103.63871],[27.077499,103.638573],[27.075359,103.636833],[27.07407,103.636208],[27.07329,103.636017],[27.072309,103.636047],[27.071739,103.636208],[27.07119,103.636482],[27.070351,103.637131],[27.0693,103.638069],[27.06863,103.638474],[27.068081,103.638657],[27.066259,103.638893],[27.065479,103.639137],[27.06492,103.639473],[27.064301,103.640038],[27.06389,103.640556],[27.06365,103.640984],[27.06341,103.641617],[27.063271,103.642319],[27.063351,103.645111],[27.06321,103.646027],[27.06299,103.646698],[27.06267,103.647324],[27.06238,103.647667],[27.06175,103.648239],[27.060841,103.64872],[27.06019,103.648888],[27.059589,103.648903],[27.058981,103.648804],[27.05514,103.647217],[27.05409,103.647003],[27.052629,103.647003],[27.051451,103.647293],[27.05052,103.647758],[27.04999,103.648079],[27.047319,103.650131],[27.045959,103.650383],[27.04484,103.650269],[27.043961,103.649933],[27.04318,103.649384],[27.04158,103.647636],[27.040319,103.646759],[27.039061,103.646202],[27.03179,103.644981],[27.0299,103.644348],[27.02809,103.643211],[27.027651,103.64283],[27.026739,103.641541],[27.02565,103.63929],[27.02478,103.638153],[27.023161,103.636528],[27.022461,103.635483],[27.02191,103.634117],[27.0217,103.632423],[27.02203,103.623558],[27.021061,103.613472],[27.02072,103.612587],[27.02059,103.612259],[27.020491,103.612167],[27.020229,103.61161],[27.01918,103.610069],[27.018311,103.6092],[27.01779,103.60881],[27.017229,103.608498],[27.015921,103.607979],[27.01515,103.607826],[27.0135,103.607803],[27.01181,103.608093],[27.011709,103.608093],[27.010019,103.608276],[27.00703,103.607964],[27.005871,103.608063],[27.00322,103.608597],[27.002371,103.60862],[27.00173,103.608582],[27.0007,103.608337],[26.999479,103.607758],[26.99892,103.607384],[26.99749,103.605911],[26.996691,103.604797],[26.99585,103.603188],[26.995411,103.601929],[26.99506,103.599991],[26.994711,103.594978],[26.994341,103.593391],[26.99378,103.592201],[26.990351,103.588181],[26.98736,103.583832],[26.98568,103.582413],[26.984591,103.581718],[26.98411,103.581467],[26.98325,103.581146],[26.98291,103.5811],[26.982059,103.58091],[26.977859,103.581146],[26.976681,103.580917],[26.97571,103.580482],[26.97448,103.579628],[26.97374,103.578789],[26.972731,103.577187],[26.97262,103.577072],[26.96594,103.565643],[26.965549,103.564171],[26.965549,103.561852],[26.96533,103.560837],[26.964781,103.559708],[26.9634,103.55764],[26.96254,103.556923],[26.96184,103.556503],[26.96139,103.556374],[26.951269,103.55677],[26.949631,103.55658],[26.94891,103.556358],[26.94841,103.556068],[26.947809,103.55555],[26.947411,103.555054],[26.94702,103.554291],[26.946119,103.5513],[26.945709,103.550461],[26.94334,103.547234],[26.94191,103.544724],[26.94112,103.543762],[26.94002,103.542824],[26.93877,103.542023],[26.93788,103.541611],[26.937149,103.541367],[26.93611,103.541443],[26.934299,103.541588],[26.933229,103.541473],[26.932819,103.541367],[26.932211,103.541054],[26.93066,103.539978],[26.93,103.539673],[26.92931,103.539543],[26.928841,103.539528],[26.928129,103.539642],[26.926069,103.540443],[26.925381,103.540588],[26.9245,103.540611],[26.923599,103.540489],[26.92186,103.539993],[26.92103,103.539917],[26.92061,103.539963],[26.919809,103.540237],[26.919241,103.540558],[26.9184,103.541283],[26.91699,103.542778],[26.915291,103.544022],[26.914021,103.544777],[26.91256,103.545868],[26.91078,103.547691],[26.907909,103.551788],[26.90708,103.552597],[26.9065,103.552979],[26.90564,103.553337],[26.904961,103.553467],[26.903021,103.553612],[26.90229,103.55378],[26.901381,103.554176],[26.90003,103.554817],[26.899111,103.555107],[26.898161,103.555237],[26.89669,103.555199],[26.89435,103.554764],[26.89176,103.553963],[26.89102,103.553658],[26.890181,103.553383],[26.888451,103.552727],[26.888281,103.552612],[26.882441,103.549599],[26.8783,103.547081],[26.87499,103.545753],[26.873461,103.545357],[26.870871,103.544884],[26.86898,103.544853],[26.866899,103.54525],[26.86474,103.545937],[26.863489,103.546127],[26.86207,103.546089],[26.86063,103.545738],[26.85984,103.545372],[26.85869,103.544601],[26.85038,103.53727],[26.84799,103.535637],[26.846399,103.534782],[26.84396,103.533813],[26.83536,103.531258],[26.8347,103.530968],[26.83407,103.530586],[26.83326,103.530037],[26.832041,103.528839],[26.83091,103.527328],[26.83005,103.525391],[26.82686,103.516579],[26.82457,103.512283],[26.821711,103.508636],[26.820379,103.507294],[26.81715,103.504631],[26.814951,103.502937],[26.812519,103.500366],[26.810841,103.498398],[26.809139,103.496788],[26.80666,103.495071],[26.80418,103.493851],[26.801371,103.493073],[26.79701,103.492371],[26.795879,103.492073],[26.79248,103.490677],[26.79015,103.489326],[26.78669,103.48716],[26.783381,103.485764],[26.78071,103.485107],[26.77058,103.482986],[26.766041,103.481598],[26.76531,103.481339],[26.76446,103.480957],[26.763821,103.480339],[26.76302,103.479523],[26.762051,103.478531],[26.761669,103.478287],[26.76128,103.478104],[26.76041,103.477943],[26.759781,103.477966],[26.759159,103.478119],[26.75857,103.478416],[26.757839,103.478989],[26.75737,103.479553],[26.75712,103.479958],[26.75683,103.480637],[26.756651,103.481377],[26.75659,103.482094],[26.756491,103.483223],[26.75629,103.483994],[26.756069,103.484467],[26.755079,103.486023],[26.753731,103.487671],[26.751841,103.489517],[26.75123,103.489983],[26.750151,103.490578],[26.74922,103.490883],[26.74822,103.491028],[26.747219,103.490982],[26.746269,103.490784],[26.744961,103.490211],[26.743071,103.489067],[26.742649,103.488876],[26.74197,103.488708],[26.74106,103.48864],[26.737221,103.488533],[26.737341,103.487473],[26.736679,103.486862],[26.736601,103.486687],[26.735531,103.485252],[26.734989,103.484703],[26.73424,103.484253],[26.732981,103.483849],[26.732,103.483582],[26.731449,103.483307],[26.7311,103.483078],[26.730499,103.482452],[26.730009,103.481682],[26.729321,103.480247],[26.728939,103.479683],[26.728479,103.479187],[26.728121,103.478951],[26.726521,103.478203],[26.72613,103.477951],[26.72559,103.477501],[26.725121,103.476929],[26.723829,103.474678],[26.72327,103.474121],[26.72208,103.473419],[26.721121,103.472977],[26.72057,103.472603],[26.71909,103.471123],[26.718109,103.470413],[26.716681,103.469528],[26.715919,103.468903],[26.71526,103.468147],[26.710609,103.461243],[26.708389,103.458847],[26.70776,103.457916],[26.70702,103.456749],[26.70652,103.456177],[26.705839,103.455643],[26.704889,103.455193],[26.70277,103.45462],[26.701481,103.454048],[26.691151,103.446541],[26.68638,103.443703],[26.685579,103.443001],[26.68322,103.440132],[26.67824,103.435547],[26.677401,103.43454],[26.67481,103.430267],[26.674141,103.429466],[26.67314,103.428673],[26.670521,103.426804],[26.669189,103.425629],[26.6684,103.424561],[26.668381,103.424461],[26.666929,103.423126],[26.666401,103.422836],[26.66445,103.420998],[26.663811,103.420197],[26.663759,103.41996],[26.66337,103.419403],[26.660549,103.416901],[26.65888,103.414871],[26.65806,103.414238],[26.654551,103.412773],[26.65377,103.41227],[26.65312,103.411682],[26.65242,103.410744],[26.650511,103.407066],[26.65012,103.406532],[26.64963,103.406036],[26.64196,103.400917],[26.638769,103.399353],[26.636061,103.398041],[26.634979,103.397331],[26.63376,103.396317],[26.63225,103.394592],[26.627741,103.389038],[26.62705,103.387947],[26.624969,103.382874],[26.62381,103.379868],[26.623381,103.379211],[26.622931,103.37886],[26.622601,103.378677],[26.62208,103.37851],[26.62118,103.378342],[26.620661,103.378143],[26.620199,103.3778],[26.618971,103.376579],[26.61879,103.376266],[26.6173,103.374977],[26.616819,103.374672],[26.61614,103.374443],[26.615271,103.374283],[26.614929,103.374153],[26.614441,103.373901],[26.613911,103.373398],[26.613041,103.372147],[26.612579,103.37178],[26.61199,103.371429],[26.610559,103.37085],[26.609949,103.370407],[26.60861,103.368393],[26.608141,103.367996],[26.60759,103.36776],[26.607281,103.367691],[26.60648,103.367706],[26.604321,103.368393],[26.603701,103.368401],[26.60276,103.368134],[26.602051,103.367638],[26.600719,103.3666],[26.600389,103.366402],[26.599649,103.366127],[26.594931,103.365623],[26.59449,103.365494],[26.59387,103.365181],[26.59334,103.364754],[26.593019,103.364357],[26.59199,103.363037],[26.58865,103.358833],[26.588079,103.358269],[26.587099,103.357651],[26.586571,103.357437],[26.585621,103.357277],[26.584681,103.357353],[26.58441,103.357368],[26.58337,103.357529],[26.582121,103.357491],[26.58202,103.35746],[26.57988,103.35688],[26.57847,103.356453],[26.576639,103.356483],[26.57616,103.356628],[26.57501,103.357262],[26.573641,103.358566],[26.572889,103.360184],[26.57221,103.361847],[26.57144,103.362839],[26.570829,103.363373],[26.570009,103.363831],[26.56896,103.36412],[26.56839,103.364113],[26.56765,103.364037],[26.56732,103.363983],[26.56605,103.36335],[26.565611,103.363037],[26.561211,103.358841],[26.56068,103.358238],[26.55739,103.352203],[26.55625,103.350777],[26.555281,103.349998],[26.551029,103.347748],[26.54763,103.345238],[26.543949,103.342262],[26.54328,103.341537],[26.54122,103.338219],[26.5352,103.32708],[26.5343,103.326233],[26.53418,103.326141],[26.5306,103.324722],[26.53013,103.324417],[26.52984,103.324158],[26.529591,103.323853],[26.52923,103.323128],[26.529131,103.322723],[26.529091,103.321892],[26.52928,103.32029],[26.529249,103.319679],[26.529091,103.319107],[26.52883,103.318604],[26.5261,103.315666],[26.5256,103.315247],[26.52487,103.314781],[26.52132,103.313271],[26.520399,103.313087],[26.51967,103.313087],[26.513321,103.313911],[26.512739,103.313904],[26.51181,103.31369],[26.511129,103.313377],[26.51038,103.312759],[26.5098,103.312019],[26.50769,103.307098],[26.506969,103.306129],[26.5065,103.305687],[26.505831,103.305313],[26.504841,103.305023],[26.499769,103.305023],[26.49926,103.304916],[26.49859,103.304657],[26.49827,103.304459],[26.49769,103.303886],[26.496719,103.302559],[26.49597,103.301826],[26.49544,103.301514],[26.494869,103.301292],[26.494061,103.301193],[26.49346,103.301247],[26.49209,103.301643],[26.487391,103.30336],[26.484831,103.303802],[26.484209,103.303802],[26.483999,103.303772],[26.482771,103.303909],[26.481871,103.304153],[26.480391,103.304916],[26.47942,103.305557],[26.4783,103.306091],[26.47756,103.306236],[26.477131,103.306213],[26.476629,103.306061],[26.476021,103.305687],[26.474951,103.304581],[26.473909,103.303993],[26.47316,103.30378],[26.472469,103.303741],[26.471979,103.303833],[26.47183,103.303886],[26.47172,103.304001],[26.471331,103.304131],[26.470421,103.304176],[26.46986,103.304047],[26.46932,103.303772],[26.468941,103.303452],[26.468309,103.302727],[26.466181,103.299278],[26.46574,103.298576],[26.46533,103.29808],[26.46483,103.297737],[26.464491,103.297577],[26.463921,103.297493],[26.46352,103.297531],[26.462311,103.297974],[26.460239,103.298714],[26.459629,103.298843],[26.459009,103.298889],[26.45858,103.298851],[26.457951,103.298683],[26.456949,103.298157],[26.456591,103.297897],[26.456091,103.297447],[26.455721,103.296959],[26.45507,103.295624],[26.453449,103.290291],[26.4531,103.289574],[26.45273,103.28907],[26.452141,103.288483],[26.447451,103.285461],[26.447041,103.285057],[26.44672,103.284607],[26.44651,103.284088],[26.44643,103.283531],[26.44644,103.282013],[26.44626,103.281258],[26.44591,103.280571],[26.442511,103.276314],[26.44105,103.274773],[26.42713,103.267792],[26.42532,103.266891],[26.424749,103.266602],[26.424561,103.266487],[26.393221,103.250977],[26.391689,103.250366],[26.391001,103.250252],[26.390511,103.250252],[26.38979,103.250359],[26.389311,103.250511],[26.388599,103.250839],[26.38796,103.251289],[26.387421,103.251831],[26.38199,103.258743],[26.380569,103.260162],[26.3787,103.261597],[26.37796,103.262077],[26.376129,103.262993],[26.374269,103.263718],[26.37236,103.264168],[26.36668,103.265137],[26.36566,103.26519],[26.36433,103.265091],[26.36381,103.264969],[26.36306,103.264641],[26.36236,103.264252],[26.359619,103.262039],[26.358789,103.261551],[26.35813,103.261337],[26.35747,103.261276],[26.355379,103.261307],[26.354601,103.261162],[26.34967,103.258942],[26.348619,103.25872],[26.34795,103.258759],[26.34745,103.258904],[26.34697,103.259163],[26.346371,103.259651],[26.34589,103.260277],[26.34553,103.261009],[26.34346,103.267906],[26.3433,103.269096],[26.343361,103.269836],[26.34374,103.271461],[26.3438,103.272087],[26.34333,103.27475],[26.34334,103.27597],[26.343531,103.277008],[26.34387,103.278038],[26.34478,103.280586],[26.344999,103.281326],[26.34659,103.285301],[26.346701,103.285789],[26.346741,103.28656],[26.346519,103.288887],[26.346769,103.292091],[26.34671,103.29287],[26.34654,103.29332],[26.344839,103.296158],[26.344681,103.296356],[26.34429,103.296669],[26.343599,103.296982],[26.34197,103.297363],[26.34129,103.297623],[26.3395,103.298767],[26.338619,103.299133],[26.334459,103.300262],[26.333811,103.300591],[26.333441,103.30088],[26.332121,103.302429],[26.328951,103.30632],[26.328211,103.307053],[26.327579,103.307518],[26.32666,103.307922],[26.32531,103.308357],[26.32243,103.309929],[26.32165,103.310471],[26.31884,103.314163],[26.31797,103.315041],[26.31698,103.315773],[26.315729,103.316521],[26.315001,103.317123],[26.31403,103.318253],[26.312361,103.320862],[26.31218,103.321312],[26.311239,103.325974],[26.31101,103.326736],[26.309771,103.329491],[26.309549,103.330276],[26.30946,103.330818],[26.30946,103.332451],[26.309401,103.332977],[26.309179,103.33374],[26.30858,103.334938],[26.3076,103.336472],[26.30689,103.338226],[26.30661,103.339333],[26.30633,103.340973],[26.30619,103.341461],[26.305849,103.342163],[26.305531,103.342537],[26.30406,103.343918],[26.30307,103.344681],[26.30007,103.347366],[26.298969,103.348038],[26.29743,103.348663],[26.294941,103.349159],[26.294559,103.349297],[26.29011,103.352043],[26.28854,103.353416],[26.287861,103.354118],[26.287491,103.354378],[26.286869,103.354637],[26.28377,103.355232],[26.283331,103.355377],[26.28273,103.355713],[26.280279,103.358047],[26.279699,103.358467],[26.277109,103.359993],[26.2764,103.360291],[26.27462,103.360687],[26.273331,103.36097],[26.27282,103.361153],[26.27235,103.361397],[26.27169,103.361893],[26.26902,103.364273],[26.26837,103.36467],[26.2679,103.364868],[26.267389,103.36499],[26.266621,103.36499],[26.26524,103.364647],[26.26186,103.363678],[26.261129,103.363548],[26.260429,103.363541],[26.26001,103.363602],[26.25942,103.363823],[26.257891,103.364769],[26.257271,103.365021],[26.256359,103.365173],[26.253691,103.365349],[26.25301,103.365479],[26.24645,103.367821],[26.244711,103.368767],[26.24288,103.370148],[26.238939,103.373947],[26.2377,103.375526],[26.236839,103.377007],[26.235729,103.379669],[26.235359,103.38105],[26.234341,103.389236],[26.23395,103.390549],[26.23344,103.39151],[26.233101,103.391953],[26.23229,103.392693],[26.23144,103.393372],[26.230499,103.394333],[26.229891,103.395218],[26.22916,103.396698],[26.22888,103.397476],[26.228121,103.400261],[26.227501,103.40213],[26.227301,103.402931],[26.227091,103.403427],[26.226641,103.404121],[26.22611,103.404709],[26.22547,103.405182],[26.224661,103.405533],[26.221069,103.406113],[26.219521,103.406143],[26.218451,103.40596],[26.21789,103.405693],[26.215919,103.404037],[26.21559,103.403633],[26.21291,103.401031],[26.21072,103.399094],[26.207279,103.39798],[26.203951,103.398811],[26.2036,103.399063],[26.203199,103.3992],[26.202829,103.399406],[26.20146,103.399971],[26.200609,103.400146],[26.19997,103.400192],[26.19912,103.400063],[26.19795,103.399513],[26.196461,103.398643],[26.195471,103.398148],[26.19492,103.397797],[26.194241,103.397324],[26.194031,103.397247],[26.19183,103.396027],[26.190729,103.39579],[26.189899,103.395866],[26.188931,103.396301],[26.18684,103.397659],[26.1859,103.39827],[26.18556,103.398376],[26.183399,103.398598],[26.18268,103.398857],[26.181829,103.399399],[26.18091,103.400352],[26.178711,103.403313],[26.17831,103.403709],[26.177891,103.403923],[26.177549,103.403999],[26.177019,103.403893],[26.176781,103.403763],[26.176559,103.403557],[26.176319,103.403137],[26.17622,103.402802],[26.17618,103.402283],[26.176229,103.401787],[26.176371,103.4011],[26.17642,103.400589],[26.17622,103.398972],[26.17621,103.397568],[26.17647,103.39576],[26.176189,103.393623],[26.175739,103.391579],[26.175739,103.391418],[26.17531,103.390739],[26.174931,103.390457],[26.174641,103.390373],[26.174351,103.390373],[26.17407,103.390442],[26.173679,103.390701],[26.173361,103.391098],[26.173,103.391907],[26.172779,103.392677],[26.172409,103.393379],[26.17231,103.393494],[26.17207,103.393646],[26.171659,103.393723],[26.168779,103.393097],[26.168171,103.392822],[26.16744,103.392273],[26.167351,103.392174],[26.166031,103.391159],[26.16197,103.38813],[26.160919,103.387016],[26.160311,103.386307],[26.15793,103.384117],[26.157539,103.383659],[26.155451,103.380707],[26.154449,103.379318],[26.153799,103.377769],[26.153231,103.375031],[26.153231,103.374878],[26.15317,103.374748],[26.15295,103.374046],[26.152229,103.373108],[26.151541,103.372322],[26.15114,103.371468],[26.1509,103.370163],[26.150761,103.369881],[26.15069,103.36956],[26.15045,103.369148],[26.14999,103.368767],[26.149561,103.368652],[26.14912,103.368683],[26.1486,103.368927],[26.147631,103.369682],[26.147181,103.369873],[26.14687,103.369904],[26.146391,103.369827],[26.14535,103.369431],[26.14488,103.36937],[26.144581,103.369408],[26.144341,103.36953],[26.14411,103.369728],[26.14381,103.370247],[26.143709,103.370888],[26.143721,103.372162],[26.1436,103.372597],[26.143379,103.373001],[26.1432,103.373222],[26.142719,103.373543],[26.14189,103.373787],[26.137711,103.373772],[26.136459,103.373596],[26.135691,103.373672],[26.13501,103.373833],[26.12385,103.377121],[26.122641,103.377708],[26.11801,103.381523],[26.116779,103.382263],[26.1161,103.38253],[26.11503,103.382759],[26.113741,103.382843],[26.111959,103.382561],[26.11124,103.382233],[26.110331,103.381683],[26.110001,103.381363],[26.108641,103.379333],[26.10817,103.378563],[26.107849,103.377998],[26.107479,103.377693],[26.10696,103.377563],[26.10442,103.377533],[26.10367,103.377296],[26.102921,103.376793],[26.102301,103.376068],[26.100321,103.372772],[26.099701,103.371986],[26.099489,103.371803],[26.09893,103.371521],[26.098669,103.371498],[26.098049,103.371613],[26.097521,103.371902],[26.096581,103.372757],[26.095949,103.373337],[26.09532,103.373833],[26.09458,103.3741],[26.09387,103.374077],[26.09329,103.373894],[26.090401,103.372589],[26.083139,103.368111],[26.082951,103.368011],[26.07933,103.364166],[26.078779,103.363388],[26.078369,103.362213],[26.078131,103.361214],[26.07766,103.360123],[26.07703,103.359161],[26.07538,103.356583],[26.07522,103.356468],[26.07472,103.356041],[26.074341,103.355797],[26.07395,103.355652],[26.07341,103.355598],[26.07279,103.35569],[26.066151,103.35788],[26.06604,103.357964],[26.06423,103.358704],[26.054621,103.363274],[26.05266,103.3638],[26.05201,103.364159],[26.051319,103.364777],[26.05094,103.365219],[26.050579,103.365707],[26.050171,103.366112],[26.049669,103.366417],[26.04929,103.366547],[26.048889,103.366623],[26.04748,103.36657],[26.04694,103.366669],[26.04641,103.36689],[26.045811,103.367363],[26.043739,103.369476],[26.042669,103.370308],[26.037701,103.373703],[26.03702,103.373978],[26.036551,103.374069],[26.035601,103.374107],[26.03249,103.37413],[26.030939,103.374496],[26.027519,103.375816],[26.02634,103.376213],[26.025709,103.376297],[26.02487,103.376244],[26.02202,103.375542],[26.015551,103.374832],[26.014351,103.374496],[26.01321,103.374023],[26.0124,103.373756],[26.011789,103.373688],[26.007721,103.373962],[26.00436,103.373741],[26.00349,103.37384],[26.000931,103.374496],[26.00028,103.374527],[25.99984,103.374474],[25.99917,103.374283],[25.99048,103.369667],[25.98843,103.368462],[25.987419,103.367493],[25.98374,103.362061],[25.98126,103.359642],[25.974859,103.354439],[25.97471,103.354286],[25.968161,103.348991],[25.967581,103.348373],[25.967051,103.347679],[25.96632,103.346207],[25.966,103.34536],[25.965891,103.344963],[25.965139,103.343102],[25.96468,103.3423],[25.96401,103.341583],[25.96048,103.339149],[25.95989,103.338921],[25.95927,103.33886],[25.95841,103.338966],[25.95583,103.339653],[25.954,103.339706],[25.95211,103.339279],[25.95129,103.339073],[25.95068,103.339043],[25.950279,103.339081],[25.949671,103.339279],[25.94873,103.339767],[25.94838,103.340057],[25.946369,103.342346],[25.945511,103.343246],[25.945009,103.343643],[25.944611,103.343849],[25.944201,103.343979],[25.943991,103.344009],[25.943371,103.343933],[25.942789,103.343681],[25.94227,103.343277],[25.941629,103.34256],[25.937929,103.337509],[25.93656,103.335693],[25.935539,103.334587],[25.934219,103.33329],[25.933281,103.33181],[25.93195,103.32885],[25.93116,103.327721],[25.93108,103.327606],[25.930941,103.327522],[25.93082,103.32737],[25.93,103.326981],[25.928551,103.326042],[25.92778,103.325394],[25.926069,103.323463],[25.925529,103.323059],[25.924589,103.322632],[25.92318,103.322243],[25.922449,103.3218],[25.921789,103.321243],[25.920389,103.319901],[25.920111,103.319733],[25.919769,103.319641],[25.91926,103.319649],[25.915279,103.321182],[25.9137,103.321838],[25.91114,103.321938],[25.91078,103.319809],[25.91044,103.316429],[25.910641,103.316177],[25.910789,103.315857],[25.911779,103.314079],[25.912121,103.313232],[25.912319,103.312576],[25.9126,103.310478],[25.913059,103.308723],[25.913099,103.308289],[25.912689,103.306068],[25.91288,103.303902],[25.912809,103.303436],[25.912411,103.302567],[25.91205,103.302177],[25.911591,103.301903],[25.91148,103.301888],[25.910851,103.301537],[25.910299,103.301361],[25.908951,103.300728],[25.9088,103.300598],[25.906731,103.299622],[25.905649,103.299858],[25.905439,103.300003],[25.905359,103.299957],[25.904671,103.300102],[25.903919,103.300034],[25.903509,103.299767],[25.90321,103.299316],[25.902201,103.295471],[25.90147,103.293877],[25.90085,103.293854],[25.90065,103.293762],[25.90052,103.293427],[25.900061,103.292648],[25.89992,103.291634],[25.899891,103.291107],[25.899771,103.290756],[25.899521,103.290352],[25.89922,103.290131],[25.899059,103.290092],[25.89883,103.290108],[25.89856,103.290039],[25.897209,103.290359],[25.8962,103.290253],[25.895651,103.289963],[25.89509,103.289436],[25.894699,103.288834],[25.894199,103.287666],[25.893629,103.287033],[25.893419,103.28688],[25.89274,103.286728],[25.89192,103.286789],[25.890381,103.287148],[25.8895,103.287239],[25.887739,103.286926],[25.88566,103.286507],[25.88493,103.286583],[25.883249,103.287277],[25.88265,103.287369],[25.881981,103.287216],[25.879101,103.28566],[25.87722,103.284523],[25.876011,103.284119],[25.871019,103.283287],[25.86895,103.283157],[25.86727,103.282509],[25.86611,103.281937],[25.865749,103.28183],[25.86347,103.281464],[25.86125,103.280663],[25.85948,103.280479],[25.856489,103.280434],[25.854349,103.280251],[25.8536,103.279984],[25.853001,103.279556],[25.852051,103.278236],[25.850981,103.276466],[25.850651,103.276039],[25.8494,103.275017],[25.849079,103.274834],[25.84857,103.274673],[25.848049,103.274628],[25.847309,103.274696],[25.84659,103.274849],[25.845449,103.274872],[25.84498,103.274757],[25.844231,103.274399],[25.843599,103.274246],[25.84259,103.274292],[25.838961,103.274857],[25.837351,103.274857],[25.83423,103.273956],[25.833731,103.273933],[25.833059,103.274109],[25.832451,103.27446],[25.8311,103.275482],[25.83045,103.275703],[25.829679,103.275757],[25.827801,103.275658],[25.82725,103.275711],[25.826559,103.275932],[25.82596,103.27626],[25.82546,103.276657],[25.82526,103.276878],[25.8204,103.277748],[25.8202,103.277733],[25.820049,103.277649],[25.81978,103.277359],[25.81876,103.276527],[25.8181,103.276207],[25.817751,103.276108],[25.816999,103.276108],[25.81418,103.276428],[25.81275,103.276459],[25.810659,103.276108],[25.80863,103.276161],[25.803711,103.276512],[25.799,103.275848],[25.797159,103.275597],[25.796749,103.275597],[25.796009,103.275749],[25.7952,103.276108],[25.79451,103.276657],[25.79405,103.277161],[25.793079,103.278763],[25.79258,103.279327],[25.79213,103.279648],[25.791451,103.279907],[25.790899,103.279999],[25.790331,103.279953],[25.789801,103.279778],[25.78635,103.277962],[25.78553,103.277649],[25.784929,103.277496],[25.784149,103.277458],[25.78261,103.277557],[25.78163,103.277496],[25.78021,103.277199],[25.77636,103.276031],[25.771879,103.274979],[25.77083,103.274529],[25.769979,103.274109],[25.769329,103.273857],[25.76755,103.273407],[25.76668,103.273247],[25.76523,103.272781],[25.76408,103.272308],[25.763359,103.272102],[25.762831,103.272057],[25.762381,103.272133],[25.76111,103.27253],[25.7603,103.272797],[25.75943,103.272858],[25.759081,103.272781],[25.7582,103.272346],[25.75625,103.271156],[25.755899,103.271004],[25.75555,103.270882],[25.75481,103.27076],[25.75461,103.27076],[25.75441,103.270798],[25.75098,103.27066],[25.74658,103.27095],[25.745951,103.270882],[25.74535,103.270699],[25.741751,103.269157],[25.740379,103.268951],[25.727909,103.269653],[25.72686,103.269577],[25.72611,103.269402],[25.72541,103.269096],[25.723101,103.267998],[25.722099,103.267677],[25.721081,103.267548],[25.72028,103.267563],[25.719259,103.267677],[25.7166,103.267754],[25.714849,103.267647],[25.71176,103.267097],[25.709009,103.26635],[25.708229,103.266197],[25.70643,103.266159],[25.703899,103.266403],[25.70166,103.266502],[25.695101,103.266151],[25.69413,103.26593],[25.69368,103.265709],[25.692631,103.26506],[25.69173,103.264702],[25.69101,103.26458],[25.6898,103.264664],[25.68721,103.265106],[25.685909,103.265381],[25.6849,103.265511],[25.68416,103.26548],[25.683701,103.265358],[25.681999,103.264557],[25.68136,103.264351],[25.68075,103.264259],[25.67716,103.265152],[25.676611,103.265182],[25.67605,103.265083],[25.67461,103.264557],[25.67281,103.263763],[25.67136,103.26326],[25.668329,103.262451],[25.667351,103.261978],[25.665979,103.261162],[25.665279,103.260902],[25.664801,103.260811],[25.664061,103.260811],[25.661209,103.261253],[25.66028,103.261253],[25.65893,103.261002],[25.65873,103.260933],[25.657881,103.26078],[25.65686,103.260857],[25.65041,103.263283],[25.64731,103.264412],[25.64706,103.264481],[25.646259,103.264603],[25.645109,103.264549],[25.64435,103.264412],[25.63361,103.261147],[25.63203,103.260757],[25.63093,103.260399],[25.62985,103.259933],[25.628759,103.259354],[25.62656,103.257698],[25.62546,103.256607],[25.62421,103.254982],[25.62351,103.25383],[25.62183,103.250664],[25.620859,103.249229],[25.61961,103.247726],[25.607679,103.235161],[25.599199,103.226303],[25.597651,103.224983],[25.595449,103.223511],[25.5819,103.217506],[25.5807,103.217133],[25.57921,103.216927],[25.578711,103.216911],[25.577959,103.216927],[25.57568,103.216881],[25.574659,103.216698],[25.566509,103.214333],[25.5655,103.213852],[25.5634,103.212646],[25.5632,103.212509],[25.55838,103.209663],[25.556431,103.208527],[25.55505,103.207977],[25.553829,103.20768],[25.550329,103.207092],[25.54949,103.206947],[25.549971,103.207581],[25.55011,103.207863],[25.55036,103.208107],[25.550711,103.208153],[25.551161,103.208252],[25.551571,103.208557],[25.55184,103.206657],[25.55212,103.2062],[25.552441,103.206009],[25.55271,103.205597],[25.552811,103.204437],[25.55295,103.201317],[25.55307,103.197433],[25.553141,103.196373],[25.553471,103.191902],[25.55352,103.191704],[25.55443,103.188454],[25.55512,103.185707],[25.55559,103.183983],[25.556129,103.182167],[25.556459,103.181473],[25.556829,103.180923],[25.557421,103.18029],[25.557961,103.179893],[25.558849,103.179443],[25.56251,103.177856],[25.56278,103.177696],[25.563021,103.177513],[25.56337,103.176979],[25.56349,103.176689],[25.56361,103.176163],[25.5637,103.175423],[25.56385,103.174667],[25.566589,103.167618],[25.56706,103.166313],[25.56739,103.165588],[25.568171,103.164452],[25.568741,103.163582],[25.569189,103.163292],[25.57011,103.16304],[25.57065,103.162827],[25.57196,103.16214],[25.572519,103.161873],[25.573351,103.16143],[25.573721,103.161507],[25.5742,103.161903],[25.57464,103.161949],[25.574829,103.161812],[25.57535,103.161179],[25.57547,103.160851],[25.575331,103.160667],[25.57497,103.160606],[25.57469,103.160347],[25.574699,103.15976],[25.5748,103.159492],[25.57592,103.158859],[25.57621,103.158661],[25.576571,103.158234],[25.57695,103.157837],[25.57728,103.157677],[25.57756,103.157677],[25.577869,103.1576],[25.578381,103.15728],[25.578501,103.157158],[25.578569,103.156998],[25.578751,103.156227],[25.57889,103.155884],[25.578951,103.155617],[25.578899,103.155373],[25.57851,103.154999],[25.578341,103.154762],[25.5783,103.154556],[25.578291,103.153717],[25.578421,103.153511],[25.578581,103.153572],[25.578779,103.153908],[25.57897,103.154114],[25.579531,103.154411],[25.5797,103.154297],[25.579691,103.154083],[25.57925,103.153549],[25.579029,103.153137],[25.57893,103.152763],[25.57901,103.152313],[25.579121,103.152031],[25.57951,103.151489],[25.57963,103.15123],[25.57971,103.150513],[25.57984,103.15023],[25.580021,103.15023],[25.58012,103.150337],[25.580151,103.150909],[25.58033,103.151741],[25.580509,103.15197],[25.580709,103.152061],[25.58091,103.152077],[25.58124,103.151878],[25.582331,103.149551],[25.583521,103.147102],[25.58371,103.146568],[25.583759,103.14608],[25.58305,103.142853],[25.582661,103.141586],[25.582661,103.141121],[25.583111,103.139793],[25.58313,103.139458],[25.58235,103.136772],[25.581261,103.134132],[25.58086,103.133087],[25.580469,103.132187],[25.58016,103.131752],[25.57819,103.130074],[25.57766,103.129532],[25.577579,103.129402],[25.57732,103.128807],[25.576981,103.127869],[25.57686,103.127609],[25.576509,103.127213],[25.57601,103.126793],[25.575859,103.126587],[25.57546,103.125763],[25.575029,103.125343],[25.574381,103.125191],[25.57383,103.125221],[25.573139,103.125366],[25.572701,103.125343],[25.572411,103.12513],[25.572041,103.124657],[25.57058,103.12236],[25.570129,103.121719],[25.56999,103.121452],[25.56992,103.12104],[25.570089,103.120644],[25.57011,103.120171],[25.569851,103.119743],[25.569521,103.119537],[25.567829,103.119141],[25.567499,103.11882],[25.567249,103.118172],[25.566469,103.117126],[25.566259,103.116653],[25.566311,103.116257],[25.56665,103.115494],[25.566719,103.114906],[25.5667,103.11467],[25.566521,103.114182],[25.56608,103.113403],[25.56568,103.112846],[25.565281,103.112373],[25.56498,103.112122],[25.563419,103.111099],[25.55805,103.107399],[25.55769,103.107231],[25.5539,103.105881],[25.5509,103.104362],[25.54928,103.103989],[25.54875,103.103996],[25.548,103.10421],[25.547489,103.104179],[25.546881,103.103958],[25.546,103.103523],[25.54587,103.103317],[25.5459,103.103203],[25.546021,103.102921],[25.54619,103.10276],[25.546551,103.102676],[25.547609,103.102509],[25.54808,103.102531],[25.548491,103.102364],[25.548651,103.102249],[25.548809,103.101883],[25.54903,103.101791],[25.549311,103.102112],[25.549601,103.102226],[25.55043,103.102081],[25.55094,103.101936],[25.55117,103.101807],[25.55135,103.101593],[25.551689,103.101341],[25.55188,103.101341],[25.55261,103.101448],[25.552971,103.101334],[25.553209,103.101028],[25.55323,103.100754],[25.552891,103.099854],[25.55262,103.099663],[25.55237,103.099602],[25.55221,103.099319],[25.552,103.098473],[25.551741,103.097923],[25.55172,103.097511],[25.55191,103.097099],[25.552271,103.096809],[25.5527,103.09684],[25.552879,103.096947],[25.553631,103.097603],[25.554001,103.097733],[25.555149,103.097931],[25.555559,103.098129],[25.55596,103.098267],[25.55673,103.097969],[25.55715,103.097763],[25.557779,103.097687],[25.558451,103.097481],[25.559259,103.096878],[25.559469,103.096367],[25.55983,103.096092],[25.55995,103.09584],[25.559891,103.095459],[25.55999,103.095337],[25.56019,103.095222],[25.56027,103.094994],[25.560261,103.09491],[25.56045,103.094612],[25.56053,103.094597],[25.560789,103.094353],[25.56094,103.093941],[25.561159,103.093773],[25.56131,103.093964],[25.56152,103.094498],[25.561859,103.094933],[25.562401,103.095062],[25.562771,103.095047],[25.563141,103.09494],[25.56348,103.094719],[25.564951,103.093613],[25.565281,103.093552],[25.56558,103.093719],[25.56576,103.093781],[25.566071,103.093773],[25.56847,103.093002],[25.568859,103.09269],[25.570089,103.091476],[25.570459,103.091301],[25.570709,103.091263],[25.571011,103.09111],[25.571091,103.090919],[25.571091,103.090347],[25.57073,103.089706],[25.570801,103.089394],[25.57111,103.089249],[25.571381,103.08902],[25.57136,103.088783],[25.570959,103.088074],[25.57095,103.087837],[25.571119,103.087791],[25.57139,103.087784],[25.572081,103.087608],[25.57238,103.08741],[25.57251,103.087021],[25.572309,103.083817],[25.57247,103.082024],[25.572451,103.081833],[25.572371,103.081642],[25.571899,103.080872],[25.57159,103.080421],[25.571381,103.08004],[25.57136,103.079712],[25.571541,103.079498],[25.571911,103.079277],[25.572201,103.078949],[25.57238,103.078491],[25.572651,103.078102],[25.573219,103.077606],[25.57412,103.076927],[25.57445,103.076408],[25.57472,103.075829],[25.57514,103.07444],[25.57538,103.073853],[25.576191,103.072327],[25.576509,103.071617],[25.576969,103.070282],[25.57692,103.069893],[25.57634,103.068428],[25.576241,103.068283],[25.57583,103.067947],[25.575491,103.067886],[25.57477,103.067917],[25.57431,103.067993],[25.573549,103.068024],[25.573231,103.067886],[25.573071,103.067589],[25.572729,103.06546],[25.572651,103.065163],[25.572309,103.064743],[25.571779,103.064262],[25.571659,103.063957],[25.57176,103.063797],[25.573151,103.062553],[25.57329,103.062248],[25.57332,103.058449],[25.57328,103.057503],[25.573191,103.056824],[25.572861,103.05513],[25.57259,103.054642],[25.5718,103.053482],[25.57119,103.052803],[25.57078,103.052467],[25.5707,103.052429],[25.5704,103.052116],[25.57029,103.051788],[25.570129,103.051514],[25.56991,103.051277],[25.569401,103.051086],[25.56897,103.051041],[25.568569,103.050858],[25.568251,103.050484],[25.56826,103.050209],[25.568439,103.050117],[25.56875,103.050163],[25.56941,103.050034],[25.56971,103.049828],[25.570129,103.049744],[25.57021,103.049751],[25.57085,103.049637],[25.57099,103.049553],[25.571159,103.049057],[25.571171,103.048843],[25.5711,103.048607],[25.57073,103.047859],[25.57004,103.046677],[25.56974,103.046463],[25.56904,103.04615],[25.56856,103.04583],[25.56805,103.045403],[25.56785,103.045097],[25.567631,103.044533],[25.567249,103.044243],[25.566759,103.044067],[25.56636,103.044167],[25.56559,103.044731],[25.56531,103.044678],[25.565241,103.043938],[25.56517,103.043663],[25.565241,103.043167],[25.565371,103.042923],[25.56538,103.042542],[25.565269,103.042374],[25.56428,103.041054],[25.563749,103.040413],[25.562929,103.039612],[25.562571,103.03894],[25.56245,103.038544],[25.562031,103.037956],[25.561899,103.037437],[25.561741,103.037323],[25.561319,103.037193],[25.56114,103.037109],[25.56098,103.036812],[25.561119,103.036598],[25.56152,103.036247],[25.56159,103.036003],[25.56147,103.035896],[25.561171,103.035744],[25.56093,103.035667],[25.56032,103.035713],[25.56004,103.035538],[25.55975,103.035011],[25.55949,103.034401],[25.55925,103.034157],[25.55895,103.033997],[25.55879,103.033691],[25.558889,103.033432],[25.55932,103.032944],[25.559469,103.032471],[25.55938,103.032204],[25.55883,103.031616],[25.55821,103.031197],[25.55794,103.030731],[25.55785,103.030411],[25.5576,103.030113],[25.556141,103.029617],[25.555771,103.029457],[25.555401,103.02948],[25.555309,103.029533],[25.554899,103.029587],[25.55475,103.029381],[25.554729,103.028687],[25.554689,103.028503],[25.554489,103.028358],[25.55349,103.028343],[25.55323,103.028152],[25.55324,103.027718],[25.55316,103.027229],[25.55294,103.026657],[25.5527,103.026413],[25.55253,103.026337],[25.552259,103.025993],[25.552361,103.025703],[25.552589,103.025459],[25.55295,103.025337],[25.55312,103.025436],[25.553419,103.025757],[25.55369,103.025909],[25.555309,103.025841],[25.55563,103.025673],[25.55615,103.025169],[25.556259,103.024849],[25.55616,103.024689],[25.55513,103.023552],[25.555019,103.023193],[25.55521,103.023087],[25.555559,103.023102],[25.556179,103.022926],[25.556749,103.02269],[25.55724,103.022552],[25.55743,103.022537],[25.557711,103.022598],[25.55817,103.022781],[25.559549,103.023666],[25.56052,103.024246],[25.561411,103.024841],[25.562189,103.025307],[25.56303,103.025551],[25.56348,103.025864],[25.563971,103.025993],[25.56423,103.026016],[25.564751,103.025917],[25.565861,103.025681],[25.566389,103.025398],[25.566771,103.025307],[25.567551,103.025284],[25.567841,103.025299],[25.56811,103.025513],[25.568371,103.02594],[25.568729,103.026199],[25.568899,103.026283],[25.569241,103.026222],[25.569469,103.026047],[25.569651,103.025772],[25.569889,103.0252],[25.569969,103.024673],[25.57015,103.024231],[25.570391,103.023933],[25.57065,103.023376],[25.57066,103.022972],[25.570589,103.022568],[25.57069,103.022057],[25.57078,103.021828],[25.570761,103.021362],[25.570669,103.021133],[25.570669,103.020638],[25.570841,103.019882],[25.570829,103.019081],[25.570971,103.018578],[25.57155,103.017769],[25.572029,103.017174],[25.572241,103.016777],[25.573,103.014839],[25.573151,103.01416],[25.573271,103.013031],[25.573271,103.012833],[25.57338,103.012459],[25.573601,103.012138],[25.5737,103.011833],[25.57345,103.011597],[25.57276,103.011101],[25.572639,103.010773],[25.57287,103.010193],[25.57291,103.009628],[25.5728,103.008873],[25.572901,103.008636],[25.573071,103.00869],[25.574011,103.009239],[25.57431,103.009277],[25.574421,103.009071],[25.574459,103.00782],[25.574369,103.007431],[25.574089,103.00692],[25.57399,103.006683],[25.57394,103.006271],[25.573971,103.005928],[25.5744,103.004807],[25.574659,103.003403],[25.574949,103.002617],[25.575359,103.001923],[25.5756,103.001801],[25.5758,103.001961],[25.576151,103.002373],[25.5765,103.002541],[25.57749,103.001961],[25.577869,103.0019],[25.578369,103.001999],[25.57873,103.001869],[25.57901,103.001549],[25.579069,103.001289],[25.577009,102.99852],[25.57688,102.998253],[25.57686,102.997772],[25.577089,102.996407],[25.57708,102.996094],[25.57691,102.995811],[25.5767,102.995773],[25.576521,102.995819],[25.575609,102.996269],[25.575411,102.99617],[25.57548,102.996048],[25.5763,102.995232],[25.57654,102.995064],[25.57675,102.995033],[25.57715,102.995049],[25.577591,102.99514],[25.57785,102.995064],[25.57794,102.99482],[25.57836,102.993217],[25.578449,102.992981],[25.578621,102.992683],[25.578791,102.992439],[25.579309,102.991913],[25.5812,102.990082],[25.58205,102.989059],[25.582279,102.988907],[25.58251,102.988792],[25.58301,102.988663],[25.583771,102.988411],[25.58437,102.988167],[25.5846,102.988037],[25.585039,102.987671],[25.58606,102.98629],[25.58633,102.986267],[25.586519,102.986343],[25.58758,102.986969],[25.587811,102.987312],[25.587959,102.987717],[25.58802,102.988091],[25.588169,102.988327],[25.588539,102.988564],[25.58975,102.988907],[25.590191,102.988777],[25.590389,102.988503],[25.590839,102.987663],[25.59111,102.987282],[25.591299,102.987152],[25.591869,102.987137],[25.592039,102.986992],[25.59201,102.986649],[25.59215,102.986328],[25.592461,102.986252],[25.5931,102.986252],[25.59341,102.986153],[25.593769,102.985893],[25.594481,102.985092],[25.59498,102.984711],[25.595209,102.984337],[25.595329,102.98391],[25.59564,102.983597],[25.59643,102.983238],[25.59668,102.983063],[25.597679,102.981483],[25.59775,102.98114],[25.597561,102.980873],[25.59642,102.979721],[25.59584,102.979057],[25.59581,102.978737],[25.59623,102.977921],[25.596569,102.977707],[25.597219,102.977814],[25.59786,102.978073],[25.59832,102.978287],[25.599661,102.9786],[25.599911,102.978561],[25.60006,102.97834],[25.6001,102.977921],[25.599991,102.977463],[25.599779,102.976967],[25.5998,102.976639],[25.600031,102.976479],[25.60071,102.976173],[25.60117,102.975754],[25.60154,102.975067],[25.601641,102.974602],[25.601561,102.974007],[25.60165,102.973717],[25.60182,102.973747],[25.602051,102.974007],[25.60243,102.97509],[25.6024,102.975471],[25.60183,102.976227],[25.60181,102.976547],[25.602011,102.976547],[25.603609,102.975906],[25.603821,102.975647],[25.603769,102.97541],[25.603359,102.974609],[25.603331,102.974472],[25.60346,102.974319],[25.604481,102.974373],[25.604771,102.974297],[25.60491,102.974197],[25.605009,102.973938],[25.60498,102.973549],[25.60494,102.973457],[25.604691,102.973167],[25.604469,102.973106],[25.60416,102.973312],[25.603689,102.973396],[25.603491,102.973343],[25.60321,102.973167],[25.60293,102.972801],[25.60251,102.972412],[25.60206,102.972237],[25.601959,102.97213],[25.601971,102.971931],[25.602171,102.971863],[25.602819,102.971992],[25.60317,102.972214],[25.60331,102.972351],[25.603649,102.972473],[25.60388,102.972321],[25.60404,102.972183],[25.60442,102.972023],[25.60486,102.972092],[25.60602,102.972649],[25.60634,102.972748],[25.606899,102.97274],[25.60745,102.972878],[25.607981,102.972961],[25.608231,102.972862],[25.60829,102.972633],[25.608471,102.972298],[25.60874,102.972343],[25.608879,102.972397],[25.60988,102.972366],[25.610029,102.972321],[25.610189,102.972076],[25.61021,102.971901],[25.610331,102.971603],[25.61055,102.971573],[25.61134,102.971786],[25.61194,102.972267],[25.612289,102.972359],[25.613131,102.972153],[25.613319,102.972054],[25.61364,102.971764],[25.613831,102.971558],[25.614111,102.971474],[25.614429,102.97155],[25.615049,102.971512],[25.615311,102.971291],[25.6154,102.971161],[25.61553,102.971077],[25.615829,102.971008],[25.615959,102.970932],[25.616211,102.970627],[25.616461,102.970528],[25.616739,102.970497],[25.617399,102.969994],[25.61771,102.969803],[25.617941,102.969498],[25.61805,102.969223],[25.618219,102.969032],[25.61842,102.969048],[25.618561,102.969223],[25.618561,102.969383],[25.618481,102.970016],[25.618481,102.970551],[25.618549,102.971062],[25.618759,102.971489],[25.618971,102.971657],[25.619221,102.97171],[25.61978,102.971733],[25.62006,102.971626],[25.620211,102.971413],[25.62038,102.970863],[25.620449,102.970512],[25.620649,102.970238],[25.62126,102.969719],[25.62174,102.969093],[25.6222,102.968323],[25.622499,102.968132],[25.62294,102.96814],[25.6234,102.968117],[25.62351,102.968178],[25.623699,102.968407],[25.623911,102.96859],[25.625469,102.967621],[25.627781,102.966187],[25.627621,102.965813],[25.627621,102.965477],[25.627859,102.96505],[25.6283,102.964462],[25.628889,102.963753],[25.629,102.963387],[25.629089,102.962563],[25.62904,102.962257],[25.628839,102.961777],[25.62862,102.961403],[25.62833,102.961143],[25.62796,102.960907],[25.627819,102.960747],[25.62731,102.959862],[25.62722,102.959396],[25.62723,102.959007],[25.627291,102.958633],[25.627211,102.958298],[25.62694,102.95784],[25.62648,102.957329],[25.62628,102.956963],[25.62595,102.956596],[25.625601,102.956352],[25.62553,102.956039],[25.62541,102.955711],[25.62524,102.955406],[25.62499,102.955162],[25.62484,102.955063],[25.623581,102.954483],[25.62315,102.954224],[25.622629,102.953583],[25.62224,102.953362],[25.62196,102.953468],[25.62182,102.953552],[25.621469,102.953529],[25.620239,102.952423],[25.61982,102.951881],[25.61858,102.950859],[25.61842,102.95076],[25.618259,102.9505],[25.61829,102.950073],[25.61845,102.949753],[25.618719,102.949577],[25.61883,102.949387],[25.618811,102.949226],[25.618719,102.948967],[25.618641,102.948402],[25.618441,102.947952],[25.61828,102.94735],[25.618179,102.946892],[25.61812,102.94632],[25.617769,102.945633],[25.61768,102.945137],[25.61776,102.94471],[25.617649,102.944382],[25.617491,102.944077],[25.61746,102.943748],[25.617781,102.942963],[25.617809,102.942078],[25.61795,102.941742],[25.61797,102.941528],[25.617781,102.94117],[25.61776,102.940407],[25.617861,102.939972],[25.617901,102.939339],[25.6178,102.938782],[25.61771,102.938461],[25.61768,102.937958],[25.617781,102.937714],[25.617821,102.937241],[25.618,102.936813],[25.61805,102.936348],[25.618099,102.935249],[25.617941,102.934036],[25.61797,102.933632],[25.617861,102.932953],[25.617729,102.932457],[25.617479,102.932083],[25.617371,102.931808],[25.617081,102.931541],[25.616779,102.931427],[25.61676,102.931282],[25.61688,102.931107],[25.61673,102.930267],[25.616631,102.929993],[25.616199,102.929237],[25.615931,102.928963],[25.614639,102.928253],[25.61445,102.928078],[25.613991,102.927422],[25.613489,102.927032],[25.6127,102.92659],[25.61248,102.926521],[25.61199,102.926628],[25.61153,102.926666],[25.611259,102.926537],[25.61105,102.925926],[25.610781,102.925697],[25.610479,102.925613],[25.6103,102.925392],[25.610371,102.924728],[25.610371,102.924301],[25.61043,102.923973],[25.610491,102.923828],[25.610439,102.9235],[25.610201,102.923363],[25.609949,102.923264],[25.609461,102.923233],[25.60914,102.923157],[25.6084,102.922737],[25.60824,102.922859],[25.608191,102.923111],[25.608259,102.923241],[25.608219,102.923508],[25.60812,102.923492],[25.607941,102.923561],[25.607849,102.923927],[25.607771,102.924011],[25.60762,102.92395],[25.60759,102.923622],[25.607691,102.922592],[25.60787,102.922256],[25.60795,102.921982],[25.607821,102.921707],[25.607491,102.921211],[25.60722,102.921173],[25.607071,102.921188],[25.60692,102.921127],[25.60644,102.92083],[25.606291,102.920807],[25.606211,102.920982],[25.606159,102.921494],[25.606091,102.921577],[25.605961,102.921516],[25.60586,102.921082],[25.60568,102.92099],[25.605619,102.920792],[25.60569,102.920547],[25.60565,102.92009],[25.60545,102.919838],[25.604271,102.91967],[25.60396,102.91951],[25.60379,102.919617],[25.60364,102.919807],[25.603559,102.920151],[25.603359,102.920151],[25.602989,102.919861],[25.60272,102.919739],[25.602579,102.919456],[25.60223,102.919037],[25.60183,102.918709],[25.60136,102.918083],[25.601191,102.917763],[25.600969,102.917557],[25.60087,102.917397],[25.600599,102.917236],[25.6003,102.917297],[25.600161,102.917664],[25.600241,102.918022],[25.60009,102.918243],[25.599541,102.918098],[25.59934,102.918182],[25.599211,102.918518],[25.599051,102.918556],[25.5989,102.918793],[25.59885,102.918968],[25.59865,102.919121],[25.59852,102.918968],[25.598511,102.918709],[25.59864,102.918373],[25.59866,102.918228],[25.598579,102.918022],[25.598511,102.917908],[25.598511,102.917587],[25.598379,102.917328],[25.598351,102.917107],[25.59819,102.916779],[25.59796,102.916611],[25.59761,102.916496],[25.59729,102.916458],[25.596769,102.916283],[25.59659,102.916077],[25.59671,102.915573],[25.596649,102.914948],[25.596519,102.914742],[25.596359,102.914711],[25.59586,102.914703],[25.59573,102.914757],[25.5954,102.915154],[25.59506,102.91571],[25.59487,102.915878],[25.59474,102.915932],[25.594431,102.915878],[25.59407,102.915756],[25.593691,102.915382],[25.593519,102.914993],[25.592871,102.914192],[25.592609,102.913803],[25.59234,102.913513],[25.59211,102.912987],[25.59197,102.912491],[25.591669,102.911789],[25.59071,102.91037],[25.590469,102.91021],[25.590071,102.910103],[25.58975,102.90995],[25.58959,102.909912],[25.589211,102.909927],[25.58868,102.910004],[25.5884,102.909897],[25.588261,102.909798],[25.58798,102.909813],[25.58782,102.909859],[25.5875,102.909882],[25.58699,102.90976],[25.585819,102.909187],[25.585449,102.908943],[25.58544,102.908699],[25.5858,102.908569],[25.586081,102.908386],[25.586241,102.908234],[25.586269,102.908043],[25.58604,102.907837],[25.585581,102.90773],[25.584961,102.907799],[25.584629,102.907753],[25.58371,102.907288],[25.583099,102.906822],[25.58275,102.906807],[25.582661,102.906822],[25.58205,102.906647],[25.58185,102.90641],[25.58164,102.905609],[25.581699,102.905273],[25.58185,102.905029],[25.581779,102.904793],[25.58152,102.904533],[25.58119,102.904556],[25.58087,102.904472],[25.580669,102.904457],[25.5804,102.904388],[25.580099,102.904373],[25.580009,102.904198],[25.58032,102.903831],[25.58083,102.903282],[25.580879,102.903183],[25.580811,102.903053],[25.580469,102.902924],[25.57958,102.902191],[25.57937,102.901939],[25.57925,102.901649],[25.57921,102.901337],[25.5791,102.901031],[25.57893,102.901062],[25.578751,102.90136],[25.578501,102.901573],[25.578369,102.901543],[25.57807,102.90139],[25.57753,102.900818],[25.577379,102.900467],[25.577169,102.899788],[25.57715,102.899384],[25.5774,102.899071],[25.57745,102.898804],[25.577271,102.898483],[25.577089,102.898247],[25.57703,102.897957],[25.577141,102.897652],[25.577379,102.897438],[25.577539,102.897362],[25.577721,102.897148],[25.577629,102.897003],[25.57741,102.896973],[25.577209,102.897003],[25.576229,102.897469],[25.57593,102.897659],[25.5756,102.897598],[25.57543,102.897522],[25.57514,102.897453],[25.57485,102.897209],[25.57473,102.896812],[25.57469,102.896591],[25.57452,102.896301],[25.57415,102.896103],[25.573811,102.896027],[25.572241,102.896133],[25.572001,102.896263],[25.57193,102.896683],[25.57172,102.896973],[25.57151,102.897011],[25.57128,102.896873],[25.571131,102.896721],[25.57074,102.896187],[25.570379,102.89521],[25.57044,102.89476],[25.57066,102.894417],[25.57089,102.894234],[25.57114,102.894127],[25.57148,102.894119],[25.571859,102.893997],[25.572029,102.893837],[25.571951,102.893669],[25.571739,102.893547],[25.57148,102.893463],[25.57128,102.893227],[25.57128,102.89296],[25.5714,102.892723],[25.571951,102.892273],[25.57198,102.892021],[25.57176,102.891647],[25.57155,102.891586],[25.571421,102.891663],[25.571011,102.891693],[25.570869,102.891327],[25.57057,102.891052],[25.57011,102.890793],[25.569719,102.890694],[25.569361,102.89035],[25.568489,102.889229],[25.567909,102.887688],[25.56793,102.88752],[25.567909,102.886253],[25.567949,102.885918],[25.56806,102.885567],[25.568069,102.885399],[25.56794,102.885048],[25.56743,102.884483],[25.567261,102.884377],[25.567141,102.884232],[25.566931,102.883827],[25.56671,102.883163],[25.566589,102.882423],[25.56633,102.881477],[25.56632,102.881042],[25.56641,102.880409],[25.56662,102.880058],[25.56691,102.879951],[25.5672,102.879997],[25.567471,102.880219],[25.567591,102.88018],[25.56765,102.878922],[25.567579,102.878487],[25.56748,102.878326],[25.5672,102.87812],[25.56711,102.877892],[25.56727,102.877777],[25.567751,102.877922],[25.56814,102.878143],[25.56839,102.878052],[25.568529,102.877747],[25.56867,102.877533],[25.568661,102.877319],[25.56848,102.877167],[25.56822,102.876717],[25.567921,102.875954],[25.56743,102.875412],[25.567089,102.874863],[25.56694,102.874687],[25.566811,102.874443],[25.56683,102.873787],[25.566799,102.873581],[25.566589,102.873062],[25.566509,102.872383],[25.566549,102.872101],[25.56629,102.871712],[25.56604,102.871521],[25.565519,102.871399],[25.565491,102.871338],[25.56555,102.87114],[25.56568,102.871109],[25.566219,102.871094],[25.566681,102.871117],[25.566839,102.871063],[25.56694,102.870743],[25.567181,102.870689],[25.567419,102.870743],[25.56765,102.870598],[25.5679,102.870247],[25.56834,102.87001],[25.56852,102.869949],[25.56879,102.869957],[25.568951,102.869881],[25.568781,102.86982],[25.56852,102.869843],[25.568211,102.869904],[25.56769,102.870216],[25.56748,102.870209],[25.567341,102.870003],[25.567181,102.869881],[25.56711,102.869911],[25.566959,102.869873],[25.56674,102.869568],[25.566549,102.869568],[25.5662,102.869759],[25.565901,102.869751],[25.565769,102.869553],[25.565639,102.869141],[25.565439,102.868973],[25.565161,102.86927],[25.56481,102.869278],[25.564409,102.869057],[25.56431,102.868896],[25.564449,102.868843],[25.564699,102.869011],[25.56496,102.868927],[25.56514,102.868698],[25.565149,102.86824],[25.565331,102.867973],[25.56554,102.867981],[25.565651,102.868149],[25.56567,102.868233],[25.56596,102.868752],[25.566059,102.86882],[25.56624,102.868729],[25.56636,102.8685],[25.56641,102.868118],[25.566561,102.867844],[25.566719,102.867844],[25.56735,102.867981],[25.56756,102.868156],[25.567579,102.868401],[25.56781,102.868553],[25.568159,102.86853],[25.568399,102.868423],[25.56855,102.868217],[25.568529,102.867973],[25.568211,102.867592],[25.568029,102.867249],[25.56786,102.867027],[25.567881,102.866783],[25.568911,102.866707],[25.569241,102.866783],[25.570761,102.86763],[25.57093,102.867523],[25.570921,102.867348],[25.57099,102.867012],[25.571159,102.86647],[25.57136,102.866241],[25.57143,102.866257],[25.571569,102.866379],[25.57169,102.866524],[25.57197,102.866653],[25.572149,102.866577],[25.572069,102.866501],[25.57164,102.866364],[25.57136,102.866058],[25.571199,102.865608],[25.571171,102.864967],[25.57122,102.864708],[25.57115,102.864471],[25.570881,102.864357],[25.570511,102.864471],[25.57025,102.864342],[25.57019,102.864197],[25.569851,102.863907],[25.569229,102.86396],[25.568859,102.863937],[25.568781,102.863853],[25.56867,102.863609],[25.568251,102.863373],[25.56687,102.86322],[25.56637,102.86319],[25.566031,102.863022],[25.565651,102.862617],[25.56531,102.862083],[25.56517,102.861656],[25.56525,102.86129],[25.565519,102.860847],[25.565741,102.860687],[25.56608,102.860863],[25.56629,102.860771],[25.566311,102.860611],[25.566139,102.860527],[25.565479,102.860512],[25.565109,102.860558],[25.56468,102.860573],[25.564329,102.860741],[25.56365,102.861557],[25.563601,102.861717],[25.563629,102.861923],[25.563789,102.862122],[25.563881,102.862328],[25.563761,102.862427],[25.563601,102.862373],[25.56307,102.861832],[25.562429,102.861343],[25.561569,102.860893],[25.561119,102.860367],[25.560459,102.859528],[25.56015,102.859093],[25.56003,102.85833],[25.559959,102.857964],[25.559919,102.857437],[25.559719,102.856163],[25.55953,102.855972],[25.55942,102.855942],[25.55896,102.855942],[25.55772,102.856003],[25.55703,102.855904],[25.55681,102.855904],[25.55654,102.855782],[25.55633,102.855614],[25.55617,102.855263],[25.55599,102.855133],[25.555901,102.855164],[25.555651,102.855431],[25.555321,102.855392],[25.55456,102.85511],[25.554291,102.855057],[25.553921,102.855179],[25.553591,102.855324],[25.553341,102.855362],[25.55294,102.855301],[25.552679,102.855202],[25.55188,102.855217],[25.55147,102.855087],[25.550859,102.854698],[25.54953,102.853508],[25.54875,102.852898],[25.548559,102.852814],[25.54796,102.852661],[25.547449,102.852577],[25.546801,102.852379],[25.546551,102.852379],[25.54578,102.852631],[25.54534,102.85257],[25.544741,102.852402],[25.544359,102.852173],[25.543779,102.85141],[25.543341,102.850937],[25.542999,102.850693],[25.54266,102.850594],[25.54203,102.850563],[25.54142,102.850288],[25.54101,102.849953],[25.540751,102.849663],[25.540251,102.849312],[25.53968,102.849091],[25.539049,102.8489],[25.53875,102.848778],[25.53825,102.848732],[25.537319,102.848907],[25.53697,102.848846],[25.53651,102.848648],[25.53606,102.848587],[25.53561,102.848587],[25.53496,102.84845],[25.53355,102.848106],[25.53294,102.847832],[25.532459,102.847412],[25.53199,102.846916],[25.53117,102.846443],[25.53091,102.846397],[25.530769,102.846527],[25.530701,102.846657],[25.530491,102.846817],[25.52914,102.847054],[25.52866,102.846939],[25.528021,102.846474],[25.526331,102.84597],[25.525669,102.845963],[25.52438,102.845863],[25.5235,102.845863],[25.521919,102.845772],[25.521441,102.845711],[25.520981,102.845543],[25.520729,102.845329],[25.520269,102.84507],[25.519991,102.844971],[25.51977,102.84494],[25.51848,102.845047],[25.51799,102.845009],[25.517521,102.844788],[25.51539,102.843437],[25.515289,102.843292],[25.51527,102.84272],[25.51557,102.841843],[25.51557,102.841537],[25.5149,102.840942],[25.514481,102.840714],[25.514111,102.840759],[25.513929,102.840874],[25.513559,102.841217],[25.513269,102.841309],[25.513109,102.841232],[25.51281,102.841003],[25.512461,102.8405],[25.51214,102.840179],[25.51178,102.839981],[25.511009,102.840279],[25.50868,102.841408],[25.507601,102.841782],[25.5072,102.841812],[25.50643,102.841499],[25.505911,102.841209],[25.50576,102.84108],[25.50568,102.840912],[25.50565,102.840752],[25.505659,102.840363],[25.50563,102.840202],[25.505501,102.840057],[25.50535,102.839996],[25.504881,102.840202],[25.50456,102.840401],[25.50433,102.840698],[25.50415,102.841026],[25.504129,102.841652],[25.504061,102.84185],[25.50346,102.842682],[25.503401,102.84285],[25.50321,102.843002],[25.50305,102.84301],[25.502899,102.842857],[25.5028,102.842712],[25.50263,102.842163],[25.502251,102.841728],[25.50206,102.841614],[25.501881,102.84156],[25.50173,102.841629],[25.50161,102.841751],[25.501551,102.841911],[25.50153,102.842102],[25.501699,102.842911],[25.50173,102.843353],[25.5016,102.843964],[25.501631,102.844162],[25.501949,102.844704],[25.502001,102.844856],[25.50201,102.845062],[25.501961,102.845253],[25.501881,102.845398],[25.50091,102.845932],[25.500811,102.846062],[25.50058,102.846848],[25.50036,102.84716],[25.500231,102.84726],[25.50005,102.847298],[25.499531,102.847183],[25.498911,102.846977],[25.498529,102.846832],[25.498199,102.846657],[25.497431,102.846008],[25.49725,102.846008],[25.497061,102.846153],[25.496731,102.846649],[25.49658,102.846779],[25.496401,102.846878],[25.49621,102.846901],[25.49605,102.846802],[25.49593,102.846649],[25.495649,102.8461],[25.49518,102.845451],[25.495001,102.845131],[25.494949,102.844948],[25.494949,102.844711],[25.495131,102.844299],[25.495461,102.84388],[25.495529,102.843681],[25.49548,102.843483],[25.495279,102.843407],[25.49511,102.843452],[25.494909,102.843552],[25.494711,102.843559],[25.49456,102.843483],[25.494431,102.843353],[25.494129,102.842613],[25.493851,102.842361],[25.49333,102.842079],[25.492979,102.842056],[25.492781,102.842102],[25.491449,102.842697],[25.491261,102.842728],[25.49066,102.842682],[25.49048,102.842712],[25.490351,102.84285],[25.49028,102.843033],[25.49025,102.843262],[25.490259,102.843498],[25.49033,102.843758],[25.49045,102.843979],[25.49118,102.844856],[25.491461,102.845497],[25.491579,102.84568],[25.492001,102.846497],[25.492149,102.846931],[25.492149,102.847107],[25.49206,102.847298],[25.491211,102.848328],[25.491131,102.84848],[25.4911,102.848663],[25.49118,102.848877],[25.492599,102.849213],[25.492929,102.849411],[25.49305,102.849602],[25.493059,102.849762],[25.492979,102.849998],[25.49276,102.850098],[25.4921,102.850159],[25.49176,102.850311],[25.491449,102.850578],[25.491261,102.850861],[25.49118,102.851227],[25.491199,102.851608],[25.491501,102.853897],[25.491631,102.854309],[25.492001,102.854851],[25.492149,102.854958],[25.492611,102.855202],[25.493151,102.855362],[25.49333,102.855461],[25.49346,102.855598],[25.493629,102.855713],[25.49371,102.855827],[25.493759,102.856033],[25.49371,102.856232],[25.49328,102.857147],[25.493151,102.857277],[25.49301,102.857353],[25.492701,102.857353],[25.49131,102.857033],[25.49065,102.856781],[25.490499,102.856781],[25.49036,102.85688],[25.49025,102.857033],[25.49,102.857529],[25.489611,102.858009],[25.48958,102.8582],[25.489651,102.858528],[25.48966,102.858711],[25.48963,102.858963],[25.489429,102.859299],[25.489309,102.859428],[25.488501,102.860626],[25.48835,102.860809],[25.48811,102.861008],[25.4869,102.861458],[25.486309,102.861809],[25.48605,102.862099],[25.485649,102.8629],[25.485399,102.863228],[25.48378,102.864662],[25.48358,102.864731],[25.4834,102.864632],[25.48321,102.864349],[25.48316,102.864159],[25.48311,102.863579],[25.482929,102.863258],[25.482731,102.863152],[25.482559,102.863007],[25.482531,102.862801],[25.48255,102.862549],[25.482599,102.862381],[25.482599,102.862183],[25.48255,102.861961],[25.48246,102.861801],[25.48225,102.861702],[25.4821,102.861763],[25.481661,102.862099],[25.48148,102.862152],[25.48131,102.862099],[25.48101,102.8619],[25.48085,102.861847],[25.4807,102.861847],[25.479509,102.862251],[25.479111,102.862358],[25.478609,102.86235],[25.478559,102.862152],[25.47875,102.861504],[25.478649,102.860329],[25.4786,102.86013],[25.47851,102.859947],[25.478331,102.859802],[25.47753,102.859261],[25.47735,102.859261],[25.477261,102.859413],[25.477261,102.860153],[25.477501,102.860397],[25.477831,102.860603],[25.47805,102.860832],[25.47806,102.861],[25.478029,102.861183],[25.477949,102.861351],[25.47761,102.861801],[25.47753,102.861977],[25.47748,102.862228],[25.47735,102.86261],[25.47736,102.862808],[25.477409,102.862999],[25.47806,102.863533],[25.478251,102.863564],[25.47891,102.863503],[25.47913,102.863411],[25.47933,102.863403],[25.47953,102.863449],[25.47961,102.863663],[25.4795,102.864311],[25.479259,102.864883],[25.47893,102.865448],[25.478809,102.865578],[25.478661,102.865662],[25.47813,102.865753],[25.4769,102.865433],[25.476549,102.86541],[25.47576,102.865562],[25.47558,102.86573],[25.47566,102.865913],[25.4758,102.866051],[25.476049,102.866379],[25.47608,102.866547],[25.476049,102.866707],[25.47596,102.866882],[25.47571,102.867126],[25.4744,102.868561],[25.47431,102.868759],[25.474331,102.868927],[25.4744,102.86911],[25.47456,102.869263],[25.47488,102.869331],[25.47506,102.869476],[25.47513,102.869713],[25.475109,102.869904],[25.47493,102.870232],[25.47411,102.87101],[25.47381,102.871529],[25.47368,102.871658],[25.473551,102.871712],[25.473181,102.871696],[25.473,102.871727],[25.47283,102.871803],[25.472731,102.871948],[25.47266,102.87236],[25.472759,102.87291],[25.4729,102.8731],[25.47308,102.873131],[25.47341,102.873062],[25.473579,102.873062],[25.473749,102.873207],[25.473881,102.873734],[25.47385,102.874153],[25.47378,102.874352],[25.473499,102.874611],[25.4734,102.874748],[25.473249,102.875282],[25.473129,102.875481],[25.473,102.875557],[25.472799,102.875633],[25.47246,102.875664],[25.47233,102.875732],[25.472231,102.875908],[25.47226,102.876083],[25.472349,102.876228],[25.472509,102.876381],[25.47296,102.87661],[25.47303,102.876762],[25.473,102.876953],[25.47278,102.87735],[25.472811,102.877548],[25.47291,102.877747],[25.473249,102.878059],[25.47333,102.878258],[25.473351,102.878433],[25.473301,102.878609],[25.4732,102.878761],[25.47295,102.878998],[25.47263,102.879112],[25.472281,102.879128],[25.471979,102.879333],[25.471901,102.879501],[25.471861,102.879677],[25.471951,102.879913],[25.47208,102.880051],[25.472361,102.880257],[25.47258,102.8806],[25.472731,102.880707],[25.473961,102.881401],[25.47415,102.881332],[25.474279,102.881203],[25.47476,102.880508],[25.474899,102.880402],[25.4751,102.880333],[25.475281,102.880432],[25.475349,102.880653],[25.47525,102.881012],[25.474911,102.881432],[25.47423,102.881828],[25.473909,102.882057],[25.473749,102.882133],[25.47356,102.882149],[25.47341,102.882103],[25.471951,102.881058],[25.47163,102.880852],[25.47106,102.880859],[25.470329,102.881081],[25.470011,102.881081],[25.46986,102.881012],[25.469761,102.880852],[25.469761,102.880661],[25.469931,102.88031],[25.47015,102.879349],[25.47028,102.879181],[25.470631,102.879051],[25.470831,102.878906],[25.47093,102.8787],[25.470949,102.878532],[25.470751,102.877808],[25.470659,102.877632],[25.47053,102.87751],[25.469311,102.876862],[25.46911,102.876801],[25.46891,102.876778],[25.46871,102.876831],[25.468081,102.877312],[25.467911,102.877861],[25.46788,102.878082],[25.467779,102.87825],[25.466949,102.879158],[25.466749,102.879227],[25.466579,102.87925],[25.46641,102.879211],[25.466129,102.87896],[25.46583,102.878448],[25.4657,102.878326],[25.465549,102.878258],[25.465401,102.87825],[25.46493,102.878311],[25.46476,102.87825],[25.464649,102.878113],[25.4646,102.87793],[25.4646,102.877731],[25.464531,102.87735],[25.464411,102.877251],[25.46426,102.877182],[25.46298,102.877258],[25.462259,102.876953],[25.461411,102.876801],[25.46125,102.87661],[25.461229,102.87645],[25.461309,102.876297],[25.46216,102.875549],[25.462311,102.875381],[25.462811,102.874962],[25.46335,102.874832],[25.463511,102.874763],[25.463631,102.874657],[25.46373,102.874512],[25.46385,102.87413],[25.46406,102.873802],[25.464211,102.873779],[25.46493,102.873901],[25.465111,102.873863],[25.465231,102.873749],[25.4653,102.87355],[25.46533,102.873352],[25.4652,102.873161],[25.464729,102.873001],[25.464581,102.87291],[25.46446,102.87278],[25.46406,102.872147],[25.463909,102.872002],[25.46356,102.87178],[25.462851,102.871513],[25.4627,102.871407],[25.46258,102.871277],[25.462379,102.870979],[25.461849,102.870407],[25.46151,102.870262],[25.4608,102.870033],[25.460461,102.869881],[25.460329,102.869759],[25.45993,102.869049],[25.45923,102.868309],[25.4587,102.868134],[25.45853,102.868027],[25.458401,102.867897],[25.45816,102.867561],[25.45788,102.866852],[25.457781,102.866699],[25.4575,102.866402],[25.457411,102.866226],[25.457399,102.866051],[25.457451,102.865463],[25.45743,102.864883],[25.457199,102.864357],[25.4571,102.863602],[25.45698,102.863449],[25.45653,102.863258],[25.456181,102.863258],[25.45583,102.863129],[25.455709,102.862984],[25.455629,102.862801],[25.45566,102.86261],[25.455851,102.862129],[25.455851,102.861954],[25.455759,102.861763],[25.455231,102.86145],[25.454981,102.861061],[25.454651,102.86071],[25.454359,102.860558],[25.45381,102.86013],[25.453501,102.859932],[25.452881,102.859734],[25.45211,102.859901],[25.45195,102.859978],[25.45178,102.860107],[25.45166,102.86026],[25.45155,102.860611],[25.4515,102.861214],[25.45145,102.861382],[25.451361,102.861526],[25.451031,102.861748],[25.450661,102.861877],[25.44981,102.862411],[25.44965,102.862556],[25.44873,102.863228],[25.447849,102.863831],[25.44751,102.863998],[25.44698,102.864159],[25.44636,102.864182],[25.44566,102.864281],[25.445311,102.86425],[25.44516,102.864159],[25.44491,102.863899],[25.44475,102.863808],[25.444401,102.863762],[25.44418,102.863808],[25.44401,102.863899],[25.44385,102.864029],[25.44346,102.864449],[25.44326,102.864563],[25.44306,102.864609],[25.44265,102.864632],[25.44243,102.864609],[25.44228,102.864563],[25.441481,102.864502],[25.441059,102.864502],[25.440861,102.864548],[25.440359,102.864807],[25.440201,102.864799],[25.440029,102.864708],[25.439581,102.864227],[25.43918,102.863983],[25.438959,102.86393],[25.438749,102.863953],[25.43853,102.864014],[25.43811,102.864197],[25.437929,102.86425],[25.4377,102.864258],[25.43751,102.864357],[25.437229,102.864754],[25.436661,102.866081],[25.43648,102.86618],[25.4363,102.86618],[25.436131,102.866081],[25.436029,102.865898],[25.435961,102.865677],[25.43586,102.865013],[25.435961,102.864311],[25.435949,102.863708],[25.436001,102.86351],[25.436279,102.862808],[25.436279,102.862633],[25.43618,102.862511],[25.436029,102.862427],[25.435881,102.862396],[25.43536,102.862381],[25.43516,102.862297],[25.435011,102.86216],[25.43471,102.861603],[25.434561,102.861427],[25.433929,102.861099],[25.43343,102.860611],[25.43306,102.860382],[25.43128,102.859863],[25.430349,102.859657],[25.43,102.85968],[25.429359,102.859863],[25.42898,102.859833],[25.4284,102.859848],[25.428209,102.859909],[25.42803,102.860031],[25.427879,102.860184],[25.427759,102.860359],[25.427731,102.86058],[25.427759,102.860802],[25.42828,102.862396],[25.42823,102.862579],[25.428101,102.862701],[25.42786,102.862709],[25.42775,102.862633],[25.427629,102.86248],[25.427481,102.862106],[25.427361,102.861931],[25.427151,102.861351],[25.427059,102.861183],[25.426809,102.860878],[25.426611,102.860558],[25.426359,102.860352],[25.4258,102.859497],[25.42568,102.859001],[25.425659,102.858482],[25.4256,102.858261],[25.425501,102.858101],[25.42535,102.857964],[25.42518,102.857857],[25.424311,102.857552],[25.42363,102.85733],[25.423401,102.8573],[25.423161,102.857307],[25.422029,102.857483],[25.42161,102.857384],[25.42083,102.857002],[25.420059,102.856499],[25.419701,102.856201],[25.4195,102.856079],[25.419081,102.855957],[25.41791,102.855911],[25.41675,102.855782],[25.416531,102.855698],[25.416349,102.855583],[25.41605,102.855278],[25.41556,102.854599],[25.41531,102.853363],[25.41511,102.852951],[25.414961,102.852783],[25.414631,102.852531],[25.413759,102.85218],[25.413309,102.851929],[25.41258,102.851334],[25.412251,102.850998],[25.411699,102.850212],[25.41028,102.848152],[25.409849,102.847504],[25.409679,102.847298],[25.409401,102.846863],[25.4091,102.846481],[25.408279,102.84568],[25.40801,102.845253],[25.407801,102.84481],[25.40765,102.84465],[25.40731,102.844383],[25.4069,102.844254],[25.406731,102.844162],[25.406561,102.844002],[25.40645,102.843811],[25.406099,102.842812],[25.40543,102.841782],[25.40526,102.841614],[25.4046,102.84108],[25.4042,102.841011],[25.404011,102.841026],[25.403851,102.840958],[25.403749,102.840828],[25.4037,102.84063],[25.403629,102.839958],[25.403549,102.839752],[25.403231,102.839432],[25.403049,102.839333],[25.402849,102.839302],[25.402651,102.83931],[25.40205,102.8395],[25.401831,102.839478],[25.401649,102.839378],[25.401461,102.839211],[25.40118,102.838852],[25.400949,102.838432],[25.400551,102.83786],[25.40011,102.83741],[25.399799,102.837196],[25.399509,102.837151],[25.399111,102.837181],[25.39893,102.83725],[25.3983,102.83741],[25.3981,102.83741],[25.397079,102.837151],[25.39666,102.837158],[25.396259,102.83725],[25.395309,102.837646],[25.394609,102.838028],[25.394279,102.838058],[25.39415,102.838013],[25.39385,102.837807],[25.39315,102.837379],[25.39286,102.837112],[25.392679,102.836731],[25.39233,102.836159],[25.392151,102.835747],[25.39205,102.835327],[25.391781,102.834534],[25.3915,102.83416],[25.388599,102.83271],[25.38818,102.832428],[25.387711,102.831909],[25.38728,102.830551],[25.38706,102.830101],[25.386909,102.829613],[25.386909,102.829399],[25.38703,102.828911],[25.38703,102.828697],[25.38698,102.828499],[25.38686,102.828346],[25.386101,102.827682],[25.3855,102.826782],[25.38496,102.825996],[25.38435,102.824959],[25.384211,102.824753],[25.38353,102.823349],[25.38341,102.823128],[25.38328,102.823029],[25.38295,102.822678],[25.382799,102.822433],[25.38241,102.821632],[25.38208,102.821159],[25.38188,102.820961],[25.381451,102.82061],[25.3806,102.82],[25.380381,102.819878],[25.37966,102.819252],[25.37941,102.81913],[25.378929,102.819061],[25.37793,102.81913],[25.37746,102.81926],[25.3766,102.81971],[25.375759,102.820084],[25.375549,102.820213],[25.375311,102.820297],[25.37466,102.820213],[25.373779,102.819809],[25.373329,102.819809],[25.371929,102.820152],[25.371679,102.820259],[25.37105,102.820633],[25.370449,102.82106],[25.369749,102.8218],[25.368879,102.822632],[25.368311,102.82296],[25.368111,102.823013],[25.36688,102.823463],[25.36648,102.823509],[25.365629,102.823448],[25.365499,102.823311],[25.365379,102.823112],[25.365179,102.822479],[25.36491,102.8218],[25.36458,102.820801],[25.36446,102.820549],[25.36393,102.819061],[25.3638,102.818878],[25.363649,102.818581],[25.36335,102.817749],[25.36265,102.816528],[25.36178,102.814552],[25.361549,102.813408],[25.36161,102.81295],[25.361879,102.811958],[25.36203,102.811501],[25.362061,102.811028],[25.3619,102.809761],[25.3619,102.809196],[25.36198,102.808327],[25.362181,102.805733],[25.36215,102.805511],[25.36198,102.805099],[25.36161,102.804459],[25.36153,102.804001],[25.361549,102.803726],[25.361429,102.803261],[25.3612,102.802811],[25.36083,102.801811],[25.36063,102.800056],[25.360531,102.79985],[25.36006,102.799309],[25.35881,102.798058],[25.35746,102.795761],[25.357,102.795113],[25.356331,102.79451],[25.35531,102.793701],[25.35508,102.793411],[25.355009,102.793198],[25.355009,102.792198],[25.35533,102.790901],[25.35535,102.790398],[25.355129,102.78878],[25.355181,102.786247],[25.35511,102.785751],[25.3549,102.785332],[25.354759,102.785133],[25.354259,102.78418],[25.35335,102.782707],[25.353201,102.782562],[25.35285,102.782303],[25.352551,102.781883],[25.352051,102.781357],[25.35166,102.781197],[25.35148,102.781181],[25.35108,102.78125],[25.350901,102.781258],[25.3507,102.781197],[25.35051,102.781097],[25.350361,102.78093],[25.3501,102.780533],[25.349751,102.780312],[25.349609,102.780159],[25.349449,102.779877],[25.3491,102.779411],[25.348579,102.779114],[25.34816,102.77903],[25.347561,102.779129],[25.34738,102.779251],[25.347231,102.779411],[25.347,102.779846],[25.346861,102.780006],[25.34668,102.780128],[25.345711,102.78035],[25.344999,102.780563],[25.3444,102.780884],[25.343981,102.781029],[25.3438,102.781128],[25.343451,102.781433],[25.342911,102.782227],[25.342751,102.782303],[25.34256,102.782303],[25.342381,102.782249],[25.341379,102.781799],[25.340401,102.780952],[25.339411,102.779709],[25.33926,102.779549],[25.339149,102.779358],[25.3389,102.779053],[25.338699,102.7789],[25.338511,102.778847],[25.33835,102.778862],[25.33798,102.77906],[25.337681,102.779182],[25.33713,102.779282],[25.33671,102.779228],[25.335751,102.778976],[25.334999,102.778748],[25.33411,102.778229],[25.33375,102.778152],[25.3332,102.778198],[25.332109,102.778458],[25.33078,102.77903],[25.329651,102.779747],[25.329109,102.780182],[25.328581,102.78038],[25.328159,102.780403],[25.32778,102.780296],[25.327459,102.780029],[25.327101,102.779297],[25.3269,102.778999],[25.326759,102.778877],[25.32641,102.778709],[25.32626,102.778709],[25.32546,102.778847],[25.32505,102.778862],[25.32481,102.778809],[25.324249,102.778603],[25.32403,102.77858],[25.32296,102.778801],[25.32276,102.778801],[25.32201,102.778458],[25.320801,102.778099],[25.3204,102.777901],[25.31953,102.777107],[25.31885,102.7761],[25.318029,102.775299],[25.3179,102.775131],[25.317801,102.774902],[25.317751,102.774658],[25.317711,102.774178],[25.317579,102.773697],[25.31743,102.773514],[25.317101,102.773201],[25.31636,102.772697],[25.31525,102.771652],[25.314301,102.770958],[25.313709,102.770607],[25.313061,102.770683],[25.312851,102.77066],[25.311979,102.770409],[25.311359,102.770302],[25.30946,102.769798],[25.30933,102.769707],[25.30883,102.769157],[25.30838,102.768501],[25.308109,102.767357],[25.308149,102.765984],[25.30813,102.76503],[25.307949,102.764412],[25.307699,102.764076],[25.30756,102.763977],[25.306709,102.762749],[25.3062,102.762283],[25.305599,102.761902],[25.30525,102.761581],[25.305149,102.761383],[25.30501,102.76091],[25.30493,102.760429],[25.3048,102.760231],[25.304609,102.760078],[25.303801,102.759712],[25.3027,102.759331],[25.30253,102.759209],[25.30241,102.759048],[25.30233,102.758827],[25.30221,102.758148],[25.3022,102.757431],[25.30213,102.75721],[25.301979,102.757057],[25.301611,102.756882],[25.301479,102.756729],[25.301081,102.755898],[25.300461,102.754181],[25.3002,102.753799],[25.300011,102.753632],[25.299101,102.752998],[25.298161,102.752251],[25.297831,102.75193],[25.29756,102.751534],[25.296909,102.750809],[25.29673,102.750702],[25.29631,102.750633],[25.295959,102.750458],[25.295811,102.750313],[25.295549,102.749947],[25.29483,102.749382],[25.29401,102.749008],[25.293579,102.748901],[25.29213,102.748711],[25.2918,102.748528],[25.289631,102.747597],[25.288031,102.7472],[25.286249,102.746384],[25.285561,102.746201],[25.28441,102.745758],[25.28348,102.745483],[25.282261,102.745361],[25.282009,102.7453],[25.281601,102.745148],[25.28043,102.744957],[25.279409,102.745033],[25.27891,102.744911],[25.27791,102.744728],[25.2775,102.744583],[25.277309,102.744453],[25.276699,102.743713],[25.276501,102.743584],[25.276331,102.74353],[25.27615,102.743553],[25.27533,102.743752],[25.27416,102.74411],[25.27375,102.744377],[25.27355,102.744476],[25.273331,102.74453],[25.272881,102.744461],[25.27243,102.744431],[25.27141,102.744263],[25.27063,102.744202],[25.26993,102.7444],[25.26943,102.744408],[25.268709,102.744331],[25.26803,102.744263],[25.26738,102.744247],[25.267179,102.744308],[25.26638,102.744659],[25.266159,102.744682],[25.26573,102.744553],[25.2649,102.74408],[25.264681,102.744034],[25.2642,102.74398],[25.263729,102.743797],[25.26333,102.74353],[25.262911,102.742996],[25.26273,102.742607],[25.26263,102.742012],[25.26255,102.741852],[25.26235,102.74176],[25.26218,102.741882],[25.261999,102.74221],[25.261829,102.74231],[25.2614,102.742279],[25.261181,102.742302],[25.260981,102.742363],[25.260799,102.742477],[25.260611,102.742554],[25.26041,102.742531],[25.260031,102.742348],[25.25985,102.742203],[25.25935,102.741982],[25.25881,102.741859],[25.25831,102.741814],[25.25808,102.74173],[25.257111,102.741249],[25.25668,102.740982],[25.256451,102.740898],[25.256201,102.740883],[25.25573,102.740952],[25.25548,102.740959],[25.254749,102.741096],[25.254511,102.741096],[25.253901,102.740807],[25.25366,102.740761],[25.252911,102.740898],[25.252159,102.740959],[25.25168,102.740883],[25.251129,102.740631],[25.250759,102.740601],[25.250111,102.740707],[25.2498,102.740646],[25.249359,102.740402],[25.249201,102.740356],[25.24901,102.740356],[25.24855,102.740601],[25.24818,102.740631],[25.24753,102.740608],[25.24736,102.740646],[25.247129,102.740578],[25.246811,102.740402],[25.24625,102.739906],[25.24605,102.739777],[25.245609,102.739662],[25.24523,102.739449],[25.245001,102.739197],[25.244551,102.7388],[25.24441,102.738731],[25.2442,102.738747],[25.243811,102.738899],[25.24361,102.738876],[25.2435,102.738777],[25.243299,102.73851],[25.24305,102.738281],[25.24271,102.738129],[25.24238,102.73806],[25.241579,102.738113],[25.241211,102.738159],[25.24103,102.738129],[25.2409,102.738029],[25.24078,102.737862],[25.24066,102.737747],[25.240179,102.737511],[25.240009,102.73748],[25.239229,102.73745],[25.238729,102.737282],[25.23835,102.737251],[25.237881,102.737297],[25.237221,102.737343],[25.235609,102.736977],[25.234329,102.736778],[25.2339,102.736633],[25.233561,102.73645],[25.23329,102.736298],[25.23288,102.736214],[25.23233,102.73616],[25.230209,102.736107],[25.229759,102.736511],[25.229549,102.736862],[25.22921,102.737083],[25.22872,102.737267],[25.228609,102.737549],[25.2286,102.737953],[25.228479,102.738281],[25.2283,102.738564],[25.2281,102.738861],[25.228081,102.739014],[25.22818,102.739159],[25.228359,102.739212],[25.22863,102.739128],[25.229,102.738701],[25.229481,102.738197],[25.229851,102.738068],[25.230709,102.738083],[25.231279,102.738281],[25.231649,102.738281],[25.231859,102.738297],[25.2321,102.738564],[25.23221,102.738762],[25.23258,102.738907],[25.232929,102.738853],[25.233179,102.739014],[25.23344,102.739212],[25.233629,102.739616],[25.23385,102.739777],[25.23403,102.73983],[25.23436,102.739761],[25.234619,102.739822],[25.235109,102.740349],[25.23571,102.740593],[25.23596,102.740913],[25.235979,102.74115],[25.235941,102.74144],[25.23563,102.741623],[25.235201,102.741631],[25.23461,102.741753],[25.234079,102.742081],[25.233801,102.742172],[25.233379,102.742126],[25.23267,102.742027],[25.2323,102.742172],[25.232019,102.742378],[25.23185,102.742706],[25.231701,102.74308],[25.231529,102.743401],[25.231359,102.743507],[25.2311,102.743477],[25.230749,102.74321],[25.230709,102.742867],[25.230579,102.742317],[25.230129,102.742027],[25.229601,102.741783],[25.22872,102.741814],[25.227989,102.741661],[25.227409,102.741661],[25.22665,102.741447],[25.226259,102.741127],[25.225981,102.74073],[25.225731,102.740448],[25.225559,102.740402],[25.22541,102.74041],[25.22529,102.740593],[25.225189,102.74073],[25.224751,102.741013],[25.22418,102.741211],[25.223949,102.741653],[25.22373,102.741837],[25.22183,102.742447],[25.219999,102.742653],[25.21899,102.742851],[25.21788,102.742699],[25.2171,102.742561],[25.215811,102.742683],[25.214781,102.742683],[25.21406,102.742882],[25.21328,102.742981],[25.21253,102.742828],[25.212231,102.743088],[25.211861,102.743858],[25.21159,102.744217],[25.211161,102.744347],[25.211029,102.744209],[25.210899,102.743446],[25.210871,102.742729],[25.21055,102.742264],[25.21018,102.74202],[25.20965,102.741982],[25.20941,102.742279],[25.209459,102.742699],[25.209351,102.742912],[25.20911,102.742943],[25.207479,102.742851],[25.205999,102.742462],[25.20532,102.742371],[25.204309,102.741959],[25.20381,102.741859],[25.203341,102.741959],[25.202749,102.741966],[25.20096,102.741631],[25.19952,102.741211],[25.19906,102.74118],[25.19445,102.741096],[25.192699,102.740768],[25.192181,102.7407],[25.191839,102.740784],[25.19108,102.741158],[25.19055,102.741158],[25.189501,102.741226],[25.18906,102.741074],[25.18828,102.740822],[25.187519,102.740784],[25.186279,102.740784],[25.185511,102.740677],[25.18507,102.740356],[25.184259,102.739868],[25.182449,102.73896],[25.180901,102.738281],[25.17981,102.737999],[25.17901,102.737846],[25.178101,102.737534],[25.177349,102.737221],[25.17658,102.736443],[25.176279,102.736061],[25.17568,102.73568],[25.17518,102.735573],[25.174761,102.735382],[25.17448,102.73513],[25.174141,102.734596],[25.174101,102.734512],[25.174061,102.734062],[25.17408,102.733528],[25.17395,102.733047],[25.173759,102.732803],[25.173281,102.732712],[25.171709,102.733147],[25.17136,102.733078],[25.170719,102.732887],[25.17041,102.73288],[25.17008,102.733032],[25.16971,102.733414],[25.169359,102.733856],[25.169081,102.734032],[25.16876,102.734001],[25.167959,102.733429],[25.166889,102.73288],[25.16662,102.732826],[25.166071,102.732826],[25.165831,102.73275],[25.16568,102.73243],[25.165621,102.732117],[25.165449,102.731796],[25.165211,102.731827],[25.16507,102.732018],[25.16501,102.732109],[25.16511,102.732559],[25.1654,102.733002],[25.16581,102.733147],[25.16637,102.733238],[25.1667,102.733253],[25.166901,102.733482],[25.16687,102.73362],[25.16671,102.733849],[25.166439,102.733757],[25.165951,102.73349],[25.165461,102.733429],[25.165001,102.733307],[25.16473,102.733078],[25.164579,102.73278],[25.164591,102.732483],[25.164579,102.732147],[25.164551,102.731758],[25.16436,102.731583],[25.16415,102.731651],[25.16408,102.731979],[25.1642,102.732529],[25.16419,102.732811],[25.164301,102.733307],[25.16448,102.733551],[25.164829,102.733658],[25.16518,102.733711],[25.165421,102.733833],[25.16543,102.734154],[25.1653,102.734283],[25.165001,102.734253],[25.16433,102.73391],[25.16366,102.733597],[25.1635,102.73317],[25.16338,102.732651],[25.163231,102.732201],[25.16297,102.731949],[25.162689,102.73188],[25.162411,102.732079],[25.16213,102.73278],[25.16194,102.733513],[25.161711,102.733711],[25.160521,102.734306],[25.1602,102.734238],[25.15971,102.733849],[25.15906,102.733299],[25.158609,102.73307],[25.158409,102.733078],[25.158159,102.732979],[25.157909,102.732857],[25.157761,102.732536],[25.157579,102.732353],[25.157471,102.732361],[25.157301,102.732452],[25.15723,102.732613],[25.1572,102.732948],[25.15723,102.733299],[25.157459,102.733528],[25.15806,102.733688],[25.15843,102.733833],[25.158751,102.734261],[25.15893,102.734871],[25.15921,102.735603],[25.15962,102.735992],[25.160009,102.736122],[25.160339,102.736259],[25.1609,102.736732],[25.161659,102.737053],[25.16231,102.737183],[25.162661,102.73716],[25.162769,102.737213],[25.162979,102.73735],[25.163139,102.73777],[25.1632,102.737846],[25.1633,102.738113],[25.16328,102.73838],[25.163059,102.738678],[25.162661,102.739052],[25.16227,102.739311],[25.161751,102.739433],[25.16147,102.739403],[25.16116,102.739403],[25.161051,102.739372],[25.160629,102.73925],[25.160061,102.739029],[25.15967,102.738876],[25.15741,102.738419],[25.156481,102.738129],[25.15554,102.737587],[25.153151,102.736588],[25.150579,102.735527],[25.149429,102.735031],[25.148701,102.734787],[25.14473,102.733528],[25.143021,102.73275],[25.141371,102.732208],[25.136999,102.730568],[25.130501,102.728256],[25.12912,102.727676],[25.12747,102.726837],[25.12598,102.725861],[25.12476,102.72522],[25.123051,102.724701],[25.121719,102.72422],[25.119909,102.72393],[25.118311,102.723679],[25.117149,102.723381],[25.11606,102.723129],[25.11553,102.723099],[25.115311,102.723259],[25.11496,102.724297],[25.114599,102.725632],[25.114111,102.72641],[25.11356,102.727448],[25.1129,102.728729],[25.108379,102.726807],[25.10449,102.725151],[25.101049,102.723686],[25.10005,102.72654],[25.09898,102.729637],[25.09713,102.73497],[25.096161,102.737579],[25.09581,102.737534],[25.09334,102.736557],[25.09148,102.735909],[25.09123,102.735817],[25.0889,102.73497],[25.08815,102.734673],[25.087391,102.734383],[25.085621,102.732613],[25.0839,102.730911],[25.081699,102.733963],[25.08021,102.736153],[25.07494,102.743919],[25.074869,102.744019],[25.071899,102.74762],[25.07069,102.749336],[25.07015,102.751411],[25.067841,102.750389],[25.066681,102.749413],[25.065109,102.747681],[25.063669,102.746552],[25.06233,102.745644],[25.060631,102.744438],[25.060289,102.744202],[25.057619,102.742691],[25.057409,102.742462],[25.05604,102.742752],[25.051701,102.742897],[25.049891,102.742989],[25.04567,102.743103],[25.04431,102.743134],[25.0413,102.743263],[25.03709,102.743469],[25.035601,102.743599],[25.033911,102.743767],[25.03154,102.74382],[25.030161,102.74353],[25.02953,102.743271],[25.02825,102.742767],[25.026091,102.741898],[25.025089,102.741814],[25.0238,102.74205],[25.0231,102.742233],[25.022341,102.742371],[25.02179,102.742477],[25.021219,102.742592],[25.01985,102.742943],[25.01964,102.743042],[25.019501,102.743187],[25.019449,102.743347],[25.01948,102.743477],[25.01955,102.74366],[25.0198,102.74395],[25.01992,102.744102],[25.02,102.744362],[25.020029,102.744621],[25.01989,102.745796],[25.01976,102.746368],[25.01919,102.749313],[25.01759,102.755577],[25.017191,102.756592],[25.01643,102.757927],[25.01516,102.759399],[25.01408,102.760368],[25.00745,102.764168],[25.005659,102.76519],[25.004789,102.765747],[25.004169,102.766327],[25.00341,102.767403],[25.00296,102.768417],[25.00198,102.770973],[25.00152,102.771751],[25.0009,102.772476],[24.9932,102.778389],[24.992041,102.779327],[24.99118,102.779999],[24.990601,102.780243],[24.98991,102.780342],[24.98925,102.780243],[24.98415,102.778168],[24.982491,102.777603],[24.98114,102.777588],[24.978029,102.777863],[24.973841,102.778633],[24.973101,102.778778],[24.972031,102.779068],[24.971201,102.779381],[24.96909,102.780296],[24.967541,102.781143],[24.966209,102.781967],[24.957451,102.787659],[24.956369,102.788292],[24.955509,102.788712],[24.95487,102.788963],[24.95372,102.78936],[24.951731,102.789703],[24.95056,102.78978],[24.93424,102.789619],[24.926109,102.788887],[24.924629,102.788948],[24.923161,102.789169],[24.92104,102.789757],[24.919081,102.79068],[24.917391,102.791763],[24.904909,102.800919],[24.90271,102.802032],[24.900499,102.802696],[24.898359,102.802963],[24.89703,102.80323],[24.895639,102.803741],[24.894461,102.804321],[24.89431,102.804398],[24.89344,102.804947],[24.89315,102.805153],[24.891251,102.806808],[24.88316,102.814201],[24.880819,102.815666],[24.878929,102.816467],[24.876221,102.817123],[24.874001,102.817291],[24.84852,102.817581],[24.84655,102.81736],[24.84318,102.816437],[24.839991,102.814957],[24.830021,102.808449],[24.828449,102.807693],[24.82411,102.806129],[24.822969,102.805481],[24.819901,102.802963],[24.817209,102.801666],[24.81572,102.801048],[24.814489,102.800247],[24.81016,102.795677],[24.8069,102.793289],[24.8011,102.787453],[24.800039,102.78669],[24.79859,102.785896],[24.79657,102.785118],[24.795799,102.784828],[24.785509,102.780983],[24.784889,102.780609],[24.784161,102.780037],[24.783541,102.779297],[24.78186,102.776398],[24.779381,102.77179],[24.77845,102.770477],[24.77702,102.76889],[24.776011,102.768021],[24.77453,102.766991],[24.77227,102.765877],[24.770599,102.765327],[24.76366,102.764069],[24.734501,102.754677],[24.732719,102.753777],[24.73086,102.752457],[24.72957,102.751198],[24.709591,102.725899],[24.69681,102.713463],[24.696119,102.712807],[24.694839,102.710548],[24.69313,102.706947],[24.69272,102.706306],[24.69241,102.705963],[24.691811,102.705513],[24.69121,102.70517],[24.68935,102.704407],[24.688761,102.704002],[24.68825,102.703491],[24.68782,102.702888],[24.68749,102.70192],[24.685551,102.695763],[24.678829,102.681763],[24.67807,102.680649],[24.67717,102.67971],[24.67095,102.675392],[24.670059,102.674568],[24.669491,102.67379],[24.668909,102.672684],[24.668631,102.671654],[24.664829,102.653343],[24.66445,102.65229],[24.66386,102.651253],[24.66073,102.647186],[24.65988,102.646393],[24.6506,102.638947],[24.643311,102.630211],[24.64097,102.628479],[24.627899,102.623543],[24.627211,102.623138],[24.626381,102.622452],[24.62466,102.620277],[24.623949,102.619698],[24.617371,102.616913],[24.61204,102.614761],[24.605829,102.610237],[24.601089,102.607674],[24.599501,102.606468],[24.597919,102.604881],[24.58987,102.595268],[24.579691,102.585068],[24.57741,102.583359],[24.57579,102.58242],[24.56934,102.579987],[24.55953,102.577469],[24.555241,102.575607],[24.554131,102.57534],[24.549549,102.575256],[24.54882,102.575157],[24.54788,102.574913],[24.542219,102.572319],[24.541121,102.571609],[24.54015,102.570663],[24.53915,102.569366],[24.53838,102.568626],[24.537069,102.567719],[24.53651,102.567162],[24.536051,102.566528],[24.53557,102.565552],[24.535021,102.56356],[24.5345,102.56234],[24.53392,102.56147],[24.533079,102.560638],[24.53204,102.55999],[24.53105,102.559647],[24.52458,102.558792],[24.523661,102.558517],[24.522989,102.558189],[24.52256,102.557877],[24.519461,102.555054],[24.51862,102.554459],[24.517719,102.554039],[24.516569,102.553757],[24.515289,102.553772],[24.514521,102.55397],[24.50947,102.556023],[24.50729,102.556717],[24.50609,102.557312],[24.500919,102.560722],[24.5002,102.561043],[24.494989,102.561996],[24.493891,102.562347],[24.49102,102.563553],[24.489889,102.563797],[24.488701,102.563843],[24.487949,102.563721],[24.487209,102.563522],[24.485359,102.562782],[24.484381,102.562553],[24.481859,102.562187],[24.481131,102.561974],[24.48068,102.561729],[24.47967,102.560867],[24.47547,102.556763],[24.471451,102.554123],[24.470181,102.55291],[24.468599,102.550987],[24.467661,102.550163],[24.466789,102.549622],[24.466089,102.549316],[24.46512,102.549049],[24.41419,102.541649],[24.40333,102.539558],[24.399929,102.53891],[24.398029,102.538544],[24.391729,102.537331],[24.390289,102.537117],[24.37652,102.535439],[24.37458,102.534958],[24.370319,102.533524],[24.359261,102.530693],[24.3577,102.530441],[24.35693,102.530312],[24.355539,102.53009],[24.353239,102.529762],[24.350981,102.529442],[24.349449,102.529114],[24.34881,102.528976],[24.33872,102.52536],[24.335779,102.523987],[24.331289,102.521278],[24.328819,102.519768],[24.32793,102.519234],[24.324511,102.517273],[24.32218,102.516609],[24.317949,102.515617],[24.316759,102.515068],[24.31604,102.514557],[24.315069,102.513573],[24.3137,102.511871],[24.312799,102.511147],[24.31176,102.510597],[24.30479,102.508911],[24.3043,102.508743],[24.30143,102.507187],[24.291599,102.50116],[24.290791,102.500458],[24.29007,102.499619],[24.28937,102.498367],[24.288759,102.497108],[24.288271,102.496353],[24.2878,102.495827],[24.28723,102.495407],[24.286591,102.495087],[24.285919,102.494888],[24.28525,102.494797],[24.282829,102.494797],[24.282221,102.494743],[24.28142,102.494476],[24.280569,102.493973],[24.2794,102.492844],[24.276489,102.4879],[24.27578,102.487053],[24.274691,102.486198],[24.273609,102.485657],[24.272449,102.485382],[24.26977,102.485046],[24.268471,102.48465],[24.26585,102.483528],[24.26474,102.483238],[24.26259,102.483109],[24.25843,102.483162],[24.25771,102.483017],[24.25713,102.482857],[24.25701,102.482826],[24.25679,102.48275],[24.256611,102.482689],[24.256069,102.482513],[24.25515,102.482117],[24.253349,102.48143],[24.25172,102.480797],[24.250879,102.480476],[24.25012,102.480263],[24.248831,102.480049],[24.247219,102.480019],[24.23737,102.481071],[24.235371,102.480927],[24.224079,102.478661],[24.212351,102.474663],[24.210661,102.473763],[24.20948,102.472878],[24.20829,102.471649],[24.204809,102.466621],[24.203409,102.46524],[24.20174,102.464043],[24.196659,102.461678],[24.19556,102.460876],[24.194941,102.460243],[24.19416,102.459106],[24.193331,102.457581],[24.191719,102.455399],[24.191389,102.454742],[24.191139,102.454033],[24.19101,102.45327],[24.19099,102.452591],[24.19091,102.45002],[24.190901,102.449692],[24.19076,102.444458],[24.19109,102.441818],[24.191771,102.437843],[24.19174,102.436836],[24.191641,102.436348],[24.19136,102.435623],[24.191099,102.435181],[24.18651,102.43042],[24.185989,102.429581],[24.185711,102.428879],[24.184311,102.419518],[24.183969,102.418533],[24.183371,102.417389],[24.182409,102.415947],[24.181881,102.414803],[24.18154,102.413551],[24.1812,102.403793],[24.180929,102.402191],[24.18042,102.400688],[24.177509,102.395042],[24.176331,102.392754],[24.17631,102.392723],[24.176149,102.392403],[24.17314,102.386574],[24.172701,102.385933],[24.170879,102.384216],[24.17062,102.383812],[24.17046,102.383347],[24.170179,102.381378],[24.16997,102.380669],[24.169609,102.380043],[24.169121,102.379478],[24.16855,102.379021],[24.16753,102.378349],[24.167021,102.377808],[24.166389,102.377007],[24.166019,102.376701],[24.165569,102.376472],[24.16416,102.376099],[24.16374,102.3759],[24.163389,102.375603],[24.163139,102.375191],[24.162661,102.374092],[24.162411,102.373703],[24.162251,102.37352],[24.16185,102.373238],[24.161409,102.373077],[24.15999,102.37294],[24.15954,102.372833],[24.159321,102.372726],[24.158939,102.372467],[24.15859,102.372147],[24.158319,102.371773],[24.15811,102.37133],[24.15798,102.37085],[24.157841,102.369583],[24.15766,102.368828],[24.157379,102.368118],[24.15666,102.367088],[24.156179,102.366371],[24.155479,102.364662],[24.15521,102.364029],[24.154329,102.363487],[24.153721,102.363167],[24.152889,102.362442],[24.15229,102.361687],[24.15196,102.361397],[24.15155,102.361153],[24.15045,102.360817],[24.149799,102.360527],[24.149441,102.360222],[24.149151,102.35984],[24.14892,102.359413],[24.14876,102.358917],[24.148399,102.356651],[24.148041,102.355782],[24.14629,102.353394],[24.14595,102.35276],[24.145611,102.35183],[24.14521,102.350128],[24.145029,102.349693],[24.14465,102.349068],[24.14324,102.347618],[24.142731,102.346786],[24.1418,102.344177],[24.14126,102.343384],[24.140659,102.342873],[24.140129,102.342621],[24.13954,102.342499],[24.138929,102.342506],[24.136841,102.342957],[24.1362,102.343002],[24.135571,102.342903],[24.13516,102.342743],[24.132589,102.340973],[24.13216,102.340759],[24.131701,102.340622],[24.130989,102.340523],[24.127661,102.340523],[24.12628,102.340202],[24.124981,102.339577],[24.12085,102.33638],[24.117701,102.334648],[24.11706,102.334412],[24.11635,102.334328],[24.11565,102.334381],[24.114941,102.334572],[24.114281,102.334923],[24.113449,102.33548],[24.11302,102.335693],[24.11256,102.335808],[24.11208,102.335823],[24.11161,102.335716],[24.111179,102.335503],[24.10861,102.333557],[24.106741,102.33268],[24.10528,102.331383],[24.10442,102.330612],[24.102909,102.329628],[24.10244,102.329132],[24.102039,102.328522],[24.101669,102.327477],[24.101049,102.32486],[24.10013,102.319603],[24.09733,102.308762],[24.097191,102.307899],[24.096939,102.306992],[24.09639,102.305817],[24.09561,102.304764],[24.094851,102.304039],[24.093651,102.30307],[24.093321,102.302711],[24.09306,102.302307],[24.092791,102.301651],[24.092609,102.300667],[24.092541,102.29995],[24.092421,102.29953],[24.092239,102.299141],[24.091841,102.298592],[24.09063,102.297256],[24.0902,102.296577],[24.08963,102.295433],[24.08935,102.295059],[24.08901,102.294746],[24.0886,102.294563],[24.088381,102.29451],[24.087959,102.294518],[24.087219,102.29483],[24.08667,102.295097],[24.08625,102.295174],[24.08585,102.295242],[24.082951,102.296356],[24.082621,102.296516],[24.08209,102.296532],[24.0816,102.296417],[24.081181,102.296318],[24.08079,102.296112],[24.08042,102.295807],[24.08012,102.295441],[24.07991,102.295013],[24.07976,102.29454],[24.079679,102.294022],[24.0797,102.293243],[24.0802,102.290543],[24.08024,102.290009],[24.08013,102.28923],[24.079941,102.288757],[24.07933,102.287903],[24.077909,102.28611],[24.0777,102.285744],[24.0776,102.285332],[24.07761,102.284912],[24.077709,102.2845],[24.077909,102.284126],[24.078409,102.283669],[24.078991,102.283257],[24.079321,102.282921],[24.07955,102.282509],[24.07966,102.282051],[24.07967,102.281578],[24.07852,102.277153],[24.07806,102.276161],[24.075491,102.272011],[24.075199,102.271309],[24.0748,102.269821],[24.074591,102.269386],[24.074459,102.269173],[24.073931,102.2686],[24.07037,102.266113],[24.069981,102.265747],[24.06966,102.26532],[24.06941,102.264839],[24.069151,102.264069],[24.06813,102.258057],[24.067631,102.25647],[24.063391,102.248207],[24.063089,102.247742],[24.06238,102.246918],[24.06155,102.246246],[24.059299,102.244904],[24.057791,102.243858],[24.057039,102.243134],[24.05673,102.242722],[24.05632,102.242027],[24.05582,102.240761],[24.054319,102.236038],[24.05357,102.234596],[24.05155,102.231468],[24.050631,102.22953],[24.04875,102.224281],[24.048401,102.223633],[24.04619,102.221077],[24.04599,102.220711],[24.045799,102.220093],[24.045759,102.219177],[24.045759,102.21759],[24.045759,102.217461],[24.04575,102.214523],[24.04575,102.213913],[24.045691,102.207733],[24.045561,102.206467],[24.045349,102.205673],[24.04513,102.205132],[24.04483,102.204391],[24.044189,102.203178],[24.037531,102.195297],[24.036949,102.194763],[24.03628,102.194359],[24.031691,102.192528],[24.03071,102.192322],[24.029181,102.192192],[24.02747,102.192032],[24.026331,102.191757],[24.02446,102.191139],[24.023439,102.190964],[24.014271,102.191002],[24.01329,102.190872],[24.0121,102.190483],[24.0112,102.189987],[24.010401,102.189377],[24.00802,102.186996],[24.007721,102.186577],[24.00737,102.18586],[24.006901,102.18457],[24.00667,102.18409],[24.006371,102.183662],[24.005791,102.183144],[24.005569,102.182983],[24.00429,102.182053],[24.004009,102.181839],[24.00309,102.181152],[24.002621,102.180801],[23.999161,102.178482],[23.99815,102.178101],[23.997219,102.177979],[23.993441,102.17823],[23.991911,102.17807],[23.98851,102.17717],[23.987881,102.177116],[23.98723,102.17717],[23.986589,102.17733],[23.98562,102.177834],[23.98452,102.178513],[23.983761,102.178818],[23.982731,102.178993],[23.981871,102.178902],[23.98102,102.178642],[23.979971,102.178177],[23.979059,102.177948],[23.9765,102.177856],[23.975559,102.177658],[23.97468,102.177238],[23.974079,102.176819],[23.971951,102.174683],[23.97135,102.174232],[23.96685,102.171967],[23.96616,102.171738],[23.965191,102.171669],[23.96447,102.171761],[23.963039,102.172127],[23.962561,102.172188],[23.96209,102.172127],[23.96162,102.171944],[23.96122,102.171661],[23.958651,102.168922],[23.95356,102.16555],[23.953131,102.16507],[23.952921,102.164711],[23.952669,102.163879],[23.95248,102.162537],[23.952339,102.162109],[23.952101,102.161728],[23.95179,102.161423],[23.946501,102.158653],[23.94496,102.157494],[23.942419,102.154846],[23.9419,102.154488],[23.941311,102.154297],[23.94047,102.154228],[23.93947,102.154266],[23.939091,102.154243],[23.93854,102.154083],[23.937599,102.153488],[23.93655,102.152649],[23.935699,102.152184],[23.93387,102.15155],[23.933331,102.151237],[23.932699,102.150703],[23.932409,102.150391],[23.931231,102.148399],[23.93082,102.14798],[23.93018,102.147568],[23.929529,102.147186],[23.92911,102.146828],[23.92877,102.146393],[23.928169,102.145157],[23.92758,102.144363],[23.926809,102.14373],[23.92609,102.143349],[23.91666,102.14122],[23.914061,102.140831],[23.913349,102.140778],[23.908159,102.14093],[23.90766,102.140877],[23.897499,102.139458],[23.89678,102.139381],[23.896061,102.139252],[23.89463,102.13871],[23.89208,102.137512],[23.890499,102.136703],[23.88798,102.134712],[23.887449,102.134132],[23.88703,102.133453],[23.88681,102.132957],[23.886379,102.13176],[23.885281,102.129013],[23.877159,102.123848],[23.876949,102.123734],[23.87628,102.123627],[23.874849,102.12368],[23.874399,102.12365],[23.87398,102.123482],[23.87368,102.123154],[23.873461,102.12278],[23.872881,102.121277],[23.872459,102.120659],[23.87211,102.1203],[23.870911,102.119453],[23.87038,102.118896],[23.87023,102.118698],[23.86998,102.118233],[23.86936,102.116547],[23.86911,102.11615],[23.86895,102.115959],[23.868561,102.115646],[23.86725,102.114952],[23.865561,102.113297],[23.864361,102.11203],[23.86401,102.11145],[23.863859,102.110832],[23.86388,102.110413],[23.864111,102.10981],[23.864361,102.109459],[23.86471,102.109177],[23.86515,102.109001],[23.867279,102.108498],[23.86791,102.108231],[23.868099,102.108109],[23.868401,102.107727],[23.86895,102.106552],[23.869209,102.10611],[23.869551,102.105713],[23.869949,102.105431],[23.870399,102.105209],[23.87126,102.104851],[23.871599,102.104584],[23.871849,102.104279],[23.871929,102.104057],[23.87195,102.103851],[23.87188,102.103378],[23.87175,102.103012],[23.871481,102.102699],[23.871111,102.102448],[23.870911,102.102364],[23.870501,102.102333],[23.87026,102.102379],[23.86981,102.1026],[23.86916,102.102798],[23.86871,102.102829],[23.8685,102.102814],[23.867149,102.102249],[23.86648,102.10183],[23.865879,102.101303],[23.86536,102.100647],[23.86388,102.098213],[23.86368,102.09761],[23.863661,102.097412],[23.8638,102.096764],[23.864031,102.096359],[23.86445,102.095848],[23.864981,102.095001],[23.865299,102.094254],[23.865681,102.093201],[23.86581,102.092934],[23.866131,102.092484],[23.86668,102.091904],[23.867149,102.091263],[23.867399,102.090759],[23.86763,102.089981],[23.867781,102.088951],[23.86775,102.088509],[23.867701,102.088303],[23.867479,102.087929],[23.867149,102.087646],[23.8666,102.087448],[23.8664,102.087448],[23.86618,102.087509],[23.865761,102.087761],[23.86545,102.088081],[23.865259,102.088478],[23.865049,102.0896],[23.864811,102.090233],[23.864599,102.090599],[23.864059,102.091103],[23.861059,102.092583],[23.86046,102.092957],[23.860161,102.093208],[23.85955,102.094032],[23.85935,102.094452],[23.859079,102.09481],[23.85873,102.095154],[23.857849,102.095581],[23.85738,102.095703],[23.857161,102.095711],[23.85676,102.095901],[23.856409,102.096161],[23.85626,102.096313],[23.856159,102.096497],[23.85605,102.096626],[23.85606,102.0989],[23.85601,102.099152],[23.855801,102.099579],[23.855511,102.099983],[23.85516,102.100304],[23.85471,102.100906],[23.854309,102.101929],[23.854,102.102547],[23.853701,102.102913],[23.853161,102.10331],[23.852949,102.103401],[23.85203,102.10363],[23.85128,102.103683],[23.85055,102.1036],[23.84981,102.103409],[23.84853,102.10321],[23.84803,102.103027],[23.847799,102.102913],[23.847401,102.102577],[23.846701,102.101784],[23.84593,102.101196],[23.84486,102.100601],[23.84428,102.100159],[23.843531,102.099258],[23.84318,102.09893],[23.842779,102.098663],[23.841961,102.098312],[23.84136,102.097954],[23.841181,102.097809],[23.84103,102.097633],[23.8407,102.096977],[23.84058,102.096527],[23.8403,102.095161],[23.840151,102.094727],[23.84005,102.094551],[23.83938,102.093979],[23.839199,102.093857],[23.837481,102.093353],[23.83728,102.093262],[23.835831,102.092857],[23.835409,102.092659],[23.835011,102.092377],[23.834681,102.092049],[23.83445,102.091698],[23.834129,102.090881],[23.8332,102.088898],[23.83288,102.08831],[23.830799,102.084099],[23.83016,102.083054],[23.829861,102.08271],[23.82933,102.082359],[23.828329,102.081863],[23.822161,102.078331],[23.82205,102.078178],[23.82181,102.077698],[23.821199,102.076813],[23.82086,102.076462],[23.8188,102.074661],[23.818331,102.074333],[23.817829,102.074112],[23.817329,102.074013],[23.81706,102.074051],[23.81608,102.073959],[23.81583,102.073883],[23.815359,102.073601],[23.81246,102.070953],[23.811911,102.070358],[23.810949,102.069153],[23.810579,102.068832],[23.81036,102.06871],[23.809879,102.068527],[23.809629,102.068497],[23.80913,102.06855],[23.808661,102.068703],[23.80765,102.069527],[23.80718,102.069809],[23.806931,102.069908],[23.806431,102.069977],[23.805929,102.069809],[23.8057,102.069702],[23.805111,102.069206],[23.804449,102.068359],[23.804079,102.067978],[23.80345,102.067581],[23.80213,102.067047],[23.80155,102.066658],[23.801029,102.0662],[23.79903,102.064003],[23.798861,102.06385],[23.79821,102.063148],[23.797501,102.062531],[23.79648,102.061852],[23.795851,102.061501],[23.79565,102.061363],[23.79418,102.060448],[23.792999,102.059502],[23.791599,102.058357],[23.79055,102.057701],[23.78875,102.056847],[23.78598,102.056],[23.78591,102.055946],[23.785601,102.055771],[23.785271,102.05555],[23.78495,102.055313],[23.784639,102.055054],[23.78433,102.054779],[23.783991,102.054497],[23.78377,102.054321],[23.783541,102.054138],[23.7833,102.053963],[23.78306,102.05378],[23.78281,102.053612],[23.78229,102.053284],[23.782021,102.053123],[23.78175,102.052963],[23.781481,102.052818],[23.7812,102.052673],[23.780661,102.052353],[23.78039,102.052193],[23.780121,102.05204],[23.77984,102.05188],[23.77957,102.05172],[23.779301,102.051559],[23.77903,102.051399],[23.77877,102.051224],[23.778509,102.051064],[23.778259,102.05088],[23.778009,102.05069],[23.777769,102.050507],[23.77754,102.050323],[23.777309,102.050117],[23.777081,102.049919],[23.776859,102.049721],[23.77664,102.049507],[23.77643,102.049316],[23.77622,102.049118],[23.77602,102.04892],[23.77581,102.048721],[23.775511,102.048431],[23.7752,102.048141],[23.7749,102.047859],[23.77459,102.047569],[23.77438,102.047371],[23.774179,102.04718],[23.773979,102.046982],[23.77376,102.046783],[23.77355,102.046593],[23.77322,102.046303],[23.772989,102.046112],[23.77276,102.045937],[23.77252,102.045761],[23.77227,102.045593],[23.77202,102.045433],[23.77178,102.045273],[23.771521,102.04512],[23.771271,102.044983],[23.771021,102.04483],[23.770769,102.044693],[23.77051,102.04454],[23.77026,102.044403],[23.77002,102.044243],[23.76977,102.044098],[23.76952,102.043953],[23.76927,102.043793],[23.76902,102.043663],[23.76878,102.04351],[23.76853,102.043373],[23.76829,102.043221],[23.76804,102.043083],[23.767799,102.042938],[23.76755,102.042801],[23.767309,102.042664],[23.767071,102.042503],[23.76683,102.042351],[23.7666,102.042198],[23.766371,102.042038],[23.766041,102.041786],[23.76582,102.041618],[23.76549,102.041344],[23.76528,102.041161],[23.76507,102.04097],[23.76486,102.040771],[23.76465,102.040573],[23.764441,102.040367],[23.764231,102.040161],[23.76403,102.039963],[23.763821,102.039757],[23.76362,102.039551],[23.76321,102.039162],[23.76289,102.038918],[23.76255,102.038696],[23.762199,102.038513],[23.76182,102.038368],[23.761419,102.038277],[23.761141,102.038239],[23.76086,102.038223],[23.760571,102.038193],[23.760269,102.038147],[23.759979,102.038116],[23.759689,102.038078],[23.757641,102.03775],[23.757311,102.037598],[23.756981,102.03743],[23.756651,102.037262],[23.756321,102.037079],[23.755989,102.036888],[23.755011,102.036324],[23.754681,102.036102],[23.75433,102.035889],[23.753969,102.03569],[23.753599,102.035492],[23.753241,102.035309],[23.752871,102.035103],[23.75251,102.034882],[23.75218,102.034607],[23.7519,102.034271],[23.751671,102.033897],[23.751459,102.033508],[23.75127,102.033119],[23.75107,102.032738],[23.750851,102.032372],[23.750629,102.032013],[23.75038,102.031677],[23.75012,102.031349],[23.749861,102.031029],[23.74958,102.030724],[23.7493,102.030403],[23.74902,102.030083],[23.748791,102.029701],[23.74864,102.029289],[23.748581,102.028877],[23.748619,102.028458],[23.74872,102.028053],[23.74893,102.027687],[23.74921,102.02739],[23.74954,102.027168],[23.749901,102.027031],[23.750259,102.026939],[23.750629,102.026894],[23.750999,102.026817],[23.75135,102.026718],[23.751659,102.026527],[23.751909,102.026268],[23.75206,102.025917],[23.752131,102.025558],[23.752119,102.025169],[23.75209,102.024773],[23.75205,102.024353],[23.752041,102.023933],[23.752081,102.023499],[23.75218,102.023071],[23.7523,102.022659],[23.752541,102.021828],[23.75256,102.021408],[23.752501,102.021004],[23.75231,102.020653],[23.75205,102.020363],[23.75172,102.02021],[23.751369,102.020126],[23.75102,102.020172],[23.750681,102.020287],[23.75042,102.020561],[23.75021,102.020889],[23.75001,102.02124],[23.74964,102.021957],[23.749451,102.022324],[23.74926,102.022667],[23.749041,102.023003],[23.748739,102.023247],[23.748409,102.02343],[23.74807,102.023537],[23.747721,102.023613],[23.74737,102.023666],[23.74703,102.023781],[23.746719,102.023956],[23.74645,102.024193],[23.74621,102.024467],[23.745991,102.024773],[23.74575,102.02507],[23.74552,102.02536],[23.74523,102.025597],[23.74489,102.025787],[23.74453,102.025871],[23.744169,102.02581],[23.74382,102.025681],[23.74349,102.02549],[23.743179,102.025299],[23.74287,102.025101],[23.742559,102.024902],[23.74225,102.024696],[23.74193,102.024513],[23.74161,102.024307],[23.741289,102.024109],[23.74095,102.023911],[23.740601,102.02372],[23.740259,102.023529],[23.73991,102.023338],[23.739571,102.023163],[23.739229,102.022987],[23.738899,102.022812],[23.73856,102.022629],[23.738239,102.022461],[23.737909,102.022293],[23.737579,102.022118],[23.737261,102.021942],[23.736931,102.021767],[23.736589,102.021599],[23.73625,102.021431],[23.73591,102.021248],[23.735571,102.021057],[23.735241,102.020844],[23.73493,102.020592],[23.734631,102.020317],[23.73436,102.020027],[23.734131,102.019699],[23.73391,102.019363],[23.733709,102.019028],[23.73349,102.0187],[23.733231,102.018402],[23.73295,102.01815],[23.73263,102.01799],[23.732281,102.017921],[23.73192,102.01796],[23.731581,102.018059],[23.73127,102.018257],[23.73101,102.018532],[23.73082,102.01886],[23.730709,102.019241],[23.730671,102.019638],[23.73073,102.020042],[23.73086,102.020432],[23.731039,102.020798],[23.73127,102.021141],[23.731501,102.021477],[23.73172,102.021843],[23.731939,102.022202],[23.73214,102.02256],[23.73234,102.022926],[23.73254,102.023277],[23.732731,102.023651],[23.732901,102.024033],[23.73307,102.024406],[23.733231,102.024803],[23.733379,102.0252],[23.73353,102.025597],[23.733681,102.026009],[23.73382,102.026413],[23.733959,102.02681],[23.73411,102.027206],[23.734249,102.027611],[23.73439,102.028023],[23.734541,102.028419],[23.734699,102.028816],[23.73485,102.029213],[23.735001,102.02961],[23.73514,102.030022],[23.735229,102.030441],[23.73527,102.030884],[23.73526,102.031319],[23.73522,102.031761],[23.73513,102.032173],[23.734989,102.03257],[23.7348,102.032944],[23.734591,102.033287],[23.734341,102.033592],[23.734051,102.033867],[23.733749,102.034103],[23.733419,102.034286],[23.73308,102.034439],[23.732719,102.034561],[23.732349,102.034653],[23.731979,102.034683],[23.7316,102.034668],[23.731199,102.034607],[23.730789,102.034538],[23.73037,102.034447],[23.729919,102.03437],[23.729469,102.034286],[23.72901,102.034233],[23.728559,102.03418],[23.728109,102.034126],[23.727659,102.034103],[23.7272,102.03405],[23.726749,102.033997],[23.726311,102.033928],[23.72587,102.033821],[23.725451,102.033691],[23.725031,102.033539],[23.724621,102.033371],[23.724211,102.033188],[23.723789,102.03302],[23.723351,102.032913],[23.7229,102.032883],[23.72246,102.032944],[23.72204,102.033089],[23.721649,102.03331],[23.721291,102.033546],[23.72093,102.033798],[23.72056,102.034027],[23.7202,102.034264],[23.71983,102.034462],[23.71946,102.034668],[23.71908,102.034866],[23.71871,102.035072],[23.71833,102.035263],[23.717951,102.035461],[23.71756,102.035637],[23.717171,102.035828],[23.716789,102.036011],[23.716419,102.036209],[23.71603,102.036308],[23.71563,102.036346],[23.71525,102.036301],[23.714899,102.036148],[23.714581,102.035927],[23.714291,102.035683],[23.71402,102.035408],[23.71372,102.035156],[23.713409,102.03492],[23.713079,102.034714],[23.712721,102.034538],[23.71236,102.034393],[23.711981,102.034264],[23.711599,102.034103],[23.711229,102.033951],[23.710871,102.033783],[23.71052,102.033577],[23.71019,102.033363],[23.709869,102.033119],[23.70957,102.032867],[23.709261,102.032623],[23.708941,102.032402],[23.708611,102.032211],[23.70826,102.032066],[23.707911,102.03196],[23.70755,102.031891],[23.70718,102.031853],[23.70681,102.031837],[23.70644,102.031822],[23.70606,102.031792],[23.7057,102.031723],[23.705351,102.031593],[23.705009,102.031433],[23.704691,102.031227],[23.704399,102.030983],[23.704121,102.030693],[23.703871,102.03038],[23.70363,102.030052],[23.703381,102.029716],[23.703119,102.029404],[23.70257,102.028763],[23.70228,102.02845],[23.701969,102.028137],[23.70167,102.027847],[23.701361,102.02755],[23.70105,102.02726],[23.700741,102.026993],[23.70059,102.026863],[23.70014,102.026466],[23.699841,102.02623],[23.699539,102.025978],[23.699261,102.025703],[23.698999,102.025414],[23.698771,102.025078],[23.69857,102.024727],[23.698389,102.024361],[23.69825,102.023987],[23.698139,102.023598],[23.698071,102.023209],[23.698021,102.022812],[23.698009,102.022423],[23.698021,102.022034],[23.698021,102.021652],[23.69804,102.021271],[23.69805,102.020889],[23.698059,102.020493],[23.698071,102.020103],[23.69809,102.019676],[23.698099,102.019257],[23.698099,102.018837],[23.698099,102.018417],[23.69808,102.017982],[23.69805,102.017548],[23.698009,102.017113],[23.69796,102.01667],[23.697889,102.016228],[23.697809,102.015793],[23.697729,102.01535],[23.69763,102.014923],[23.697531,102.014503],[23.69742,102.014076],[23.697321,102.01368],[23.69721,102.013283],[23.697109,102.012894],[23.69701,102.012489],[23.696911,102.012093],[23.6968,102.011703],[23.696699,102.011307],[23.69659,102.01091],[23.696489,102.010513],[23.69639,102.010117],[23.696289,102.009727],[23.69619,102.009331],[23.696079,102.008942],[23.69598,102.008537],[23.695869,102.008148],[23.69577,102.007751],[23.695669,102.007362],[23.69557,102.006973],[23.695471,102.006577],[23.69537,102.006203],[23.695271,102.005829],[23.695169,102.005463],[23.69507,102.005089],[23.694969,102.004723],[23.69488,102.004356],[23.69478,102.00399],[23.694679,102.003616],[23.69458,102.003242],[23.694481,102.002869],[23.694389,102.002487],[23.69429,102.002121],[23.694189,102.001747],[23.69409,102.001373],[23.693991,102.000999],[23.693899,102.000633],[23.6938,102.000259],[23.693701,101.999893],[23.693609,101.999542],[23.69352,101.999191],[23.693411,101.998848],[23.693279,101.998497],[23.69315,101.998154],[23.69301,101.997803],[23.692869,101.997437],[23.692711,101.99707],[23.692539,101.996696],[23.692381,101.996323],[23.6922,101.995949],[23.692011,101.995567],[23.69183,101.995193],[23.691641,101.994797],[23.691441,101.994423],[23.69125,101.994034],[23.69105,101.993637],[23.690861,101.993248],[23.69066,101.992859],[23.69047,101.992462],[23.690281,101.992073],[23.6901,101.991653],[23.689939,101.991241],[23.689791,101.990822],[23.68964,101.990387],[23.689501,101.989967],[23.689369,101.989563],[23.689251,101.989128],[23.68915,101.988708],[23.689051,101.988281],[23.688971,101.987862],[23.68889,101.987442],[23.68882,101.987022],[23.688761,101.986603],[23.688721,101.986183],[23.688681,101.985764],[23.68865,101.985352],[23.688629,101.98494],[23.68861,101.984528],[23.688589,101.984123],[23.68858,101.983711],[23.68856,101.983307],[23.688551,101.98291],[23.68852,101.982513],[23.68849,101.982101],[23.68845,101.981697],[23.688391,101.981293],[23.688311,101.980888],[23.688219,101.980492],[23.68811,101.980087],[23.68799,101.979691],[23.687851,101.979301],[23.687691,101.978912],[23.687531,101.978523],[23.68737,101.978127],[23.68722,101.977753],[23.687059,101.977364],[23.686899,101.976967],[23.686741,101.976593],[23.68659,101.976212],[23.68643,101.97583],[23.686279,101.975456],[23.686131,101.975098],[23.685961,101.974747],[23.68578,101.974442],[23.685579,101.974136],[23.68536,101.973877],[23.68512,101.973633],[23.684879,101.973412],[23.684629,101.973221],[23.68438,101.973053],[23.684151,101.9729],[23.68383,101.972603],[23.683571,101.972458],[23.68306,101.972168],[23.682819,101.971977],[23.682501,101.971779],[23.682249,101.971626],[23.681971,101.971443],[23.681641,101.971237],[23.681391,101.971077],[23.68115,101.970932],[23.680889,101.970779],[23.68063,101.970627],[23.680349,101.970459],[23.680071,101.970284],[23.679779,101.970108],[23.679489,101.969933],[23.67918,101.969757],[23.678881,101.969597],[23.67857,101.969452],[23.678261,101.96933],[23.67794,101.969223],[23.67762,101.969131],[23.677299,101.969063],[23.67697,101.969009],[23.67663,101.968971],[23.676291,101.968933],[23.675949,101.968887],[23.6756,101.968826],[23.67527,101.968727],[23.67462,101.968483],[23.67432,101.968277],[23.67403,101.968079],[23.67374,101.967857],[23.67345,101.967644],[23.673161,101.96743],[23.672859,101.967239],[23.67255,101.967056],[23.672239,101.966927],[23.67193,101.96682],[23.671619,101.966743],[23.67131,101.966667],[23.671021,101.966621],[23.67075,101.966614],[23.670349,101.966614],[23.66995,101.966637],[23.66091,101.97168],[23.660431,101.971909],[23.66013,101.972076],[23.659809,101.972214],[23.659479,101.972313],[23.65914,101.972366],[23.658791,101.972412],[23.658449,101.97242],[23.65773,101.972427],[23.65737,101.97242],[23.657,101.972412],[23.65662,101.972397],[23.65624,101.972389],[23.655849,101.972366],[23.65547,101.972298],[23.6551,101.97216],[23.654751,101.97197],[23.65443,101.971764],[23.65411,101.971542],[23.65379,101.971336],[23.65346,101.971184],[23.65312,101.971046],[23.652769,101.970978],[23.652399,101.970947],[23.65204,101.970963],[23.651661,101.970993],[23.65127,101.971024],[23.650909,101.971001],[23.65053,101.970917],[23.650181,101.970757],[23.649851,101.970558],[23.649561,101.970299],[23.649281,101.970032],[23.64901,101.969772],[23.64875,101.969513],[23.648491,101.969261],[23.64823,101.969002],[23.64797,101.96875],[23.647699,101.968491],[23.64743,101.968231],[23.64716,101.967957],[23.646891,101.967682],[23.646641,101.967377],[23.64642,101.967056],[23.64624,101.966698],[23.646099,101.966316],[23.645969,101.965927],[23.64583,101.965553],[23.6457,101.965149],[23.645559,101.964767],[23.645399,101.964409],[23.64522,101.964088],[23.644991,101.963814],[23.644739,101.963562],[23.64447,101.963341],[23.643101,101.962318],[23.64275,101.96209],[23.64241,101.961853],[23.642071,101.961632],[23.641741,101.961411],[23.641399,101.961182],[23.641069,101.96096],[23.640751,101.960716],[23.64043,101.96048],[23.640141,101.96022],[23.63987,101.959953],[23.63962,101.959686],[23.638901,101.958862],[23.63866,101.958588],[23.638479,101.958397],[23.63728,101.957024],[23.63489,101.954277],[23.63361,101.952621],[23.633329,101.951576],[23.63299,101.948517],[23.632059,101.946426],[23.63175,101.945503],[23.632021,101.944267],[23.63216,101.943573],[23.632389,101.942902],[23.63249,101.942574],[23.632521,101.942223],[23.632259,101.93898],[23.632299,101.938667],[23.632351,101.938339],[23.63238,101.938011],[23.632401,101.937683],[23.632401,101.937332],[23.63241,101.936653],[23.632389,101.936287],[23.63237,101.935944],[23.632351,101.935593],[23.632339,101.935226],[23.63236,101.934883],[23.63245,101.934517],[23.632561,101.934174],[23.63269,101.93383],[23.63283,101.933472],[23.63298,101.933113],[23.633129,101.932747],[23.633289,101.932404],[23.633591,101.931664],[23.63368,101.931267],[23.633711,101.930862],[23.63368,101.930473],[23.633631,101.930069],[23.63357,101.929688],[23.633459,101.929329],[23.633369,101.92897],[23.63332,101.928612],[23.63331,101.928253],[23.633329,101.927528],[23.63336,101.927162],[23.633511,101.926819],[23.633711,101.926514],[23.63435,101.925613],[23.635139,101.924377],[23.635309,101.923653],[23.63538,101.923286],[23.635441,101.92292],[23.6355,101.922546],[23.635559,101.922188],[23.63562,101.921806],[23.635691,101.921448],[23.635771,101.921082],[23.635851,101.920723],[23.63595,101.920349],[23.636061,101.919983],[23.636169,101.919609],[23.63629,101.919243],[23.63641,101.918869],[23.63653,101.918503],[23.636641,101.918121],[23.636761,101.917747],[23.636869,101.917374],[23.63698,101.917],[23.63711,101.916634],[23.637251,101.916267],[23.637409,101.915909],[23.637581,101.915573],[23.637791,101.915253],[23.63802,101.914963],[23.63826,101.914673],[23.638519,101.914398],[23.638809,101.914162],[23.63909,101.913933],[23.639971,101.913269],[23.640249,101.913033],[23.640499,101.912773],[23.640751,101.912514],[23.64097,101.912216],[23.641159,101.911926],[23.641331,101.911613],[23.64147,101.911301],[23.641581,101.91098],[23.64167,101.91066],[23.641729,101.910339],[23.641781,101.910027],[23.64183,101.909714],[23.64188,101.909401],[23.64193,101.909103],[23.641979,101.908813],[23.64201,101.908386],[23.642031,101.90799],[23.64205,101.9076],[23.642071,101.907204],[23.64213,101.906799],[23.642191,101.906387],[23.64225,101.905983],[23.6423,101.905571],[23.64238,101.905151],[23.642521,101.904739],[23.642651,101.904472],[23.642799,101.904221],[23.642969,101.903976],[23.64316,101.903763],[23.64337,101.903542],[23.643591,101.903343],[23.64382,101.903152],[23.644039,101.902946],[23.64427,101.90274],[23.64447,101.902519],[23.644661,101.902283],[23.644831,101.902023],[23.645029,101.901604],[23.64513,101.901299],[23.64521,101.900993],[23.645281,101.900658],[23.64535,101.900337],[23.64542,101.900009],[23.6455,101.899681],[23.645611,101.899353],[23.645729,101.89904],[23.64588,101.898743],[23.646061,101.898438],[23.646259,101.898163],[23.646469,101.897881],[23.646681,101.897598],[23.646891,101.897301],[23.647091,101.897003],[23.647261,101.896683],[23.647421,101.896362],[23.647539,101.896019],[23.64765,101.895683],[23.64773,101.895317],[23.647791,101.894958],[23.647829,101.894592],[23.647881,101.894234],[23.647921,101.893852],[23.647961,101.893494],[23.64802,101.89312],[23.6481,101.892761],[23.648199,101.892403],[23.648319,101.892067],[23.648451,101.891739],[23.6486,101.891434],[23.64876,101.891121],[23.64893,101.890831],[23.64909,101.890533],[23.64922,101.890244],[23.649361,101.889954],[23.64949,101.889671],[23.649639,101.889397],[23.649771,101.889122],[23.64991,101.888847],[23.650049,101.888573],[23.65019,101.888298],[23.65033,101.888023],[23.650471,101.887733],[23.65062,101.887428],[23.65077,101.887123],[23.650921,101.88681],[23.65107,101.886497],[23.65123,101.886177],[23.65139,101.885849],[23.65156,101.885521],[23.65172,101.885178],[23.65189,101.884842],[23.65204,101.884499],[23.65221,101.884163],[23.65237,101.88382],[23.65254,101.883492],[23.6527,101.883179],[23.652849,101.882874],[23.653009,101.882584],[23.653151,101.882294],[23.653299,101.882019],[23.653521,101.88163],[23.65366,101.881378],[23.653799,101.881149],[23.6539,101.880768],[23.6546,101.878288],[23.65497,101.877052],[23.65519,101.876587],[23.65564,101.875954],[23.657261,101.874313],[23.657681,101.873672],[23.657881,101.873199],[23.65803,101.8722],[23.658001,101.868111],[23.65777,101.867126],[23.657431,101.866409],[23.656799,101.865631],[23.65568,101.864571],[23.65534,101.864098],[23.655069,101.863403],[23.654449,101.860573],[23.653891,101.859253],[23.65309,101.857887],[23.652849,101.857109],[23.6527,101.855202],[23.652519,101.854607],[23.652201,101.854088],[23.65103,101.852982],[23.650789,101.852661],[23.650499,101.851913],[23.65053,101.851082],[23.650631,101.85022],[23.6506,101.849571],[23.650471,101.849152],[23.650129,101.848633],[23.649679,101.848213],[23.647881,101.847023],[23.64748,101.846626],[23.647169,101.846169],[23.64691,101.845627],[23.64591,101.842331],[23.64588,101.841537],[23.646021,101.840973],[23.646509,101.839737],[23.64658,101.839371],[23.646561,101.838982],[23.646391,101.838463],[23.6462,101.838158],[23.645679,101.837677],[23.644739,101.836983],[23.64422,101.836113],[23.643431,101.833298],[23.643379,101.832687],[23.643419,101.832283],[23.643539,101.831909],[23.64373,101.831596],[23.64398,101.831306],[23.644661,101.830681],[23.645029,101.830032],[23.64509,101.829674],[23.645069,101.829277],[23.644979,101.828918],[23.64468,101.82843],[23.64443,101.828194],[23.64377,101.827888],[23.64187,101.827499],[23.641439,101.827347],[23.641121,101.827271],[23.64064,101.827003],[23.64023,101.82666],[23.6397,101.825867],[23.638741,101.824013],[23.63851,101.823723],[23.63822,101.823479],[23.63772,101.823273],[23.634621,101.822853],[23.63373,101.822456],[23.633289,101.822166],[23.63265,101.821503],[23.632271,101.820862],[23.63167,101.819717],[23.631189,101.819206],[23.630751,101.818939],[23.63028,101.818771],[23.629459,101.818718],[23.628241,101.818901],[23.627939,101.818893],[23.62748,101.818764],[23.62705,101.818542],[23.626699,101.818192],[23.62628,101.817398],[23.625401,101.815086],[23.625311,101.814537],[23.62536,101.813812],[23.62553,101.813271],[23.62578,101.812782],[23.627951,101.810028],[23.628139,101.809547],[23.628189,101.809029],[23.62818,101.808868],[23.627979,101.808357],[23.627661,101.807938],[23.627119,101.807632],[23.62405,101.80632],[23.625191,101.808884],[23.62512,101.809036],[23.625,101.80941],[23.624729,101.809753],[23.624331,101.8106],[23.623581,101.811707],[23.623159,101.811996],[23.622641,101.812172],[23.62188,101.81218],[23.619591,101.811241],[23.618839,101.811234],[23.61693,101.811867],[23.616489,101.81189],[23.616039,101.811752],[23.61566,101.81147],[23.615379,101.811073],[23.615351,101.810913],[23.615259,101.810677],[23.61528,101.810501],[23.61525,101.810333],[23.6154,101.809113],[23.61533,101.808052],[23.615101,101.807381],[23.61482,101.806931],[23.61384,101.805931],[23.61338,101.804947],[23.612089,101.804108],[23.606489,101.800911],[23.60602,101.800377],[23.605721,101.79985],[23.60515,101.798477],[23.60471,101.798012],[23.603531,101.797302],[23.602871,101.79673],[23.601749,101.795517],[23.601049,101.794998],[23.600031,101.794533],[23.59981,101.794533],[23.597759,101.793373],[23.59746,101.793297],[23.59713,101.79306],[23.596479,101.792343],[23.59548,101.790649],[23.59395,101.787376],[23.593281,101.787666],[23.593069,101.787567],[23.59271,101.787483],[23.59218,101.787453],[23.591379,101.787331],[23.591049,101.787209],[23.59067,101.786911],[23.588079,101.784103],[23.58736,101.783546],[23.583599,101.781487],[23.58288,101.780853],[23.58206,101.779671],[23.581341,101.77845],[23.579889,101.77681],[23.57777,101.773178],[23.57704,101.772392],[23.57626,101.771942],[23.574301,101.771294],[23.57362,101.770897],[23.569811,101.767776],[23.568859,101.767281],[23.56444,101.765839],[23.563801,101.765472],[23.56325,101.764969],[23.56292,101.764526],[23.56076,101.761436],[23.56049,101.761147],[23.560011,101.760841],[23.559481,101.760651],[23.55802,101.760628],[23.557501,101.760529],[23.55702,101.760277],[23.556749,101.760063],[23.556431,101.759598],[23.55628,101.759247],[23.55587,101.756828],[23.555571,101.756027],[23.55514,101.75531],[23.554581,101.754723],[23.55154,101.752617],[23.55105,101.752113],[23.55064,101.751312],[23.549629,101.747353],[23.5494,101.746819],[23.54907,101.746384],[23.54847,101.745941],[23.547041,101.74514],[23.54565,101.743851],[23.540291,101.738487],[23.52383,101.719322],[23.52364,101.719063],[23.523529,101.718758],[23.523479,101.718697],[23.52347,101.718613],[23.523279,101.718323],[23.522591,101.716637],[23.521999,101.715767],[23.52058,101.714523],[23.52,101.713913],[23.519779,101.713562],[23.51964,101.71315],[23.5196,101.712479],[23.519739,101.711777],[23.521111,101.707848],[23.52124,101.70697],[23.521231,101.706749],[23.52112,101.706306],[23.520889,101.705887],[23.52058,101.705521],[23.520399,101.70536],[23.51824,101.70433],[23.51787,101.704071],[23.51755,101.703743],[23.51734,101.703331],[23.51722,101.702873],[23.51722,101.7024],[23.517321,101.701958],[23.518999,101.698547],[23.51775,101.698097],[23.51767,101.6978],[23.517309,101.697159],[23.51687,101.69648],[23.516701,101.695976],[23.516529,101.69442],[23.51643,101.693939],[23.516211,101.693497],[23.515921,101.693123],[23.515539,101.692818],[23.515129,101.692596],[23.51243,101.691757],[23.51194,101.691704],[23.51141,101.691719],[23.51091,101.691818],[23.50996,101.692207],[23.507971,101.693314],[23.507601,101.693588],[23.50729,101.693932],[23.507059,101.694366],[23.50691,101.694847],[23.506861,101.695351],[23.507,101.696098],[23.50742,101.697243],[23.5075,101.697701],[23.507481,101.698158],[23.507339,101.698608],[23.507099,101.699013],[23.506781,101.699333],[23.506161,101.699654],[23.50526,101.700027],[23.504829,101.700287],[23.504471,101.700638],[23.50415,101.701057],[23.503901,101.701538],[23.503441,101.703049],[23.503309,101.703537],[23.50313,101.703979],[23.50301,101.704163],[23.50268,101.704491],[23.502291,101.70472],[23.501909,101.704857],[23.501499,101.704849],[23.50091,101.704697],[23.50058,101.704491],[23.500111,101.704033],[23.49843,101.701653],[23.498051,101.700943],[23.49762,101.699638],[23.497089,101.697792],[23.49687,101.697281],[23.496441,101.696579],[23.49609,101.696167],[23.493389,101.694],[23.492741,101.693573],[23.49201,101.69326],[23.491501,101.693169],[23.49099,101.693161],[23.49048,101.693253],[23.49,101.69342],[23.482491,101.698227],[23.481791,101.698517],[23.481319,101.698624],[23.47983,101.698692],[23.47933,101.698769],[23.478849,101.698921],[23.47797,101.699402],[23.476339,101.700623],[23.47547,101.701134],[23.474991,101.701286],[23.47427,101.701363],[23.473539,101.701248],[23.47261,101.70092],[23.471729,101.700432],[23.470921,101.699806],[23.4702,101.699051],[23.469601,101.698143],[23.467279,101.693512],[23.4664,101.692177],[23.46524,101.690804],[23.46394,101.689568],[23.462299,101.688393],[23.45648,101.68544],[23.45483,101.684227],[23.451571,101.679291],[23.45013,101.677612],[23.44994,101.67746],[23.449751,101.677254],[23.44949,101.677063],[23.44916,101.676651],[23.44833,101.676033],[23.44721,101.675468],[23.446461,101.675232],[23.445459,101.675049],[23.444201,101.675041],[23.44323,101.675217],[23.43902,101.67688],[23.43664,101.677452],[23.432159,101.677811],[23.43161,101.677773],[23.431431,101.677727],[23.431009,101.677711],[23.43075,101.677757],[23.430719,101.677887],[23.43041,101.678017],[23.42782,101.678543],[23.42403,101.680153],[23.423691,101.680183],[23.42275,101.680458],[23.422331,101.68055],[23.42065,101.680603],[23.41925,101.680367],[23.41754,101.679703],[23.416361,101.679008],[23.41523,101.678017],[23.41408,101.67662],[23.409769,101.67025],[23.409281,101.66922],[23.408991,101.667892],[23.408939,101.666992],[23.40909,101.665619],[23.409439,101.664513],[23.410669,101.661987],[23.4111,101.660606],[23.41157,101.658386],[23.4119,101.657417],[23.41876,101.645554],[23.422489,101.637756],[23.4282,101.62957],[23.42873,101.628517],[23.429131,101.626556],[23.42959,101.622337],[23.42943,101.621048],[23.42898,101.619904],[23.42824,101.618896],[23.427191,101.618149],[23.42573,101.617706],[23.424709,101.617783],[23.42399,101.617973],[23.421801,101.619003],[23.42082,101.619186],[23.41987,101.61908],[23.4189,101.618713],[23.418091,101.617973],[23.417589,101.617203],[23.417191,101.615929],[23.41724,101.6147],[23.41798,101.611702],[23.41794,101.610687],[23.417459,101.60936],[23.417101,101.608871],[23.416019,101.608063],[23.41116,101.606781],[23.410561,101.606598],[23.409781,101.606407],[23.408819,101.605873],[23.40723,101.604347],[23.40661,101.603989],[23.40645,101.603943],[23.40589,101.603752],[23.40432,101.603638],[23.403259,101.603188],[23.40159,101.602028],[23.393909,101.58802],[23.392799,101.586533],[23.392191,101.585709],[23.391319,101.584778],[23.390221,101.583527],[23.38945,101.582977],[23.38868,101.582642],[23.383381,101.580978],[23.382919,101.580917],[23.376631,101.581413],[23.37141,101.58181],[23.370029,101.581902],[23.365709,101.581863],[23.364161,101.581528],[23.36342,101.580582],[23.36319,101.579971],[23.363119,101.57975],[23.36302,101.578888],[23.363171,101.577911],[23.36417,101.574783],[23.36421,101.57399],[23.36409,101.572906],[23.36302,101.568893],[23.362671,101.566399],[23.36252,101.565987],[23.36227,101.565643],[23.36195,101.565338],[23.360991,101.564751],[23.36055,101.564323],[23.36034,101.563942],[23.36025,101.563507],[23.360241,101.563011],[23.36146,101.555557],[23.361481,101.555077],[23.36145,101.554817],[23.3613,101.554359],[23.361059,101.553932],[23.35988,101.552742],[23.359739,101.552559],[23.359541,101.552139],[23.35944,101.551666],[23.359461,101.551193],[23.3596,101.550743],[23.35985,101.550331],[23.360359,101.549797],[23.3624,101.548019],[23.36273,101.547653],[23.363001,101.547234],[23.363171,101.546722],[23.36323,101.546188],[23.363171,101.545624],[23.362129,101.542778],[23.36191,101.542297],[23.361429,101.541649],[23.36083,101.54113],[23.356621,101.539139],[23.355459,101.538544],[23.35391,101.537888],[23.353291,101.53775],[23.35309,101.53775],[23.35268,101.537857],[23.35231,101.538101],[23.352011,101.538452],[23.35129,101.539688],[23.351,101.539993],[23.35067,101.540222],[23.350281,101.540352],[23.349859,101.540367],[23.349211,101.54026],[23.34816,101.539841],[23.347811,101.539619],[23.34753,101.53933],[23.34734,101.538963],[23.34724,101.538513],[23.347269,101.537819],[23.347429,101.53669],[23.34742,101.536232],[23.347321,101.535797],[23.346979,101.535103],[23.346121,101.533829],[23.34573,101.533813],[23.344851,101.533127],[23.344709,101.532967],[23.34454,101.532593],[23.344469,101.532181],[23.344481,101.531754],[23.344749,101.531113],[23.345341,101.530067],[23.34547,101.52964],[23.34549,101.529419],[23.34544,101.528961],[23.345369,101.528732],[23.34515,101.528313],[23.344681,101.527786],[23.343719,101.526917],[23.34347,101.526573],[23.343281,101.526154],[23.34318,101.525703],[23.34318,101.525223],[23.343321,101.52449],[23.343639,101.523193],[23.34362,101.522339],[23.34285,101.519333],[23.34116,101.5177],[23.34013,101.517014],[23.33942,101.516563],[23.33905,101.51619],[23.335939,101.511429],[23.335501,101.510902],[23.335039,101.510536],[23.333469,101.510399],[23.3328,101.510399],[23.332359,101.510406],[23.331421,101.510529],[23.33069,101.510742],[23.33045,101.510841],[23.32917,101.511803],[23.32873,101.512032],[23.328251,101.512169],[23.327749,101.51223],[23.327009,101.512154],[23.323721,101.511398],[23.32324,101.511223],[23.322809,101.510941],[23.322451,101.510597],[23.322161,101.510147],[23.320351,101.505699],[23.32012,101.505348],[23.319851,101.505074],[23.316191,101.503098],[23.316031,101.50293],[23.315781,101.502434],[23.315651,101.501892],[23.315639,101.501511],[23.31591,101.500183],[23.31591,101.499603],[23.31584,101.499207],[23.31547,101.498512],[23.31509,101.4981],[23.313749,101.497139],[23.313049,101.4963],[23.311449,101.493736],[23.310949,101.49324],[23.310511,101.49295],[23.309811,101.492706],[23.309259,101.49263],[23.308701,101.492653],[23.30798,101.492867],[23.307329,101.493263],[23.30624,101.494263],[23.30578,101.494499],[23.30526,101.494598],[23.30475,101.494522],[23.30443,101.494408],[23.304001,101.494133],[23.30332,101.493523],[23.302679,101.493134],[23.302151,101.492973],[23.300329,101.492828],[23.29982,101.492691],[23.29936,101.492416],[23.29896,101.492058],[23.298651,101.49157],[23.29851,101.491203],[23.29841,101.490593],[23.298441,101.489937],[23.29887,101.488731],[23.29994,101.486298],[23.30003,101.485863],[23.300039,101.485397],[23.299959,101.484947],[23.29982,101.484512],[23.29916,101.483093],[23.29899,101.48246],[23.298941,101.479362],[23.29888,101.478943],[23.29845,101.477783],[23.29397,101.471352],[23.293539,101.470367],[23.293381,101.469688],[23.29336,101.469353],[23.293779,101.464844],[23.2936,101.460899],[23.29335,101.459717],[23.29188,101.454727],[23.29196,101.453789],[23.292139,101.453323],[23.29254,101.452782],[23.293091,101.452377],[23.29735,101.450317],[23.29784,101.450218],[23.298019,101.450157],[23.29837,101.45005],[23.300659,101.448982],[23.301109,101.448647],[23.301611,101.448097],[23.30344,101.445053],[23.303631,101.44455],[23.30373,101.44381],[23.303711,101.443443],[23.302691,101.440353],[23.30262,101.439346],[23.303419,101.434143],[23.30341,101.433594],[23.30246,101.428864],[23.30212,101.426933],[23.30205,101.425301],[23.30209,101.423752],[23.30225,101.423042],[23.302509,101.422371],[23.30275,101.421272],[23.30324,101.419991],[23.30357,101.418121],[23.304411,101.41581],[23.30448,101.414879],[23.3043,101.414093],[23.303921,101.412971],[23.30341,101.411713],[23.303289,101.411186],[23.302959,101.410378],[23.302151,101.407608],[23.302019,101.403557],[23.30205,101.399788],[23.301559,101.398216],[23.299601,101.394699],[23.29941,101.394173],[23.298491,101.388153],[23.29851,101.387039],[23.299,101.381798],[23.299179,101.379967],[23.299601,101.375473],[23.29952,101.37381],[23.29854,101.368073],[23.298491,101.367287],[23.298559,101.366814],[23.29862,101.366577],[23.29883,101.366158],[23.298969,101.365967],[23.299129,101.365807],[23.29973,101.365448],[23.30014,101.365318],[23.300591,101.365318],[23.300791,101.365372],[23.301411,101.365631],[23.302679,101.366463],[23.30315,101.366669],[23.305269,101.367111],[23.308611,101.368553],[23.30908,101.368668],[23.309549,101.368683],[23.30978,101.368637],[23.310221,101.368462],[23.31061,101.368179],[23.310921,101.367813],[23.311159,101.367348],[23.311291,101.366852],[23.31131,101.3666],[23.31126,101.366089],[23.31119,101.365829],[23.310949,101.365372],[23.310631,101.36496],[23.31044,101.364777],[23.308399,101.363472],[23.30801,101.363098],[23.30773,101.362648],[23.307541,101.362137],[23.30748,101.361893],[23.30747,101.361351],[23.307541,101.360817],[23.30772,101.360313],[23.30801,101.359863],[23.30838,101.359489],[23.30883,101.3592],[23.309771,101.358704],[23.310181,101.358353],[23.31049,101.357941],[23.31069,101.357468],[23.31078,101.356972],[23.310459,101.352417],[23.31035,101.351883],[23.310141,101.351357],[23.30983,101.350891],[23.309111,101.350021],[23.308661,101.349297],[23.30788,101.347549],[23.3076,101.347076],[23.30723,101.346687],[23.305611,101.345879],[23.305229,101.345596],[23.304939,101.345253],[23.30475,101.344803],[23.304661,101.344322],[23.30468,101.343826],[23.304729,101.343597],[23.30492,101.343163],[23.305201,101.342789],[23.30537,101.342644],[23.306009,101.34227],[23.308861,101.341087],[23.309299,101.340843],[23.309669,101.3405],[23.309959,101.340073],[23.310141,101.3396],[23.31019,101.339104],[23.310141,101.338593],[23.30998,101.338097],[23.309719,101.337692],[23.309549,101.337517],[23.30913,101.337242],[23.308649,101.337067],[23.30817,101.337013],[23.30768,101.337082],[23.30719,101.337273],[23.305771,101.33799],[23.301991,101.340103],[23.30154,101.340286],[23.30106,101.340393],[23.30057,101.34037],[23.29932,101.340088],[23.29855,101.34005],[23.297001,101.340271],[23.29649,101.34024],[23.29598,101.340118],[23.293831,101.339027],[23.293381,101.338768],[23.29261,101.338577],[23.29154,101.338562],[23.288971,101.338783],[23.288191,101.338737],[23.287689,101.338608],[23.287201,101.338387],[23.28404,101.335876],[23.283569,101.335587],[23.283079,101.335388],[23.28257,101.335274],[23.282049,101.335251],[23.281521,101.33532],[23.28101,101.335487],[23.28054,101.335732],[23.27841,101.337212],[23.277769,101.337517],[23.277321,101.337593],[23.27689,101.337547],[23.27648,101.33741],[23.2761,101.337143],[23.27562,101.336594],[23.27515,101.335983],[23.27478,101.335617],[23.274361,101.335373],[23.274139,101.335289],[23.273899,101.335243],[23.273439,101.335251],[23.272051,101.335579],[23.27157,101.335564],[23.27112,101.335403],[23.27072,101.335167],[23.27021,101.334663],[23.26919,101.333076],[23.269051,101.332809],[23.26845,101.332222],[23.267771,101.331757],[23.267241,101.331573],[23.266479,101.33149],[23.265961,101.331558],[23.265221,101.331787],[23.263969,101.332336],[23.263201,101.332497],[23.261641,101.332603],[23.261129,101.332733],[23.260651,101.332947],[23.260201,101.333229],[23.26,101.333397],[23.259661,101.333832],[23.259109,101.334793],[23.259041,101.334999],[23.257879,101.336838],[23.25754,101.337242],[23.256929,101.337769],[23.25646,101.33802],[23.25596,101.338181],[23.255699,101.338219],[23.255159,101.338188],[23.25489,101.338142],[23.24906,101.335602],[23.248369,101.335197],[23.24132,101.329826],[23.24147,101.328873],[23.24135,101.32872],[23.24053,101.327087],[23.24011,101.326118],[23.2397,101.325417],[23.239361,101.325027],[23.23761,101.323486],[23.23728,101.323082],[23.23691,101.322357],[23.236731,101.321823],[23.236641,101.321274],[23.236641,101.320442],[23.23761,101.314987],[23.23786,101.314232],[23.238091,101.313751],[23.23838,101.313309],[23.238939,101.312729],[23.239361,101.312393],[23.240049,101.312019],[23.24082,101.311768],[23.241579,101.311661],[23.24288,101.311569],[23.24366,101.311401],[23.244169,101.311203],[23.24485,101.310791],[23.24724,101.308578],[23.249371,101.306458],[23.25046,101.305717],[23.2514,101.305183],[23.252029,101.304672],[23.25238,101.30426],[23.253401,101.302597],[23.25375,101.3022],[23.254169,101.301857],[23.25576,101.300957],[23.256809,101.300117],[23.25803,101.298683],[23.259621,101.296432],[23.26001,101.295692],[23.260309,101.294907],[23.260509,101.293823],[23.260599,101.28904],[23.260759,101.28791],[23.26182,101.283836],[23.26189,101.283279],[23.261841,101.282417],[23.26166,101.281563],[23.2612,101.280502],[23.25816,101.275703],[23.25787,101.27494],[23.25729,101.272781],[23.25692,101.271729],[23.256861,101.271446],[23.25684,101.270866],[23.25701,101.269768],[23.2575,101.267838],[23.257601,101.266983],[23.257561,101.265312],[23.25761,101.264763],[23.25774,101.264198],[23.25815,101.263153],[23.258499,101.261742],[23.259399,101.259422],[23.26021,101.255463],[23.2605,101.254677],[23.261391,101.253326],[23.26161,101.252808],[23.261709,101.252228],[23.26173,101.251953],[23.26165,101.251404],[23.26148,101.2509],[23.261221,101.25042],[23.257629,101.245293],[23.25453,101.24102],[23.25424,101.240463],[23.25411,101.240051],[23.25407,101.239372],[23.254141,101.238907],[23.25489,101.237106],[23.255079,101.236382],[23.255131,101.235603],[23.25507,101.234787],[23.25494,101.234009],[23.254641,101.232986],[23.253679,101.230522],[23.253099,101.228249],[23.25218,101.224899],[23.252119,101.224251],[23.252159,101.223793],[23.25227,101.223343],[23.25267,101.222473],[23.255369,101.21814],[23.25563,101.217392],[23.255819,101.216293],[23.255989,101.211189],[23.25593,101.210632],[23.255699,101.209801],[23.25515,101.208397],[23.255079,101.207947],[23.255119,101.207291],[23.25556,101.205559],[23.25559,101.204849],[23.255541,101.204369],[23.253651,101.197647],[23.25321,101.190193],[23.253139,101.189636],[23.252899,101.18885],[23.25223,101.187347],[23.252081,101.186821],[23.252029,101.186028],[23.252029,101.184959],[23.251909,101.184181],[23.251471,101.182693],[23.251419,101.182167],[23.251471,101.181671],[23.251711,101.180946],[23.25214,101.179993],[23.252359,101.179207],[23.25268,101.176117],[23.253679,101.172638],[23.253969,101.17189],[23.25404,101.171608],[23.25423,101.17112],[23.25482,101.170181],[23.255159,101.169746],[23.259211,101.165756],[23.259529,101.165337],[23.25967,101.165108],[23.2598,101.164597],[23.25979,101.164093],[23.258751,101.160049],[23.25845,101.159592],[23.258369,101.15921],[23.258289,101.158447],[23.258169,101.158096],[23.257179,101.156563],[23.25629,101.155159],[23.255951,101.154793],[23.255541,101.154503],[23.25308,101.15316],[23.24979,101.150223],[23.247089,101.148514],[23.246321,101.147751],[23.244961,101.146111],[23.244539,101.145798],[23.244101,101.145569],[23.243641,101.145447],[23.243139,101.145439],[23.237881,101.146713],[23.23527,101.146896],[23.23027,101.148399],[23.227171,101.148933],[23.226601,101.149139],[23.226101,101.149513],[23.225031,101.150719],[23.22471,101.150948],[23.22401,101.151237],[23.223459,101.151314],[23.2229,101.151283],[23.21833,101.149529],[23.217529,101.149437],[23.21492,101.150093],[23.214319,101.150146],[23.21393,101.150101],[23.213551,101.149986],[23.212259,101.149292],[23.211651,101.149101],[23.20582,101.149193],[23.20516,101.149101],[23.20451,101.148857],[23.20013,101.146408],[23.197161,101.144211],[23.196699,101.14399],[23.196171,101.143883],[23.19566,101.143867],[23.18998,101.145264],[23.18713,101.146263],[23.182751,101.14782],[23.18214,101.147957],[23.18144,101.147972],[23.17918,101.148079],[23.176701,101.148148],[23.176439,101.148087],[23.1756,101.147591],[23.173691,101.145157],[23.173109,101.144783],[23.17226,101.144508],[23.17214,101.144493],[23.171379,101.144051],[23.17091,101.143517],[23.17028,101.14193],[23.17,101.14164],[23.16972,101.141602],[23.169439,101.141708],[23.168489,101.142616],[23.168249,101.142776],[23.167931,101.142853],[23.16761,101.14283],[23.167219,101.142616],[23.166941,101.142342],[23.165541,101.140137],[23.165371,101.139969],[23.165131,101.139893],[23.1649,101.1399],[23.16469,101.140007],[23.164539,101.140213],[23.16445,101.14048],[23.16448,101.140793],[23.16538,101.143227],[23.16543,101.14357],[23.16539,101.143867],[23.165239,101.144112],[23.16502,101.14431],[23.16489,101.144363],[23.16461,101.144333],[23.16432,101.144157],[23.163019,101.142433],[23.16272,101.142174],[23.162319,101.142067],[23.16206,101.142113],[23.16169,101.142326],[23.16151,101.142563],[23.16139,101.143013],[23.161699,101.14537],[23.161659,101.145683],[23.161551,101.14595],[23.16135,101.146149],[23.16123,101.146217],[23.161091,101.14624],[23.16082,101.146202],[23.16057,101.146072],[23.160259,101.145714],[23.159731,101.144867],[23.159531,101.144707],[23.159149,101.144577],[23.157949,101.144608],[23.157829,101.144577],[23.15764,101.144417],[23.15748,101.144173],[23.15741,101.14389],[23.15745,101.143623],[23.157551,101.143349],[23.159639,101.140259],[23.159769,101.139923],[23.15979,101.139557],[23.159719,101.139076],[23.159531,101.138649],[23.15921,101.138329],[23.156639,101.137047],[23.156389,101.136993],[23.156059,101.137062],[23.1558,101.137283],[23.155689,101.137459],[23.1556,101.137772],[23.155609,101.138649],[23.155491,101.139977],[23.15535,101.140266],[23.15517,101.140411],[23.154699,101.140518],[23.153589,101.140503],[23.15336,101.140556],[23.153191,101.140694],[23.15309,101.140862],[23.152969,101.14135],[23.15296,101.141541],[23.152849,101.141853],[23.152651,101.142036],[23.15243,101.142143],[23.15204,101.142143],[23.15184,101.142113],[23.151449,101.142242],[23.1513,101.14238],[23.15011,101.145851],[23.149879,101.146141],[23.149561,101.146332],[23.149179,101.146339],[23.148781,101.146133],[23.14868,101.146019],[23.14852,101.145737],[23.148199,101.14447],[23.14818,101.144096],[23.148239,101.143761],[23.148491,101.14312],[23.148529,101.142517],[23.14846,101.142067],[23.147579,101.140503],[23.14716,101.139427],[23.146629,101.138603],[23.1465,101.13829],[23.146351,101.137589],[23.146191,101.137383],[23.1458,101.137131],[23.1457,101.137131],[23.14535,101.136864],[23.145149,101.136597],[23.14497,101.136078],[23.145,101.135048],[23.144831,101.134483],[23.144569,101.134003],[23.14341,101.13269],[23.14303,101.131958],[23.14296,101.131317],[23.142981,101.130791],[23.143021,101.13031],[23.14278,101.12957],[23.142031,101.128441],[23.14192,101.12812],[23.14188,101.127731],[23.14192,101.127457],[23.14204,101.12693],[23.141991,101.126511],[23.141701,101.125992],[23.140921,101.124786],[23.140791,101.124329],[23.140751,101.123627],[23.140591,101.123238],[23.13983,101.122459],[23.139219,101.122047],[23.13895,101.121941],[23.13866,101.12191],[23.137951,101.122078],[23.13674,101.122704],[23.135241,101.123283],[23.13401,101.123489],[23.133511,101.123459],[23.13283,101.123253],[23.13246,101.123253],[23.130779,101.123734],[23.130409,101.123901],[23.12991,101.124283],[23.12949,101.124657],[23.129351,101.124763],[23.128851,101.12487],[23.12851,101.124863],[23.126789,101.12442],[23.126419,101.124367],[23.12533,101.124573],[23.12499,101.124588],[23.12468,101.124496],[23.124411,101.124329],[23.124189,101.124077],[23.123911,101.123688],[23.123671,101.123543],[23.1227,101.12326],[23.12211,101.122917],[23.120399,101.121613],[23.119591,101.120728],[23.11902,101.120232],[23.117861,101.119186],[23.11676,101.118294],[23.11643,101.117828],[23.11591,101.116852],[23.115431,101.116112],[23.113951,101.11451],[23.113501,101.114166],[23.112789,101.11393],[23.112261,101.113762],[23.11195,101.113548],[23.111401,101.112953],[23.111071,101.112709],[23.110701,101.112541],[23.110331,101.112419],[23.11002,101.112228],[23.10965,101.111816],[23.10878,101.110573],[23.107849,101.109497],[23.107559,101.1091],[23.10708,101.108177],[23.10644,101.106758],[23.10614,101.105141],[23.106171,101.104942],[23.106541,101.103653],[23.10606,101.099571],[23.10594,101.099129],[23.105619,101.098534],[23.102871,101.095078],[23.102421,101.094269],[23.10216,101.093369],[23.10181,101.091087],[23.10194,101.087334],[23.101749,101.084717],[23.101681,101.084343],[23.10136,101.08358],[23.095289,101.071663],[23.092871,101.062553],[23.09272,101.062317],[23.092489,101.062149],[23.088921,101.061073],[23.08243,101.056297],[23.0809,101.055191],[23.080441,101.055038],[23.078341,101.055092],[23.07649,101.055237],[23.07522,101.055809],[23.074841,101.05587],[23.074341,101.055779],[23.073879,101.055496],[23.073151,101.054863],[23.07061,101.053688],[23.070391,101.053497],[23.07021,101.053238],[23.069651,101.050728],[23.069481,101.050293],[23.06922,101.050041],[23.06679,101.048531],[23.066,101.048271],[23.06559,101.048264],[23.065319,101.048363],[23.0651,101.048523],[23.06461,101.048958],[23.06423,101.049133],[23.063789,101.049156],[23.063459,101.049057],[23.062389,101.048508],[23.059759,101.048233],[23.058189,101.048424],[23.057249,101.048233],[23.05648,101.047813],[23.055799,101.047012],[23.05534,101.046501],[23.055099,101.046356],[23.05422,101.046242],[23.04863,101.048233],[23.04837,101.04837],[23.047871,101.048431],[23.02458,101.048302],[23.024071,101.048157],[23.02363,101.047836],[23.02182,101.045883],[23.01825,101.044289],[23.017651,101.044228],[23.010521,101.045853],[23.01018,101.045998],[23.009899,101.046257],[23.009689,101.0466],[23.00923,101.047546],[23.00905,101.047729],[23.008829,101.047852],[23.008591,101.047897],[23.008221,101.047829],[23.0072,101.047447],[23.00699,101.04744],[23.00671,101.047546],[23.00486,101.049133],[23.004459,101.049347],[23.004141,101.049469],[23.003429,101.049538],[23.002609,101.049538],[23.001209,101.0495],[22.99102,101.050056],[22.990601,101.050232],[22.988979,101.051308],[22.986931,101.052177],[22.983101,101.053596],[22.98258,101.053596],[22.98111,101.053093],[22.980881,101.052917],[22.98064,101.052544],[22.98027,101.051727],[22.980181,101.051598],[22.979851,101.051323],[22.977791,101.050697],[22.977329,101.050682],[22.97683,101.050743],[22.97641,101.05069],[22.976101,101.050507],[22.97517,101.049477],[22.975031,101.049393],[22.97488,101.049339],[22.97471,101.049347],[22.97455,101.049408],[22.974409,101.049507],[22.974291,101.049789],[22.974131,101.051559],[22.973989,101.051819],[22.9736,101.052063],[22.97324,101.052071],[22.97154,101.051743],[22.97117,101.05188],[22.97064,101.052979],[22.9704,101.053261],[22.9699,101.053467],[22.969589,101.053482],[22.96904,101.053253],[22.967541,101.051788],[22.96735,101.051491],[22.967199,101.050926],[22.96707,101.050056],[22.966869,101.04985],[22.96673,101.049789],[22.966591,101.049767],[22.966249,101.049873],[22.96386,101.051697],[22.9636,101.05175],[22.963301,101.051643],[22.959089,101.045609],[22.956141,101.043243],[22.95582,101.042763],[22.95554,101.041786],[22.955561,101.041611],[22.955469,101.041199],[22.95533,101.040993],[22.955111,101.040871],[22.95499,101.04084],[22.95459,101.040916],[22.95439,101.041054],[22.95409,101.041618],[22.95377,101.042618],[22.953621,101.0429],[22.9533,101.043198],[22.95293,101.043343],[22.952551,101.043373],[22.95105,101.043114],[22.94944,101.042679],[22.94734,101.042618],[22.945259,101.041969],[22.943899,101.041206],[22.9433,101.0411],[22.94108,101.041023],[22.940371,101.040817],[22.93914,101.040337],[22.938881,101.040291],[22.937981,101.040459],[22.937111,101.040733],[22.936819,101.040688],[22.93659,101.040581],[22.9363,101.040291],[22.935471,101.038452],[22.934389,101.037483],[22.93408,101.036903],[22.933861,101.03627],[22.93358,101.035828],[22.930759,101.033897],[22.928329,101.0327],[22.92807,101.032654],[22.92779,101.032707],[22.925079,101.034653],[22.923201,101.035942],[22.92071,101.03714],[22.91906,101.038437],[22.918779,101.038589],[22.91832,101.038673],[22.913601,101.038834],[22.90958,101.038292],[22.909451,101.0383],[22.907591,101.039146],[22.90667,101.039864],[22.906139,101.040077],[22.903391,101.040199],[22.9011,101.039917],[22.899839,101.04007],[22.898951,101.040367],[22.894341,101.042671],[22.892481,101.043266],[22.89069,101.044769],[22.890381,101.04493],[22.89023,101.044968],[22.89006,101.044968],[22.88994,101.044899],[22.88973,101.04493],[22.885571,101.044243],[22.885229,101.044144],[22.884729,101.044144],[22.883869,101.044243],[22.882971,101.044228],[22.88155,101.043968],[22.879829,101.044067],[22.87952,101.044228],[22.87929,101.044434],[22.879181,101.044807],[22.87919,101.045258],[22.87907,101.045502],[22.878929,101.045624],[22.878759,101.045647],[22.87855,101.045624],[22.87825,101.045418],[22.87788,101.044594],[22.877769,101.044441],[22.87748,101.044289],[22.87735,101.044273],[22.87706,101.044327],[22.87561,101.045067],[22.87435,101.045563],[22.874069,101.045738],[22.873659,101.046143],[22.87348,101.046463],[22.873461,101.046783],[22.87372,101.047661],[22.873671,101.048126],[22.873381,101.048607],[22.8731,101.049057],[22.87294,101.049553],[22.872959,101.049843],[22.87299,101.051071],[22.873091,101.051468],[22.87307,101.051727],[22.872841,101.052048],[22.87248,101.052231],[22.872129,101.052238],[22.871901,101.052139],[22.871731,101.05201],[22.87158,101.051781],[22.87137,101.051331],[22.870871,101.050537],[22.87031,101.050301],[22.87015,101.050247],[22.86977,101.050247],[22.868971,101.05014],[22.868629,101.050194],[22.86834,101.050377],[22.86783,101.051132],[22.867571,101.051727],[22.86725,101.052254],[22.86702,101.052406],[22.866871,101.052437],[22.86664,101.052406],[22.8664,101.052299],[22.86628,101.0522],[22.86537,101.051041],[22.864679,101.049889],[22.864491,101.049759],[22.86417,101.04966],[22.863911,101.049744],[22.863689,101.049896],[22.86302,101.050751],[22.862921,101.050842],[22.8627,101.050903],[22.862459,101.050858],[22.862341,101.050789],[22.862141,101.050583],[22.86179,101.049911],[22.86162,101.049759],[22.861549,101.049652],[22.861429,101.049568],[22.861179,101.04953],[22.860901,101.049637],[22.86054,101.050079],[22.860201,101.050247],[22.85998,101.050201],[22.859751,101.050087],[22.85951,101.049782],[22.85891,101.049133],[22.858801,101.048973],[22.85874,101.048752],[22.85858,101.04847],[22.85841,101.047997],[22.858,101.047462],[22.857731,101.047256],[22.85655,101.046967],[22.8563,101.046959],[22.855829,101.046768],[22.85537,101.04673],[22.854799,101.046623],[22.85006,101.045921],[22.845831,101.044746],[22.84557,101.044601],[22.84523,101.044167],[22.84511,101.043877],[22.845091,101.043388],[22.845209,101.042717],[22.84556,101.04084],[22.84547,101.039772],[22.84502,101.038681],[22.84433,101.037338],[22.844259,101.03698],[22.84441,101.03569],[22.84409,101.032707],[22.843941,101.032372],[22.84374,101.032219],[22.843361,101.032143],[22.84267,101.032249],[22.842449,101.032204],[22.84227,101.032082],[22.84207,101.03154],[22.84198,101.029114],[22.842051,101.028877],[22.842239,101.02861],[22.84289,101.028084],[22.843069,101.027802],[22.843121,101.027473],[22.842661,101.025063],[22.84259,101.023514],[22.8423,101.022087],[22.842039,101.021744],[22.841921,101.021637],[22.840469,101.021187],[22.83992,101.020882],[22.839251,101.020699],[22.83877,101.020607],[22.83643,101.020943],[22.83602,101.020882],[22.83543,101.020538],[22.835251,101.02018],[22.835159,101.019417],[22.835239,101.019051],[22.835609,101.018333],[22.835791,101.017487],[22.83559,101.016022],[22.835461,101.015701],[22.835409,101.015404],[22.83482,101.014267],[22.83457,101.014038],[22.83433,101.013992],[22.833139,101.014503],[22.83259,101.014458],[22.831869,101.014343],[22.83053,101.014374],[22.830259,101.014282],[22.83005,101.014122],[22.82991,101.013893],[22.82984,101.013634],[22.829969,101.011917],[22.829901,101.011574],[22.829679,101.011261],[22.82835,101.010513],[22.82818,101.01033],[22.82806,101.010017],[22.828091,101.009712],[22.82819,101.009499],[22.828621,101.008827],[22.82872,101.008507],[22.828699,101.008148],[22.828489,101.007767],[22.828329,101.007561],[22.828199,101.007271],[22.82818,101.006958],[22.828251,101.006508],[22.82892,101.004562],[22.828939,101.004387],[22.82892,101.004211],[22.82877,101.003937],[22.828609,101.00386],[22.82851,101.003838],[22.827129,101.004417],[22.82692,101.004593],[22.8267,101.004982],[22.82649,101.006523],[22.82633,101.00679],[22.82616,101.006943],[22.82592,101.007004],[22.825689,101.006958],[22.82403,101.006088],[22.823681,101.00605],[22.82346,101.006119],[22.82337,101.006187],[22.82324,101.006432],[22.823219,101.006813],[22.82399,101.008453],[22.82399,101.008774],[22.823879,101.008957],[22.823681,101.009087],[22.82329,101.009109],[22.822479,101.008789],[22.8221,101.00872],[22.82177,101.008583],[22.821529,101.008583],[22.820789,101.008713],[22.81996,101.008583],[22.81974,101.008629],[22.81953,101.008781],[22.81933,101.009148],[22.819201,101.009819],[22.818939,101.010223],[22.81875,101.01033],[22.81855,101.010323],[22.81834,101.010223],[22.81811,101.009933],[22.81785,101.008659],[22.817579,101.008057],[22.817181,101.007607],[22.81698,101.007149],[22.816971,101.006393],[22.817101,101.005531],[22.81698,101.004761],[22.81669,101.004066],[22.81662,101.003967],[22.816351,101.003433],[22.816111,101.00322],[22.8158,101.003128],[22.815439,101.003159],[22.81422,101.003883],[22.813881,101.003998],[22.81366,101.004013],[22.813259,101.003754],[22.81312,101.00354],[22.813089,101.003281],[22.813181,101.002853],[22.813629,101.002243],[22.81424,101.001587],[22.814421,101.00119],[22.81451,100.999588],[22.81435,100.99884],[22.813931,100.997803],[22.81389,100.997131],[22.8141,100.995453],[22.81406,100.995247],[22.813869,100.99498],[22.81354,100.994713],[22.812071,100.994713],[22.811621,100.994812],[22.811399,100.994797],[22.811131,100.994667],[22.811001,100.994537],[22.810301,100.993599],[22.810169,100.99321],[22.809681,100.992577],[22.808121,100.991653],[22.80743,100.990997],[22.80442,100.986687],[22.803289,100.985558],[22.800989,100.9842],[22.79668,100.982613],[22.79608,100.982559],[22.795641,100.98262],[22.79413,100.983139],[22.79402,100.983147],[22.78949,100.984673],[22.78833,100.984734],[22.78718,100.984337],[22.786381,100.98378],[22.785009,100.982468],[22.783701,100.981873],[22.78307,100.981773],[22.778049,100.982323],[22.775881,100.981888],[22.773491,100.98156],[22.77161,100.981628],[22.770651,100.981438],[22.76981,100.98101],[22.769211,100.980476],[22.76837,100.979477],[22.76026,100.960899],[22.757999,100.955803],[22.757441,100.955391],[22.75708,100.955048],[22.75721,100.954697],[22.757549,100.954514],[22.75704,100.954567],[22.755301,100.954819],[22.75485,100.955139],[22.7547,100.95517],[22.75456,100.955002],[22.75416,100.954086],[22.7537,100.952957],[22.75363,100.952232],[22.753639,100.951859],[22.753731,100.95031],[22.75379,100.949226],[22.75386,100.948143],[22.753901,100.947762],[22.754181,100.947342],[22.754499,100.947273],[22.75466,100.947357],[22.75481,100.947609],[22.754841,100.947906],[22.754721,100.948082],[22.75465,100.948151],[22.75444,100.948288],[22.75411,100.948311],[22.753559,100.948311],[22.751921,100.947998],[22.75135,100.947693],[22.74992,100.946747],[22.74894,100.945709],[22.74827,100.944641],[22.74794,100.943817],[22.747869,100.943604],[22.747629,100.942703],[22.74728,100.940529],[22.747,100.939323],[22.746799,100.938171],[22.74645,100.937271],[22.74609,100.936653],[22.74593,100.936523],[22.74559,100.936256],[22.745041,100.935921],[22.744431,100.935699],[22.743589,100.935547],[22.74295,100.935478],[22.742531,100.935432],[22.742319,100.93541],[22.74148,100.935318],[22.740669,100.935219],[22.73987,100.935173],[22.73967,100.935181],[22.738371,100.935532],[22.737089,100.935951],[22.737221,100.937561],[22.736879,100.938103],[22.736759,100.93824],[22.736469,100.938568],[22.735411,100.939491],[22.735109,100.939758],[22.73385,100.938789],[22.73255,100.937866],[22.73188,100.937424],[22.7313,100.937263],[22.73031,100.937019],[22.72901,100.936897],[22.72834,100.93692],[22.727659,100.936996],[22.726971,100.937157],[22.72587,100.937553],[22.725189,100.937759],[22.72473,100.937843],[22.72377,100.937927],[22.723061,100.937889],[22.72282,100.937859],[22.72212,100.937721],[22.721439,100.937607],[22.72052,100.937538],[22.71982,100.937569],[22.718861,100.937721],[22.71837,100.937798],[22.71788,100.937851],[22.71763,100.937859],[22.716881,100.937851],[22.716391,100.937813],[22.715691,100.937683],[22.714161,100.937149],[22.71335,100.936859],[22.70923,100.935532],[22.706129,100.935272],[22.7059,100.935303],[22.70228,100.935913],[22.698429,100.936508],[22.697969,100.936501],[22.695841,100.935799],[22.69434,100.934319],[22.693859,100.933487],[22.692881,100.931847],[22.692579,100.931488],[22.69058,100.929947],[22.688129,100.929352],[22.687429,100.929367],[22.686251,100.929581],[22.68441,100.93026],[22.684179,100.930351],[22.6835,100.930618],[22.68281,100.93087],[22.681641,100.931152],[22.680941,100.93116],[22.68004,100.930992],[22.678801,100.930367],[22.67804,100.92984],[22.677851,100.92971],[22.675659,100.928902],[22.67326,100.929527],[22.673059,100.929657],[22.672211,100.930489],[22.671471,100.931808],[22.67083,100.933502],[22.67029,100.934967],[22.66975,100.936409],[22.669571,100.936882],[22.668791,100.938911],[22.668209,100.940453],[22.667789,100.941566],[22.667259,100.942947],[22.666759,100.944099],[22.666229,100.944946],[22.66468,100.94651],[22.664499,100.946678],[22.663601,100.9478],[22.6632,100.94841],[22.66169,100.949921],[22.661079,100.950256],[22.65884,100.951897],[22.65867,100.952042],[22.65498,100.95533],[22.652889,100.957962],[22.650261,100.962303],[22.649429,100.963142],[22.646749,100.965019],[22.64267,100.968117],[22.637991,100.972588],[22.635099,100.975403],[22.634501,100.975807],[22.63336,100.976723],[22.632851,100.977272],[22.63204,100.97821],[22.630671,100.979149],[22.62907,100.979347],[22.626699,100.979889],[22.62571,100.98082],[22.625561,100.981003],[22.625271,100.981339],[22.624451,100.982117],[22.621981,100.983459],[22.621571,100.983727],[22.62063,100.984596],[22.62031,100.985008],[22.619671,100.986153],[22.619551,100.986382],[22.61792,100.989319],[22.617081,100.990868],[22.616619,100.99173],[22.615801,100.99321],[22.615339,100.994034],[22.613991,100.99749],[22.61388,100.99794],[22.613501,101.000053],[22.613371,101.000763],[22.612659,101.004387],[22.612049,101.00573],[22.611759,101.006104],[22.610201,101.00721],[22.609751,101.007362],[22.607679,101.007797],[22.606541,101.008034],[22.605619,101.008209],[22.604639,101.006989],[22.60265,101.008003],[22.602079,101.008499],[22.601891,101.008682],[22.600941,101.009567],[22.60054,101.009903],[22.599701,101.010483],[22.599489,101.010628],[22.598221,101.011467],[22.59697,101.012291],[22.595961,101.013023],[22.5944,101.014282],[22.5931,101.015518],[22.59235,101.016289],[22.591801,101.016899],[22.591261,101.017517],[22.590919,101.01796],[22.59057,101.018387],[22.59005,101.01902],[22.589531,101.019653],[22.58902,101.020264],[22.58886,101.020462],[22.58802,101.021461],[22.58716,101.0224],[22.5863,101.023323],[22.5856,101.024063],[22.58543,101.024239],[22.58489,101.024803],[22.583969,101.025703],[22.583059,101.026604],[22.582319,101.027351],[22.58213,101.027542],[22.58135,101.02832],[22.580959,101.028717],[22.58037,101.029327],[22.579769,101.02993],[22.579161,101.03051],[22.578529,101.031021],[22.577629,101.031601],[22.576929,101.031967],[22.57407,101.032806],[22.57268,101.033127],[22.569481,101.033974],[22.566851,101.035629],[22.564631,101.038254],[22.562571,101.04084],[22.561569,101.042],[22.56105,101.042549],[22.55653,101.046677],[22.551979,101.050056],[22.549089,101.051498],[22.54871,101.051857],[22.547211,101.054031],[22.545851,101.055611],[22.54336,101.057426],[22.538851,101.060677],[22.536671,101.062241],[22.535339,101.063202],[22.53406,101.064117],[22.53334,101.064636],[22.533159,101.064774],[22.532261,101.065422],[22.530951,101.066353],[22.53075,101.06649],[22.52914,101.067642],[22.527901,101.068542],[22.52706,101.069153],[22.525999,101.069908],[22.52557,101.070213],[22.524731,101.070824],[22.523899,101.071411],[22.523279,101.071854],[22.52087,101.073593],[22.519039,101.074821],[22.515511,101.076576],[22.51333,101.077263],[22.51284,101.077393],[22.507811,101.078346],[22.502991,101.079971],[22.4993,101.081062],[22.49831,101.081284],[22.497311,101.081467],[22.49608,101.081688],[22.4951,101.081871],[22.49365,101.082123],[22.49098,101.082588],[22.49074,101.082626],[22.48781,101.08316],[22.48311,101.084023],[22.479179,101.084732],[22.47846,101.084869],[22.47751,101.085037],[22.47727,101.085091],[22.474871,101.085403],[22.472151,101.084801],[22.47193,101.084686],[22.469971,101.083214],[22.46851,101.081123],[22.46838,101.080887],[22.46525,101.076134],[22.46405,101.075218],[22.46118,101.073936],[22.46097,101.07383],[22.46055,101.073578],[22.46015,101.073303],[22.45813,101.071114],[22.454941,101.066788],[22.45241,101.063629],[22.451441,101.062912],[22.450809,101.062576],[22.450399,101.062378],[22.449249,101.061684],[22.44907,101.061531],[22.448311,101.060661],[22.44747,101.058617],[22.44726,101.057877],[22.447041,101.057114],[22.446621,101.055618],[22.44656,101.055382],[22.44626,101.054199],[22.446159,101.053268],[22.44618,101.052567],[22.446199,101.052338],[22.44644,101.051201],[22.44669,101.050537],[22.446791,101.050323],[22.44743,101.049301],[22.44944,101.047501],[22.45256,101.045052],[22.45421,101.043716],[22.45508,101.042671],[22.455469,101.041603],[22.45558,101.040413],[22.455441,101.039482],[22.455299,101.039047],[22.454571,101.037857],[22.453421,101.036743],[22.452419,101.035797],[22.451059,101.034531],[22.44902,101.032204],[22.448139,101.03109],[22.448,101.030907],[22.447321,101.030052],[22.446791,101.029404],[22.446239,101.028793],[22.445601,101.028267],[22.445089,101.027977],[22.44455,101.027733],[22.44379,101.027473],[22.442869,101.027039],[22.44202,101.026077],[22.441919,101.025887],[22.440689,101.022301],[22.439899,101.018692],[22.43993,101.01844],[22.44076,101.016403],[22.441521,101.014671],[22.441589,101.013519],[22.441429,101.012611],[22.441191,101.011757],[22.440969,101.010933],[22.44091,101.010727],[22.440741,101.010117],[22.44063,101.009697],[22.44046,101.009087],[22.440399,101.008888],[22.44026,101.008293],[22.43997,101.007103],[22.43926,101.005013],[22.438971,101.004204],[22.43878,101.003777],[22.43825,101.003036],[22.43762,101.002419],[22.437071,101.002037],[22.435881,101.001503],[22.43569,101.001411],[22.43453,101.000877],[22.432699,101.00032],[22.431379,100.999817],[22.429871,100.999237],[22.429649,100.999161],[22.42835,100.998688],[22.42729,100.998253],[22.425751,100.997887],[22.425079,100.997864],[22.424191,100.99781],[22.422859,100.997726],[22.42264,100.997711],[22.42198,100.997673],[22.42152,100.996429],[22.421169,100.995857],[22.420839,100.995033],[22.420691,100.994614],[22.420389,100.993767],[22.42004,100.992973],[22.41968,100.992416],[22.41955,100.992264],[22.41909,100.991814],[22.418539,100.991493],[22.41814,100.991341],[22.417721,100.991249],[22.416821,100.99128],[22.41659,100.991333],[22.414579,100.991943],[22.413879,100.992104],[22.41272,100.992363],[22.412491,100.992409],[22.412029,100.992523],[22.411489,100.99173],[22.410629,100.991402],[22.409349,100.990982],[22.408449,100.990921],[22.40686,100.991699],[22.406151,100.992973],[22.406,100.993713],[22.40591,100.994217],[22.40572,100.995506],[22.405109,100.997917],[22.40416,100.998901],[22.403561,100.999229],[22.40292,100.999512],[22.40205,100.999962],[22.40163,101.000214],[22.401421,101.000351],[22.400829,101.000778],[22.40065,101.000923],[22.399929,101.001457],[22.398781,101.001991],[22.39797,101.001999],[22.39777,101.001953],[22.39657,101.001633],[22.396379,101.001579],[22.39558,101.001373],[22.39538,101.001312],[22.39526,100.999611],[22.394581,100.999031],[22.39352,100.99868],[22.39287,100.998627],[22.39201,100.998672],[22.391159,100.998779],[22.390329,100.998871],[22.389509,100.99894],[22.38932,100.998947],[22.38833,100.999069],[22.38817,100.999077],[22.38769,100.999107],[22.386909,100.999184],[22.386049,100.999191],[22.385309,100.99913],[22.38492,100.999077],[22.384109,100.998894],[22.38331,100.998627],[22.38269,100.998428],[22.382271,100.998299],[22.38162,100.9981],[22.381399,100.998016],[22.379789,100.997589],[22.37746,100.997719],[22.37701,100.997803],[22.37565,100.99794],[22.374069,100.997757],[22.371149,100.996773],[22.36879,100.996872],[22.36677,100.998077],[22.36544,100.998917],[22.363939,100.999222],[22.36371,100.999207],[22.361771,100.998497],[22.361561,100.998383],[22.36068,100.997917],[22.35667,100.996277],[22.355659,100.996132],[22.35545,100.996094],[22.3552,100.996048],[22.35351,100.995506],[22.352989,100.995354],[22.35206,100.994911],[22.351191,100.9944],[22.350361,100.99382],[22.349239,100.992828],[22.3489,100.992477],[22.347679,100.990936],[22.34753,100.990723],[22.347231,100.990303],[22.3466,100.989418],[22.346451,100.989197],[22.345881,100.988319],[22.3456,100.987877],[22.344879,100.987053],[22.34469,100.986832],[22.3444,100.986397],[22.343929,100.985764],[22.34325,100.984917],[22.342899,100.98452],[22.34236,100.983963],[22.341551,100.983261],[22.341339,100.983093],[22.340931,100.982758],[22.340309,100.982277],[22.33968,100.98185],[22.33882,100.981354],[22.337931,100.980911],[22.337259,100.980621],[22.33658,100.980331],[22.335899,100.980011],[22.335011,100.979507],[22.334351,100.979088],[22.333929,100.978783],[22.333309,100.978302],[22.33271,100.977814],[22.332319,100.97747],[22.33115,100.976021],[22.33066,100.975357],[22.33033,100.974922],[22.32984,100.974281],[22.32935,100.97364],[22.328871,100.973007],[22.328541,100.972603],[22.328211,100.972168],[22.327511,100.971367],[22.32696,100.970787],[22.32638,100.970261],[22.325781,100.969727],[22.32449,100.968719],[22.323839,100.968231],[22.322981,100.967537],[22.32235,100.966988],[22.32173,100.966423],[22.32111,100.965813],[22.320511,100.965157],[22.31974,100.964256],[22.319361,100.963791],[22.319,100.963318],[22.31883,100.963081],[22.318489,100.962601],[22.318001,100.961853],[22.317539,100.961113],[22.31683,100.959846],[22.3167,100.959587],[22.316441,100.959053],[22.31583,100.95768],[22.315411,100.956596],[22.31521,100.956093],[22.314989,100.955597],[22.314751,100.955116],[22.31435,100.954437],[22.31389,100.953796],[22.31356,100.953377],[22.3132,100.953003],[22.313021,100.952812],[22.312639,100.952461],[22.312241,100.952141],[22.31143,100.951508],[22.310619,100.950844],[22.309799,100.950172],[22.30938,100.949837],[22.30875,100.949333],[22.30834,100.948967],[22.30776,100.948433],[22.307011,100.947678],[22.30665,100.947304],[22.30629,100.94693],[22.305771,100.946358],[22.30448,100.944847],[22.302361,100.942863],[22.30135,100.942192],[22.300039,100.941544],[22.29891,100.941139],[22.298679,100.941078],[22.29401,100.939636],[22.29364,100.939407],[22.29315,100.939018],[22.292601,100.938454],[22.292191,100.937828],[22.291941,100.937363],[22.29166,100.936699],[22.29142,100.936028],[22.291241,100.935516],[22.291,100.934837],[22.290689,100.933968],[22.29043,100.933243],[22.290171,100.932518],[22.289909,100.931793],[22.28965,100.931053],[22.28944,100.930489],[22.289181,100.929733],[22.288919,100.92897],[22.288719,100.928398],[22.288429,100.927658],[22.288191,100.927109],[22.28772,100.926224],[22.28751,100.925888],[22.28701,100.925056],[22.286711,100.924561],[22.286501,100.924217],[22.2857,100.922897],[22.283091,100.922768],[22.2829,100.922638],[22.282551,100.92234],[22.282061,100.921547],[22.28171,100.920723],[22.281401,100.919838],[22.28109,100.919243],[22.280649,100.918709],[22.280479,100.918556],[22.279711,100.918083],[22.27906,100.917793],[22.27845,100.917397],[22.27788,100.916908],[22.27706,100.91597],[22.276711,100.915627],[22.27635,100.915314],[22.275961,100.915047],[22.275339,100.914749],[22.274691,100.91449],[22.27426,100.914291],[22.273479,100.913727],[22.27298,100.913193],[22.27249,100.912582],[22.271811,100.911751],[22.271299,100.911133],[22.2708,100.9105],[22.270121,100.909691],[22.269621,100.909081],[22.26911,100.908478],[22.2686,100.907867],[22.267941,100.907059],[22.26745,100.906471],[22.26729,100.906281],[22.266529,100.905327],[22.26638,100.905159],[22.266109,100.904793],[22.265181,100.903084],[22.26512,100.902878],[22.26486,100.901817],[22.264759,100.901176],[22.264681,100.900543],[22.26461,100.900162],[22.264441,100.899437],[22.264219,100.898758],[22.264151,100.89859],[22.263769,100.897781],[22.262951,100.896568],[22.26133,100.89476],[22.25939,100.892632],[22.257799,100.890877],[22.25618,100.889526],[22.254049,100.888847],[22.252899,100.888924],[22.249889,100.889832],[22.24725,100.890663],[22.24247,100.892181],[22.24225,100.89225],[22.241619,100.892464],[22.240801,100.892723],[22.240601,100.892776],[22.239651,100.893082],[22.23909,100.89325],[22.237379,100.893532],[22.23546,100.892883],[22.233191,100.891357],[22.23279,100.891243],[22.229931,100.891037],[22.227671,100.891037],[22.22744,100.891037],[22.22624,100.890999],[22.226,100.890961],[22.22529,100.890846],[22.224819,100.890739],[22.222071,100.889473],[22.221689,100.889198],[22.220579,100.88842],[22.217211,100.886803],[22.216749,100.886673],[22.21537,100.886177],[22.215151,100.88607],[22.213539,100.884918],[22.21335,100.884743],[22.21269,100.883972],[22.211559,100.88224],[22.21076,100.881287],[22.209181,100.880188],[22.20785,100.879623],[22.20566,100.878441],[22.20363,100.876953],[22.20343,100.876793],[22.20179,100.875679],[22.20072,100.875061],[22.199169,100.874298],[22.19618,100.873253],[22.19453,100.872864],[22.192659,100.872551],[22.191271,100.872337],[22.189659,100.872108],[22.18873,100.872002],[22.18466,100.871529],[22.184441,100.871552],[22.18379,100.871658],[22.18276,100.872009],[22.18195,100.872292],[22.181749,100.872353],[22.18115,100.872498],[22.18075,100.872551],[22.17971,100.872528],[22.1782,100.872253],[22.17522,100.871643],[22.17458,100.871513],[22.1733,100.871239],[22.172661,100.871101],[22.17029,100.87149],[22.168579,100.872566],[22.16478,100.875488],[22.164101,100.877136],[22.164101,100.878738],[22.16431,100.880547],[22.163891,100.882553],[22.162741,100.884567],[22.16111,100.888344],[22.15967,100.889977],[22.15947,100.890106],[22.15798,100.8908],[22.156429,100.891068],[22.154831,100.890587],[22.15423,100.890297],[22.15365,100.889992],[22.15346,100.889893],[22.15308,100.889687],[22.1521,100.889374],[22.1511,100.889267],[22.1509,100.889297],[22.15032,100.889381],[22.149731,100.889503],[22.1486,100.889763],[22.147829,100.889931],[22.146811,100.890137],[22.146601,100.890182],[22.1453,100.890213],[22.1434,100.889481],[22.141661,100.88871],[22.14024,100.888573],[22.13888,100.88858],[22.13842,100.888573],[22.136339,100.888329],[22.13586,100.888229],[22.13463,100.888077],[22.133619,100.88813],[22.133141,100.88826],[22.132429,100.888542],[22.13179,100.888947],[22.13122,100.889442],[22.13084,100.889793],[22.130289,100.890343],[22.13011,100.890518],[22.129749,100.890877],[22.12937,100.891243],[22.12919,100.891434],[22.128811,100.891777],[22.128059,100.892509],[22.12748,100.893066],[22.127279,100.893272],[22.12668,100.893837],[22.125839,100.894562],[22.125389,100.894897],[22.124491,100.895523],[22.12426,100.895668],[22.123569,100.896049],[22.12311,100.896271],[22.122881,100.896378],[22.121969,100.896767],[22.12151,100.896927],[22.121059,100.897087],[22.120359,100.897293],[22.1199,100.8974],[22.119209,100.897537],[22.118031,100.897697],[22.117319,100.897758],[22.117081,100.897774],[22.116381,100.897797],[22.115919,100.897781],[22.115219,100.897751],[22.114771,100.897697],[22.11454,100.897667],[22.113411,100.897438],[22.113171,100.897377],[22.112221,100.897087],[22.1113,100.896767],[22.109541,100.896072],[22.109329,100.896004],[22.108931,100.895844],[22.107821,100.895363],[22.10671,100.894867],[22.1063,100.894707],[22.105659,100.894447],[22.104509,100.894028],[22.10401,100.893913],[22.102751,100.893784],[22.102249,100.893806],[22.10034,100.894386],[22.09577,100.896683],[22.09535,100.896889],[22.09514,100.897003],[22.091,100.899063],[22.09016,100.899467],[22.08934,100.899872],[22.0875,100.90078],[22.086281,100.901398],[22.086069,100.901497],[22.084459,100.90229],[22.082359,100.903587],[22.08218,100.90374],[22.080879,100.904747],[22.08029,100.905144],[22.079691,100.905487],[22.07802,100.906349],[22.076559,100.907097],[22.074671,100.908073],[22.074459,100.90818],[22.07284,100.909088],[22.072651,100.909233],[22.071779,100.910347],[22.07155,100.911049],[22.07114,100.91275],[22.07007,100.914352],[22.06971,100.914612],[22.06798,100.915222],[22.06732,100.915314],[22.06707,100.915398],[22.067011,100.915398],[22.066839,100.915367],[22.06671,100.915428],[22.06671,100.915428],[22.066191,100.915527],[22.065809,100.915627],[22.065701,100.915657],[22.0648,100.915863],[22.064171,100.915993],[22.06389,100.916054],[22.063181,100.916206],[22.06303,100.916252],[22.06241,100.916389],[22.06175,100.916527],[22.061239,100.916649],[22.059919,100.916832],[22.05904,100.916962],[22.05825,100.916946],[22.05735,100.916603],[22.05529,100.916061],[22.052691,100.91539],[22.043591,100.899223],[22.04199,100.896301],[22.040911,100.894302],[22.04068,100.893753],[22.04048,100.893158],[22.040251,100.892387],[22.04018,100.892197],[22.03977,100.891548],[22.039471,100.891258],[22.03857,100.890778],[22.03838,100.890678],[22.037889,100.890312],[22.037439,100.889587],[22.037371,100.889359],[22.03727,100.888687],[22.03849,100.887321],[22.038231,100.886932],[22.03797,100.886543],[22.03784,100.886353],[22.037319,100.885567],[22.03694,100.884987],[22.0368,100.884804],[22.03665,100.884613],[22.03618,100.885109],[22.035931,100.885269],[22.03573,100.885452],[22.035629,100.886169],[22.035851,100.886627],[22.036329,100.887131],[22.03694,100.887589],[22.037371,100.887947],[22.037769,100.888542],[22.038059,100.889397],[22.038601,100.890022],[22.038759,100.890091],[22.03908,100.890213],[22.039551,100.890381],[22.039709,100.890427],[22.040171,100.890617],[22.04055,100.890907],[22.04085,100.891487],[22.04088,100.891983],[22.040859,100.892303],[22.041019,100.893082],[22.04133,100.893448],[22.04187,100.893829],[22.042009,100.893929],[22.04236,100.894287],[22.042669,100.894897],[22.042761,100.895416],[22.04281,100.89608],[22.04302,100.896843],[22.043171,100.8974],[22.043329,100.897919],[22.04336,100.898033],[22.04343,100.898308],[22.043329,100.898941],[22.043221,100.899231],[22.04311,100.89959],[22.04307,100.899696],[22.042959,100.900017],[22.042801,100.900459],[22.04266,100.901329],[22.04273,100.901848],[22.042891,100.902496],[22.043011,100.903023],[22.04307,100.90329],[22.0431,100.903831],[22.04306,100.904114],[22.04298,100.904373],[22.042709,100.904846],[22.0425,100.905212],[22.042471,100.90583],[22.042601,100.906067],[22.042801,100.906258],[22.043329,100.906708],[22.04343,100.906807],[22.0436,100.907654],[22.04347,100.907928],[22.0432,100.908363],[22.042931,100.908813],[22.042509,100.909538],[22.042471,100.910461],[22.0427,100.910889],[22.042801,100.911018],[22.04372,100.911949],[22.043859,100.912079],[22.044359,100.912582],[22.04472,100.913528],[22.04451,100.913986],[22.04413,100.91433],[22.043119,100.915154],[22.04287,100.915573],[22.04269,100.916199],[22.04266,100.916359],[22.042521,100.917137],[22.04232,100.917717],[22.042139,100.918114],[22.04208,100.918228],[22.041771,100.919312],[22.041821,100.920036],[22.041901,100.920273],[22.04212,100.920998],[22.041929,100.921722],[22.041439,100.922592],[22.04129,100.924171],[22.04126,100.92466],[22.04137,100.925926],[22.041439,100.926308],[22.0415,100.928253],[22.041519,100.929138],[22.04121,100.929947],[22.0408,100.930191],[22.038839,100.931381],[22.03824,100.932617],[22.03816,100.932838],[22.03783,100.933723],[22.0376,100.93438],[22.03727,100.935242],[22.037001,100.935867],[22.03648,100.936867],[22.035589,100.938187],[22.03503,100.938904],[22.03474,100.939247],[22.03359,100.940689],[22.03301,100.941406],[22.032301,100.942299],[22.031099,100.943787],[22.03026,100.94487],[22.029539,100.945839],[22.029261,100.946281],[22.029091,100.946602],[22.02861,100.94767],[22.028391,100.948227],[22.02833,100.948433],[22.02803,100.949387],[22.02774,100.950394],[22.027679,100.950592],[22.02737,100.95163],[22.027,100.952888],[22.026939,100.953102],[22.0266,100.954163],[22.026011,100.955406],[22.02549,100.956146],[22.02519,100.956497],[22.02504,100.956673],[22.02302,100.958931],[22.02248,100.959717],[22.02177,100.960983],[22.021351,100.961884],[22.021231,100.962097],[22.020651,100.963203],[22.019051,100.965302],[22.01857,100.965767],[22.017229,100.967117],[22.016939,100.967453],[22.01679,100.967613],[22.016109,100.968483],[22.01552,100.96946],[22.015409,100.969658],[22.015011,100.970444],[22.01482,100.970802],[22.014271,100.971931],[22.014071,100.972328],[22.013821,100.972816],[22.013639,100.97316],[22.01335,100.973732],[22.01317,100.974136],[22.01281,100.974823],[22.011311,100.976913],[22.011169,100.977074],[22.010731,100.977562],[22.01045,100.97789],[22.010059,100.978409],[22.00983,100.978767],[22.00942,100.979523],[22.00905,100.980263],[22.0086,100.981056],[22.008369,100.981331],[22.00786,100.981812],[22.007601,100.982002],[22.007469,100.982094],[22.00699,100.982437],[22.006559,100.982841],[22.00647,100.982948],[22.005951,100.983681],[22.005751,100.9841],[22.005449,100.985153],[22.005381,100.985611],[22.00523,100.986397],[22.0049,100.987267],[22.00474,100.987556],[22.00428,100.98819],[22.00396,100.988487],[22.003151,100.989082],[22.00243,100.989517],[22.001011,100.990921],[22.000919,100.991051],[22.000191,100.992073],[21.99983,100.992554],[21.99975,100.992683],[21.999149,100.993523],[21.99906,100.993629],[21.998871,100.993843],[21.99811,100.994507],[21.99707,100.995071],[21.99651,100.995293],[21.995951,100.995506],[21.995399,100.995743],[21.99486,100.995956],[21.99436,100.996239],[21.992809,100.99765],[21.992701,100.99781],[21.99198,100.998779],[21.99185,100.998947],[21.99131,100.999641],[21.99102,100.999992],[21.990459,101.000717],[21.9888,101.00293],[21.98838,101.003487],[21.98786,101.003998],[21.987049,101.004883],[21.98671,101.005211],[21.986349,101.005539],[21.986179,101.005699],[21.98562,101.006172],[21.98525,101.006493],[21.984249,101.007271],[21.983841,101.007568],[21.98321,101.008003],[21.98258,101.008438],[21.98197,101.008873],[21.98177,101.009018],[21.98078,101.009811],[21.97967,101.010818],[21.976709,101.013283],[21.97607,101.013962],[21.975679,101.014252],[21.97489,101.014801],[21.97427,101.015198],[21.973869,101.015503],[21.973471,101.015793],[21.973101,101.016113],[21.97262,101.016701],[21.97249,101.016899],[21.97216,101.017563],[21.972071,101.017776],[21.971621,101.01918],[21.97146,101.019653],[21.971149,101.020576],[21.970921,101.021278],[21.97084,101.021507],[21.9706,101.022209],[21.97053,101.022453],[21.970289,101.02314],[21.970209,101.023376],[21.96982,101.024544],[21.969509,101.025467],[21.96785,101.026176],[21.967251,101.026573],[21.96661,101.026871],[21.966169,101.027061],[21.965309,101.027412],[21.96509,101.027496],[21.96422,101.027847],[21.964001,101.027946],[21.96335,101.028214],[21.9627,101.028503],[21.96207,101.028816],[21.961081,101.02951],[21.959749,101.030479],[21.95956,101.030617],[21.95937,101.031616],[21.95859,101.033081],[21.95812,101.034248],[21.95792,101.034698],[21.957279,101.035843],[21.956381,101.037048],[21.95595,101.037666],[21.95558,101.038307],[21.955469,101.038544],[21.955259,101.038979],[21.95509,101.039436],[21.954941,101.039902],[21.954729,101.040619],[21.95439,101.041817],[21.95418,101.042542],[21.95396,101.043243],[21.953409,101.044312],[21.953291,101.04451],[21.95188,101.046097],[21.95171,101.046272],[21.950581,101.047478],[21.95042,101.047653],[21.94935,101.048798],[21.94685,101.05146],[21.946529,101.051804],[21.94636,101.051964],[21.94483,101.053726],[21.94429,101.054443],[21.943529,101.055481],[21.943279,101.055817],[21.942329,101.057137],[21.942209,101.057312],[21.941851,101.0578],[21.941481,101.058273],[21.94095,101.058861],[21.940399,101.059402],[21.940269,101.05954],[21.939581,101.060219],[21.93902,101.060753],[21.93784,101.061127],[21.936701,101.061577],[21.93651,101.061684],[21.935301,101.062218],[21.933491,101.063057],[21.933109,101.063278],[21.930639,101.065109],[21.929501,101.066231],[21.92934,101.066391],[21.92901,101.066727],[21.92783,101.067917],[21.926649,101.069092],[21.925051,101.07045],[21.923241,101.071693],[21.921989,101.072533],[21.92062,101.073593],[21.92009,101.074112],[21.919189,101.075279],[21.917681,101.078453],[21.91642,101.081444],[21.916321,101.081673],[21.91571,101.083008],[21.915051,101.084587],[21.914379,101.087097],[21.914391,101.08876],[21.91444,101.089287],[21.914471,101.089722],[21.91452,101.090286],[21.914539,101.090439],[21.914579,101.091003],[21.914721,101.092216],[21.91493,101.095016],[21.91506,101.097748],[21.915051,101.103523],[21.914909,101.107643],[21.9149,101.107872],[21.914909,101.109596],[21.91526,101.113564],[21.91547,101.115044],[21.915751,101.11705],[21.915939,101.118347],[21.915991,101.118874],[21.916019,101.119141],[21.916071,101.119949],[21.91601,101.121269],[21.9158,101.122299],[21.915449,101.123268],[21.91511,101.123947],[21.914339,101.125504],[21.913811,101.127823],[21.91431,101.129951],[21.9146,101.13063],[21.91634,101.134247],[21.91654,101.134712],[21.91663,101.134933],[21.91839,101.139374],[21.918449,101.139603],[21.918631,101.140579],[21.91876,101.14238],[21.918859,101.14476],[21.9189,101.145813],[21.91894,101.146584],[21.918949,101.147102],[21.91897,101.147614],[21.91897,101.147873],[21.918949,101.148628],[21.91885,101.149399],[21.91869,101.150139],[21.918539,101.150879],[21.918449,101.151123],[21.91787,101.151672],[21.91713,101.152397],[21.914841,101.154327],[21.914499,101.154694],[21.914339,101.154877],[21.91366,101.155952],[21.913231,101.156891],[21.912741,101.158127],[21.91255,101.158638],[21.912081,101.159897],[21.911791,101.160652],[21.911501,101.1614],[21.911221,101.16214],[21.910749,101.163353],[21.910561,101.163811],[21.91011,101.164993],[21.909559,101.166382],[21.90947,101.166618],[21.90922,101.167343],[21.908661,101.170502],[21.908001,101.175049],[21.90786,101.175529],[21.907351,101.177269],[21.9072,101.177757],[21.90691,101.178757],[21.90649,101.180817],[21.906509,101.182121],[21.906549,101.182381],[21.90708,101.184097],[21.90826,101.186363],[21.90966,101.189034],[21.909769,101.189247],[21.911289,101.191254],[21.91147,101.191406],[21.912081,101.191833],[21.91445,101.193123],[21.91466,101.193253],[21.91526,101.193687],[21.916121,101.194618],[21.91687,101.195992],[21.91704,101.196457],[21.91711,101.196709],[21.91733,101.197769],[21.9175,101.198914],[21.917601,101.199783],[21.91777,101.200951],[21.91785,101.201508],[21.917971,101.202339],[21.918619,101.205002],[21.918949,101.20575],[21.92004,101.207611],[21.92045,101.208313],[21.920891,101.209213],[21.92137,101.210838],[21.92153,101.212631],[21.92156,101.213158],[21.921659,101.215263],[21.922371,101.219688],[21.922689,101.220886],[21.922979,101.221992],[21.92321,101.222763],[21.92333,101.223259],[21.923441,101.223701],[21.92392,101.226082],[21.92395,101.22644],[21.923969,101.226624],[21.923981,101.227013],[21.923981,101.227837],[21.923941,101.228706],[21.92392,101.228943],[21.9238,101.23037],[21.92371,101.231903],[21.923519,101.233963],[21.92304,101.239906],[21.92206,101.242363],[21.920389,101.244179],[21.920219,101.24437],[21.91906,101.246536],[21.918921,101.247253],[21.918831,101.249329],[21.918831,101.250221],[21.91881,101.250877],[21.91881,101.251099],[21.91873,101.252403],[21.918659,101.252838],[21.917749,101.255157],[21.91548,101.257736],[21.9149,101.258217],[21.9147,101.258377],[21.913401,101.259087],[21.912701,101.259354],[21.91222,101.259483],[21.910749,101.259811],[21.909769,101.26001],[21.90855,101.260277],[21.904751,101.261467],[21.904381,101.261726],[21.90402,101.262016],[21.902321,101.264214],[21.90143,101.265541],[21.90106,101.26609],[21.90019,101.267357],[21.89957,101.26825],[21.899309,101.26857],[21.898569,101.269302],[21.897261,101.269974],[21.89506,101.26992],[21.89484,101.269852],[21.89373,101.269432],[21.89328,101.269257],[21.89189,101.268799],[21.889059,101.268402],[21.88468,101.268173],[21.88446,101.26815],[21.880329,101.268433],[21.87883,101.269524],[21.87771,101.271393],[21.87731,101.273888],[21.87648,101.276787],[21.874929,101.278214],[21.8743,101.278458],[21.87303,101.278679],[21.872,101.278687],[21.871189,101.278717],[21.870171,101.278763],[21.868931,101.278839],[21.868509,101.278893],[21.86767,101.279099],[21.86746,101.279167],[21.86684,101.279404],[21.866631,101.279488],[21.864929,101.280167],[21.86426,101.280296],[21.86335,101.280312],[21.86289,101.280228],[21.86204,101.279892],[21.861469,101.279503],[21.860571,101.278488],[21.85997,101.277496],[21.85952,101.276718],[21.859289,101.276337],[21.85895,101.275749],[21.858391,101.274803],[21.85804,101.274223],[21.857809,101.273827],[21.857309,101.273087],[21.85689,101.272568],[21.856409,101.272102],[21.855659,101.271606],[21.855261,101.271423],[21.85461,101.271233],[21.854389,101.271179],[21.853291,101.271133],[21.852421,101.27121],[21.851561,101.271378],[21.851351,101.271423],[21.85051,101.271637],[21.849689,101.27195],[21.84889,101.272293],[21.8487,101.272392],[21.848129,101.272713],[21.847771,101.272957],[21.847429,101.273247],[21.84683,101.273911],[21.84646,101.274467],[21.846029,101.275543],[21.84589,101.276451],[21.845881,101.276939],[21.845921,101.277412],[21.84621,101.278847],[21.84626,101.279083],[21.846439,101.280022],[21.846581,101.280724],[21.84668,101.281174],[21.846979,101.282547],[21.847031,101.282784],[21.84713,101.283241],[21.847349,101.284653],[21.847349,101.285362],[21.8473,101.285828],[21.847019,101.286682],[21.84655,101.287537],[21.846081,101.288116],[21.84572,101.288437],[21.844709,101.288986],[21.844259,101.28907],[21.84314,101.2892],[21.842449,101.289177],[21.84178,101.289192],[21.840891,101.289299],[21.840441,101.289413],[21.83959,101.289742],[21.838961,101.290031],[21.838329,101.290314],[21.83728,101.290787],[21.83707,101.290894],[21.836439,101.291168],[21.83539,101.291641],[21.83518,101.291733],[21.837179,101.294617],[21.83725,101.295601],[21.837299,101.296066],[21.837339,101.296532],[21.83736,101.296997],[21.837311,101.297943],[21.83708,101.298828],[21.836729,101.299622],[21.836349,101.300133],[21.835699,101.300697],[21.83474,101.301224],[21.833679,101.301613],[21.832809,101.301918],[21.832371,101.302078],[21.83148,101.302383],[21.83082,101.302612],[21.829941,101.302917],[21.82951,101.303078],[21.82864,101.303383],[21.82777,101.303688],[21.827339,101.303841],[21.827129,101.303917],[21.82626,101.304222],[21.825411,101.304497],[21.82457,101.304688],[21.82436,101.304718],[21.823521,101.304771],[21.822651,101.304733],[21.822201,101.30468],[21.821079,101.304573],[21.82085,101.304527],[21.819771,101.304443],[21.81955,101.304428],[21.81811,101.304497],[21.81752,101.30468],[21.816549,101.305153],[21.81568,101.305801],[21.815121,101.306473],[21.81469,101.307243],[21.81444,101.307861],[21.81424,101.308502],[21.81418,101.308723],[21.81395,101.309578],[21.8139,101.309792],[21.81373,101.310448],[21.81356,101.311096],[21.81325,101.31218],[21.81319,101.312401],[21.81284,101.313881],[21.81263,101.31456],[21.8123,101.315376],[21.81167,101.316238],[21.81151,101.316383],[21.81098,101.31675],[21.810591,101.316917],[21.80978,101.317047],[21.808729,101.316933],[21.808331,101.316833],[21.80751,101.316612],[21.80731,101.316551],[21.806709,101.316383],[21.806101,101.316223],[21.8053,101.316002],[21.804489,101.315781],[21.804079,101.315666],[21.80308,101.315407],[21.802679,101.315308],[21.80188,101.315117],[21.801279,101.31498],[21.80068,101.314873],[21.79945,101.314781],[21.79841,101.314857],[21.798201,101.314888],[21.797569,101.315033],[21.795139,101.316109],[21.793831,101.316849],[21.792339,101.317703],[21.79178,101.318008],[21.789539,101.319283],[21.78265,101.342934],[21.78219,101.344131],[21.781931,101.34478],[21.781851,101.344978],[21.781731,101.345337],[21.781601,101.345802],[21.781321,101.347321],[21.781321,101.348717],[21.78134,101.348991],[21.78142,101.349808],[21.781549,101.350937],[21.78159,101.351227],[21.781731,101.352409],[21.78182,101.353279],[21.781839,101.353569],[21.781839,101.354141],[21.781771,101.35498],[21.78137,101.356293],[21.78125,101.356529],[21.780661,101.357407],[21.780331,101.357803],[21.780149,101.357986],[21.779631,101.35849],[21.77928,101.35881],[21.778761,101.359261],[21.778431,101.359573],[21.77767,101.360451],[21.77689,101.361717],[21.77639,101.362892],[21.776091,101.363632],[21.7756,101.364861],[21.77527,101.365578],[21.77515,101.365807],[21.774731,101.366463],[21.77421,101.367027],[21.77383,101.36734],[21.773621,101.36747],[21.77272,101.367897],[21.77083,101.368332],[21.770361,101.368439],[21.768511,101.368843],[21.76614,101.369759],[21.765829,101.370018],[21.765699,101.370163],[21.7647,101.371513],[21.764299,101.372093],[21.763041,101.37394],[21.76263,101.374557],[21.762211,101.375183],[21.76193,101.375603],[21.7612,101.375648],[21.75919,101.376251],[21.757509,101.376091],[21.7568,101.375893],[21.75511,101.375412],[21.754869,101.375359],[21.75362,101.375191],[21.752081,101.375168],[21.75131,101.375191],[21.750299,101.375198],[21.749281,101.375198],[21.748529,101.375168],[21.74777,101.37513],[21.74675,101.375053],[21.745741,101.374924],[21.745489,101.374878],[21.744989,101.374809],[21.74449,101.374741],[21.74399,101.37468],[21.74349,101.374619],[21.74324,101.374588],[21.74173,101.374428],[21.74098,101.374313],[21.73995,101.374153],[21.738661,101.373993],[21.73815,101.373947],[21.737619,101.373917],[21.736851,101.373947],[21.73633,101.374008],[21.735069,101.374283],[21.73406,101.37468],[21.73381,101.374786],[21.73307,101.375107],[21.73283,101.375229],[21.73185,101.375648],[21.7311,101.375923],[21.730591,101.376083],[21.7293,101.376266],[21.728769,101.376282],[21.727711,101.376221],[21.72718,101.37619],[21.72665,101.376152],[21.72613,101.376167],[21.725349,101.376213],[21.724819,101.376312],[21.72456,101.376373],[21.72378,101.376556],[21.723,101.376747],[21.72221,101.3769],[21.720619,101.37709],[21.71957,101.377083],[21.718781,101.377083],[21.718,101.37706],[21.71748,101.377029],[21.71697,101.377022],[21.715139,101.376961],[21.71434,101.37693],[21.713289,101.376907],[21.712761,101.376877],[21.712231,101.376862],[21.71196,101.376839],[21.71143,101.376793],[21.71064,101.376678],[21.710131,101.376579],[21.709869,101.376511],[21.708151,101.375938],[21.707439,101.375671],[21.70673,101.375397],[21.70648,101.375298],[21.705759,101.375038],[21.70479,101.374771],[21.70454,101.374733],[21.703791,101.374649],[21.703541,101.374641],[21.70084,101.374786],[21.699369,101.374687],[21.696461,101.374207],[21.69548,101.374046],[21.694759,101.373917],[21.69404,101.373779],[21.692101,101.373558],[21.68832,101.373627],[21.68716,101.373703],[21.68671,101.373718],[21.68626,101.373734],[21.68581,101.373756],[21.684259,101.373848],[21.68294,101.373917],[21.68227,101.373962],[21.68181,101.373993],[21.677691,101.374207],[21.6772,101.374252],[21.67627,101.37429],[21.67564,101.374329],[21.675261,101.374352],[21.674931,101.374367],[21.674431,101.374397],[21.674231,101.374382],[21.67403,101.374367],[21.673719,101.374367],[21.67363,101.374397],[21.67362,101.374397],[21.673281,101.374443],[21.672291,101.374519],[21.672041,101.374527],[21.669769,101.374817],[21.668909,101.374962],[21.66818,101.375053],[21.667589,101.375069],[21.66655,101.374992],[21.66567,101.37484],[21.66522,101.374733],[21.66452,101.374573],[21.66358,101.374336],[21.662609,101.374107],[21.660681,101.37365],[21.66044,101.373596],[21.65901,101.37326],[21.658279,101.373192],[21.65803,101.373199],[21.65778,101.37323],[21.65707,101.373413],[21.656429,101.373741],[21.65411,101.375397],[21.65262,101.376442],[21.651871,101.376961],[21.651131,101.37748],[21.649639,101.378517],[21.64854,101.379333],[21.648359,101.379478],[21.647209,101.38092],[21.64658,101.382469],[21.646481,101.382919],[21.646391,101.383598],[21.64636,101.384529],[21.64633,101.385681],[21.646311,101.386139],[21.646299,101.386581],[21.64628,101.387253],[21.64625,101.388138],[21.64624,101.38858],[21.646231,101.389023],[21.646259,101.389893],[21.646299,101.390961],[21.64636,101.391586],[21.646391,101.392227],[21.64641,101.392662],[21.646429,101.392883],[21.646481,101.394188],[21.646429,101.395058],[21.646339,101.395477],[21.646061,101.396561],[21.645821,101.3974],[21.64576,101.397614],[21.645651,101.398033],[21.64547,101.398666],[21.64535,101.399094],[21.64529,101.3993],[21.645109,101.399933],[21.64506,101.400139],[21.643129,101.399544],[21.64254,101.399788],[21.6415,101.400208],[21.640881,101.400436],[21.639811,101.400787],[21.639601,101.400864],[21.639179,101.400993],[21.638599,101.401253],[21.63805,101.401588],[21.637421,101.402153],[21.63689,101.402802],[21.636669,101.403191],[21.63641,101.40377],[21.63624,101.404167],[21.63607,101.404556],[21.63582,101.405159],[21.635731,101.405357],[21.635389,101.406151],[21.635139,101.406754],[21.6348,101.407539],[21.63463,101.407944],[21.63438,101.408531],[21.634041,101.409317],[21.633869,101.409721],[21.638929,101.41069],[21.6392,101.411049],[21.63945,101.411423],[21.639811,101.411957],[21.64032,101.412682],[21.64068,101.413223],[21.641041,101.41375],[21.641399,101.414284],[21.641649,101.414627],[21.641899,101.414993],[21.64266,101.416107],[21.643089,101.416939],[21.64325,101.417381],[21.643419,101.418068],[21.643499,101.418533],[21.6436,101.419006],[21.64378,101.41996],[21.64397,101.420914],[21.64411,101.421623],[21.644251,101.42234],[21.64114,101.423126],[21.640671,101.423347],[21.64003,101.423569],[21.63954,101.423698],[21.63903,101.423843],[21.6387,101.423912],[21.638,101.424049],[21.6373,101.424187],[21.63678,101.424309],[21.63625,101.424438],[21.634991,101.424744],[21.63446,101.424873],[21.63378,101.425079],[21.63345,101.425209],[21.632799,101.425537],[21.632339,101.42585],[21.631901,101.426201],[21.63147,101.426613],[21.631081,101.42704],[21.630831,101.427322],[21.630569,101.427612],[21.63015,101.427834],[21.62956,101.42836],[21.62854,101.429283],[21.628099,101.42968],[21.62752,101.430206],[21.62678,101.430862],[21.618349,101.454582],[21.618311,101.454857],[21.61771,101.456886],[21.616671,101.45816],[21.61628,101.458443],[21.615459,101.458977],[21.61483,101.459373],[21.613991,101.459908],[21.61311,101.46048],[21.61268,101.460747],[21.61224,101.460999],[21.61179,101.461197],[21.610849,101.461502],[21.6096,101.461723],[21.60911,101.4618],[21.60862,101.461884],[21.60788,101.462013],[21.606421,101.462273],[21.6057,101.462334],[21.60523,101.462303],[21.60499,101.46225],[21.604521,101.46212],[21.60429,101.462029],[21.603821,101.461838],[21.60358,101.461731],[21.6031,101.461517],[21.60235,101.461327],[21.601851,101.461273],[21.601089,101.461357],[21.599911,101.461807],[21.59948,101.462097],[21.598249,101.463051],[21.597851,101.463371],[21.597231,101.463837],[21.597031,101.463997],[21.596621,101.46431],[21.59622,101.464577],[21.595289,101.465027],[21.594259,101.465149],[21.593731,101.465141],[21.592951,101.46508],[21.59244,101.465012],[21.59144,101.464943],[21.59119,101.464928],[21.5907,101.464928],[21.59045,101.464943],[21.588699,101.465279],[21.58823,101.465553],[21.58778,101.465813],[21.586901,101.466393],[21.585779,101.467117],[21.5851,101.467484],[21.58486,101.46759],[21.58313,101.467796],[21.581961,101.467537],[21.58009,101.467323],[21.57918,101.467537],[21.57896,101.467628],[21.578751,101.467743],[21.57708,101.469528],[21.57564,101.471237],[21.573721,101.47213],[21.57185,101.47226],[21.571609,101.472267],[21.570921,101.47242],[21.5707,101.472504],[21.56967,101.473106],[21.56683,101.474373],[21.56468,101.474983],[21.564091,101.475304],[21.563181,101.47596],[21.562389,101.476761],[21.56115,101.478378],[21.561001,101.478561],[21.55938,101.480637],[21.559231,101.480827],[21.55831,101.481956],[21.5578,101.482483],[21.55722,101.48291],[21.556589,101.483231],[21.556141,101.483383],[21.554979,101.483566],[21.55451,101.483582],[21.554279,101.483589],[21.552191,101.48365],[21.551279,101.483681],[21.55061,101.483704],[21.548849,101.483757],[21.547979,101.483788],[21.54689,101.483841],[21.546671,101.483856],[21.546049,101.483971],[21.54414,101.484978],[21.54397,101.48513],[21.54348,101.485657],[21.542891,101.48642],[21.54274,101.48661],[21.542,101.487556],[21.541861,101.487747],[21.540859,101.489021],[21.54043,101.48954],[21.540291,101.489708],[21.539841,101.490173],[21.5392,101.4907],[21.53886,101.490921],[21.538691,101.49102],[21.538151,101.491287],[21.537781,101.491432],[21.537041,101.491669],[21.536671,101.491783],[21.5347,101.492409],[21.53422,101.492554],[21.533739,101.492706],[21.533421,101.492813],[21.53117,101.493507],[21.52005,101.497276],[21.51823,101.497932],[21.516729,101.498421],[21.516121,101.498749],[21.515369,101.499313],[21.51487,101.499863],[21.5142,101.500954],[21.51395,101.501404],[21.51309,101.502617],[21.512489,101.50341],[21.5119,101.504204],[21.51145,101.504799],[21.51115,101.505203],[21.509859,101.505867],[21.50952,101.506233],[21.508989,101.506767],[21.508471,101.507317],[21.508301,101.5075],[21.50812,101.507683],[21.50765,101.508568],[21.50758,101.508743],[21.50746,101.509407],[21.507481,101.510117],[21.507641,101.511124],[21.50786,101.512627],[21.507959,101.513397],[21.507151,101.514633],[21.50692,101.515289],[21.506491,101.516243],[21.5063,101.516731],[21.506149,101.517258],[21.506001,101.518044],[21.50596,101.518547],[21.50596,101.518784],[21.50597,101.518982],[21.505989,101.519333],[21.506029,101.519653],[21.506069,101.519997],[21.50596,101.522263],[21.50559,101.523567],[21.50539,101.524117],[21.505199,101.524643],[21.50493,101.525421],[21.504669,101.526169],[21.504499,101.526657],[21.50436,101.527168],[21.50421,101.527679],[21.50399,101.528442],[21.503691,101.529457],[21.50388,101.531113],[21.503839,101.531891],[21.50375,101.532417],[21.503469,101.53344],[21.503189,101.534187],[21.502741,101.535393],[21.502649,101.535629],[21.50247,101.536118],[21.50219,101.53685],[21.502001,101.537354],[21.50169,101.538101],[21.50135,101.539108],[21.50128,101.540138],[21.50182,101.541763],[21.502119,101.54213],[21.502279,101.542297],[21.502819,101.542686],[21.50433,101.543671],[21.505131,101.544182],[21.50856,101.546333],[21.50975,101.547249],[21.51009,101.547607],[21.51037,101.548019],[21.510691,101.548714],[21.51091,101.549713],[21.51087,101.550743],[21.510019,101.552643],[21.50943,101.553497],[21.507971,101.555656],[21.507099,101.556976],[21.50695,101.55722],[21.506689,101.557663],[21.50597,101.558723],[21.5054,101.55957],[21.50499,101.560188],[21.504021,101.561607],[21.50321,101.562866],[21.501711,101.565132],[21.500299,101.567253],[21.49931,101.568764],[21.498329,101.570236],[21.496941,101.572327],[21.49625,101.573372],[21.49472,101.575684],[21.491819,101.579353],[21.48933,101.58075],[21.48888,101.580887],[21.486139,101.581078],[21.48407,101.580566],[21.481621,101.579582],[21.481171,101.579399],[21.480721,101.579224],[21.47644,101.57753],[21.474199,101.57666],[21.47193,101.57579],[21.467951,101.574188],[21.46373,101.572517],[21.46306,101.572258],[21.46283,101.572166],[21.461531,101.571663],[21.45727,101.570129],[21.45557,101.56974],[21.450569,101.568871],[21.450121,101.568939],[21.449129,101.569443],[21.448389,101.570358],[21.447821,101.571732],[21.44714,101.573059],[21.447001,101.573257],[21.44635,101.573936],[21.44599,101.574226],[21.44524,101.574738],[21.44451,101.575249],[21.44367,101.576317],[21.443371,101.57695],[21.44311,101.577583],[21.44302,101.577797],[21.44268,101.578644],[21.442419,101.579277],[21.442169,101.579933],[21.442089,101.580139],[21.441589,101.581169],[21.441469,101.581367],[21.439939,101.583168],[21.43919,101.583748],[21.43844,101.584328],[21.43825,101.584473],[21.43788,101.584763],[21.437309,101.58519],[21.43712,101.585327],[21.43615,101.584167],[21.43479,101.583832],[21.4333,101.582962],[21.43273,101.582451],[21.432541,101.582253],[21.431669,101.581284],[21.430969,101.580513],[21.430269,101.57975],[21.43008,101.579567],[21.429501,101.579071],[21.428391,101.578491],[21.427919,101.578346],[21.427429,101.578247],[21.425461,101.578407],[21.424049,101.579048],[21.420389,101.581108],[21.419979,101.581337],[21.41571,101.583321],[21.41457,101.583511],[21.41366,101.583542],[21.41206,101.583427],[21.408621,101.583557],[21.40716,101.584686],[21.4049,101.588074],[21.403959,101.589478],[21.40303,101.590919],[21.402679,101.592781],[21.403009,101.593674],[21.40378,101.594841],[21.40402,101.595253],[21.40432,101.595886],[21.404461,101.596336],[21.404591,101.597549],[21.40451,101.598282],[21.40427,101.599258],[21.404169,101.599762],[21.40451,101.601669],[21.406111,101.604439],[21.40613,101.605873],[21.4058,101.606552],[21.404699,101.607536],[21.404261,101.607697],[21.403339,101.607971],[21.402929,101.608177],[21.402559,101.608459],[21.401739,101.610237],[21.401871,101.611267],[21.40221,101.612251],[21.402809,101.613823],[21.40299,101.614487],[21.40303,101.614967],[21.40284,101.616112],[21.401939,101.618828],[21.40192,101.619072],[21.40217,101.620598],[21.40247,101.621201],[21.40373,101.623901],[21.40465,101.626793],[21.40407,101.628906],[21.40324,101.63076],[21.403139,101.630989],[21.40155,101.634537],[21.40093,101.636017],[21.40012,101.637909],[21.399981,101.638763],[21.400181,101.639793],[21.400709,101.640717],[21.40102,101.641144],[21.401131,101.641296],[21.40196,101.642464],[21.402081,101.642639],[21.402981,101.643921],[21.404921,101.645638],[21.40534,101.645882],[21.406879,101.646599],[21.407089,101.646721],[21.40806,101.647476],[21.40929,101.649406],[21.40995,101.651413],[21.410191,101.652168],[21.412201,101.65831],[21.412661,101.659714],[21.413031,101.660873],[21.41342,101.661987],[21.413731,101.66288],[21.414021,101.663788],[21.4142,101.664726],[21.4142,101.665672],[21.414061,101.666344],[21.41399,101.66655],[21.41383,101.666992],[21.413389,101.66777],[21.41296,101.668297],[21.41247,101.668762],[21.411989,101.669197],[21.411329,101.669762],[21.410851,101.670174],[21.409861,101.671089],[21.409519,101.671387],[21.40654,101.674118],[21.40633,101.674179],[21.405331,101.675163],[21.40472,101.675667],[21.403,101.676773],[21.402309,101.677094],[21.402069,101.677193],[21.401581,101.677368],[21.40037,101.677727],[21.39938,101.678017],[21.397619,101.678543],[21.39686,101.678772],[21.39661,101.678848],[21.39558,101.679153],[21.393749,101.679703],[21.39349,101.679787],[21.39068,101.680634],[21.3897,101.680923],[21.388531,101.681267],[21.3883,101.681343],[21.38497,101.681824],[21.38472,101.681793],[21.38423,101.681709],[21.383301,101.681473],[21.38283,101.681328],[21.381849,101.681137],[21.3811,101.681099],[21.37989,101.681252],[21.374399,101.682503],[21.371639,101.683113],[21.37097,101.683243],[21.370119,101.683434],[21.369711,101.683517],[21.36779,101.683937],[21.366369,101.684273],[21.363689,101.684883],[21.358419,101.68605],[21.355499,101.686691],[21.35397,101.687172],[21.351471,101.688713],[21.34923,101.689758],[21.34716,101.689621],[21.346491,101.689499],[21.34627,101.689461],[21.3445,101.68914],[21.34428,101.68911],[21.34269,101.688812],[21.340111,101.68895],[21.33828,101.689888],[21.337641,101.690331],[21.334961,101.692108],[21.332781,101.692627],[21.3321,101.692612],[21.331181,101.692581],[21.330429,101.692551],[21.330179,101.692528],[21.326281,101.692917],[21.324341,101.693268],[21.324089,101.693314],[21.32147,101.693352],[21.31986,101.693321],[21.317921,101.694153],[21.317711,101.69426],[21.31728,101.694427],[21.316139,101.69445],[21.314119,101.693893],[21.3139,101.693832],[21.31188,101.693459],[21.30991,101.693947],[21.308069,101.69548],[21.30736,101.696136],[21.306259,101.697166],[21.30348,101.699059],[21.30176,101.699493],[21.29907,101.699257],[21.293909,101.698067],[21.292749,101.697807],[21.289789,101.697159],[21.289129,101.697006],[21.28742,101.696632],[21.286369,101.696388],[21.28471,101.696053],[21.28323,101.696136],[21.281811,101.696793],[21.28023,101.698433],[21.27973,101.699074],[21.279221,101.699722],[21.27784,101.701424],[21.27766,101.70163],[21.276819,101.70269],[21.276661,101.702904],[21.275181,101.70472],[21.27319,101.706131],[21.271839,101.706734],[21.271469,101.707047],[21.270941,101.70787],[21.26981,101.711739],[21.26972,101.711983],[21.2689,101.713188],[21.2665,101.715477],[21.26597,101.715958],[21.265369,101.716316],[21.26404,101.716522],[21.263161,101.716293],[21.260771,101.714844],[21.25922,101.713852],[21.257099,101.712517],[21.25647,101.712128],[21.256081,101.711884],[21.255791,101.711723],[21.25561,101.711571],[21.25526,101.711327],[21.25515,101.711273],[21.2542,101.710693],[21.253139,101.710037],[21.253019,101.709969],[21.252831,101.709846],[21.251011,101.708702],[21.250351,101.708321],[21.249781,101.70813],[21.24929,101.707947],[21.24873,101.70787],[21.24799,101.707802],[21.246639,101.707718],[21.24645,101.707703],[21.24424,101.707573],[21.24391,101.707512],[21.24243,101.707199],[21.23983,101.706123],[21.237459,101.705139],[21.232361,101.703072],[21.232071,101.702988],[21.229389,101.702309],[21.229059,101.702217],[21.22883,101.702263],[21.22781,101.702744],[21.227631,101.702858],[21.226589,101.703712],[21.22473,101.704857],[21.22368,101.705063],[21.221531,101.704613],[21.22003,101.704063],[21.217899,101.703362],[21.21722,101.703201],[21.21579,101.703049],[21.21278,101.70285],[21.209311,101.702278],[21.207649,101.701683],[21.20392,101.700203],[21.202351,101.699127],[21.200911,101.696533],[21.1991,101.693657],[21.19673,101.692017],[21.194309,101.690483],[21.19376,101.690102],[21.193081,101.689651],[21.1917,101.688637],[21.190769,101.687233],[21.19038,101.68663],[21.190069,101.686272],[21.189859,101.686096],[21.18948,101.685799],[21.188499,101.68512],[21.18718,101.684097],[21.18701,101.683723],[21.186689,101.683517],[21.186279,101.683693],[21.18615,101.683632],[21.185841,101.683296],[21.18573,101.682793],[21.18601,101.681519],[21.18609,101.680992],[21.18647,101.680603],[21.186871,101.680237],[21.187,101.679932],[21.18693,101.678787],[21.18714,101.678131],[21.187559,101.677711],[21.18775,101.677139],[21.18775,101.676033],[21.187361,101.675491],[21.18634,101.67466],[21.186001,101.674156],[21.185749,101.673912],[21.18507,101.673508],[21.184771,101.673378],[21.184389,101.673187],[21.18375,101.672913],[21.182159,101.67215],[21.180889,101.671158],[21.179991,101.670067],[21.17861,101.669197],[21.17667,101.668991],[21.17417,101.668457],[21.173349,101.668541],[21.17028,101.669739],[21.16925,101.670959],[21.1682,101.672523],[21.16785,101.672813],[21.166189,101.673027],[21.16534,101.672256],[21.16515,101.671768],[21.16436,101.671318],[21.164221,101.671341],[21.162239,101.671417],[21.15913,101.672249],[21.158449,101.672173],[21.157101,101.671822],[21.156509,101.671494],[21.15626,101.671288],[21.155239,101.671181],[21.15383,101.6716],[21.153191,101.672234],[21.15299,101.67263],[21.152439,101.67305],[21.151421,101.673592],[21.150631,101.67337],[21.15029,101.672989],[21.15037,101.672081],[21.150669,101.671257],[21.150391,101.670158],[21.15033,101.670067],[21.14954,101.669273],[21.14859,101.668411],[21.14756,101.668449],[21.14698,101.668678],[21.145809,101.668266],[21.14555,101.667824],[21.14522,101.666992],[21.14439,101.666809],[21.14426,101.666893],[21.14325,101.666779],[21.141621,101.665131],[21.140881,101.664749],[21.139521,101.664429],[21.138849,101.664528],[21.13736,101.665062],[21.1367,101.665047],[21.133381,101.664391],[21.13324,101.66433],[21.132509,101.663429],[21.13204,101.662064],[21.13155,101.661484],[21.12817,101.657883],[21.12644,101.656097],[21.124781,101.654663],[21.123831,101.654449],[21.122801,101.654503],[21.121611,101.653748],[21.12063,101.65239],[21.119909,101.652184],[21.119591,101.652199],[21.118719,101.651787],[21.116011,101.64978],[21.114189,101.648827],[21.11272,101.647827],[21.11216,101.647171],[21.11198,101.646858],[21.110399,101.645432],[21.10799,101.643784],[21.1066,101.642517],[21.105141,101.642128],[21.10467,101.642021],[21.10405,101.641533],[21.10235,101.639343],[21.10084,101.638039],[21.10059,101.637817],[21.099581,101.637688],[21.098789,101.637917],[21.097651,101.637497],[21.09745,101.636864],[21.097389,101.636368],[21.0968,101.635696],[21.09623,101.635429],[21.095579,101.635422],[21.094721,101.635567],[21.093611,101.635033],[21.0937,101.634087],[21.093571,101.633324],[21.093201,101.633339],[21.09173,101.633362],[21.091311,101.634033],[21.091339,101.634407],[21.090811,101.634972],[21.090679,101.634956],[21.090429,101.634933],[21.09004,101.63427],[21.090031,101.633827],[21.08955,101.633232],[21.08824,101.63266],[21.08761,101.631882],[21.08699,101.629753],[21.086281,101.629288],[21.085979,101.629883],[21.085951,101.630363],[21.085409,101.631233],[21.08371,101.633232],[21.08346,101.633499],[21.08213,101.634163],[21.081591,101.634033],[21.08135,101.633919],[21.08079,101.63427],[21.08078,101.634552],[21.080839,101.635437],[21.08036,101.63588],[21.08003,101.635902],[21.07967,101.636673],[21.079691,101.638252],[21.079399,101.639343],[21.078541,101.639977],[21.077511,101.640182],[21.07645,101.639679],[21.076229,101.639442],[21.075251,101.639282],[21.0749,101.639587],[21.074249,101.640633],[21.0742,101.641724],[21.074301,101.642326],[21.073811,101.642967],[21.07135,101.643784],[21.06925,101.644409],[21.06815,101.643997],[21.06529,101.641731],[21.06399,101.64122],[21.063589,101.640419],[21.06303,101.6399],[21.062799,101.640053],[21.06217,101.640602],[21.061819,101.641602],[21.061831,101.641678],[21.061939,101.64257],[21.061939,101.643494],[21.06189,101.64373],[21.06179,101.644058],[21.061331,101.644096],[21.060949,101.644112],[21.060551,101.64415],[21.058901,101.644211],[21.05814,101.644142],[21.057421,101.643707],[21.0557,101.641777],[21.054649,101.639397],[21.054371,101.637123],[21.05472,101.636192],[21.05496,101.635902],[21.055201,101.634933],[21.05521,101.633789],[21.05562,101.633133],[21.056,101.632858],[21.056259,101.632507],[21.056231,101.631889],[21.056009,101.631126],[21.056009,101.63031],[21.055611,101.629601],[21.05542,101.629463],[21.055229,101.629066],[21.05549,101.628708],[21.055759,101.628609],[21.056959,101.628326],[21.05728,101.628036],[21.057211,101.627663],[21.05706,101.627472],[21.056881,101.627289],[21.056749,101.626503],[21.056881,101.625992],[21.056391,101.625427],[21.056259,101.62542],[21.055861,101.625381],[21.055531,101.624649],[21.05567,101.624107],[21.05521,101.623482],[21.055071,101.623451],[21.054529,101.623337],[21.053841,101.623421],[21.05345,101.623573],[21.05257,101.623238],[21.052481,101.623108],[21.05212,101.622597],[21.05159,101.622292],[21.05098,101.622124],[21.05027,101.621071],[21.04999,101.617973],[21.050171,101.617203],[21.0518,101.614067],[21.053329,101.611893],[21.05361,101.610832],[21.054119,101.609283],[21.05393,101.608627],[21.05303,101.606812],[21.05307,101.605743],[21.053431,101.604851],[21.05352,101.60408],[21.05327,101.602287],[21.05216,101.599876],[21.052219,101.598587],[21.052691,101.596916],[21.052589,101.596092],[21.051649,101.59243],[21.05213,101.591179],[21.054859,101.588188],[21.055071,101.586418],[21.055019,101.58622],[21.053671,101.583351],[21.053471,101.583023],[21.05316,101.581673],[21.05213,101.580551],[21.05195,101.580467],[21.048651,101.579102],[21.047661,101.577583],[21.047159,101.575447],[21.04752,101.574654],[21.047939,101.574249],[21.047831,101.573502],[21.04771,101.573387],[21.045891,101.571762],[21.04542,101.57132],[21.044941,101.570572],[21.043739,101.569817],[21.043119,101.569893],[21.040911,101.57045],[21.039921,101.570267],[21.03924,101.569939],[21.038771,101.569153],[21.038679,101.568779],[21.03887,101.567871],[21.03911,101.56739],[21.038759,101.56649],[21.03618,101.56472],[21.034491,101.564079],[21.03421,101.563957],[21.033649,101.563393],[21.033291,101.562782],[21.03249,101.562347],[21.03064,101.561867],[21.02869,101.56057],[21.027941,101.558998],[21.028431,101.557823],[21.02883,101.557358],[21.0292,101.556396],[21.02948,101.554993],[21.03001,101.553947],[21.030121,101.553062],[21.03009,101.55275],[21.02957,101.552261],[21.0285,101.551842],[21.02776,101.551918],[21.02747,101.551987],[21.02669,101.551743],[21.025669,101.550957],[21.02426,101.549026],[21.024151,101.548843],[21.02359,101.546783],[21.022961,101.546013],[21.022449,101.545723],[21.02191,101.545181],[21.02103,101.544579],[21.01865,101.544144],[21.01754,101.543259],[21.017481,101.543068],[21.01631,101.540771],[21.01417,101.53756],[21.01343,101.536171],[21.01198,101.534866],[21.01107,101.533409],[21.01088,101.532593],[21.01087,101.53167],[21.01041,101.530777],[21.00898,101.529266],[21.00782,101.526787],[21.00745,101.525253],[21.00626,101.522858],[21.00585,101.522148],[21.005159,101.521637],[21.0049,101.521523],[21.004641,101.520668],[21.00502,101.518944],[21.00486,101.518288],[21.004499,101.517731],[21.003889,101.517303],[21.003651,101.517212],[21.003281,101.516609],[21.00312,101.515732],[21.002621,101.515251],[21.001989,101.514832],[21.00145,101.514183],[21.000019,101.513237],[20.99921,101.513107],[20.99798,101.513229],[20.997299,101.513573],[20.995371,101.514557],[20.99423,101.514267],[20.99411,101.514107],[20.993151,101.51326],[20.99276,101.512451],[20.99169,101.509193],[20.99136,101.508392],[20.99144,101.507004],[20.99139,101.506577],[20.99114,101.505531],[20.990749,101.504936],[20.990391,101.50457],[20.9893,101.504051],[20.988171,101.503937],[20.987301,101.503036],[20.986629,101.502098],[20.986059,101.501862],[20.98563,101.501823],[20.985189,101.501129],[20.98535,101.5009],[20.98554,101.500671],[20.985479,101.499657],[20.985201,101.499428],[20.984381,101.498848],[20.9841,101.4981],[20.98411,101.497597],[20.983919,101.496964],[20.982651,101.493713],[20.982571,101.49353],[20.98209,101.492943],[20.98139,101.492027],[20.98027,101.491493],[20.979931,101.491463],[20.97905,101.490608],[20.978979,101.490211],[20.97872,101.486893],[20.97826,101.484161],[20.977501,101.481491],[20.977671,101.480797],[20.97838,101.479523],[20.978571,101.478737],[20.97826,101.477966],[20.97625,101.475441],[20.975889,101.474953],[20.97571,101.474243],[20.97571,101.473801],[20.975189,101.473083],[20.974569,101.472763],[20.971781,101.472397],[20.971319,101.472343],[20.97085,101.471573],[20.9708,101.470627],[20.970989,101.469879],[20.97171,101.468323],[20.9718,101.46756],[20.97176,101.466614],[20.97085,101.464706],[20.96999,101.464142],[20.96937,101.463982],[20.968889,101.463127],[20.969021,101.462761],[20.96921,101.462219],[20.969311,101.459877],[20.96875,101.458588],[20.96818,101.458328],[20.967899,101.458344],[20.96715,101.457619],[20.966829,101.456596],[20.96603,101.456177],[20.964979,101.456093],[20.964399,101.455673],[20.96394,101.455139],[20.96306,101.454193],[20.96171,101.452744],[20.96068,101.451591],[20.956091,101.446877],[20.95311,101.443123],[20.94928,101.435982],[20.947901,101.432739],[20.947109,101.430893],[20.944679,101.423531],[20.94459,101.423302],[20.94437,101.422813],[20.94393,101.422318],[20.94335,101.421989],[20.940571,101.421303],[20.937679,101.420601],[20.93697,101.42028],[20.934799,101.41803],[20.934759,101.417976],[20.933929,101.41713],[20.931311,101.414238],[20.930401,101.411774],[20.928591,101.406677],[20.92713,101.402611],[20.926319,101.400558],[20.9261,101.400032],[20.92557,101.399147],[20.924749,101.397987],[20.92362,101.397202],[20.92201,101.396652],[20.919701,101.396263],[20.916941,101.396027],[20.91567,101.396103],[20.91518,101.396057],[20.91395,101.395683],[20.912701,101.395607],[20.912001,101.395248],[20.91086,101.393898],[20.91008,101.392738],[20.90941,101.39241],[20.908859,101.392418],[20.908319,101.392258],[20.907619,101.391838],[20.90641,101.391373],[20.90514,101.390343],[20.90481,101.390007],[20.90452,101.389236],[20.904369,101.387253],[20.90424,101.386543],[20.90419,101.385681],[20.904249,101.385193],[20.903959,101.384361],[20.902889,101.383614],[20.902361,101.382896],[20.901699,101.381378],[20.901421,101.38102],[20.90081,101.380478],[20.900419,101.379936],[20.89982,101.378464],[20.89942,101.377693],[20.89913,101.376877],[20.898861,101.375717],[20.89913,101.374657],[20.899389,101.373901],[20.899771,101.373192],[20.900129,101.372658],[20.900181,101.371742],[20.89929,101.370667],[20.899111,101.369743],[20.89933,101.36908],[20.89933,101.368187],[20.89893,101.366798],[20.898621,101.365959],[20.897791,101.364807],[20.89596,101.363327],[20.89566,101.363159],[20.894501,101.362846],[20.893221,101.362282],[20.89233,101.362289],[20.891911,101.362503],[20.89109,101.362419],[20.890869,101.361862],[20.890989,101.361412],[20.891991,101.359993],[20.892191,101.359543],[20.892321,101.359039],[20.892361,101.357803],[20.891979,101.356918],[20.89134,101.356422],[20.89098,101.355713],[20.89085,101.354797],[20.890739,101.354477],[20.890169,101.353882],[20.88908,101.35334],[20.887831,101.352203],[20.887449,101.351532],[20.887051,101.350227],[20.886459,101.347748],[20.88616,101.345627],[20.885771,101.344566],[20.885139,101.343468],[20.88505,101.342644],[20.885099,101.342339],[20.884859,101.341637],[20.88353,101.339973],[20.882351,101.338768],[20.880859,101.3377],[20.87953,101.335678],[20.878099,101.334183],[20.87734,101.333168],[20.876961,101.332138],[20.87657,101.331589],[20.87565,101.330719],[20.875271,101.329689],[20.875191,101.328537],[20.874901,101.327873],[20.87468,101.327583],[20.874399,101.326897],[20.87429,101.325577],[20.87417,101.325081],[20.87361,101.324387],[20.87336,101.323647],[20.87372,101.323196],[20.8745,101.322937],[20.87533,101.322411],[20.876341,101.321587],[20.87653,101.320892],[20.876419,101.320633],[20.87587,101.319832],[20.8755,101.319199],[20.874941,101.31871],[20.8743,101.318604],[20.87339,101.318153],[20.87311,101.317917],[20.872601,101.317039],[20.87215,101.316429],[20.87092,101.316002],[20.87092,101.315643],[20.87122,101.314941],[20.871281,101.314583],[20.871241,101.314484],[20.87109,101.314323],[20.870701,101.314133],[20.87014,101.313477],[20.869671,101.313187],[20.869301,101.312759],[20.86846,101.312218],[20.86771,101.311951],[20.8671,101.311447],[20.86688,101.311409],[20.866301,101.3116],[20.86607,101.311523],[20.865959,101.311409],[20.865801,101.310837],[20.86561,101.31041],[20.865049,101.309357],[20.86484,101.309067],[20.86454,101.308907],[20.86376,101.309387],[20.86334,101.309227],[20.86293,101.308487],[20.862379,101.308144],[20.86187,101.308067],[20.86134,101.307678],[20.86109,101.307343],[20.86058,101.307114],[20.859579,101.306999],[20.859261,101.307022],[20.858521,101.306557],[20.85837,101.306557],[20.85812,101.306839],[20.857849,101.307281],[20.85762,101.307373],[20.85746,101.307266],[20.85737,101.306808],[20.85758,101.304932],[20.85774,101.304482],[20.857809,101.303909],[20.85762,101.303467],[20.857031,101.302849],[20.85684,101.302551],[20.856741,101.301697],[20.85685,101.301376],[20.857031,101.301117],[20.857401,101.300873],[20.8578,101.300407],[20.857809,101.299911],[20.85775,101.299751],[20.85659,101.298553],[20.85626,101.298347],[20.85582,101.297791],[20.8554,101.297028],[20.8552,101.296783],[20.85458,101.296593],[20.854441,101.296631],[20.85359,101.296577],[20.85334,101.296173],[20.853201,101.295738],[20.852631,101.295326],[20.85215,101.295288],[20.85099,101.294746],[20.849661,101.293571],[20.84874,101.292473],[20.84767,101.291672],[20.845869,101.291008],[20.845289,101.290916],[20.84473,101.290749],[20.8437,101.289886],[20.84339,101.289398],[20.842211,101.288437],[20.842039,101.288353],[20.84111,101.288147],[20.839911,101.287758],[20.839411,101.287682],[20.837811,101.286537],[20.836929,101.2864],[20.83576,101.286842],[20.83511,101.28685],[20.834379,101.286758],[20.83363,101.286812],[20.83313,101.286972],[20.832451,101.28698],[20.83209,101.286903],[20.83136,101.286858],[20.8307,101.286659],[20.82987,101.286171],[20.827419,101.284218],[20.82687,101.283821],[20.826639,101.2836],[20.826469,101.282822],[20.827129,101.280853],[20.827259,101.280098],[20.827181,101.279358],[20.827009,101.278397],[20.82641,101.276901],[20.82559,101.276009],[20.823879,101.273521],[20.823151,101.272568],[20.82159,101.269386],[20.82069,101.2687],[20.81974,101.268578],[20.81888,101.268013],[20.818501,101.26712],[20.818159,101.266602],[20.81764,101.265961],[20.8174,101.265213],[20.817101,101.263397],[20.81666,101.26268],[20.81521,101.260689],[20.81455,101.2593],[20.81427,101.257919],[20.813629,101.256981],[20.812321,101.256058],[20.81144,101.255783],[20.81056,101.255829],[20.80987,101.255524],[20.809561,101.254936],[20.809259,101.254532],[20.808781,101.25428],[20.80657,101.253616],[20.8057,101.252892],[20.805111,101.25174],[20.804529,101.251251],[20.804199,101.25116],[20.80361,101.250793],[20.803249,101.25042],[20.802361,101.250076],[20.80204,101.250076],[20.80131,101.249603],[20.801081,101.248833],[20.800421,101.248154],[20.799601,101.24794],[20.79903,101.247581],[20.79871,101.247009],[20.79841,101.246651],[20.798059,101.246368],[20.797729,101.245918],[20.79738,101.245552],[20.796869,101.245453],[20.796061,101.245071],[20.795691,101.244034],[20.79571,101.24337],[20.79591,101.242928],[20.79604,101.242363],[20.79582,101.242012],[20.79541,101.241859],[20.79455,101.241829],[20.79377,101.241577],[20.79318,101.241508],[20.792471,101.241676],[20.791559,101.241417],[20.79118,101.241043],[20.79059,101.240044],[20.79001,101.239571],[20.78912,101.239166],[20.788349,101.238457],[20.78746,101.23822],[20.787109,101.238312],[20.7859,101.238449],[20.78516,101.238167],[20.784611,101.237091],[20.78401,101.236816],[20.783689,101.236809],[20.78311,101.236382],[20.782841,101.235779],[20.78194,101.234947],[20.78125,101.234741],[20.780479,101.234016],[20.780319,101.233017],[20.7799,101.232117],[20.77844,101.230377],[20.778259,101.229301],[20.778521,101.22863],[20.778641,101.228104],[20.77836,101.227226],[20.77755,101.225906],[20.77619,101.222702],[20.775499,101.221542],[20.775351,101.220627],[20.775431,101.219948],[20.775299,101.21936],[20.774981,101.219063],[20.774429,101.218277],[20.77429,101.217552],[20.774059,101.21685],[20.77401,101.21595],[20.7736,101.214958],[20.77289,101.214157],[20.772711,101.213707],[20.77206,101.213028],[20.77157,101.212852],[20.77067,101.212082],[20.769079,101.211403],[20.76856,101.210831],[20.7684,101.210358],[20.76782,101.209717],[20.766581,101.208923],[20.766041,101.208389],[20.76475,101.206596],[20.7642,101.20533],[20.763359,101.204628],[20.76206,101.204338],[20.76133,101.203827],[20.760889,101.203232],[20.76026,101.202133],[20.75979,101.201714],[20.75909,101.201591],[20.758789,101.201103],[20.758659,101.200577],[20.758289,101.199913],[20.756969,101.198578],[20.75625,101.197777],[20.75568,101.197388],[20.754919,101.196739],[20.754379,101.196007],[20.753799,101.194603],[20.753019,101.193871],[20.752131,101.193619],[20.75107,101.192886],[20.75004,101.191017],[20.749201,101.190369],[20.74798,101.190247],[20.747049,101.189789],[20.746679,101.189377],[20.74592,101.18782],[20.744631,101.186089],[20.744249,101.185173],[20.743811,101.18457],[20.742531,101.18351],[20.74172,101.181969],[20.740219,101.179893],[20.739519,101.178558],[20.73938,101.178192],[20.73859,101.177406],[20.73609,101.17572],[20.735571,101.175194],[20.735161,101.174278],[20.734949,101.173271],[20.73436,101.171417],[20.73366,101.16983],[20.733391,101.168877],[20.73332,101.167488],[20.73292,101.166161],[20.732599,101.165382],[20.7318,101.164146],[20.730471,101.162468],[20.729731,101.161346],[20.728519,101.158813],[20.727631,101.157448],[20.727249,101.156227],[20.72673,101.155281],[20.72649,101.154922],[20.72521,101.153793],[20.72459,101.152687],[20.724159,101.150543],[20.723579,101.148811],[20.722309,101.14669],[20.721519,101.145203],[20.72089,101.142311],[20.72014,101.139526],[20.719931,101.138321],[20.71986,101.13755],[20.71986,101.135567],[20.71977,101.135147],[20.71953,101.134521],[20.719139,101.133034],[20.719021,101.131973],[20.71859,101.131027],[20.716841,101.128883],[20.715891,101.127151],[20.71361,101.123306],[20.713131,101.122078],[20.71228,101.120903],[20.71139,101.119331],[20.71073,101.116898],[20.71067,101.116501],[20.71023,101.115593],[20.70933,101.11425],[20.70879,101.112427],[20.70808,101.111382],[20.70723,101.10994],[20.70668,101.108551],[20.706181,101.106972],[20.70561,101.10614],[20.70388,101.104538],[20.70244,101.102783],[20.70118,101.09993],[20.70072,101.09906],[20.6994,101.097847],[20.69784,101.095589],[20.69607,101.093971],[20.69558,101.093132],[20.69499,101.0914],[20.69352,101.089119],[20.689859,101.084457],[20.68833,101.082237],[20.68816,101.081863],[20.68788,101.079727],[20.68796,101.077667],[20.688219,101.076057],[20.688129,101.075287],[20.68651,101.071457],[20.686211,101.070671],[20.68609,101.069862],[20.68597,101.068253],[20.685909,101.066559],[20.68614,101.0644],[20.686119,101.062973],[20.686029,101.062637],[20.685539,101.061783],[20.68491,101.061203],[20.68383,101.060493],[20.68259,101.059792],[20.68153,101.059624],[20.68082,101.059608],[20.67993,101.059982],[20.67845,101.061462],[20.67696,101.063042],[20.676001,101.063911],[20.67528,101.064041],[20.67485,101.063957],[20.674549,101.06398],[20.67375,101.06414],[20.672791,101.063828],[20.67153,101.063164],[20.67119,101.063087],[20.670349,101.06321],[20.66991,101.063431],[20.669331,101.063477],[20.66877,101.063271],[20.66786,101.063087],[20.667271,101.062637],[20.66712,101.06237],[20.666519,101.061897],[20.666201,101.061867],[20.664379,101.061996],[20.663731,101.062233],[20.6633,101.0625],[20.66238,101.0625],[20.662001,101.061981],[20.661909,101.061668],[20.661579,101.061172],[20.66132,101.061043],[20.660379,101.060806],[20.659349,101.060799],[20.658239,101.06041],[20.657511,101.060318],[20.656771,101.060303],[20.656139,101.060768],[20.65538,101.064034],[20.654011,101.066132],[20.653879,101.06678],[20.65395,101.067062],[20.653839,101.067787],[20.65346,101.068527],[20.65251,101.069458],[20.65188,101.069992],[20.65143,101.070847],[20.651449,101.073021],[20.65098,101.073807],[20.650551,101.073967],[20.647909,101.074493],[20.647511,101.07473],[20.647209,101.075127],[20.647039,101.076431],[20.64661,101.077271],[20.646231,101.07766],[20.645269,101.078148],[20.64476,101.078644],[20.644279,101.07943],[20.64299,101.080406],[20.64089,101.081017],[20.640221,101.081093],[20.639441,101.081612],[20.638889,101.082474],[20.63821,101.082863],[20.63739,101.082977],[20.63587,101.08374],[20.63508,101.083847],[20.633369,101.083763],[20.63271,101.083946],[20.632099,101.084244],[20.631451,101.084351],[20.629339,101.083977],[20.628559,101.083351],[20.628071,101.082176],[20.62792,101.081711],[20.627359,101.080887],[20.626101,101.079613],[20.62479,101.078598],[20.622829,101.077782],[20.62022,101.076309],[20.61867,101.07502],[20.617029,101.073868],[20.616859,101.073776],[20.615549,101.073547],[20.614929,101.073242],[20.61466,101.072731],[20.61433,101.071564],[20.61392,101.070877],[20.61338,101.069649],[20.612909,101.069092],[20.611031,101.068062],[20.6094,101.067436],[20.608749,101.067139],[20.607571,101.066399],[20.60638,101.065758],[20.605659,101.065567],[20.604589,101.065857],[20.60412,101.066147],[20.6033,101.0662],[20.602989,101.066032],[20.60177,101.064842],[20.601231,101.064377],[20.60047,101.063942],[20.59808,101.063057],[20.597231,101.062599],[20.596189,101.06221],[20.59548,101.061638],[20.59498,101.060852],[20.59428,101.060387],[20.59376,101.060303],[20.593109,101.059952],[20.591631,101.058723],[20.59132,101.058113],[20.590731,101.055931],[20.589729,101.053772],[20.58914,101.051903],[20.588221,101.050682],[20.586269,101.048897],[20.585609,101.048561],[20.584181,101.048302],[20.58263,101.048203],[20.58144,101.047684],[20.579809,101.047829],[20.578791,101.046982],[20.578609,101.046478],[20.578621,101.045578],[20.578329,101.045082],[20.57781,101.04483],[20.576771,101.043968],[20.575359,101.04261],[20.57526,101.042007],[20.57534,101.041771],[20.5756,101.041321],[20.57601,101.040932],[20.57641,101.04068],[20.57692,101.040031],[20.57786,101.038063],[20.57855,101.037613],[20.57943,101.037949],[20.579651,101.0382],[20.580391,101.039436],[20.58083,101.039673],[20.58103,101.039307],[20.58106,101.03894],[20.58148,101.0383],[20.581739,101.038254],[20.582291,101.037956],[20.58223,101.037659],[20.582001,101.03701],[20.582211,101.036247],[20.582529,101.036034],[20.58309,101.035378],[20.583151,101.034973],[20.58288,101.034416],[20.582211,101.03434],[20.581659,101.03476],[20.58082,101.034737],[20.58021,101.033791],[20.58004,101.033241],[20.58007,101.032333],[20.579781,101.031731],[20.577749,101.029953],[20.57756,101.029602],[20.577141,101.029343],[20.57696,101.029427],[20.57642,101.029877],[20.57612,101.02993],[20.575781,101.0299],[20.57556,101.029831],[20.57505,101.028816],[20.574751,101.028816],[20.57456,101.028908],[20.57383,101.028847],[20.572729,101.028511],[20.57069,101.028091],[20.5688,101.027817],[20.56827,101.027237],[20.568291,101.026779],[20.568439,101.026031],[20.56822,101.025513],[20.567841,101.025352],[20.567329,101.02552],[20.566971,101.025757],[20.56641,101.025757],[20.564489,101.024986],[20.564039,101.02459],[20.56389,101.024231],[20.563801,101.02388],[20.563551,101.023453],[20.563129,101.023178],[20.562531,101.023003],[20.562229,101.022728],[20.56225,101.02198],[20.56193,101.021362],[20.561541,101.021072],[20.56139,101.020493],[20.561449,101.020393],[20.56163,101.019592],[20.561159,101.019112],[20.560499,101.018959],[20.55938,101.019341],[20.558701,101.01915],[20.55862,101.019051],[20.55801,101.018784],[20.5574,101.01857],[20.55698,101.01754],[20.556499,101.01696],[20.55608,101.016747],[20.555599,101.016113],[20.55518,101.014618],[20.554899,101.013847],[20.55479,101.012917],[20.555,101.012421],[20.555349,101.011757],[20.555389,101.011497],[20.55579,101.011002],[20.55604,101.01088],[20.55661,101.01004],[20.556971,101.008743],[20.557289,101.008118],[20.557541,101.007347],[20.55731,101.006798],[20.55694,101.006767],[20.556709,101.006798],[20.55617,101.006683],[20.555639,101.006241],[20.55555,101.005898],[20.555599,101.005508],[20.555901,101.004578],[20.555861,101.00415],[20.555599,101.003983],[20.55525,101.003532],[20.555149,101.003014],[20.55477,101.002808],[20.554411,101.002403],[20.554399,101.002052],[20.55467,101.000832],[20.55497,101.000343],[20.555241,101.000122],[20.5555,100.999748],[20.555519,100.99926],[20.555429,100.996834],[20.554729,100.995697],[20.55479,100.995163],[20.55497,100.994797],[20.55489,100.994133],[20.55426,100.993599],[20.55397,100.993568],[20.55353,100.993156],[20.55308,100.992416],[20.552521,100.992332],[20.55209,100.992523],[20.551741,100.99231],[20.551531,100.991898],[20.55085,100.990868],[20.55032,100.990334],[20.549789,100.990082],[20.549299,100.989761],[20.54896,100.989288],[20.54842,100.988937],[20.547911,100.989052],[20.547541,100.989052],[20.54726,100.988808],[20.547199,100.988564],[20.547291,100.988129],[20.54792,100.987732],[20.548281,100.987221],[20.54855,100.986969],[20.54892,100.98597],[20.549141,100.985703],[20.54917,100.985458],[20.549219,100.984077],[20.548691,100.982964],[20.54842,100.981506],[20.548479,100.980377],[20.5481,100.978722],[20.54752,100.978149],[20.54685,100.977989],[20.54624,100.97744],[20.5457,100.976273],[20.5452,100.975906],[20.544399,100.975807],[20.54377,100.975662],[20.542471,100.975243],[20.54208,100.974892],[20.54159,100.974548],[20.539921,100.973717],[20.53916,100.973557],[20.538691,100.973351],[20.538179,100.973351],[20.5369,100.974091],[20.536739,100.974319],[20.536341,100.974571],[20.535971,100.974487],[20.535299,100.974068],[20.53492,100.973717],[20.534109,100.973328],[20.53293,100.973343],[20.531759,100.97274],[20.53125,100.972107],[20.53051,100.970657],[20.53039,100.969528],[20.5303,100.969162],[20.53018,100.968811],[20.5298,100.968231],[20.52944,100.967308],[20.529369,100.966843],[20.528959,100.966469],[20.528351,100.966072],[20.528219,100.965103],[20.527941,100.963737],[20.527439,100.963303],[20.526911,100.962936],[20.526951,100.962593],[20.526859,100.962067],[20.526461,100.961693],[20.526291,100.961227],[20.526251,100.960648],[20.525999,100.960114],[20.525721,100.959808],[20.525379,100.959648],[20.52515,100.95961],[20.52487,100.959358],[20.524879,100.959],[20.52479,100.958633],[20.524349,100.957977],[20.52438,100.957527],[20.52458,100.956757],[20.524401,100.956306],[20.523899,100.955887],[20.52313,100.955688],[20.521749,100.955513],[20.52129,100.955353],[20.520531,100.955307],[20.519991,100.955101],[20.51984,100.954948],[20.51955,100.954887],[20.51899,100.954674],[20.51889,100.954483],[20.518459,100.954193],[20.517891,100.954369],[20.51753,100.954918],[20.517229,100.955589],[20.516911,100.955673],[20.516781,100.955406],[20.51675,100.955177],[20.516399,100.95488],[20.516001,100.955002],[20.51556,100.954964],[20.515129,100.955009],[20.51465,100.954941],[20.514441,100.954613],[20.514151,100.954613],[20.513359,100.954933],[20.512911,100.955147],[20.512659,100.955383],[20.512381,100.955353],[20.512211,100.955177],[20.511669,100.954857],[20.510799,100.954773],[20.51033,100.95462],[20.509859,100.95462],[20.509159,100.954979],[20.508619,100.95491],[20.508591,100.954819],[20.50824,100.954483],[20.507959,100.954536],[20.50754,100.954376],[20.50742,100.953873],[20.5072,100.953484],[20.506941,100.953117],[20.506491,100.952904],[20.50629,100.95295],[20.50569,100.952927],[20.505541,100.952667],[20.505461,100.95208],[20.505541,100.951523],[20.50552,100.951027],[20.50514,100.95005],[20.504801,100.949707],[20.5047,100.949722],[20.504009,100.949532],[20.50391,100.949249],[20.50391,100.948463],[20.504061,100.94799],[20.50411,100.947418],[20.50355,100.946037],[20.503401,100.945763],[20.503059,100.945679],[20.502661,100.945686],[20.50226,100.945457],[20.501881,100.945129],[20.50157,100.945236],[20.501011,100.945084],[20.500731,100.944633],[20.500641,100.944183],[20.49922,100.941566],[20.499359,100.940933],[20.499519,100.94046],[20.499371,100.940048],[20.499241,100.93988],[20.498859,100.93972],[20.498159,100.939621],[20.4972,100.939293],[20.496759,100.939034],[20.495871,100.938087],[20.49571,100.937851],[20.49563,100.937263],[20.495661,100.93663],[20.495871,100.936119],[20.49629,100.935638],[20.496309,100.935127],[20.496031,100.934868],[20.49571,100.934036],[20.49589,100.933388],[20.495741,100.932892],[20.49498,100.932777],[20.49445,100.932426],[20.49431,100.931923],[20.494341,100.931267],[20.49431,100.931099],[20.494011,100.930893],[20.49321,100.930763],[20.492571,100.930313],[20.49185,100.928413],[20.491751,100.927803],[20.49176,100.927254],[20.49139,100.92659],[20.49098,100.926178],[20.490841,100.925911],[20.490829,100.925552],[20.491171,100.924057],[20.49114,100.923424],[20.49077,100.92276],[20.489731,100.921677],[20.48945,100.921021],[20.489349,100.920464],[20.489,100.919884],[20.4884,100.919647],[20.48777,100.919579],[20.487341,100.919411],[20.487,100.918861],[20.486811,100.918312],[20.485781,100.918266],[20.48568,100.918182],[20.485201,100.917587],[20.48465,100.916412],[20.484159,100.91584],[20.482771,100.914902],[20.4821,100.914253],[20.48135,100.912987],[20.480671,100.912178],[20.480471,100.911392],[20.480471,100.91098],[20.480089,100.910461],[20.479731,100.910301],[20.479071,100.90979],[20.47794,100.909103],[20.477369,100.908531],[20.476601,100.906883],[20.47571,100.90554],[20.474541,100.904732],[20.473881,100.904083],[20.472811,100.903282],[20.47242,100.903183],[20.472,100.903503],[20.471279,100.904449],[20.470301,100.904877],[20.469681,100.904831],[20.46957,100.904793],[20.46909,100.904823],[20.46899,100.9049],[20.468519,100.905083],[20.468321,100.904953],[20.467649,100.904373],[20.46719,100.904243],[20.466841,100.904373],[20.46665,100.904541],[20.4662,100.90477],[20.466,100.904678],[20.46546,100.903999],[20.465309,100.903397],[20.465151,100.902946],[20.464861,100.902763],[20.464399,100.902634],[20.464001,100.902367],[20.463751,100.901993],[20.463631,100.901466],[20.46343,100.901207],[20.463039,100.901466],[20.46282,100.90168],[20.462469,100.901588],[20.46212,100.900787],[20.46162,100.900551],[20.46133,100.900681],[20.46069,100.900719],[20.45845,100.899513],[20.457861,100.899582],[20.45747,100.899841],[20.456659,100.900284],[20.456261,100.900414],[20.455641,100.900398],[20.455151,100.900307],[20.455021,100.900269],[20.454729,100.900047],[20.45451,100.899963],[20.45429,100.899986],[20.45396,100.900497],[20.45385,100.901176],[20.453739,100.90139],[20.453609,100.901497],[20.452829,100.901802],[20.452379,100.902184],[20.452061,100.902313],[20.451651,100.902046],[20.451401,100.902023],[20.451059,100.902046],[20.450279,100.902458],[20.45005,100.902367],[20.449881,100.902206],[20.44982,100.902008],[20.4499,100.901688],[20.45009,100.90136],[20.45014,100.900932],[20.449961,100.900688],[20.449631,100.900429],[20.44912,100.900352],[20.448231,100.900642],[20.447929,100.900574],[20.44776,100.900124],[20.447121,100.899727],[20.446989,100.89901],[20.446911,100.898842],[20.44643,100.898232],[20.44639,100.897873],[20.446119,100.897621],[20.445709,100.897324],[20.44548,100.897087],[20.44516,100.896988],[20.44486,100.896957],[20.44445,100.896759],[20.443979,100.896339],[20.44319,100.89537],[20.44272,100.895103],[20.44248,100.894997],[20.44202,100.894943],[20.441351,100.894531],[20.441059,100.893669],[20.44046,100.892189],[20.43977,100.890793],[20.43943,100.890282],[20.438919,100.889763],[20.43788,100.889023],[20.43775,100.888542],[20.437759,100.888077],[20.43762,100.887833],[20.43714,100.887604],[20.43623,100.887047],[20.43495,100.886482],[20.43429,100.886368],[20.433781,100.886124],[20.433281,100.885551],[20.432489,100.884438],[20.43186,100.883698],[20.431721,100.883377],[20.43148,100.882393],[20.43161,100.881477],[20.431881,100.880569],[20.432011,100.879272],[20.432039,100.878532],[20.4324,100.877853],[20.43273,100.877502],[20.432911,100.877068],[20.43289,100.876793],[20.4321,100.875381],[20.43191,100.874802],[20.43194,100.87458],[20.432581,100.872719],[20.432581,100.872276],[20.43252,100.872063],[20.43162,100.870483],[20.431311,100.870262],[20.430981,100.870163],[20.43005,100.869987],[20.429199,100.869553],[20.428631,100.869164],[20.42746,100.868912],[20.42679,100.868423],[20.425791,100.865967],[20.425171,100.865547],[20.42388,100.865791],[20.42346,100.865646],[20.422541,100.865097],[20.42201,100.865021],[20.42149,100.86512],[20.421021,100.865021],[20.42034,100.864563],[20.41993,100.86441],[20.418819,100.864616],[20.4179,100.864693],[20.417549,100.864601],[20.417191,100.864342],[20.416691,100.863647],[20.41651,100.863052],[20.416361,100.862183],[20.41654,100.86145],[20.417061,100.861153],[20.417681,100.86113],[20.418091,100.860687],[20.41827,100.859192],[20.418051,100.858353],[20.41744,100.857529],[20.41696,100.856644],[20.41647,100.855377],[20.416161,100.854729],[20.41585,100.853371],[20.41531,100.852493],[20.414829,100.851921],[20.41411,100.851807],[20.413851,100.851913],[20.41334,100.851891],[20.41227,100.851173],[20.411011,100.850693],[20.41024,100.850456],[20.409161,100.850647],[20.4083,100.851181],[20.40797,100.851501],[20.407829,100.85173],[20.407471,100.851898],[20.40719,100.851692],[20.406799,100.851608],[20.406441,100.85186],[20.40589,100.851952],[20.405939,100.851692],[20.40617,100.851547],[20.406401,100.851303],[20.406481,100.850723],[20.4063,100.850304],[20.4062,100.849747],[20.406031,100.849426],[20.40575,100.84903],[20.405689,100.848663],[20.405701,100.848289],[20.4056,100.848053],[20.405199,100.847672],[20.404961,100.847282],[20.4039,100.844551],[20.40336,100.84343],[20.40317,100.84256],[20.402519,100.841721],[20.40229,100.841179],[20.402269,100.840698],[20.40242,100.840233],[20.40267,100.839737],[20.402769,100.838913],[20.40255,100.838364],[20.402349,100.838127],[20.401461,100.837593],[20.401011,100.837212],[20.40053,100.836159],[20.400261,100.835037],[20.39954,100.833992],[20.399269,100.83374],[20.398939,100.83287],[20.398991,100.832283],[20.39875,100.83165],[20.398331,100.83136],[20.3974,100.83091],[20.39673,100.83007],[20.396311,100.829826],[20.3958,100.829758],[20.395069,100.82946],[20.39382,100.828629],[20.39279,100.828011],[20.392191,100.827499],[20.391821,100.826736],[20.391741,100.825974],[20.39159,100.8255],[20.391411,100.825127],[20.38825,100.819542],[20.38793,100.819183],[20.387569,100.818626],[20.387489,100.818451],[20.387341,100.817963],[20.38714,100.816818],[20.386801,100.815941],[20.386749,100.815369],[20.38707,100.81385],[20.387199,100.813408],[20.387409,100.813042],[20.387449,100.81279],[20.38743,100.812622],[20.387119,100.812263],[20.386539,100.81205],[20.386061,100.811661],[20.385509,100.811409],[20.38489,100.811539],[20.3846,100.811523],[20.38423,100.811234],[20.383739,100.810417],[20.38348,100.810173],[20.38299,100.809921],[20.382561,100.809387],[20.38196,100.807297],[20.38113,100.805763],[20.380911,100.804916],[20.38061,100.804077],[20.38055,100.803352],[20.38064,100.802711],[20.3804,100.801903],[20.379869,100.801193],[20.3792,100.8004],[20.378929,100.799477],[20.378759,100.798393],[20.37841,100.797707],[20.377251,100.796219],[20.376989,100.795158],[20.376949,100.793961],[20.37689,100.793716],[20.375931,100.79213],[20.37571,100.791107],[20.375681,100.789543],[20.375401,100.788361],[20.374701,100.786774],[20.374371,100.785843],[20.372959,100.782387],[20.372789,100.781883],[20.3727,100.781303],[20.37212,100.780533],[20.37154,100.779892],[20.371189,100.779694],[20.37081,100.779663],[20.37048,100.7798],[20.36981,100.780281],[20.368521,100.780807],[20.368019,100.780952],[20.367649,100.780861],[20.367491,100.780609],[20.367319,100.780083],[20.367041,100.779579],[20.36451,100.776817],[20.364189,100.776627],[20.363819,100.776787],[20.363609,100.777168],[20.3634,100.777367],[20.362921,100.777603],[20.3626,100.777847],[20.36236,100.777977],[20.362089,100.77774],[20.362089,100.777489],[20.362631,100.776283],[20.36305,100.774963],[20.363199,100.7743],[20.36344,100.773872],[20.363831,100.773392],[20.363911,100.77298],[20.363729,100.772507],[20.363569,100.772301],[20.36347,100.771698],[20.363581,100.771027],[20.36319,100.770531],[20.36265,100.769958],[20.36215,100.769112],[20.36161,100.768837],[20.36137,100.768867],[20.36116,100.768822],[20.36088,100.768646],[20.360689,100.768097],[20.360809,100.767242],[20.360649,100.766617],[20.36017,100.765137],[20.36006,100.764549],[20.360109,100.763947],[20.360519,100.763573],[20.36062,100.763557],[20.36084,100.76339],[20.360979,100.762657],[20.361469,100.762306],[20.36165,100.762062],[20.361641,100.761658],[20.361,100.760948],[20.36079,100.760422],[20.36071,100.76001],[20.3608,100.759506],[20.360941,100.759323],[20.361179,100.759109],[20.36128,100.758728],[20.361179,100.758553],[20.36101,100.757988],[20.361059,100.757187],[20.361031,100.756912],[20.36109,100.756393],[20.360991,100.75592],[20.360701,100.755699],[20.360519,100.755363],[20.3605,100.755219],[20.360491,100.754608],[20.3606,100.754219],[20.36092,100.753792],[20.36104,100.752907],[20.360901,100.752434],[20.36084,100.750587],[20.36058,100.749977],[20.360451,100.749313],[20.3603,100.748833],[20.360041,100.748421],[20.359171,100.747307],[20.35895,100.746758],[20.358841,100.745842],[20.358509,100.744392],[20.358709,100.743652],[20.35891,100.743362],[20.35898,100.742538],[20.3589,100.742188],[20.35845,100.741653],[20.357941,100.741547],[20.35754,100.741432],[20.356831,100.740913],[20.356331,100.740807],[20.35593,100.740837],[20.35537,100.740517],[20.355209,100.740196],[20.354429,100.738113],[20.35376,100.736107],[20.353001,100.734627],[20.352421,100.733772],[20.352209,100.733543],[20.351999,100.733192],[20.351879,100.73275],[20.351839,100.732262],[20.351891,100.731537],[20.35169,100.730789],[20.351521,100.730362],[20.35149,100.729736],[20.35153,100.729507],[20.35186,100.729012],[20.353081,100.727547],[20.355471,100.725609],[20.355841,100.724991],[20.35594,100.724503],[20.35598,100.721733],[20.355761,100.721252],[20.354799,100.7202],[20.354271,100.719833],[20.35388,100.719398],[20.35384,100.718674],[20.35331,100.717789],[20.35264,100.717194],[20.35252,100.71669],[20.35284,100.715897],[20.35318,100.715599],[20.353701,100.715561],[20.35397,100.715111],[20.35391,100.714462],[20.354231,100.713768],[20.35479,100.713478],[20.35507,100.71312],[20.355579,100.712921],[20.35626,100.713051],[20.357,100.71286],[20.35745,100.712578],[20.358089,100.711929],[20.35874,100.711441],[20.35887,100.711403],[20.35931,100.711357],[20.35961,100.711456],[20.36083,100.712143],[20.36128,100.71212],[20.36129,100.711639],[20.36125,100.71096],[20.36128,100.710663],[20.361561,100.710159],[20.36167,100.709839],[20.361679,100.709351],[20.36149,100.708809],[20.3615,100.70829],[20.36186,100.707458],[20.361879,100.706818],[20.36179,100.705933],[20.361799,100.704933],[20.361879,100.704659],[20.36215,100.704163],[20.36253,100.703773],[20.36327,100.703308],[20.36344,100.70314],[20.363621,100.702858],[20.363569,100.7024],[20.363199,100.701279],[20.36265,100.700531],[20.362511,100.700272],[20.3627,100.698997],[20.363359,100.69799],[20.363741,100.696861],[20.364189,100.695938],[20.365049,100.694862],[20.36602,100.693771],[20.367121,100.692047],[20.367201,100.691879],[20.36727,100.690613],[20.36672,100.689194],[20.366659,100.688438],[20.366449,100.687683],[20.366079,100.687073],[20.365471,100.686607],[20.36454,100.686203],[20.364031,100.685371],[20.364111,100.684464],[20.36484,100.682533],[20.36484,100.682167],[20.364559,100.680946],[20.364309,100.680222],[20.364389,100.679558],[20.36446,100.679359],[20.364479,100.678917],[20.364429,100.678467],[20.364491,100.678032],[20.364611,100.677727],[20.364639,100.677147],[20.36442,100.676842],[20.36405,100.676666],[20.3631,100.676376],[20.36293,100.676277],[20.362341,100.675774],[20.36183,100.675163],[20.36145,100.674423],[20.361349,100.674026],[20.361389,100.672523],[20.36096,100.670631],[20.36039,100.66877],[20.36035,100.667908],[20.3601,100.667038],[20.359289,100.665192],[20.358999,100.664146],[20.35878,100.663017],[20.35887,100.662514],[20.358971,100.662277],[20.35936,100.661819],[20.359591,100.661163],[20.359501,100.660599],[20.359249,100.659683],[20.35911,100.657623],[20.358919,100.657127],[20.35828,100.656113],[20.358061,100.655678],[20.358009,100.654892],[20.3578,100.65432],[20.356991,100.653603],[20.356319,100.652359],[20.35602,100.651573],[20.355881,100.650909],[20.355579,100.648392],[20.355459,100.647987],[20.355089,100.647163],[20.355061,100.646568],[20.35541,100.646088],[20.3556,100.6455],[20.35557,100.644867],[20.355499,100.644569],[20.35507,100.643646],[20.35486,100.642967],[20.35471,100.642616],[20.354441,100.642212],[20.354469,100.641777],[20.355169,100.641617],[20.35548,100.641289],[20.355471,100.641037],[20.35537,100.640633],[20.35556,100.640099],[20.35564,100.639603],[20.35552,100.639214],[20.35527,100.638763],[20.35511,100.637718],[20.35515,100.637253],[20.355499,100.636238],[20.355551,100.635612],[20.35533,100.634941],[20.355101,100.634422],[20.355089,100.633911],[20.35535,100.633087],[20.355749,100.632797],[20.356001,100.632721],[20.35652,100.632339],[20.35663,100.632118],[20.357059,100.631897],[20.357349,100.632187],[20.35779,100.633057],[20.35833,100.633522],[20.359249,100.633881],[20.35972,100.633789],[20.3606,100.633453],[20.36109,100.63372],[20.36145,100.633698],[20.36198,100.633423],[20.36241,100.6325],[20.36285,100.631653],[20.36348,100.631264],[20.36356,100.630981],[20.36334,100.629883],[20.363649,100.629463],[20.363951,100.629417],[20.364241,100.629646],[20.36475,100.630089],[20.366261,100.630089],[20.36676,100.630257],[20.36722,100.630241],[20.367359,100.630096],[20.367661,100.62915],[20.36801,100.628601],[20.36879,100.628143],[20.369249,100.627342],[20.36919,100.6269],[20.368679,100.626373],[20.36817,100.624977],[20.36775,100.62352],[20.36764,100.622238],[20.36821,100.621208],[20.368561,100.620399],[20.36894,100.617233],[20.36931,100.615646],[20.369789,100.614014],[20.370131,100.613327],[20.37133,100.612297],[20.371679,100.611603],[20.37171,100.611191],[20.371889,100.610779],[20.37208,100.610573],[20.372219,100.610008],[20.371969,100.609047],[20.372511,100.607971],[20.374069,100.606483],[20.374969,100.605927],[20.376051,100.606056],[20.38036,100.602577],[20.38096,100.601677],[20.381519,100.600143],[20.38242,100.598907],[20.382891,100.596527],[20.383659,100.594353],[20.385059,100.59182],[20.38669,100.590233],[20.387131,100.587471],[20.387171,100.586563],[20.38603,100.583878],[20.380939,100.576797],[20.380171,100.575996],[20.36994,100.571991],[20.36841,100.570488],[20.3664,100.568863],[20.36528,100.567017],[20.364679,100.564987],[20.360701,100.554718],[20.358471,100.553917],[20.35429,100.54924],[20.35074,100.543022],[20.349541,100.541199],[20.348101,100.539291],[20.347191,100.538368],[20.342621,100.534698],[20.341419,100.533577],[20.340731,100.532547],[20.338511,100.530228],[20.337061,100.528732],[20.336281,100.528328],[20.33316,100.527657],[20.33197,100.526894],[20.33049,100.525299],[20.329559,100.524841],[20.32822,100.524857],[20.32708,100.524368],[20.32666,100.523468],[20.326349,100.5215],[20.325621,100.518784],[20.324909,100.518204],[20.324181,100.518158],[20.323641,100.518646],[20.321939,100.520767],[20.321239,100.521683],[20.320419,100.522118],[20.319901,100.522209],[20.318251,100.522148],[20.317381,100.522507],[20.316191,100.523354],[20.31547,100.523369],[20.31489,100.522926],[20.314529,100.52272],[20.313761,100.522552],[20.311609,100.520554],[20.310949,100.519928],[20.30965,100.518463],[20.30732,100.516968],[20.306,100.516747],[20.30275,100.517471],[20.300171,100.516441],[20.29899,100.51564],[20.29772,100.514442],[20.29727,100.512657],[20.297359,100.511261],[20.29715,100.510277],[20.296301,100.509506],[20.29497,100.509071],[20.29368,100.509033],[20.29195,100.506844],[20.2903,100.50457],[20.285521,100.502708],[20.283449,100.498299],[20.283251,100.496407],[20.280399,100.493027],[20.27717,100.491127],[20.27722,100.485771],[20.27581,100.479683],[20.274639,100.478523],[20.276501,100.473183],[20.27618,100.469414],[20.274891,100.467171],[20.273279,100.463387],[20.26845,100.46254],[20.26667,100.463539],[20.264891,100.464142],[20.263081,100.463921],[20.261669,100.464081],[20.26067,100.463333],[20.25362,100.451843],[20.251631,100.44397],[20.249929,100.44194],[20.24954,100.441002],[20.24959,100.439781],[20.249439,100.438667],[20.24979,100.437653],[20.250509,100.43676],[20.251249,100.436211],[20.251579,100.435791],[20.2516,100.434952],[20.25148,100.434082],[20.251381,100.433037],[20.25115,100.432297],[20.250879,100.431953],[20.25086,100.43148],[20.251381,100.430908],[20.25153,100.430489],[20.25128,100.430344],[20.25071,100.430359],[20.25016,100.430138],[20.25004,100.429741],[20.24996,100.428307],[20.25029,100.426987],[20.2505,100.426437],[20.25102,100.425758],[20.251671,100.425217],[20.252331,100.42408],[20.25292,100.42347],[20.25317,100.422729],[20.25334,100.422363],[20.254629,100.420921],[20.25526,100.420212],[20.25573,100.419533],[20.256161,100.418854],[20.2575,100.418037],[20.26022,100.416687],[20.26158,100.416077],[20.26276,100.415337],[20.263371,100.415131],[20.264509,100.415283],[20.26535,100.415337],[20.26556,100.415237],[20.26605,100.414757],[20.26685,100.414177],[20.267191,100.414017],[20.26763,100.413971],[20.26852,100.413879],[20.269581,100.413933],[20.270361,100.413727],[20.27227,100.413208],[20.27359,100.412773],[20.274349,100.412514],[20.27471,100.412376],[20.27606,100.411873],[20.276831,100.411552],[20.276409,100.410561],[20.276279,100.410294],[20.27615,100.409988],[20.27606,100.409683],[20.27594,100.409302],[20.275141,100.406822],[20.27511,100.40654],[20.275169,100.406197],[20.275311,100.406013],[20.275841,100.405251],[20.27589,100.404793],[20.275749,100.404839],[20.27441,100.405243],[20.27425,100.403351],[20.27413,100.402611],[20.27413,100.401932],[20.27434,100.401443],[20.274639,100.401062],[20.274851,100.400742],[20.274929,100.400337],[20.27487,100.399857],[20.27471,100.399567],[20.27459,100.399223],[20.274679,100.398827],[20.27494,100.398552],[20.27527,100.398163],[20.275551,100.397858],[20.275881,100.397522],[20.276079,100.397163],[20.276199,100.396843],[20.27632,100.396652],[20.27663,100.396622],[20.276911,100.396667],[20.27717,100.396584],[20.277411,100.396347],[20.27774,100.396149],[20.278099,100.39595],[20.27853,100.395973],[20.27895,100.396049],[20.279409,100.396217],[20.279831,100.396118],[20.280199,100.395813],[20.28047,100.3955],[20.280781,100.395203],[20.281601,100.394882],[20.282761,100.394447],[20.28368,100.394043],[20.28441,100.393593],[20.28524,100.393028],[20.28595,100.392647],[20.28698,100.391853],[20.28813,100.390877],[20.288759,100.390312],[20.289141,100.390083],[20.289619,100.389954],[20.289841,100.389992],[20.290581,100.390106],[20.291149,100.390129],[20.291599,100.390091],[20.29217,100.389877],[20.292589,100.389542],[20.292999,100.389359],[20.293369,100.389374],[20.293961,100.389542],[20.29447,100.389641],[20.294821,100.38961],[20.295271,100.38929],[20.295679,100.388977],[20.296261,100.388687],[20.296801,100.388641],[20.29731,100.388573],[20.29837,100.388542],[20.30019,100.388527],[20.30183,100.388512],[20.302429,100.388474],[20.30319,100.38829],[20.303801,100.388153],[20.3043,100.388008],[20.304621,100.387787],[20.304831,100.387444],[20.30509,100.386993],[20.30526,100.386574],[20.305479,100.386139],[20.30575,100.385818],[20.30608,100.385567],[20.306459,100.385223],[20.30687,100.38485],[20.307541,100.384323],[20.308189,100.383972],[20.30883,100.383537],[20.309139,100.383232],[20.309401,100.382782],[20.309681,100.382477],[20.31003,100.382294],[20.31057,100.382057],[20.31098,100.381866],[20.31156,100.381599],[20.31197,100.381378],[20.3123,100.381279],[20.312639,100.381027],[20.312889,100.380707],[20.313,100.380417],[20.313311,100.380112],[20.313641,100.379959],[20.31443,100.380043],[20.314791,100.380081],[20.315161,100.380127],[20.315491,100.379982],[20.31592,100.379784],[20.31637,100.379608],[20.31674,100.379433],[20.317169,100.379242],[20.3176,100.379158],[20.318119,100.379059],[20.31848,100.378937],[20.31889,100.37886],[20.319321,100.37886],[20.319889,100.37899],[20.3204,100.379143],[20.3209,100.379341],[20.321369,100.379547],[20.3218,100.379631],[20.322241,100.379623],[20.322611,100.379562],[20.32299,100.379532],[20.323339,100.379608],[20.323641,100.379692],[20.32411,100.379707],[20.32449,100.379662],[20.324921,100.379608],[20.32535,100.379517],[20.325729,100.379341],[20.326059,100.379143],[20.326441,100.379028],[20.32682,100.378967],[20.327221,100.37899],[20.32765,100.37886],[20.328011,100.378616],[20.32826,100.378326],[20.32863,100.377823],[20.328859,100.377487],[20.329109,100.377243],[20.32934,100.37706],[20.32963,100.376953],[20.329941,100.37664],[20.330299,100.376266],[20.330561,100.376167],[20.330811,100.376137],[20.331169,100.37616],[20.33145,100.376137],[20.331779,100.37606],[20.33213,100.375977],[20.332411,100.375961],[20.33263,100.376106],[20.332979,100.376221],[20.33329,100.376259],[20.33354,100.376228],[20.3339,100.37606],[20.3342,100.375877],[20.334539,100.375771],[20.334829,100.375763],[20.335251,100.37574],[20.335541,100.375763],[20.336029,100.375687],[20.33626,100.375671],[20.33643,100.375603],[20.3367,100.375473],[20.33703,100.37532],[20.337179,100.375252],[20.33742,100.375221],[20.337721,100.375191],[20.33802,100.375168],[20.338261,100.375038],[20.3384,100.37484],[20.33847,100.374542],[20.338579,100.374367],[20.33876,100.374283],[20.33905,100.374123],[20.339331,100.37397],[20.33963,100.373917],[20.33988,100.373917],[20.340219,100.37394],[20.34067,100.374039],[20.34096,100.374138],[20.34128,100.374191],[20.341631,100.374268],[20.34194,100.374222],[20.342171,100.374153],[20.34252,100.373993],[20.342779,100.373787],[20.342979,100.373619],[20.343149,100.37355],[20.343321,100.373573],[20.343439,100.373718],[20.343571,100.373993],[20.343639,100.374237],[20.343809,100.374451],[20.343969,100.374527],[20.3442,100.374588],[20.34449,100.374496],[20.34466,100.374367],[20.34499,100.374252],[20.345261,100.374168],[20.34564,100.373993],[20.3459,100.373756],[20.346201,100.373489],[20.346491,100.373222],[20.346901,100.372871],[20.34734,100.372421],[20.347401,100.372139],[20.347389,100.371803],[20.34742,100.371429],[20.34758,100.371147],[20.347691,100.370857],[20.347719,100.370499],[20.34775,100.370102],[20.34761,100.369751],[20.34746,100.369431],[20.347361,100.369164],[20.347429,100.368942],[20.34758,100.368767],[20.347799,100.368683],[20.348209,100.368736],[20.34856,100.368912],[20.34897,100.36911],[20.34931,100.369164],[20.349791,100.369118],[20.349871,100.368912],[20.34984,100.368584],[20.349751,100.368134],[20.34972,100.367828],[20.349819,100.367561],[20.35001,100.367409],[20.35022,100.367233],[20.3503,100.367058],[20.35021,100.366707],[20.34993,100.366386],[20.349001,100.365578],[20.34866,100.365158],[20.34852,100.364922],[20.34848,100.364563],[20.348579,100.364326],[20.34877,100.36412],[20.34897,100.363853],[20.348961,100.363533],[20.348801,100.363327],[20.348669,100.362938],[20.34873,100.362701],[20.348989,100.362427],[20.349251,100.362289],[20.34955,100.362137],[20.349911,100.362083],[20.35025,100.362068],[20.350719,100.361977],[20.351009,100.361893],[20.35121,100.361671],[20.35161,100.361397],[20.35191,100.361214],[20.35211,100.360901],[20.352079,100.360527],[20.35183,100.360138],[20.35158,100.359779],[20.35137,100.359253],[20.351299,100.358719],[20.351219,100.358002],[20.351151,100.357384],[20.35108,100.356857],[20.35088,100.356483],[20.3505,100.35611],[20.350109,100.355629],[20.349871,100.355217],[20.349701,100.354683],[20.349489,100.353912],[20.3491,100.352753],[20.348801,100.351936],[20.347561,100.350304],[20.346901,100.349297],[20.34656,100.348129],[20.34656,100.346901],[20.34639,100.345123],[20.34589,100.342987],[20.34516,100.339973],[20.344601,100.337914],[20.34466,100.335854],[20.344879,100.334167],[20.345329,100.333328],[20.34606,100.332893],[20.346901,100.333107],[20.34745,100.332718],[20.34734,100.3321],[20.34667,100.3321],[20.34568,100.33152],[20.34479,100.33123],[20.344589,100.330742],[20.34436,100.330368],[20.3437,100.330139],[20.34333,100.329803],[20.343019,100.32917],[20.342899,100.328369],[20.342899,100.32785],[20.343189,100.327393],[20.34322,100.326973],[20.34284,100.326714],[20.341669,100.326073],[20.341101,100.325531],[20.34067,100.325218],[20.339979,100.325218],[20.33952,100.325363],[20.338831,100.325241],[20.337999,100.324783],[20.33737,100.324211],[20.336769,100.323593],[20.335369,100.321274],[20.33522,100.320747],[20.334881,100.320259],[20.334339,100.319633],[20.334311,100.319199],[20.334391,100.318741],[20.33345,100.317093],[20.33288,100.317253],[20.332331,100.317337],[20.332081,100.317047],[20.33202,100.316566],[20.331619,100.316277],[20.32967,100.315422],[20.328091,100.314957],[20.32715,100.314362],[20.32658,100.313927],[20.326229,100.313393],[20.32612,100.312607],[20.32629,100.311546],[20.326151,100.310982],[20.325741,100.310516],[20.325371,100.310013],[20.325371,100.30941],[20.325689,100.307892],[20.32563,100.307426],[20.32514,100.306969],[20.324711,100.306427],[20.324051,100.305222],[20.323879,100.304573],[20.32357,100.303909],[20.32328,100.302879],[20.32291,100.301643],[20.322769,100.299751],[20.322571,100.298439],[20.32239,100.298073],[20.32202,100.297722],[20.32185,100.297348],[20.32165,100.296204],[20.321079,100.29483],[20.32073,100.293877],[20.32056,100.293022],[20.320789,100.290817],[20.320669,100.290329],[20.32053,100.289558],[20.31967,100.287437],[20.319361,100.287117],[20.31864,100.287163],[20.31818,100.28672],[20.31793,100.286179],[20.317381,100.284973],[20.31695,100.284317],[20.31624,100.283859],[20.31472,100.282997],[20.31423,100.2826],[20.313431,100.281357],[20.311621,100.277206],[20.31111,100.275887],[20.31082,100.275146],[20.30908,100.273827],[20.308451,100.273232],[20.307671,100.27137],[20.306641,100.269279],[20.306499,100.268623],[20.306499,100.265617],[20.306391,100.264183],[20.306129,100.263184],[20.305241,100.259972],[20.304871,100.258171],[20.304581,100.256622],[20.304291,100.253304],[20.30401,100.252586],[20.30341,100.252007],[20.302691,100.251839],[20.30192,100.251839],[20.301399,100.251747],[20.301121,100.251442],[20.300911,100.250214],[20.301001,100.247398],[20.30077,100.24614],[20.30043,100.245506],[20.29974,100.243019],[20.29954,100.240044],[20.29954,100.239563],[20.2992,100.239067],[20.29874,100.23864],[20.29825,100.238319],[20.29814,100.238037],[20.298161,100.234253],[20.29882,100.231483],[20.29908,100.229813],[20.299391,100.228607],[20.29949,100.227859],[20.299549,100.227211],[20.299721,100.226501],[20.299419,100.226082],[20.29817,100.224533],[20.29698,100.223846],[20.29533,100.22316],[20.29389,100.222473],[20.29315,100.222061],[20.292789,100.22155],[20.29199,100.221207],[20.29141,100.220932],[20.29093,100.220421],[20.29035,100.220078],[20.289249,100.219971],[20.288321,100.219727],[20.28706,100.219116],[20.28581,100.218048],[20.28484,100.217056],[20.283461,100.215637],[20.28233,100.214523],[20.280979,100.213013],[20.280149,100.211906],[20.27915,100.210457],[20.27844,100.209396],[20.278021,100.208717],[20.27783,100.207817],[20.27783,100.206902],[20.277571,100.205872],[20.27689,100.204773],[20.27615,100.203918],[20.27496,100.202103],[20.27429,100.200829],[20.27364,100.199516],[20.27281,100.19873],[20.271811,100.197639],[20.27062,100.196159],[20.27001,100.195267],[20.26927,100.194267],[20.26849,100.193413],[20.266081,100.191048],[20.265209,100.190262],[20.264339,100.189812],[20.26322,100.188988],[20.262699,100.188507],[20.26235,100.187859],[20.26174,100.186447],[20.260771,100.184647],[20.26021,100.182938],[20.26037,100.181908],[20.260679,100.180908],[20.2579,100.180527],[20.25491,100.17997],[20.253241,100.179314],[20.25135,100.179642],[20.249689,100.178421],[20.24847,100.17775],[20.247311,100.177437],[20.24621,100.177254],[20.2451,100.176331],[20.2435,100.174347],[20.242241,100.171883],[20.24194,100.171043],[20.24098,100.169128],[20.240601,100.167412],[20.24003,100.166458],[20.23889,100.165314],[20.238159,100.16391],[20.2374,100.161568],[20.237129,100.160439],[20.23694,100.157692],[20.23774,100.155632],[20.240351,100.150452],[20.24041,100.149551],[20.24004,100.149002],[20.238899,100.148613],[20.230089,100.145058],[20.227119,100.143799],[20.2234,100.144203],[20.22238,100.144028],[20.22163,100.14357],[20.22163,100.142311],[20.221689,100.136833],[20.22123,100.135452],[20.220779,100.134201],[20.2202,100.133003],[20.22032,100.132187],[20.220551,100.131569],[20.220949,100.130943],[20.22146,100.130539],[20.22238,100.130081],[20.2234,100.130028],[20.22426,100.130081],[20.225401,100.12957],[20.226839,100.128822],[20.228889,100.127907],[20.231239,100.126938],[20.232719,100.126312],[20.234501,100.125633],[20.235689,100.125282],[20.236549,100.125282],[20.23838,100.125557],[20.238951,100.125633],[20.239269,100.125359],[20.24003,100.124641],[20.24082,100.124222],[20.24209,100.123596],[20.24258,100.123177],[20.24321,100.122581],[20.24362,100.121933],[20.244169,100.120911],[20.244329,100.11969],[20.244141,100.114143],[20.244221,100.112823],[20.24461,100.111748],[20.24552,100.107658],[20.245569,100.105873],[20.246019,100.10495],[20.247499,100.102898],[20.248671,100.102791],[20.24914,100.102608],[20.25177,100.100777],[20.25688,100.097267],[20.258829,100.095711],[20.260731,100.093811],[20.259911,100.086281],[20.26025,100.084396],[20.261,100.082962],[20.262091,100.08181],[20.26926,100.076973],[20.26903,100.076843],[20.26845,100.076431],[20.26779,100.075684],[20.267691,100.075569],[20.2675,100.075333],[20.26725,100.074577],[20.267429,100.073776],[20.267599,100.073517],[20.267969,100.073036],[20.26873,100.072037],[20.268869,100.071808],[20.26894,100.071388],[20.268921,100.071098],[20.268801,100.069023],[20.26877,100.068626],[20.268709,100.067993],[20.26874,100.06781],[20.268801,100.067451],[20.269529,100.065788],[20.269621,100.065353],[20.26969,100.058792],[20.269739,100.057213],[20.269831,100.05687],[20.269979,100.056557],[20.27109,100.05513],[20.27137,100.054642],[20.27169,100.053932],[20.271879,100.053352],[20.2719,100.053291],[20.27212,100.051521],[20.27227,100.050903],[20.272511,100.050468],[20.272829,100.050049],[20.27322,100.049713],[20.27532,100.048187],[20.27696,100.046913],[20.278509,100.045799],[20.27902,100.04528],[20.279329,100.045052],[20.28196,100.043381],[20.28227,100.042969],[20.28232,100.042664],[20.28199,100.039772],[20.28216,100.037811],[20.28245,100.036713],[20.28249,100.03656],[20.283291,100.033943],[20.283461,100.032356],[20.28355,100.031937],[20.284889,100.027328],[20.28492,100.027069],[20.284889,100.026711],[20.284451,100.025642],[20.283649,100.02253],[20.282631,100.019608],[20.282459,100.019379],[20.2822,100.019218],[20.281549,100.018822],[20.281281,100.018517],[20.28104,100.017998],[20.28096,100.01783],[20.28046,100.016228],[20.280319,100.015823],[20.27994,100.014809],[20.27947,100.013863],[20.27894,100.012939],[20.278629,100.01239],[20.278191,100.011948],[20.277611,100.011673],[20.276871,100.011414],[20.276529,100.011253],[20.27626,100.010933],[20.2761,100.010567],[20.276011,100.009956],[20.276039,100.008537],[20.276131,100.008118],[20.276381,100.007423],[20.27643,100.007057],[20.27619,100.006447],[20.27611,100.005913],[20.276131,100.005661],[20.276541,100.004341],[20.27739,100.002243],[20.277519,100.001602],[20.27751,100.00135],[20.27717,100.000137],[20.27632,99.99839],[20.27622,99.997864],[20.27598,99.995117],[20.27578,99.994469],[20.2752,99.993393],[20.27483,99.992889],[20.274389,99.992393],[20.273899,99.991982],[20.2733,99.991608],[20.272711,99.991333],[20.27207,99.991112],[20.271151,99.990799],[20.26943,99.990196],[20.267929,99.989693],[20.26746,99.989517],[20.265051,99.98867],[20.260799,99.986908],[20.26021,99.986603],[20.25956,99.986122],[20.258579,99.98526],[20.25312,99.980637],[20.250441,99.978249],[20.249901,99.977707],[20.24902,99.976723],[20.24851,99.976128],[20.24799,99.975517],[20.243361,99.969711],[20.24229,99.968307],[20.23768,99.961952],[20.237089,99.961243],[20.23678,99.960907],[20.236469,99.960709],[20.23546,99.960403],[20.235189,99.960258],[20.235001,99.960167],[20.23457,99.959831],[20.23427,99.959534],[20.231171,99.955971],[20.23019,99.954781],[20.229759,99.954353],[20.22612,99.950317],[20.225361,99.949493],[20.223261,99.947304],[20.22253,99.946472],[20.22105,99.944946],[20.2173,99.940514],[20.21426,99.936852],[20.213909,99.936417],[20.210979,99.933022],[20.20336,99.924316],[20.20289,99.923752],[20.20256,99.923363],[20.20229,99.922813],[20.20085,99.919243],[20.200251,99.917732],[20.199671,99.916267],[20.199181,99.915077],[20.19784,99.911629],[20.19697,99.90963],[20.19672,99.908997],[20.196461,99.908287],[20.19632,99.907944],[20.19614,99.907539],[20.195181,99.905983],[20.19488,99.905342],[20.19462,99.904213],[20.19449,99.903137],[20.194229,99.901459],[20.19413,99.900963],[20.193979,99.90033],[20.19376,99.899719],[20.19334,99.898857],[20.192921,99.898331],[20.192261,99.897476],[20.1915,99.896606],[20.190639,99.895409],[20.187269,99.891022],[20.18634,99.889763],[20.185221,99.888191],[20.18457,99.887154],[20.18409,99.886269],[20.18368,99.885536],[20.18329,99.884857],[20.182751,99.883904],[20.18235,99.883186],[20.181841,99.882294],[20.181511,99.881844],[20.18092,99.881378],[20.18082,99.881287],[20.180349,99.880959],[20.179501,99.880363],[20.17819,99.879387],[20.176781,99.878387],[20.174061,99.87645],[20.17366,99.876106],[20.17345,99.875771],[20.1723,99.87352],[20.17215,99.873253],[20.17174,99.872673],[20.17095,99.872009],[20.169439,99.871193],[20.169069,99.87088],[20.16851,99.870308],[20.1668,99.869034],[20.16614,99.868408],[20.164459,99.866531],[20.163719,99.866043],[20.162889,99.865593],[20.160891,99.86451],[20.160801,99.864464],[20.16007,99.864059],[20.15867,99.863297],[20.157801,99.862694],[20.156269,99.861603],[20.156019,99.861389],[20.15589,99.861023],[20.15583,99.860527],[20.15589,99.860184],[20.155491,99.860199],[20.1551,99.860184],[20.1548,99.860092],[20.154181,99.859833],[20.154079,99.859734],[20.153299,99.8591],[20.152769,99.858704],[20.15164,99.858276],[20.147631,99.857521],[20.14694,99.857384],[20.14674,99.857361],[20.145821,99.857262],[20.14502,99.85717],[20.144711,99.85714],[20.143869,99.85704],[20.143379,99.856987],[20.142599,99.856903],[20.139759,99.856598],[20.13909,99.856613],[20.13855,99.856728],[20.137991,99.856918],[20.137341,99.85746],[20.13419,99.860947],[20.13195,99.862442],[20.13092,99.863426],[20.130289,99.863953],[20.12956,99.864464],[20.12685,99.867111],[20.12649,99.867317],[20.126051,99.867447],[20.12459,99.867813],[20.122669,99.868134],[20.12114,99.868584],[20.119909,99.869034],[20.119301,99.869392],[20.118059,99.87043],[20.11643,99.872063],[20.11577,99.87249],[20.11545,99.872627],[20.114981,99.872757],[20.09539,99.874527],[20.09425,99.874573],[20.090561,99.874893],[20.08865,99.874657],[20.08559,99.874527],[20.08499,99.87455],[20.080891,99.874908],[20.079241,99.875107],[20.07443,99.875717],[20.07328,99.875687],[20.06992,99.875542],[20.064859,99.875557],[20.06189,99.875443],[20.05637,99.875359],[20.05394,99.875443],[20.05282,99.875542],[20.049891,99.875992],[20.046709,99.876244],[20.0462,99.876266],[20.04603,99.876282],[20.045691,99.876312],[20.04425,99.876404],[20.04303,99.876297],[20.041679,99.876137],[20.04003,99.875839],[20.03854,99.875542],[20.03141,99.874046],[20.028919,99.873497],[20.026489,99.872787],[20.02272,99.87146],[20.01881,99.870377],[20.014919,99.86937],[20.01181,99.868759],[20.00489,99.867264],[20.004431,99.867188],[20.001101,99.866623],[19.99958,99.866287],[19.998461,99.865959],[19.994511,99.864754],[19.993469,99.864433],[19.991541,99.86377],[19.987789,99.862572],[19.983509,99.861198],[19.977421,99.859497],[19.9772,99.859444],[19.973289,99.858208],[19.969009,99.856873],[19.968769,99.856796],[19.967291,99.856339],[19.962219,99.854317],[19.96102,99.853737],[19.95957,99.853073],[19.956461,99.851562],[19.950371,99.848991],[19.95006,99.848846],[19.94776,99.848],[19.94174,99.8461],[19.941191,99.845947],[19.940399,99.845627],[19.939939,99.845512],[19.939461,99.845451],[19.93458,99.844978],[19.93329,99.844856],[19.9328,99.844833],[19.932329,99.844788],[19.93128,99.844658],[19.930479,99.844559],[19.92926,99.844452],[19.928101,99.844383],[19.927031,99.844254],[19.926519,99.844254],[19.9261,99.844322],[19.925659,99.844429],[19.924841,99.844704],[19.92466,99.844772],[19.92452,99.844833],[19.92285,99.84539],[19.91926,99.84671],[19.919029,99.846786],[19.9188,99.846863],[19.91856,99.846893],[19.918301,99.846916],[19.918011,99.846939],[19.9177,99.846916],[19.91733,99.846863],[19.91716,99.846832],[19.91688,99.846786],[19.91614,99.846657],[19.91597,99.846603],[19.915791,99.846542],[19.915649,99.846451],[19.9156,99.846413],[19.915449,99.846298],[19.91519,99.8461],[19.91506,99.845932],[19.914909,99.845734],[19.91482,99.845551],[19.9144,99.844727],[19.914,99.843964],[19.9137,99.843246],[19.913469,99.842857],[19.9133,99.842613],[19.913071,99.842331],[19.912821,99.842087],[19.91238,99.841667],[19.912121,99.841469],[19.911831,99.841248],[19.911221,99.840927],[19.9109,99.840782],[19.910589,99.840668],[19.910259,99.840652],[19.909861,99.840714],[19.90881,99.840759],[19.908581,99.840767],[19.90823,99.840813],[19.907591,99.840927],[19.907049,99.840973],[19.90662,99.840919],[19.906231,99.840958],[19.90579,99.840981],[19.90518,99.840973],[19.904579,99.840897],[19.903761,99.840767],[19.90309,99.840523],[19.9025,99.840378],[19.901751,99.840179],[19.901529,99.840134],[19.89817,99.839073],[19.896799,99.838638],[19.895309,99.838242],[19.89484,99.838097],[19.89209,99.837196],[19.89089,99.836861],[19.88945,99.836433],[19.879311,99.833359],[19.878031,99.832413],[19.87665,99.831192],[19.872709,99.827423],[19.862711,99.821381],[19.84935,99.809143],[19.836611,99.787727],[19.82707,99.775383],[19.824829,99.766403],[19.82202,99.763603],[19.80855,99.75489],[19.800699,99.753487],[19.78414,99.743393],[19.76815,99.736092],[19.7572,99.733566],[19.746201,99.726852],[19.74276,99.724037],[19.73921,99.722839],[19.72596,99.716492],[19.72014,99.716148],[19.716591,99.71666],[19.71174,99.720444],[19.708179,99.720268],[19.70447,99.719063],[19.688629,99.723358],[19.68475,99.727127],[19.679899,99.727821],[19.67149,99.731598],[19.6681,99.734169],[19.664539,99.734337],[19.65662,99.735718],[19.653709,99.736923],[19.64983,99.737259],[19.644501,99.738632],[19.637711,99.743103],[19.620081,99.743271],[19.61006,99.747726],[19.600519,99.749619],[19.595181,99.748589],[19.591459,99.746529],[19.582239,99.744987],[19.57626,99.746529],[19.57011,99.751678],[19.56736,99.752197],[19.550541,99.747391],[19.541479,99.742073],[19.51705,99.745667],[19.504271,99.746872],[19.50135,99.746696],[19.49699,99.748589],[19.48016,99.751678],[19.472389,99.753738],[19.469641,99.754082],[19.467211,99.755112],[19.462839,99.75563],[19.45928,99.755798],[19.453939,99.757172],[19.44973,99.758034],[19.44228,99.758202],[19.432249,99.761978],[19.42415,99.766098],[19.410549,99.770393],[19.37849,99.78756],[19.357759,99.799057],[19.339621,99.811943],[19.3218,99.838371],[19.310631,99.845917],[19.30415,99.852272],[19.29945,99.853127],[19.290051,99.855881],[19.275141,99.856392],[19.268181,99.857773],[19.255369,99.857422],[19.24938,99.858627],[19.240629,99.860863],[19.23674,99.862923],[19.229931,99.863426],[19.227011,99.863953],[19.20772,99.871498],[19.2001,99.872528],[19.19735,99.874763],[19.188431,99.889008],[19.178049,99.901016],[19.17128,99.906563],[19.16725,99.909927],[19.161579,99.914177],[19.158171,99.914436],[19.152809,99.912689],[19.141399,99.910896],[19.12985,99.910072],[19.115681,99.90567],[19.106331,99.908417],[19.095181,99.912193],[19.09145,99.913727],[19.082689,99.92231],[19.075069,99.927979],[19.069059,99.92746],[19.05657,99.932098],[19.05316,99.933472],[19.050079,99.935867],[19.04554,99.935532],[19.043261,99.934669],[19.04018,99.931236],[19.038719,99.931068],[19.03775,99.930382],[19.02947,99.927116],[19.02639,99.923523],[19.019899,99.920433],[19.019251,99.919052],[19.01503,99.911163],[19.00983,99.906013],[19.00659,99.902573],[19.005449,99.899307],[19.00334,99.898109],[19.00042,99.899483],[18.99782,99.901367],[18.994419,99.903259],[18.991011,99.904289],[18.988569,99.906174],[18.985979,99.906349],[18.98127,99.907204],[18.977051,99.91098],[18.976231,99.912872],[18.97364,99.914413],[18.9699,99.915283],[18.96796,99.918709],[18.96455,99.920937],[18.95822,99.920593],[18.95627,99.922829],[18.95075,99.923523],[18.93889,99.929008],[18.934999,99.931923],[18.93354,99.932793],[18.929319,99.931763],[18.924931,99.933983],[18.922171,99.935013],[18.91876,99.937424],[18.905769,99.943771],[18.902519,99.944633],[18.89814,99.946342],[18.893259,99.946693],[18.887251,99.944633],[18.88319,99.945312],[18.8741,99.947548],[18.867599,99.948402],[18.858829,99.948921],[18.851681,99.948059],[18.846161,99.947891],[18.834141,99.949432],[18.82406,99.949089],[18.821791,99.949608],[18.807159,99.958527],[18.804079,99.960587],[18.78701,99.964371],[18.78587,99.965233],[18.781969,99.969177],[18.776609,99.970032],[18.76491,99.97364],[18.76214,99.973457],[18.757429,99.970032],[18.753201,99.970032],[18.7428,99.975014],[18.74004,99.975357],[18.73597,99.973984],[18.733049,99.971237],[18.73012,99.971237],[18.72703,99.968491],[18.72541,99.968491],[18.72323,99.967339],[18.72118,99.966263],[18.719721,99.966263],[18.718901,99.964706],[18.71516,99.960938],[18.71386,99.958527],[18.71175,99.957161],[18.7085,99.958023],[18.706869,99.957497],[18.7059,99.956131],[18.70134,99.954758],[18.699551,99.952698],[18.69809,99.948753],[18.696951,99.947548],[18.68996,99.944283],[18.687691,99.944801],[18.68573,99.943604],[18.68037,99.934502],[18.674021,99.928673],[18.6724,99.927803],[18.66736,99.92643],[18.661659,99.924202],[18.65711,99.921967],[18.655649,99.92025],[18.65044,99.920433],[18.64784,99.920593],[18.645069,99.918709],[18.641821,99.91819],[18.635799,99.914589],[18.63434,99.911667],[18.626699,99.909103],[18.62442,99.90892],[18.618561,99.907722],[18.61824,99.906349],[18.614981,99.908234],[18.61091,99.907043],[18.6075,99.9048],[18.6049,99.904289],[18.60343,99.903603],[18.601971,99.902397],[18.598881,99.900681],[18.596109,99.898453],[18.592529,99.898621],[18.589769,99.896744],[18.588461,99.89502],[18.58684,99.89399],[18.58391,99.893471],[18.582609,99.89296],[18.58082,99.89193],[18.57691,99.886597],[18.575769,99.886093],[18.575121,99.886597],[18.57398,99.88575],[18.57333,99.88472],[18.572029,99.883858],[18.571541,99.882141],[18.56975,99.881287],[18.568291,99.879051],[18.5665,99.878883],[18.56373,99.875618],[18.56324,99.872871],[18.56275,99.87133],[18.56292,99.86927],[18.560801,99.866348],[18.55966,99.865997],[18.55966,99.864288],[18.558359,99.861198],[18.55673,99.859657],[18.555269,99.854507],[18.55348,99.853821],[18.5525,99.852448],[18.550871,99.851418],[18.54925,99.849182],[18.547291,99.848328],[18.543711,99.840767],[18.540131,99.839912],[18.53964,99.838707],[18.537849,99.838203],[18.53558,99.835617],[18.530531,99.832191],[18.529881,99.830299],[18.52581,99.828934],[18.51783,99.82412],[18.513769,99.820862],[18.5149,99.81897],[18.499439,99.812279],[18.47893,99.807472],[18.47648,99.806099],[18.47323,99.805237],[18.47225,99.80558],[18.466881,99.804207],[18.466709,99.802673],[18.463301,99.804382],[18.462971,99.803703],[18.459061,99.801292],[18.455641,99.797684],[18.45402,99.797173],[18.45385,99.795113],[18.451571,99.793404],[18.452061,99.790131],[18.45125,99.788589],[18.448311,99.786697],[18.448311,99.783607],[18.44245,99.776047],[18.44066,99.775017],[18.43952,99.772797],[18.43692,99.772453],[18.434799,99.769867],[18.42487,99.754601],[18.42519,99.752022],[18.42161,99.749107],[18.42128,99.747902],[18.4221,99.743103],[18.42112,99.741547],[18.420309,99.739487],[18.41995,99.737396],[18.42004,99.735573],[18.42008,99.733253],[18.41995,99.732552],[18.41889,99.730331],[18.41873,99.729698],[18.418711,99.72905],[18.418791,99.728363],[18.4195,99.727074],[18.419979,99.726349],[18.420231,99.726128],[18.421,99.7258],[18.424561,99.724602],[18.425671,99.724037],[18.426571,99.723328],[18.427401,99.722572],[18.428101,99.721451],[18.42823,99.720734],[18.42827,99.719788],[18.42893,99.718018],[18.429291,99.716713],[18.42931,99.715942],[18.429251,99.714172],[18.42909,99.71257],[18.42915,99.711746],[18.429159,99.710548],[18.42911,99.709961],[18.42881,99.709312],[18.42832,99.708794],[18.42795,99.708214],[18.427919,99.707649],[18.42795,99.706039],[18.42767,99.704086],[18.427589,99.702888],[18.427589,99.70208],[18.426929,99.700233],[18.426741,99.699043],[18.426781,99.698059],[18.42658,99.697319],[18.42609,99.696053],[18.42481,99.694153],[18.424101,99.693573],[18.423691,99.692886],[18.42347,99.69194],[18.423491,99.689323],[18.423241,99.688538],[18.423031,99.68734],[18.42272,99.686203],[18.422131,99.684937],[18.422041,99.684174],[18.42222,99.683647],[18.422501,99.683128],[18.422661,99.682358],[18.42264,99.680542],[18.422541,99.679131],[18.42197,99.675194],[18.42194,99.67244],[18.42174,99.671631],[18.421301,99.670486],[18.420971,99.669319],[18.42094,99.665627],[18.42099,99.663811],[18.42087,99.663017],[18.42053,99.66185],[18.417959,99.653954],[18.4172,99.651909],[18.41601,99.649818],[18.412809,99.644562],[18.406851,99.639587],[18.40027,99.634438],[18.392811,99.624962],[18.385281,99.615044],[18.37586,99.599113],[18.36557,99.581909],[18.355709,99.565353],[18.34586,99.548767],[18.33902,99.541557],[18.31636,99.528687],[18.310011,99.528687],[18.305771,99.527657],[18.285431,99.512939],[18.2847,99.512192],[18.284321,99.511879],[18.28384,99.511429],[18.283501,99.511009],[18.28231,99.50872],[18.282021,99.506973],[18.281969,99.506752],[18.281931,99.506447],[18.28183,99.504372],[18.281799,99.503326],[18.2817,99.501801],[18.28154,99.498703],[18.281389,99.496017],[18.28134,99.495178],[18.281179,99.492928],[18.28109,99.491997],[18.28097,99.491493],[18.280741,99.490639],[18.280491,99.490067],[18.280251,99.489571],[18.276279,99.484016],[18.275089,99.482361],[18.271931,99.477943],[18.26992,99.475143],[18.265791,99.469559],[18.264151,99.467949],[18.263901,99.467728],[18.259399,99.462921],[18.254829,99.457451],[18.25322,99.45546],[18.25285,99.455002],[18.252251,99.454407],[18.251181,99.453377],[18.248911,99.451523],[18.24684,99.449829],[18.246321,99.449249],[18.246229,99.449158],[18.24357,99.446136],[18.240339,99.442268],[18.240231,99.442131],[18.23794,99.439133],[18.237009,99.43779],[18.234949,99.434761],[18.234051,99.433434],[18.233271,99.432281],[18.232941,99.431862],[18.23254,99.431396],[18.231871,99.43087],[18.23115,99.430443],[18.23048,99.430099],[18.223049,99.426353],[18.219999,99.42485],[18.214729,99.422234],[18.2141,99.421783],[18.213449,99.421173],[18.21044,99.417763],[18.20784,99.414848],[18.206091,99.41288],[18.20507,99.411789],[18.2041,99.410851],[18.203369,99.410233],[18.202881,99.409859],[18.202271,99.409431],[18.20149,99.408997],[18.20116,99.408768],[18.20055,99.408447],[18.199909,99.408142],[18.198891,99.40773],[18.19791,99.407379],[18.19705,99.407158],[18.19627,99.40699],[18.195271,99.406807],[18.194441,99.406723],[18.193081,99.406639],[18.19174,99.406708],[18.190941,99.406807],[18.190041,99.406929],[18.18878,99.407204],[18.186609,99.407761],[18.184031,99.408447],[18.182199,99.408928],[18.18095,99.409187],[18.180309,99.409233],[18.17975,99.409233],[18.179211,99.409149],[18.17749,99.408699],[18.17017,99.406662],[18.166981,99.405777],[18.163481,99.404831],[18.15963,99.403793],[18.158501,99.403519],[18.157089,99.403229],[18.15344,99.402649],[18.150881,99.402184],[18.15004,99.402046],[18.149481,99.401962],[18.149,99.401863],[18.148581,99.401703],[18.147989,99.401352],[18.14753,99.400978],[18.14703,99.40033],[18.1467,99.399567],[18.14559,99.395081],[18.1453,99.394173],[18.144859,99.393402],[18.144341,99.3927],[18.14374,99.392097],[18.142941,99.391563],[18.14249,99.391312],[18.14209,99.391144],[18.141621,99.390961],[18.14101,99.390823],[18.14044,99.390778],[18.139891,99.390747],[18.13619,99.390709],[18.13114,99.390762],[18.128851,99.391121],[18.124069,99.392548],[18.10453,99.398163],[18.10178,99.398788],[18.099609,99.398727],[18.096781,99.398109],[18.094761,99.397583],[18.092661,99.397118],[18.091841,99.396919],[18.0884,99.396072],[18.085541,99.395348],[18.083891,99.394974],[18.075769,99.392998],[18.070539,99.391769],[18.066629,99.390846],[18.062481,99.390266],[18.05871,99.389839],[18.05596,99.389267],[18.054411,99.388397],[18.051821,99.386383],[18.050211,99.38546],[18.045561,99.383141],[18.043961,99.381851],[18.04265,99.380638],[18.041,99.379402],[18.036779,99.376457],[18.036421,99.376259],[18.034201,99.375107],[18.033239,99.374786],[18.032431,99.374603],[18.031601,99.374496],[18.030519,99.37442],[18.024441,99.373947],[18.0229,99.373329],[18.02154,99.37207],[18.012831,99.358124],[18.01133,99.357002],[18.009991,99.356583],[17.99893,99.355247],[17.98905,99.357224],[17.982321,99.356018],[17.979931,99.355743],[17.97489,99.356071],[17.973339,99.355614],[17.970539,99.353241],[17.969101,99.352692],[17.96756,99.352707],[17.962151,99.354393],[17.961781,99.354492],[17.96125,99.354637],[17.961029,99.35466],[17.96056,99.35466],[17.95981,99.354637],[17.959379,99.354561],[17.95863,99.354279],[17.95808,99.353981],[17.95723,99.353378],[17.95643,99.352737],[17.95587,99.352371],[17.955059,99.351822],[17.95433,99.351357],[17.95396,99.351189],[17.95359,99.351044],[17.953091,99.350883],[17.95245,99.350838],[17.951981,99.350853],[17.951429,99.350929],[17.95067,99.351082],[17.95013,99.351196],[17.94813,99.351593],[17.946581,99.351837],[17.946051,99.351921],[17.945681,99.351936],[17.945511,99.351929],[17.945129,99.351883],[17.944559,99.351707],[17.94421,99.351593],[17.943859,99.351433],[17.94348,99.351257],[17.94228,99.350517],[17.941111,99.349838],[17.93996,99.349243],[17.93936,99.348953],[17.93882,99.348679],[17.93819,99.348473],[17.9373,99.348289],[17.93652,99.348137],[17.934759,99.347778],[17.93421,99.347687],[17.932699,99.347427],[17.93189,99.347298],[17.92786,99.346573],[17.92705,99.346413],[17.92444,99.34594],[17.92285,99.345657],[17.92038,99.345207],[17.9198,99.345093],[17.91939,99.345001],[17.91836,99.344711],[17.91785,99.344589],[17.917351,99.344429],[17.917009,99.344269],[17.9163,99.343849],[17.915291,99.343246],[17.915051,99.343117],[17.91415,99.342613],[17.913731,99.342377],[17.913441,99.342216],[17.91333,99.342163],[17.913191,99.342133],[17.9125,99.342003],[17.91172,99.341957],[17.91118,99.341927],[17.910681,99.341873],[17.90926,99.341827],[17.908791,99.341797],[17.90661,99.341667],[17.904579,99.341522],[17.9039,99.341476],[17.903549,99.341469],[17.902691,99.341431],[17.902109,99.3414],[17.90139,99.341362],[17.900949,99.341331],[17.899851,99.341217],[17.899229,99.341133],[17.89868,99.341026],[17.898109,99.340927],[17.89765,99.340851],[17.89702,99.340736],[17.89642,99.340637],[17.895901,99.340553],[17.89366,99.340157],[17.89069,99.33963],[17.88946,99.339417],[17.888769,99.33931],[17.88637,99.338882],[17.88438,99.338531],[17.882891,99.33828],[17.881689,99.338081],[17.88026,99.337822],[17.87919,99.337646],[17.87808,99.337471],[17.87718,99.337318],[17.8766,99.337257],[17.87611,99.337181],[17.87467,99.337128],[17.874229,99.337143],[17.87361,99.337143],[17.871771,99.337196],[17.87114,99.337242],[17.870489,99.337273],[17.870131,99.337273],[17.86964,99.337196],[17.869011,99.337082],[17.8687,99.337013],[17.868401,99.336838],[17.86796,99.336563],[17.86767,99.336349],[17.86746,99.336197],[17.86726,99.336014],[17.86688,99.33551],[17.86599,99.334396],[17.865061,99.333237],[17.864401,99.332397],[17.863991,99.331802],[17.86343,99.331001],[17.86311,99.33049],[17.862749,99.32975],[17.86245,99.328903],[17.862289,99.328217],[17.86224,99.327454],[17.862181,99.326714],[17.862129,99.32605],[17.86191,99.322456],[17.861759,99.319107],[17.861549,99.315567],[17.86153,99.315292],[17.861521,99.31517],[17.861481,99.315033],[17.86117,99.313766],[17.8608,99.312477],[17.860331,99.310944],[17.86005,99.310051],[17.859909,99.309601],[17.859859,99.309486],[17.85973,99.309273],[17.85928,99.308662],[17.85885,99.308243],[17.858391,99.307747],[17.85741,99.306763],[17.85648,99.305923],[17.855591,99.305107],[17.85523,99.304764],[17.854839,99.304314],[17.854601,99.304031],[17.85445,99.303741],[17.85433,99.303513],[17.85412,99.303017],[17.85392,99.302223],[17.85384,99.30159],[17.85371,99.300491],[17.8533,99.296638],[17.853251,99.296318],[17.85321,99.296013],[17.853029,99.295303],[17.852871,99.2948],[17.852711,99.29451],[17.85252,99.294228],[17.852261,99.293854],[17.852079,99.293587],[17.85186,99.293404],[17.851761,99.293297],[17.85161,99.293198],[17.851259,99.292953],[17.850969,99.29277],[17.850731,99.292641],[17.85043,99.292542],[17.85,99.292397],[17.8496,99.29232],[17.84923,99.29229],[17.84869,99.29232],[17.84779,99.292458],[17.847481,99.292511],[17.844879,99.293228],[17.843941,99.293472],[17.843321,99.293587],[17.842369,99.293701],[17.841961,99.293739],[17.84166,99.293732],[17.84104,99.293709],[17.840599,99.293633],[17.840219,99.293533],[17.839899,99.293449],[17.83931,99.293243],[17.83873,99.292923],[17.83827,99.29261],[17.83799,99.292389],[17.836639,99.2911],[17.836531,99.291023],[17.836411,99.290932],[17.836281,99.290848],[17.835911,99.290672],[17.8354,99.290413],[17.83526,99.290337],[17.83514,99.290298],[17.834579,99.290268],[17.83226,99.290161],[17.831779,99.290154],[17.831591,99.290154],[17.831499,99.290138],[17.830999,99.289932],[17.83036,99.289597],[17.83024,99.28952],[17.83003,99.289322],[17.82963,99.288872],[17.82939,99.288643],[17.829281,99.28849],[17.82917,99.288239],[17.828871,99.287407],[17.82847,99.286018],[17.82832,99.285347],[17.828159,99.284813],[17.82811,99.284683],[17.82798,99.284462],[17.82766,99.284058],[17.82745,99.283836],[17.82724,99.2836],[17.827101,99.28347],[17.826941,99.283363],[17.826679,99.283234],[17.826389,99.283081],[17.82618,99.282997],[17.82585,99.282921],[17.825569,99.282867],[17.825081,99.282806],[17.824591,99.282799],[17.821569,99.28289],[17.82082,99.282898],[17.820551,99.282898],[17.81995,99.28286],[17.8197,99.282852],[17.819,99.282806],[17.818501,99.282753],[17.81819,99.282692],[17.8179,99.282547],[17.817579,99.282333],[17.817209,99.282066],[17.816971,99.281822],[17.816771,99.281609],[17.816601,99.281326],[17.81636,99.280884],[17.816179,99.280487],[17.816031,99.280083],[17.81386,99.273483],[17.81365,99.272911],[17.81352,99.272583],[17.813181,99.271957],[17.81295,99.271584],[17.8127,99.27124],[17.81225,99.270798],[17.81126,99.269852],[17.810381,99.269119],[17.80974,99.26857],[17.80872,99.267761],[17.80821,99.267357],[17.807859,99.267128],[17.80744,99.266907],[17.806999,99.266693],[17.80674,99.266617],[17.80644,99.266571],[17.80608,99.266533],[17.805759,99.266533],[17.805401,99.266533],[17.80504,99.266617],[17.80337,99.266998],[17.802469,99.267174],[17.802071,99.267227],[17.801889,99.267227],[17.801689,99.267227],[17.80142,99.267174],[17.8009,99.267036],[17.800541,99.266937],[17.80023,99.266861],[17.800051,99.266777],[17.798241,99.266006],[17.79715,99.265556],[17.79257,99.263641],[17.791861,99.263344],[17.78828,99.26181],[17.78756,99.261513],[17.78669,99.261124],[17.7859,99.260757],[17.78512,99.260429],[17.78488,99.260292],[17.784559,99.260033],[17.7843,99.259827],[17.783911,99.259506],[17.783489,99.259117],[17.78289,99.258347],[17.781799,99.257004],[17.78129,99.256287],[17.77948,99.254051],[17.7777,99.251877],[17.77697,99.251038],[17.77673,99.250763],[17.776421,99.250481],[17.77618,99.250313],[17.7756,99.250031],[17.775,99.249786],[17.773529,99.249382],[17.773161,99.249283],[17.770929,99.248657],[17.769039,99.248009],[17.768499,99.247833],[17.768101,99.247627],[17.7679,99.247437],[17.76725,99.246834],[17.76651,99.246017],[17.76532,99.244629],[17.76475,99.243988],[17.764339,99.243607],[17.763969,99.243401],[17.763491,99.243141],[17.76297,99.242897],[17.76252,99.242783],[17.761299,99.24247],[17.76108,99.242416],[17.76034,99.242218],[17.759871,99.242073],[17.759029,99.241737],[17.75853,99.241524],[17.758101,99.241241],[17.757481,99.240791],[17.756941,99.240318],[17.75658,99.239883],[17.754259,99.236938],[17.75318,99.235573],[17.752991,99.235367],[17.75267,99.235062],[17.752399,99.234879],[17.75209,99.234688],[17.751051,99.234238],[17.750351,99.234001],[17.7498,99.233772],[17.748859,99.233276],[17.748581,99.233093],[17.747829,99.232452],[17.746889,99.231583],[17.746691,99.231377],[17.74646,99.231194],[17.74609,99.230972],[17.74564,99.230827],[17.745159,99.230682],[17.744881,99.230637],[17.744419,99.230629],[17.743931,99.23069],[17.74349,99.230782],[17.743191,99.230873],[17.74276,99.231102],[17.74197,99.231628],[17.74017,99.232971],[17.73991,99.233147],[17.739531,99.233292],[17.73864,99.233566],[17.73842,99.233589],[17.73773,99.233589],[17.73707,99.233582],[17.736509,99.233513],[17.73584,99.233383],[17.73542,99.233292],[17.734819,99.233177],[17.73427,99.23304],[17.733521,99.232773],[17.732241,99.232307],[17.730801,99.231644],[17.730061,99.231293],[17.728479,99.230621],[17.727859,99.230362],[17.72703,99.230057],[17.726549,99.229881],[17.726231,99.229767],[17.725981,99.229721],[17.724819,99.229462],[17.72401,99.229309],[17.723749,99.229263],[17.723499,99.229233],[17.72278,99.229134],[17.72213,99.22905],[17.72184,99.229019],[17.72105,99.228928],[17.720671,99.228889],[17.720409,99.228859],[17.720261,99.228859],[17.720039,99.228882],[17.71792,99.229012],[17.71751,99.229027],[17.7131,99.229362],[17.71036,99.229683],[17.709999,99.229729],[17.709591,99.229782],[17.709379,99.229797],[17.70927,99.22982],[17.709061,99.229874],[17.708929,99.229912],[17.70859,99.230003],[17.703871,99.231422],[17.6992,99.232727],[17.69821,99.233017],[17.69763,99.233177],[17.697451,99.233223],[17.69726,99.233238],[17.696751,99.233276],[17.696369,99.233292],[17.69614,99.233307],[17.69598,99.233299],[17.69591,99.233292],[17.69561,99.233223],[17.69491,99.23304],[17.694389,99.23291],[17.694099,99.232841],[17.69388,99.232811],[17.69368,99.232803],[17.693279,99.23275],[17.692961,99.232727],[17.692671,99.232697],[17.69244,99.232697],[17.692301,99.232697],[17.692169,99.232727],[17.691891,99.232803],[17.69169,99.232857],[17.691191,99.233093],[17.691019,99.233177],[17.69067,99.233437],[17.690411,99.233658],[17.690121,99.233994],[17.689871,99.234283],[17.689671,99.234543],[17.689461,99.234879],[17.688641,99.236259],[17.68808,99.23719],[17.68734,99.238152],[17.68705,99.238503],[17.686781,99.238724],[17.6863,99.239014],[17.68573,99.239311],[17.68515,99.239563],[17.68358,99.24015],[17.679119,99.241768],[17.67421,99.243568],[17.670959,99.244667],[17.669821,99.24501],[17.66951,99.245102],[17.669319,99.245163],[17.669201,99.245171],[17.669081,99.245171],[17.66873,99.245163],[17.667709,99.245064],[17.66604,99.244743],[17.66552,99.244629],[17.66523,99.244583],[17.66506,99.24456],[17.664921,99.24456],[17.66469,99.244583],[17.6644,99.244614],[17.664009,99.244637],[17.663759,99.24469],[17.66358,99.244743],[17.663389,99.244812],[17.663219,99.244904],[17.662809,99.245117],[17.66263,99.245247],[17.662331,99.245453],[17.66197,99.245811],[17.660839,99.247223],[17.660061,99.248207],[17.659401,99.2491],[17.65922,99.249313],[17.659121,99.249413],[17.65889,99.249588],[17.658171,99.25016],[17.657921,99.250343],[17.657669,99.250473],[17.65728,99.250641],[17.656561,99.250893],[17.656309,99.250961],[17.655861,99.25103],[17.655359,99.251091],[17.654989,99.251106],[17.65469,99.251106],[17.654181,99.251038],[17.653561,99.25087],[17.653231,99.250763],[17.652941,99.250641],[17.652571,99.250427],[17.652439,99.250351],[17.652189,99.250183],[17.651711,99.249847],[17.65132,99.249489],[17.650909,99.249039],[17.650351,99.248322],[17.649651,99.247177],[17.64868,99.245667],[17.64819,99.244987],[17.647699,99.244331],[17.64736,99.243896],[17.647091,99.243652],[17.646799,99.243439],[17.646021,99.24292],[17.644899,99.242287],[17.643909,99.241737],[17.64311,99.24131],[17.641239,99.240349],[17.640791,99.240097],[17.640671,99.240044],[17.64039,99.239937],[17.640221,99.239883],[17.63924,99.239662],[17.639059,99.239616],[17.63826,99.239517],[17.63669,99.239388],[17.635361,99.23925],[17.63233,99.238876],[17.63176,99.238823],[17.631161,99.238739],[17.630199,99.238609],[17.63006,99.238586],[17.629971,99.238579],[17.62962,99.238541],[17.629141,99.238472],[17.62866,99.238403],[17.628309,99.23835],[17.627979,99.238281],[17.62742,99.238197],[17.62673,99.238037],[17.62583,99.237892],[17.625059,99.237633],[17.622801,99.236839],[17.621441,99.236008],[17.61692,99.232162],[17.61537,99.230904],[17.61335,99.229797],[17.60886,99.227928],[17.602249,99.22522],[17.597521,99.223282],[17.59412,99.222054],[17.587271,99.220108],[17.58593,99.219467],[17.584789,99.218277],[17.5783,99.208618],[17.57519,99.203941],[17.574329,99.203087],[17.573111,99.202309],[17.57239,99.202087],[17.57156,99.201981],[17.57074,99.202003],[17.564529,99.203102],[17.56094,99.203789],[17.559891,99.203529],[17.559389,99.203369],[17.55278,99.200447],[17.545259,99.197067],[17.537621,99.193703],[17.52972,99.190163],[17.522421,99.186867],[17.517151,99.184593],[17.511311,99.183838],[17.50985,99.183296],[17.508881,99.182648],[17.503361,99.178322],[17.499451,99.175423],[17.499241,99.175041],[17.48904,99.167084],[17.47415,99.162407],[17.469481,99.161247],[17.423571,99.157494],[17.41935,99.157249],[17.41753,99.156578],[17.411221,99.151299],[17.40942,99.150032],[17.40662,99.149208],[17.39879,99.149406],[17.39036,99.148537],[17.38191,99.147797],[17.377081,99.149017],[17.37434,99.149094],[17.36429,99.146599],[17.3626,99.146698],[17.354561,99.148918],[17.35183,99.149513],[17.34754,99.14946],[17.34433,99.149437],[17.34161,99.149643],[17.33868,99.151382],[17.335911,99.153374],[17.33367,99.154083],[17.33156,99.153992],[17.30291,99.147034],[17.295,99.142593],[17.28458,99.141388],[17.28159,99.140633],[17.25828,99.132843],[17.24894,99.128304],[17.23995,99.123833],[17.238461,99.122993],[17.237061,99.122704],[17.207069,99.123238],[17.20488,99.123596],[17.20418,99.123947],[17.2031,99.12455],[17.19191,99.130913],[17.179131,99.138077],[17.17695,99.138298],[17.17457,99.137848],[17.16736,99.135223],[17.15797,99.131851],[17.15015,99.129463],[17.147699,99.128029],[17.13851,99.112953],[17.13471,99.106644],[17.132629,99.104424],[17.126169,99.098793],[17.115339,99.091873],[17.113079,99.08847],[17.111059,99.084801],[17.109261,99.080406],[17.10791,99.077362],[17.105841,99.075607],[17.103371,99.074699],[17.089741,99.072487],[17.074369,99.06559],[17.07151,99.06543],[17.069031,99.066544],[17.06661,99.06781],[17.05814,99.072273],[17.047461,99.078308],[17.03545,99.087624],[17.023211,99.097221],[17.00762,99.108757],[16.997351,99.112717],[16.988581,99.117897],[16.980551,99.122093],[16.979561,99.122704],[16.978951,99.12368],[16.976191,99.128593],[16.97452,99.130058],[16.97257,99.130501],[16.968321,99.13092],[16.96356,99.131462],[16.96092,99.13134],[16.920919,99.115631],[16.919189,99.11586],[16.91795,99.11602],[16.91305,99.118767],[16.90901,99.121246],[16.9007,99.126984],[16.89715,99.128098],[16.893391,99.129143],[16.89175,99.129051],[16.885201,99.127052],[16.88372,99.126694],[16.881399,99.127083],[16.876499,99.130058],[16.87117,99.133377],[16.863501,99.13826],[16.85927,99.12957],[16.856239,99.123466],[16.855671,99.12233],[16.85342,99.117859],[16.85202,99.115067],[16.85084,99.113182],[16.84898,99.111923],[16.84684,99.111504],[16.84412,99.112358],[16.8416,99.11367],[16.84152,99.113724],[16.837959,99.115807],[16.835329,99.117531],[16.821699,99.130074],[16.801649,99.148598],[16.799669,99.150833],[16.798031,99.15358],[16.795401,99.157867],[16.79244,99.162163],[16.78866,99.166969],[16.76845,99.18911],[16.76483,99.192543],[16.7096,99.240257],[16.68836,99.258202],[16.679461,99.264771],[16.67762,99.266113],[16.677481,99.266212],[16.6754,99.267906],[16.67342,99.269623],[16.67309,99.270317],[16.67288,99.271057],[16.672859,99.271423],[16.67281,99.272797],[16.672779,99.273537],[16.672729,99.27478],[16.672661,99.275673],[16.672489,99.276649],[16.672251,99.277786],[16.67214,99.278313],[16.67173,99.280197],[16.671499,99.281181],[16.6712,99.283028],[16.671181,99.283287],[16.671249,99.285454],[16.671789,99.288597],[16.671829,99.288857],[16.672001,99.289909],[16.67218,99.290947],[16.672421,99.292236],[16.6726,99.293266],[16.67338,99.298218],[16.673161,99.300034],[16.672979,99.300537],[16.672041,99.302116],[16.66967,99.304527],[16.666189,99.308037],[16.665819,99.308411],[16.663031,99.31118],[16.66287,99.311348],[16.66259,99.31163],[16.6623,99.311943],[16.66151,99.312729],[16.6612,99.313026],[16.66095,99.313278],[16.66025,99.314003],[16.659611,99.314667],[16.659439,99.314842],[16.658159,99.316139],[16.65443,99.319923],[16.65276,99.321609],[16.652571,99.3218],[16.649229,99.325203],[16.647921,99.326508],[16.646601,99.32785],[16.64641,99.328041],[16.64311,99.331429],[16.64192,99.332878],[16.64097,99.334152],[16.64082,99.334373],[16.637951,99.338142],[16.63311,99.344543],[16.630091,99.348587],[16.629789,99.348991],[16.629169,99.349792],[16.628531,99.350601],[16.62711,99.352493],[16.62414,99.356438],[16.62381,99.35685],[16.62253,99.358543],[16.62108,99.360443],[16.618429,99.363991],[16.61496,99.368683],[16.61392,99.370857],[16.613609,99.37159],[16.61319,99.372566],[16.613079,99.37281],[16.61297,99.373062],[16.612749,99.373558],[16.611071,99.377563],[16.610439,99.379044],[16.60939,99.381523],[16.60792,99.384987],[16.60771,99.385483],[16.607599,99.385727],[16.607189,99.386703],[16.60689,99.387444],[16.606569,99.388168],[16.606159,99.389153],[16.605419,99.390877],[16.605009,99.391869],[16.603491,99.395462],[16.603121,99.396317],[16.60302,99.396568],[16.602591,99.397552],[16.600929,99.401466],[16.60062,99.402206],[16.600519,99.402458],[16.59807,99.408287],[16.596411,99.412201],[16.596001,99.41317],[16.595791,99.413658],[16.595591,99.414146],[16.594521,99.416603],[16.594311,99.417084],[16.594101,99.41758],[16.594,99.417831],[16.59269,99.420998],[16.591021,99.424927],[16.588301,99.431328],[16.586519,99.435532],[16.58543,99.437042],[16.584,99.438202],[16.58209,99.439056],[16.580641,99.439629],[16.580151,99.439812],[16.578939,99.440331],[16.57461,99.442101],[16.57412,99.442299],[16.57338,99.442596],[16.57313,99.442703],[16.571659,99.443283],[16.57023,99.443893],[16.567341,99.44503],[16.566139,99.445511],[16.563231,99.446663],[16.56251,99.446953],[16.55891,99.448486],[16.55868,99.448608],[16.558229,99.448868],[16.556589,99.45018],[16.554319,99.4524],[16.55036,99.456284],[16.548071,99.458511],[16.54731,99.459251],[16.544491,99.461937],[16.544331,99.462097],[16.543751,99.462677],[16.543159,99.463272],[16.54306,99.463379],[16.542561,99.463837],[16.5424,99.463989],[16.542191,99.464241],[16.542009,99.464417],[16.541679,99.464737],[16.541269,99.465134],[16.540661,99.465729],[16.540331,99.466057],[16.53981,99.466583],[16.539049,99.4673],[16.538851,99.467484],[16.53808,99.468224],[16.53751,99.468781],[16.536751,99.469521],[16.53598,99.470268],[16.53504,99.471191],[16.534849,99.471367],[16.53429,99.471931],[16.53392,99.472313],[16.533001,99.473228],[16.53264,99.473587],[16.530359,99.475601],[16.528509,99.47641],[16.52446,99.477753],[16.52404,99.47789],[16.52319,99.478142],[16.52297,99.47821],[16.522091,99.478523],[16.52186,99.478592],[16.521629,99.478683],[16.521151,99.478859],[16.51795,99.479942],[16.516251,99.480507],[16.51479,99.481003],[16.51083,99.482323],[16.50983,99.482658],[16.509581,99.482742],[16.508089,99.483253],[16.507589,99.483414],[16.507099,99.483589],[16.506849,99.483673],[16.50609,99.483887],[16.504271,99.484047],[16.502211,99.483627],[16.501431,99.483429],[16.50091,99.483299],[16.498619,99.482689],[16.497601,99.482422],[16.497089,99.482277],[16.49658,99.48214],[16.49402,99.481621],[16.492479,99.481903],[16.491171,99.482773],[16.48962,99.484154],[16.48595,99.487839],[16.485571,99.488213],[16.48538,99.488403],[16.483351,99.490791],[16.482929,99.491463],[16.48209,99.49276],[16.48167,99.493408],[16.481529,99.493629],[16.481239,99.494072],[16.481091,99.494301],[16.480101,99.495537],[16.479,99.496292],[16.47747,99.496696],[16.47649,99.496689],[16.476089,99.496658],[16.47576,99.496643],[16.475479,99.496613],[16.47537,99.496597],[16.47506,99.496567],[16.474609,99.496552],[16.472771,99.496483],[16.471889,99.496407],[16.471439,99.496384],[16.470751,99.496323],[16.470169,99.496246],[16.469761,99.496193],[16.468161,99.496147],[16.467911,99.496132],[16.46665,99.496063],[16.465639,99.495987],[16.464371,99.495918],[16.46105,99.495689],[16.460541,99.495644],[16.4568,99.495323],[16.455311,99.495621],[16.453951,99.496407],[16.45089,99.498993],[16.4485,99.500977],[16.447519,99.501823],[16.44635,99.5028],[16.445999,99.503113],[16.44545,99.503563],[16.44314,99.505539],[16.439569,99.508553],[16.438971,99.509071],[16.436991,99.51075],[16.43314,99.513939],[16.428801,99.517578],[16.424419,99.521103],[16.422661,99.521637],[16.421869,99.521713],[16.42108,99.521698],[16.4182,99.521629],[16.415039,99.521561],[16.414009,99.521538],[16.412491,99.5215],[16.411449,99.521492],[16.409679,99.521538],[16.409161,99.521561],[16.40608,99.521568],[16.405041,99.521561],[16.400579,99.521568],[16.40032,99.521568],[16.397169,99.521553],[16.395321,99.521553],[16.393999,99.521561],[16.39348,99.521561],[16.393221,99.521561],[16.391121,99.521568],[16.390341,99.521584],[16.38854,99.521942],[16.3883,99.522041],[16.38677,99.523033],[16.38658,99.523209],[16.385611,99.524483],[16.38533,99.52494],[16.38464,99.5261],[16.384501,99.526337],[16.38258,99.529541],[16.382441,99.529778],[16.382299,99.529999],[16.38088,99.53231],[16.380739,99.532539],[16.380051,99.53373],[16.37991,99.533958],[16.37948,99.53466],[16.377069,99.538559],[16.374229,99.543198],[16.37394,99.543663],[16.37365,99.544144],[16.370649,99.549042],[16.370359,99.549507],[16.36949,99.550911],[16.366779,99.555702],[16.365179,99.558617],[16.364639,99.559593],[16.36409,99.560547],[16.363819,99.561043],[16.363279,99.562012],[16.36249,99.563469],[16.360201,99.567574],[16.357809,99.572144],[16.354179,99.579102],[16.3515,99.584412],[16.35004,99.587318],[16.34803,99.591476],[16.345989,99.595329],[16.343031,99.599533],[16.341009,99.602783],[16.340269,99.605164],[16.338449,99.611328],[16.33709,99.614616],[16.33412,99.621323],[16.33148,99.627182],[16.331369,99.627449],[16.331261,99.627708],[16.330481,99.629509],[16.330259,99.630028],[16.327971,99.635368],[16.325199,99.641823],[16.32476,99.642838],[16.32181,99.649696],[16.319851,99.654007],[16.318529,99.655403],[16.31654,99.656693],[16.314871,99.657768],[16.312389,99.659416],[16.306021,99.663673],[16.305111,99.664284],[16.304211,99.664886],[16.303789,99.665169],[16.3034,99.665428],[16.30304,99.665657],[16.30287,99.665779],[16.30233,99.666168],[16.301941,99.666451],[16.3013,99.666878],[16.299049,99.668381],[16.29727,99.669563],[16.29705,99.669693],[16.2957,99.670593],[16.291679,99.673317],[16.28627,99.676964],[16.281839,99.679993],[16.279289,99.681396],[16.27492,99.682663],[16.27183,99.68354],[16.27051,99.683891],[16.269991,99.684036],[16.26354,99.685898],[16.26153,99.686478],[16.261141,99.6866],[16.260651,99.68676],[16.26017,99.686951],[16.25979,99.687103],[16.25938,99.687233],[16.258711,99.687469],[16.257021,99.688049],[16.252399,99.689629],[16.24692,99.691513],[16.2456,99.691933],[16.239849,99.693893],[16.238029,99.694511],[16.23308,99.696198],[16.23126,99.696831],[16.225599,99.698792],[16.218821,99.701103],[16.212601,99.703194],[16.20962,99.704193],[16.20705,99.70507],[16.206079,99.705429],[16.20174,99.706932],[16.19735,99.708397],[16.191231,99.710533],[16.188431,99.711472],[16.18173,99.713753],[16.18017,99.714302],[16.173941,99.716423],[16.16938,99.717972],[16.168091,99.718399],[16.16556,99.719292],[16.16477,99.719543],[16.16378,99.719856],[16.161659,99.720573],[16.16049,99.720901],[16.15974,99.721077],[16.159121,99.721191],[16.158421,99.721283],[16.157591,99.721336],[16.156981,99.721367],[16.15621,99.721359],[16.15048,99.721077],[16.14863,99.721024],[16.14603,99.720886],[16.13858,99.720573],[16.131781,99.720222],[16.12528,99.719902],[16.12373,99.719841],[16.122801,99.719818],[16.1194,99.719658],[16.118521,99.719597],[16.113729,99.719383],[16.11319,99.719353],[16.1068,99.719032],[16.105841,99.718987],[16.105129,99.719032],[16.10462,99.719116],[16.104019,99.719231],[16.10347,99.71936],[16.10277,99.719597],[16.10154,99.720123],[16.100809,99.720444],[16.099581,99.72094],[16.09844,99.72142],[16.09675,99.722153],[16.094219,99.723213],[16.09005,99.724953],[16.08955,99.725159],[16.084841,99.727127],[16.083389,99.72776],[16.077311,99.730301],[16.073151,99.732063],[16.07266,99.732262],[16.069929,99.733414],[16.06741,99.734489],[16.066401,99.73497],[16.065611,99.735367],[16.064939,99.735817],[16.06447,99.736214],[16.063801,99.73674],[16.06336,99.737137],[16.06078,99.739899],[16.056009,99.745132],[16.05513,99.746132],[16.05422,99.747093],[16.051439,99.750137],[16.050329,99.75135],[16.04903,99.752762],[16.04497,99.757187],[16.04143,99.761009],[16.041059,99.761414],[16.039579,99.763023],[16.037701,99.765007],[16.03714,99.76561],[16.036949,99.765823],[16.033899,99.769058],[16.03371,99.769257],[16.032,99.771072],[16.030279,99.772903],[16.03009,99.773102],[16.02557,99.777908],[16.02293,99.780693],[16.022169,99.781502],[16.02067,99.783081],[16.017441,99.786484],[16.016199,99.787788],[16.01602,99.787971],[16.01585,99.788147],[16.01568,99.788322],[16.015511,99.788498],[16.012739,99.791367],[16.011209,99.792999],[16.009171,99.795059],[16.00786,99.796494],[16.00614,99.798203],[16.0058,99.798553],[16.00466,99.799652],[16.003059,99.801308],[16.002541,99.801842],[16.00178,99.802597],[16.00106,99.803329],[15.99995,99.804489],[15.99944,99.805008],[15.99893,99.805519],[15.99852,99.805931],[15.99809,99.806351],[15.99742,99.807022],[15.99617,99.80825],[15.9937,99.810783],[15.98944,99.815048],[15.98454,99.819893],[15.97968,99.824661],[15.97439,99.829727],[15.97032,99.833603],[15.96583,99.83783],[15.96129,99.842163],[15.95713,99.846077],[15.95294,99.849953],[15.94795,99.854523],[15.9424,99.859627],[15.93697,99.864578],[15.93211,99.868973],[15.92862,99.872124],[15.9278,99.872879],[15.9247,99.875671],[15.92328,99.876953],[15.91854,99.880997],[15.91306,99.885612],[15.9105,99.887657],[15.90986,99.888168],[15.9086,99.889183],[15.90651,99.890747],[15.90628,99.890923],[15.90516,99.891769],[15.90126,99.894272],[15.89934,99.895317],[15.89693,99.896713],[15.8955,99.897507],[15.89383,99.898468],[15.89143,99.899841],[15.89,99.900673],[15.88886,99.90136],[15.88588,99.903069],[15.88534,99.903381],[15.88477,99.903732],[15.88452,99.903877],[15.8836,99.904411],[15.88287,99.904839],[15.8822,99.90519],[15.88194,99.905327],[15.88062,99.906067],[15.87939,99.906723],[15.87742,99.907837],[15.87723,99.907944],[15.87684,99.908173],[15.87643,99.908409],[15.87577,99.908791],[15.87485,99.909317],[15.87437,99.909599],[15.87366,99.910019],[15.86913,99.912613],[15.86472,99.915161],[15.86172,99.916901],[15.85842,99.918762],[15.8563,99.919983],[15.85584,99.920273],[15.85352,99.921623],[15.84915,99.924141],[15.848,99.924797],[15.84266,99.927872],[15.8408,99.92894],[15.83893,99.929993],[15.83869,99.930107],[15.83772,99.930634],[15.83604,99.931587],[15.83532,99.932007],[15.83225,99.933769],[15.83179,99.934036],[15.83115,99.934402],[15.83021,99.934952],[15.82925,99.935547],[15.82839,99.93605],[15.82702,99.936836],[15.82609,99.93734],[15.82586,99.937469],[15.82543,99.937714],[15.82486,99.938042],[15.82453,99.938217],[15.82423,99.938393],[15.82276,99.939194],[15.82242,99.939377],[15.82224,99.939491],[15.82184,99.939728],[15.81962,99.941002],[15.81839,99.941757],[15.81794,99.942009],[15.81565,99.943443],[15.81245,99.946007],[15.80879,99.949387],[15.80795,99.95015],[15.80672,99.951286],[15.80631,99.95166],[15.8061,99.951851],[15.80549,99.952423],[15.80023,99.957314],[15.79641,99.960907],[15.79151,99.965446],[15.79109,99.96582],[15.79089,99.966019],[15.79047,99.966408],[15.78922,99.967567],[15.78465,99.971817],[15.78341,99.972961],[15.77872,99.977364],[15.77314,99.98259],[15.77137,99.984322],[15.77118,99.984497],[15.771,99.98468],[15.7703,99.985336],[15.76963,99.985992],[15.76806,99.98748],[15.76747,99.988037],[15.76677,99.988701],[15.76587,99.989563],[15.76536,99.990021],[15.76506,99.990311],[15.76447,99.990868],[15.76404,99.99128],[15.76343,99.991859],[15.76275,99.9925],[15.76078,99.99437],[15.75662,99.99836],[15.75542,99.999496],[15.75523,99.99968],[15.75283,100.001961],[15.75206,100.002693],[15.75028,100.004356],[15.7501,100.004539],[15.74955,100.005058],[15.74901,100.005569],[15.74865,100.005913],[15.74847,100.006073],[15.74829,100.006241],[15.74811,100.006409],[15.74671,100.007736],[15.74604,100.008377],[15.74588,100.008537],[15.74571,100.00869],[15.74555,100.00885],[15.74347,100.010841],[15.74286,100.011513],[15.74271,100.011703],[15.74197,100.012627],[15.74139,100.013474],[15.74012,100.015778],[15.73951,100.017059],[15.73938,100.017326],[15.73767,100.020683],[15.73662,100.022697],[15.73636,100.023193],[15.73404,100.027718],[15.7334,100.028908],[15.73182,100.031929],[15.73156,100.03244],[15.73129,100.032944],[15.73064,100.034187],[15.72901,100.037308],[15.72816,100.038933],[15.72779,100.039627],[15.72742,100.040352],[15.72717,100.040833],[15.72655,100.042023],[15.7244,100.04612],[15.72409,100.046707],[15.72305,100.048714],[15.72204,100.050598],[15.72073,100.053078],[15.72005,100.054352],[15.71917,100.056023],[15.71907,100.05619],[15.71891,100.056511],[15.71863,100.057007],[15.71828,100.057648],[15.71801,100.058121],[15.71785,100.058388],[15.71766,100.058548],[15.71751,100.058578],[15.71732,100.058617],[15.71702,100.058617],[15.71687,100.058578],[15.71626,100.058357],[15.71531,100.058052],[15.71488,100.057907],[15.71418,100.057663],[15.71319,100.057289],[15.70982,100.056313],[15.70848,100.056099],[15.70526,100.055977],[15.70499,100.055977],[15.70418,100.055969],[15.69769,100.055939],[15.69256,100.055923],[15.68718,100.05587],[15.68639,100.055878],[15.68184,100.055962],[15.67809,100.056519],[15.67601,100.057114],[15.67575,100.05719],[15.67549,100.057281],[15.67423,100.05777],[15.67133,100.059227],[15.67039,100.059776],[15.66859,100.06102],[15.66796,100.061508],[15.66775,100.061684],[15.66653,100.062759],[15.66613,100.063141],[15.66593,100.063339],[15.66535,100.063927],[15.66513,100.064194],[15.66399,100.065514],[15.66335,100.066238],[15.6628,100.066879],[15.66244,100.067307],[15.65813,100.072357],[15.65441,100.076736],[15.65335,100.07798],[15.64987,100.082092],[15.64952,100.082497],[15.64579,100.086853],[15.64386,100.089127],[15.64161,100.091782],[15.63819,100.095734],[15.63676,100.097382],[15.63577,100.098457],[15.63527,100.099083],[15.63476,100.099693],[15.63253,100.10228],[15.63229,100.102562],[15.6313,100.103737],[15.63024,100.105003],[15.62668,100.109123],[15.6219,100.114677],[15.62155,100.115082],[15.62043,100.116333],[15.61751,100.119652],[15.61555,100.121933],[15.61525,100.122299],[15.61512,100.122459],[15.61465,100.122726],[15.61421,100.12278],[15.61356,100.12236],[15.61316,100.121872],[15.61283,100.121582],[15.6123,100.121407],[15.61209,100.121422],[15.61115,100.121536],[15.6109,100.121559],[15.61037,100.121597],[15.60577,100.122017],[15.60203,100.122414],[15.60097,100.122528],[15.59964,100.122673],[15.59883,100.122726],[15.59727,100.122887],[15.594,100.123238],[15.59322,100.123322],[15.59139,100.123497],[15.59112,100.123528],[15.58641,100.124046],[15.58456,100.12426],[15.58217,100.124512],[15.57952,100.124786],[15.57741,100.125023],[15.57477,100.125313],[15.57104,100.12571],[15.5673,100.126099],[15.56677,100.126152],[15.56257,100.126587],[15.55892,100.126907],[15.55866,100.126938],[15.55732,100.127083],[15.55625,100.12719],[15.55572,100.127258],[15.55546,100.127289],[15.55467,100.127388],[15.54787,100.128113],[15.54605,100.128242],[15.54499,100.128197],[15.54446,100.128113],[15.54343,100.127853],[15.5396,100.126534],[15.53935,100.126427],[15.53479,100.124977],[15.53266,100.124817],[15.53055,100.125191],[15.52954,100.125526],[15.52501,100.127136],[15.52288,100.127296],[15.52028,100.126984],[15.51816,100.126678],[15.51471,100.126213],[15.5098,100.125504],[15.50955,100.125473],[15.50904,100.125397],[15.50748,100.125252],[15.50665,100.125229],[15.50425,100.125526],[15.50321,100.125801],[15.50295,100.125893],[15.50144,100.126472],[15.49994,100.127098],[15.49968,100.127197],[15.4979,100.127907],[15.49206,100.130219],[15.49181,100.130333],[15.48732,100.132233],[15.48482,100.133888],[15.48358,100.134918],[15.48048,100.137543],[15.47986,100.138069],[15.47966,100.138237],[15.47863,100.139107],[15.4778,100.139793],[15.47758,100.139954],[15.4769,100.140404],[15.47667,100.140549],[15.4762,100.140823],[15.47547,100.141182],[15.47293,100.142067],[15.47161,100.142403],[15.46452,100.144142],[15.46318,100.144463],[15.46139,100.144882],[15.46078,100.145027],[15.45703,100.145958],[15.45379,100.14653],[15.45133,100.146538],[15.44864,100.146118],[15.44813,100.145958],[15.44761,100.145798],[15.44397,100.144928],[15.44036,100.144043],[15.43984,100.143913],[15.43825,100.143509],[15.43669,100.143097],[15.43405,100.142403],[15.43217,100.142311],[15.43031,100.142761],[15.42954,100.143051],[15.42879,100.143341],[15.42844,100.143471],[15.42729,100.143898],[15.42502,100.144737],[15.41997,100.146683],[15.41895,100.147003],[15.41788,100.147179],[15.41599,100.147247],[15.41572,100.147247],[15.41438,100.147217],[15.41276,100.147232],[15.41113,100.147217],[15.40869,100.147186],[15.40271,100.147087],[15.40135,100.147087],[15.40056,100.147079],[15.39872,100.147141],[15.39752,100.147209],[15.39729,100.147232],[15.39668,100.147301],[15.39601,100.147377],[15.39561,100.147438],[15.39551,100.147453],[15.3949,100.14756],[15.39478,100.147583],[15.39407,100.14772],[15.39362,100.147827],[15.393,100.148003],[15.39124,100.148438],[15.39037,100.148712],[15.39014,100.148788],[15.38919,100.149109],[15.38869,100.149261],[15.38818,100.149422],[15.38664,100.14994],[15.38307,100.151154],[15.38178,100.151604],[15.38048,100.152039],[15.38021,100.15213],[15.37995,100.152222],[15.37785,100.152931],[15.37759,100.153023],[15.37479,100.153976],[15.3707,100.155373],[15.36592,100.157043],[15.36289,100.158073],[15.35931,100.159286],[15.35477,100.16095],[15.35355,100.161484],[15.34929,100.163544],[15.34725,100.164627],[15.34634,100.165154],[15.34216,100.16748],[15.341,100.168121],[15.33988,100.168739],[15.3395,100.168953],[15.33886,100.169312],[15.33798,100.1698],[15.33737,100.170143],[15.33693,100.170387],[15.33648,100.170631],[15.33251,100.172836],[15.33088,100.173737],[15.32901,100.174782],[15.32783,100.17543],[15.32526,100.176849],[15.32505,100.176971],[15.32421,100.177437],[15.32274,100.178253],[15.32159,100.178886],[15.32127,100.17907],[15.31896,100.180351],[15.31723,100.18132],[15.3147,100.182716],[15.31442,100.182877],[15.31256,100.183907],[15.31003,100.185318],[15.30866,100.186073],[15.30612,100.187477],[15.30554,100.187843],[15.30511,100.18808],[15.30416,100.188568],[15.30307,100.189117],[15.30274,100.189278],[15.30025,100.190407],[15.2999,100.190559],[15.29957,100.190697],[15.2993,100.190811],[15.29896,100.190964],[15.29851,100.191147],[15.29838,100.1912],[15.29825,100.191261],[15.29813,100.191307],[15.29798,100.191368],[15.29782,100.191437],[15.2976,100.191521],[15.29703,100.191742],[15.29618,100.192047],[15.29541,100.192329],[15.29437,100.19268],[15.29415,100.192757],[15.29393,100.192833],[15.29348,100.192978],[15.29326,100.193047],[15.28926,100.194153],[15.28852,100.194344],[15.28729,100.194672],[15.28608,100.195],[15.28584,100.195061],[15.28535,100.19519],[15.28036,100.196571],[15.27729,100.197403],[15.27612,100.197723],[15.2747,100.198097],[15.27351,100.198418],[15.27231,100.198738],[15.26826,100.199837],[15.26282,100.201271],[15.26071,100.201843],[15.26047,100.20192],[15.25882,100.202377],[15.2581,100.202583],[15.25691,100.202904],[15.25644,100.203018],[15.25549,100.203247],[15.25526,100.2033],[15.2548,100.203407],[15.25265,100.203819],[15.24998,100.204338],[15.24949,100.20443],[15.24851,100.204643],[15.24778,100.204781],[15.24681,100.204987],[15.24633,100.205078],[15.24512,100.205307],[15.24278,100.20578],[15.24127,100.206078],[15.24049,100.20623],[15.23587,100.207352],[15.23538,100.207481],[15.23346,100.208],[15.23133,100.208572],[15.22951,100.209053],[15.22351,100.210709],[15.2228,100.210907],[15.22038,100.211639],[15.22014,100.211723],[15.21967,100.211884],[15.21848,100.212288],[15.21754,100.212608],[15.21614,100.21312],[15.21521,100.213493],[15.21316,100.214401],[15.20888,100.216461],[15.20757,100.217171],[15.20649,100.217796],[15.20231,100.220222],[15.19877,100.222237],[15.19429,100.224808],[15.19122,100.226486],[15.18906,100.227707],[15.18715,100.228844],[15.18267,100.231468],[15.18014,100.233093],[15.17931,100.23365],[15.17829,100.23436],[15.17748,100.234932],[15.17647,100.235672],[15.17547,100.236397],[15.17467,100.237],[15.17427,100.237297],[15.17085,100.239853],[15.16943,100.240891],[15.16743,100.242371],[15.16702,100.242668],[15.16662,100.242973],[15.1636,100.245178],[15.16119,100.246941],[15.15867,100.248703],[15.15807,100.249092],[15.1566,100.249992],[15.15618,100.250237],[15.1529,100.251968],[15.15093,100.25296],[15.14985,100.25354],[15.14877,100.254128],[15.14688,100.255127],[15.14652,100.25531],[15.14462,100.256218],[15.14441,100.25631],[15.14381,100.256569],[15.14345,100.256737],[15.14328,100.256813],[15.14258,100.257141],[15.1424,100.257233],[15.13979,100.258553],[15.13638,100.260277],[15.13618,100.260384],[15.13599,100.260468],[15.13366,100.261642],[15.13288,100.262032],[15.13269,100.262131],[15.13211,100.262428],[15.13091,100.263031],[15.13071,100.26313],[15.13028,100.263344],[15.13006,100.263458],[15.12984,100.263573],[15.12871,100.26413],[15.12803,100.26445],[15.12519,100.265984],[15.12263,100.267998],[15.12059,100.270264],[15.12029,100.270668],[15.11829,100.273659],[15.11704,100.275551],[15.11691,100.275757],[15.11476,100.279121],[15.11189,100.283524],[15.1103,100.286003],[15.10981,100.286713],[15.10929,100.287376],[15.107,100.289864],[15.1045,100.291901],[15.10075,100.294456],[15.09984,100.29509],[15.09925,100.295486],[15.09802,100.296333],[15.09573,100.29789],[15.09328,100.299507],[15.08991,100.301826],[15.08797,100.303169],[15.08675,100.304001],[15.08506,100.305168],[15.08359,100.306198],[15.08292,100.306671],[15.08214,100.307297],[15.08133,100.307953],[15.07951,100.30954],[15.07753,100.31144],[15.07606,100.312767],[15.07379,100.315063],[15.07118,100.317436],[15.06834,100.319649],[15.06525,100.32151],[15.05924,100.324608],[15.05301,100.327957],[15.04762,100.330757],[15.04751,100.330833],[15.04493,100.332314],[15.04151,100.334091],[15.0373,100.335579],[15.03228,100.336708],[15.02009,100.339088],[15.01539,100.340363],[15.01103,100.342216],[14.99827,100.348938],[14.98775,100.3545],[14.97862,100.359711],[14.94595,100.385002],[14.93855,100.390968],[14.93602,100.392723],[14.93327,100.394218],[14.9229,100.399612],[14.9125,100.405006],[14.90917,100.406914],[14.90763,100.408119],[14.90623,100.409462],[14.90454,100.411537],[14.90295,100.413712],[14.89979,100.418411],[14.89884,100.419594],[14.89781,100.420708],[14.89672,100.421722],[14.89556,100.422684],[14.88987,100.426567],[14.88409,100.430473],[14.87735,100.435089],[14.87514,100.43644],[14.87249,100.437813],[14.87109,100.438423],[14.86971,100.43895],[14.86837,100.439407],[14.86738,100.439743],[14.84928,100.445084],[14.84726,100.445663],[14.84332,100.446716],[14.83894,100.447487],[14.83473,100.44767],[14.82958,100.44735],[14.82374,100.446953],[14.81974,100.446632],[14.81552,100.447098],[14.81223,100.448128],[14.80827,100.450729],[14.80396,100.454041],[14.7992,100.45681],[14.79534,100.458],[14.79177,100.458366],[14.78836,100.457741],[14.78346,100.455803],[14.77892,100.453453],[14.77537,100.451897],[14.77126,100.450951],[14.76771,100.450951],[14.76466,100.451317],[14.76021,100.452454],[14.75194,100.45343],[14.74029,100.454597],[14.72864,100.454987],[14.71756,100.455673],[14.71203,100.455742],[14.70655,100.455513],[14.70081,100.456139],[14.69838,100.456802],[14.69604,100.457611],[14.69409,100.458519],[14.69224,100.459549],[14.68872,100.461807],[14.68175,100.466316],[14.67903,100.468048],[14.67772,100.468758],[14.67635,100.469383],[14.6747,100.470032],[14.6729,100.470589],[14.67138,100.470947],[14.6698,100.471199],[14.66144,100.472649],[14.65078,100.474442],[14.64606,100.474808],[14.6414,100.474693],[14.63213,100.473251],[14.61383,100.469772],[14.60978,100.468941],[14.60526,100.469658],[14.60155,100.470863],[14.596,100.473961],[14.58557,100.480904],[14.5814,100.483727],[14.57584,100.487503],[14.57241,100.489838],[14.56537,100.493813],[14.55793,100.497063],[14.5467,100.500923],[14.53397,100.504532],[14.52399,100.507629],[14.51725,100.512268],[14.51076,100.517433],[14.50352,100.520782],[14.48903,100.526711],[14.48318,100.529457],[14.47226,100.534416],[14.46707,100.536926],[14.46552,100.537682],[14.46439,100.538063],[14.4626,100.538567],[14.45988,100.539131],[14.45759,100.539543],[14.45528,100.540001],[14.45267,100.540497],[14.45009,100.540977],[14.44627,100.541733],[14.44432,100.542099],[14.4423,100.542282],[14.43974,100.54303],[14.43799,100.543922],[14.43635,100.545029],[14.43472,100.546593],[14.4333,100.548424],[14.42962,100.553459],[14.42807,100.555634],[14.42727,100.556686],[14.42557,100.558952],[14.41425,100.574028],[14.40527,100.584137],[14.40375,100.585831],[14.40259,100.587097],[14.40093,100.588966],[14.39634,100.594048],[14.39526,100.595238],[14.39514,100.595383],[14.39509,100.595413],[14.39261,100.597809],[14.38907,100.600853],[14.38355,100.604683],[14.38173,100.605766],[14.37816,100.607613],[14.37716,100.608047],[14.37459,100.609138],[14.37241,100.609978],[14.36911,100.610939],[14.36623,100.611748],[14.36269,100.612419],[14.35971,100.613007],[14.35777,100.613167],[14.35565,100.613297],[14.35309,100.613327],[14.34958,100.613258],[14.34487,100.613213],[14.332,100.613342],[14.32856,100.613327],[14.31873,100.613327],[14.30838,100.613342],[14.3044,100.613373],[14.30383,100.613373],[14.30248,100.613388],[14.28388,100.613457],[14.26434,100.613449],[14.26224,100.613487],[14.25709,100.613564],[14.2519,100.613564],[14.24813,100.613564],[14.24431,100.613411],[14.24005,100.612999],[14.23393,100.612228],[14.23293,100.612091],[14.23122,100.61187],[14.21575,100.609734],[14.21111,100.609123],[14.21052,100.609062],[14.20943,100.608963],[14.20799,100.60891],[14.20694,100.608932],[14.2055,100.608994],[14.2024,100.609047],[14.20071,100.609154],[14.19831,100.609467],[14.19601,100.609779],[14.19276,100.610519],[14.18953,100.61145],[14.18302,100.613777],[14.17835,100.61557],[14.17814,100.615677],[14.17804,100.615761],[14.17794,100.615837],[14.17783,100.615936],[14.17773,100.616058],[14.17759,100.616257],[14.17754,100.616348],[14.17745,100.616524],[14.17739,100.616699],[14.17736,100.616814],[14.17734,100.616943],[14.17734,100.617081],[14.17737,100.617218],[14.17741,100.617348],[14.17747,100.61747],[14.17755,100.617599],[14.17835,100.618568],[14.17858,100.618782],[14.17868,100.618927],[14.17905,100.619164],[14.17952,100.619453],[14.17988,100.619713],[14.18023,100.620003],[14.18057,100.620293],[14.18088,100.620598],[14.18122,100.620956],[14.18154,100.621353],[14.18183,100.621742],[14.1821,100.622139],[14.18238,100.622627],[14.18266,100.623169],[14.18351,100.624786],[14.18394,100.625603],[14.1876,100.6325],[14.18777,100.632629],[14.18804,100.632973],[14.18819,100.633118],[14.18844,100.633324],[14.1886,100.633423],[14.18879,100.633507],[14.18898,100.633583],[14.18944,100.633728],[14.18958,100.633781],[14.18973,100.633858],[14.18985,100.633949],[14.18996,100.634079],[14.19003,100.634178],[14.1901,100.6343],[14.19017,100.634453],[14.19021,100.634598],[14.19024,100.634697],[14.19024,100.634773],[14.19026,100.634903],[14.19025,100.635078],[14.19024,100.635193],[14.19022,100.635292],[14.1902,100.635384],[14.19014,100.635567],[14.19004,100.635803],[14.18993,100.636009],[14.18973,100.636276],[14.18955,100.636513],[14.18934,100.636711],[14.18917,100.636848],[14.18869,100.637123],[14.18505,100.63929],[14.18225,100.640869],[14.16198,100.65229],[14.15898,100.653976],[14.14369,100.662613],[14.14085,100.664207],[14.12254,100.67453],[14.11993,100.676003],[14.1014,100.686447],[14.09778,100.688477],[14.08837,100.693787],[14.08782,100.694069],[14.08718,100.694328],[14.08655,100.694542],[14.08592,100.694717],[14.08521,100.694847],[14.08467,100.694923],[14.0686,100.696533],[14.06346,100.697052],[14.05247,100.698151],[14.05158,100.698227],[14.05068,100.698273],[14.02581,100.698288],[14.02536,100.698311],[14.02491,100.698341],[14.02444,100.698387],[14.02399,100.698463],[14.0235,100.698547],[14.02317,100.698624],[14.02292,100.698692],[14.0224,100.698837],[14.02195,100.698982],[14.02148,100.69915],[14.02108,100.699318],[14.02067,100.699501],[14.01956,100.699989],[14.00956,100.704399],[13.99926,100.708946],[13.99298,100.711723],[13.99042,100.712837],[13.98989,100.713013],[13.98935,100.713173],[13.98881,100.713287],[13.98828,100.713371],[13.98776,100.713417],[13.98726,100.713463],[13.98675,100.713448],[13.9863,100.713417],[13.98523,100.713333],[13.98473,100.713333],[13.9826,100.713287],[13.95215,100.71286],[13.95173,100.712837],[13.95132,100.712822],[13.95075,100.712784],[13.9502,100.712723],[13.94955,100.712624],[13.94912,100.712547],[13.94865,100.712463],[13.94311,100.710999],[13.93615,100.709167],[13.93011,100.707581],[13.92421,100.706032],[13.92266,100.705643],[13.92128,100.705261],[13.92036,100.704964],[13.91983,100.704773],[13.91909,100.704483],[13.9177,100.703888],[13.91276,100.701317],[13.90788,100.698799],[13.90705,100.698357],[13.89609,100.692703],[13.89326,100.691231],[13.88801,100.688507],[13.88746,100.688217],[13.87732,100.682983],[13.87618,100.682381],[13.86972,100.679039],[13.86879,100.678574],[13.86822,100.678307],[13.86793,100.6782],[13.86763,100.678101],[13.86725,100.677994],[13.86686,100.677887],[13.8578,100.675797],[13.8572,100.675636],[13.85666,100.675484],[13.85623,100.675323],[13.85546,100.675003],[13.8538,100.674316],[13.85204,100.673592],[13.85131,100.673302],[13.85097,100.67318],[13.85063,100.67308],[13.85029,100.672997],[13.84993,100.672928],[13.84957,100.672882],[13.84612,100.672638],[13.84541,100.672592],[13.84291,100.672417],[13.84251,100.672401],[13.84197,100.672401],[13.84152,100.672432],[13.84111,100.672478],[13.84064,100.672546],[13.84026,100.672623],[13.83963,100.672783],[13.83788,100.673233],[13.83672,100.673523],[13.83597,100.673721],[13.83529,100.673866],[13.83487,100.673943],[13.83439,100.674011],[13.83402,100.674049],[13.83295,100.674118],[13.83175,100.674179],[13.82532,100.67453],[13.8245,100.674606],[13.82378,100.674713],[13.8232,100.674828],[13.82128,100.675308],[13.81476,100.677017],[13.79887,100.681221],[13.79574,100.682037],[13.78257,100.685516],[13.78209,100.685669],[13.78161,100.685822],[13.7809,100.686073],[13.78006,100.686363],[13.77943,100.686623],[13.77875,100.68692],[13.77829,100.687134],[13.77761,100.687462],[13.77604,100.688309],[13.77088,100.691109],[13.76983,100.691681],[13.76765,100.692863],[13.76654,100.693466],[13.76069,100.696648],[13.75988,100.69709],[13.75691,100.6987],[13.75131,100.701736],[13.75102,100.701881],[13.75072,100.702011],[13.75036,100.702148],[13.7501,100.70224],[13.74983,100.702316],[13.74956,100.7024],[13.74928,100.702469],[13.74898,100.70253],[13.7487,100.702583],[13.7481,100.70266],[13.74738,100.702713],[13.74684,100.702713],[13.74257,100.702789],[13.74221,100.70298],[13.73885,100.703033],[13.73849,100.703217],[13.73729,100.703247],[13.73711,100.703346],[13.7362,100.70343],[13.73587,100.703499],[13.73561,100.703598],[13.73523,100.70388],[13.73436,100.704857],[13.73386,100.705383],[13.73325,100.705803],[13.73292,100.706093],[13.73268,100.706451],[13.73245,100.707199],[13.73227,100.70813],[13.7322,100.708519],[13.73188,100.710297],[13.7304,100.723747],[13.73037,100.724022],[13.72961,100.73085],[13.72959,100.731033],[13.72935,100.73317],[13.72933,100.733917],[13.72933,100.734703],[13.72949,100.740051],[13.72953,100.741081],[13.72953,100.741257],[13.7296,100.744133],[13.7297,100.748718],[13.72977,100.751572],[13.72991,100.757378],[13.72997,100.757896],[13.7309,100.761551],[13.73172,100.764793],[13.7318,100.765182],[13.73183,100.765602],[13.73191,100.76786],[13.73211,100.771118],[13.73215,100.773232],[13.73228,100.783249],[13.73232,100.784142],[13.73249,100.785889],[13.73291,100.79023],[13.73429,100.803726],[13.73383,100.805557],[13.73315,100.807281],[13.73138,100.809334],[13.72858,100.811081],[13.72721,100.81176],[13.7256,100.812553],[13.71357,100.818466],[13.71015,100.820236],[13.67427,100.838043],[13.67241,100.840233],[13.66908,100.845444],[13.60214,100.949783],[13.59885,100.954903],[13.59275,100.964043],[13.57161,100.981888],[13.55248,100.997871],[13.5509,100.999191],[13.5466,101.002937],[13.54299,101.005966],[13.53928,101.009087],[13.5367,101.011261],[13.49601,101.045448],[13.4933,101.046761],[13.49057,101.04705],[13.47329,101.04612],[13.4541,101.046257],[13.44076,101.046288],[13.42756,101.046783],[13.39933,101.047531],[13.39226,101.047073],[13.38711,101.046272],[13.36243,101.038658],[13.35742,101.036041],[13.35643,101.035423],[13.35091,101.031921],[13.34394,101.027634],[13.32626,101.016411],[13.31824,101.010399],[13.303,100.998978],[13.30144,100.997482],[13.30042,100.99649],[13.29915,100.99559],[13.29733,100.994743],[13.29551,100.993729],[13.29331,100.992599],[13.29079,100.991959],[13.28824,100.991524],[13.2831,100.991096],[13.27806,100.990791],[13.27206,100.990356],[13.26595,100.989998],[13.26406,100.989861],[13.26223,100.989769],[13.26119,100.98983],[13.26009,100.98996],[13.25884,100.990173],[13.25766,100.990509],[13.25655,100.990868],[13.25397,100.991837],[13.25177,100.992706],[13.24063,100.996986],[13.23351,100.99971],[13.22734,101.002083],[13.22418,101.003311],[13.22106,101.004509],[13.21955,101.005058],[13.21801,101.005463],[13.21637,101.005692],[13.21487,101.005783],[13.21191,101.005524],[13.20789,101.004379],[13.20639,101.003883],[13.19684,101.00074],[13.19001,100.99852],[13.18317,100.996277],[13.17575,100.993828],[13.16839,100.99144],[13.16099,100.989037],[13.15633,100.987556],[13.15439,100.986961],[13.15364,100.986717],[13.15228,100.986397],[13.15062,100.986153],[13.14806,100.986031],[13.14536,100.985947],[13.14282,100.985809],[13.13809,100.985718],[13.13165,100.985413],[13.12547,100.985199],[13.12188,100.985008],[13.12003,100.985031],[13.11832,100.985123],[13.11127,100.986557],[13.10656,100.987534],[13.10132,100.988663],[13.09598,100.989754],[13.09082,100.990791],[13.08545,100.99192],[13.07498,100.994072],[13.06974,100.995102],[13.06474,100.996117],[13.05745,100.996262],[13.05021,100.996323],[13.03819,100.996429],[13.025,100.996498],[13.01834,100.996536],[13.01381,100.996597],[13.01173,100.996452],[13.00731,100.995232],[12.99751,100.991707],[12.99483,100.990753],[12.98278,100.986504],[12.97491,100.983803],[12.97186,100.982681],[12.96919,100.981857],[12.96762,100.981293],[12.96685,100.981194],[12.9663,100.981056],[12.96574,100.98101],[12.96515,100.981056],[12.96462,100.981377],[12.96341,100.982033],[12.96096,100.98378],[12.95902,100.984718],[12.95468,100.98716],[12.95261,100.988342],[12.94143,100.994949],[12.93028,101.001678],[12.92805,101.003357],[12.92681,101.00486],[12.92379,101.009621],[12.92007,101.015747],[12.91659,101.0214],[12.91547,101.022774],[12.9151,101.023117],[12.91215,101.025848],[12.90933,101.028763],[12.90849,101.029533],[12.90795,101.03009],[12.90274,101.035248],[12.90131,101.036652],[12.90082,101.03714],[12.89481,101.043053],[12.88653,101.051193],[12.88284,101.05481],[12.87155,101.065903],[12.86993,101.067871],[12.86114,101.083557],[12.85287,101.098701],[12.84665,101.109756],[12.84072,101.120407],[12.83925,101.121857],[12.83811,101.12278],[12.83599,101.12429],[12.83082,101.127808],[12.82666,101.130661],[12.82239,101.133537],[12.81921,101.135651],[12.81603,101.137787],[12.80908,101.142593],[12.80223,101.147209],[12.79566,101.151749],[12.78903,101.15638],[12.78129,101.163872],[12.77738,101.167793],[12.77337,101.171707],[12.76987,101.175087],[12.76591,101.179092],[12.76228,101.182678],[12.75869,101.186302],[12.75254,101.192291],[12.7495,101.195259],[12.74631,101.198151],[12.73827,101.20517],[12.73008,101.212349],[12.72737,101.214783],[12.72482,101.217682],[12.72087,101.222397],[12.71684,101.227226],[12.70798,101.237846],[12.70502,101.241524],[12.7044,101.242378],[12.7039,101.243347],[12.70129,101.250237],[12.69903,101.256577],[12.69825,101.264671],[12.69778,101.270447],[12.69759,101.273117],[12.69682,101.279663],[12.69649,101.282837],[12.69607,101.285477],[12.69359,101.291321],[12.69267,101.293213],[12.69164,101.294777],[12.69023,101.29615],[12.68867,101.297241],[12.68297,101.299988],[12.67723,101.302818],[12.66358,101.309792],[12.66238,101.311333],[12.66135,101.316528],[12.66116,101.317993],[12.65854,101.326317],[12.65777,101.328644],[12.65398,101.336578],[12.6483,101.344757],[12.64673,101.348091],[12.64639,101.348824],[12.64616,101.349297],[12.64595,101.349747],[12.64557,101.350563],[12.64334,101.355293],[12.64314,101.355721],[12.63985,101.362717],[12.63967,101.363518],[12.63899,101.372093],[12.64012,101.388603],[12.64075,101.398293],[12.64155,101.408882],[12.64237,101.422127],[12.64219,101.424332],[12.64124,101.42881],[12.64327,101.435623],[12.65019,101.447891],[12.65435,101.455276],[12.6613,101.472076],[12.66057,101.488861],[12.66082,101.495087],[12.66561,101.511528],[12.67204,101.521507],[12.68008,101.523369],[12.68229,101.525742],[12.68671,101.534187],[12.70008,101.541809],[12.70731,101.54882],[12.71304,101.560768],[12.71314,101.563553],[12.71917,101.568703],[12.72148,101.574471],[12.72651,101.577766],[12.73162,101.587303],[12.73595,101.595383],[12.75103,101.609909],[12.75394,101.613403],[12.7559,101.615753],[12.76348,101.624847],[12.77363,101.639168],[12.77632,101.64283],[12.78186,101.646896],[12.78272,101.650703],[12.78339,101.653229],[12.78356,101.653877],[12.78415,101.656662],[12.78494,101.6586],[12.7862,101.661133],[12.78678,101.662407],[12.78695,101.663277],[12.78691,101.664818],[12.78645,101.669197],[12.78565,101.679581],[12.78532,101.681557],[12.78398,101.68602],[12.78172,101.693832],[12.77642,101.711746],[12.77624,101.712372],[12.77546,101.715767],[12.77636,101.718887],[12.77753,101.722893],[12.78054,101.732933],[12.78879,101.760483],[12.78925,101.762283],[12.78942,101.766441],[12.78921,101.76889],[12.78892,101.772278],[12.78788,101.785912],[12.78737,101.788971],[12.78692,101.789993],[12.7862,101.791634],[12.78431,101.79554],[12.78356,101.796959],[12.78314,101.798241],[12.78285,101.800392],[12.78164,101.810562],[12.78092,101.815964],[12.78046,101.819359],[12.77996,101.821373],[12.77896,101.824249],[12.77678,101.830948],[12.77469,101.837212],[12.7741,101.838966],[12.77222,101.842232],[12.77109,101.843819],[12.76665,101.850388],[12.76581,101.851372],[12.76473,101.852402],[12.76247,101.854286],[12.76138,101.855186],[12.7597,101.857162],[12.75732,101.859947],[12.75564,101.861931],[12.75476,101.863258],[12.75255,101.867813],[12.74983,101.873299],[12.7466,101.880547],[12.74455,101.885017],[12.74267,101.889313],[12.74187,101.890121],[12.7407,101.8909],[12.73957,101.89167],[12.73878,101.892616],[12.73798,101.894157],[12.73551,101.899353],[12.73346,101.904243],[12.73224,101.907806],[12.73099,101.911499],[12.73091,101.912956],[12.73053,101.91626],[12.72299,101.941582],[12.72316,101.953247],[12.72295,101.954933],[12.72217,101.957153],[12.72216,101.958961],[12.72146,101.971413],[12.7209,101.972687],[12.72015,101.973846],[12.71939,101.975357],[12.71882,101.976128],[12.71659,101.978317],[12.71395,101.980293],[12.71165,101.981361],[12.70043,101.986168],[12.69917,101.986771],[12.69767,101.988274],[12.69088,101.995911],[12.68599,102.001244],[12.68335,102.00415],[12.6823,102.005096],[12.68121,102.005569],[12.67991,102.005608],[12.67862,102.005386],[12.67744,102.00518],[12.67636,102.005051],[12.67552,102.005013],[12.67451,102.00518],[12.65326,102.011581],[12.65151,102.012482],[12.65004,102.016434],[12.64939,102.018707],[12.64882,102.021049],[12.64871,102.021553],[12.64862,102.021927],[12.64854,102.022362],[12.6485,102.02282],[12.64855,102.023499],[12.64883,102.025787],[12.64942,102.03067],[12.65019,102.040031],[12.65722,102.058571],[12.66028,102.066811],[12.66145,102.071777],[12.66534,102.088951],[12.66677,102.0914],[12.66697,102.091743],[12.66748,102.092644],[12.6629,102.119957],[12.6499,102.129128],[12.64373,102.130623],[12.64176,102.131866],[12.63252,102.142036],[12.62387,102.151543],[12.62117,102.148933],[12.61644,102.141602],[12.61577,102.140556],[12.60959,102.134377],[12.60811,102.133591],[12.60534,102.133743],[12.60309,102.135002],[12.60275,102.1353],[12.60235,102.135674],[12.60058,102.137268],[12.59573,102.143303],[12.58852,102.155151],[12.57278,102.162529],[12.56758,102.162529],[12.55827,102.157852],[12.54606,102.155487],[12.54006,102.157417],[12.53078,102.157288],[12.53014,102.157707],[12.52137,102.163589],[12.51361,102.168503],[12.50319,102.170288],[12.50093,102.170937],[12.48798,102.174721],[12.48346,102.179352],[12.48312,102.181931],[12.47407,102.190857],[12.46938,102.195831],[12.46737,102.199783],[12.46502,102.206131],[12.4658,102.220001],[12.45995,102.230057],[12.45079,102.245682],[12.4543,102.258827],[12.45664,102.262444],[12.45698,102.269478],[12.45161,102.284752],[12.44726,102.288696],[12.4439,102.297287],[12.44038,102.300537],[12.43006,102.313637],[12.42664,102.318916],[12.41257,102.330421],[12.39741,102.350517],[12.39663,102.354973],[12.39218,102.364067],[12.38945,102.368896],[12.38737,102.370117],[12.38571,102.37117],[12.38241,102.373177],[12.381,102.374153],[12.37111,102.388428],[12.36611,102.395821],[12.36796,102.410751],[12.36292,102.425003],[12.34096,102.4468],[12.33492,102.456932],[12.32819,102.45916],[12.32289,102.459846],[12.31658,102.465607],[12.31094,102.468086],[12.30272,102.475471],[12.29473,102.480309],[12.28444,102.484909],[12.27337,102.493149],[12.25648,102.507713],[12.25171,102.509537],[12.25944,102.518356],[12.26459,102.532806],[12.26085,102.543793],[12.25926,102.553307],[12.25758,102.555817],[12.2537,102.560799],[12.25156,102.568703],[12.25103,102.578362],[12.25093,102.587677],[12.25035,102.608727],[12.25054,102.611641],[12.24529,102.625427],[12.23383,102.627869],[12.23004,102.632057],[12.22525,102.645149],[12.20238,102.657333],[12.19404,102.659683],[12.18628,102.665611],[12.16334,102.679649],[12.15023,102.683006],[12.13089,102.691048],[12.1194,102.694992],[12.11467,102.697151],[12.1053,102.700394],[12.09618,102.705383],[12.08143,102.718521],[12.07709,102.725151],[12.06748,102.731934],[12.06485,102.73616],[12.06065,102.739113],[12.05058,102.75132],[12.04662,102.753799],[12.04233,102.758507],[12.01981,102.769608],[12.01509,102.77037],[12.00404,102.770599],[11.98184,102.776588],[11.96461,102.783089],[11.92141,102.80452],[11.90769,102.808289],[11.90115,102.811401],[11.88415,102.814987],[11.87684,102.818672],[11.86838,102.820839],[11.84824,102.831734],[11.84367,102.837181],[11.81262,102.853706],[11.80578,102.860786],[11.78507,102.874878],[11.7791,102.883461],[11.77862,102.884491],[11.77812,102.886162],[11.77667,102.886948],[11.77323,102.888817],[11.77145,102.888847],[11.7708,102.889069],[11.76782,102.890984],[11.76454,102.894508],[11.75899,102.896049],[11.75711,102.896729],[11.75476,102.896507],[11.75231,102.897057],[11.75154,102.897423],[11.7498,102.897713],[11.74754,102.898857],[11.74599,102.899002],[11.74284,102.900726],[11.74084,102.901321],[11.73924,102.902321],[11.73823,102.902657],[11.73688,102.904053],[11.73105,102.906174],[11.72379,102.905197],[11.71887,102.907021],[11.71666,102.907227],[11.7156,102.907669],[11.71261,102.907578],[11.71073,102.907593],[11.70928,102.906769],[11.70047,102.906502],[11.69846,102.904984],[11.69535,102.904503],[11.69275,102.904793],[11.68926,102.903084],[11.68662,102.902481],[11.68326,102.903008],[11.68151,102.903816],[11.67983,102.904114],[11.67867,102.904861],[11.67712,102.905067],[11.67607,102.905533],[11.67155,102.904831],[11.6703,102.905792],[11.66651,102.906242],[11.66574,102.906036],[11.66491,102.906464],[11.66189,102.906693],[11.65979,102.907532],[11.65812,102.906967],[11.65571,102.907349],[11.65356,102.908577],[11.65165,102.908836],[11.64946,102.911377],[11.64477,102.916077],[11.6429,102.918373],[11.64362,102.923988],[11.64301,102.928268],[11.64347,102.933006],[11.63845,102.941254],[11.63771,102.943657],[11.63596,102.946564],[11.63056,102.94841],[11.62356,102.949257],[11.62305,102.959099],[11.61957,102.962143],[11.61888,102.962822],[11.6163,102.979683],[11.61549,102.983543],[11.6144,102.988731],[11.60786,102.99955],[11.602,103.010292],[11.60196,103.01226],[11.60207,103.013702],[11.60248,103.015457],[11.60349,103.018707],[11.60551,103.024986],[11.60552,103.025497],[11.60557,103.02755],[11.6056,103.030159],[11.60596,103.035187],[11.60501,103.03965],[11.60492,103.040741],[11.60497,103.043221],[11.60483,103.045799],[11.60459,103.051231],[11.60384,103.054947],[11.60387,103.055687],[11.60395,103.056992],[11.60426,103.060738],[11.60432,103.061996],[11.60429,103.062576],[11.60388,103.063538],[11.60186,103.065804],[11.60169,103.06633],[11.60166,103.066963],[11.60207,103.070351],[11.60197,103.071091],[11.60167,103.071609],[11.6012,103.072037],[11.60047,103.072578],[11.59986,103.072983],[11.59913,103.073311],[11.59821,103.073441],[11.59735,103.073799],[11.59625,103.074707],[11.59593,103.075119],[11.59537,103.076553],[11.59405,103.079643],[11.59234,103.082916],[11.59217,103.085197],[11.59172,103.085518],[11.58763,103.08609],[11.58631,103.087021],[11.58491,103.087578],[11.58245,103.087196],[11.58056,103.086647],[11.57998,103.08696],[11.57799,103.089256],[11.57315,103.091026],[11.5725,103.091621],[11.57233,103.091957],[11.57225,103.092667],[11.57285,103.094414],[11.57348,103.095551],[11.57386,103.096298],[11.5736,103.098068],[11.5731,103.099411],[11.57245,103.100128],[11.57032,103.103363],[11.57003,103.104584],[11.56918,103.108437],[11.56847,103.11319],[11.56842,103.117027],[11.56869,103.118782],[11.56872,103.119423],[11.56863,103.120323],[11.56853,103.121597],[11.56842,103.12207],[11.56795,103.122673],[11.5659,103.12368],[11.56546,103.124168],[11.56533,103.124733],[11.56502,103.128433],[11.5649,103.12986],[11.5649,103.130928],[11.56522,103.131577],[11.5656,103.131882],[11.56614,103.132057],[11.56714,103.132141],[11.56756,103.132301],[11.56791,103.132591],[11.56859,103.13308],[11.56917,103.133186],[11.57056,103.133148],[11.57129,103.133347],[11.57193,103.133659],[11.57353,103.135071],[11.57457,103.135872],[11.57491,103.136261],[11.57502,103.136902],[11.57487,103.137917],[11.57441,103.140404],[11.57429,103.141327],[11.57433,103.142113],[11.57444,103.142891],[11.57476,103.144463],[11.57497,103.144943],[11.57528,103.145447],[11.57682,103.146919],[11.57742,103.147034],[11.57778,103.147011],[11.57831,103.147133],[11.57866,103.147537],[11.57868,103.148178],[11.57848,103.148842],[11.57848,103.150169],[11.57856,103.15094],[11.57885,103.151627],[11.57896,103.152298],[11.57817,103.156929],[11.57748,103.15934],[11.57724,103.160477],[11.57753,103.162361],[11.57745,103.163803],[11.57709,103.165443],[11.57664,103.168533],[11.57636,103.172096],[11.57614,103.175041],[11.57617,103.176277],[11.5766,103.177353],[11.57753,103.179581],[11.57851,103.181953],[11.57915,103.183578],[11.57981,103.185051],[11.5804,103.185829],[11.58186,103.187073],[11.58236,103.187508],[11.58281,103.188171],[11.58325,103.188911],[11.58361,103.189934],[11.58373,103.193459],[11.58285,103.196899],[11.58268,103.199982],[11.58339,103.202049],[11.58439,103.203133],[11.58479,103.204308],[11.58481,103.206703],[11.58574,103.20929],[11.58657,103.21035],[11.58873,103.212334],[11.59018,103.213943],[11.5904,103.214432],[11.5906,103.21769],[11.59058,103.217781],[11.59035,103.218803],[11.5882,103.220268],[11.58678,103.221764],[11.58348,103.22261],[11.57834,103.220749],[11.57638,103.221848],[11.57541,103.223122],[11.57472,103.22464],[11.57318,103.228439],[11.57241,103.229523],[11.57052,103.231133],[11.56974,103.232101],[11.56895,103.233109],[11.5683,103.234047],[11.56771,103.234581],[11.56548,103.235992],[11.56257,103.237617],[11.56186,103.237663],[11.56118,103.237488],[11.5604,103.237297],[11.55926,103.237343],[11.55846,103.236687],[11.55735,103.234642],[11.55677,103.233994],[11.55431,103.233093],[11.55359,103.232971],[11.55289,103.233101],[11.55138,103.233681],[11.54972,103.234703],[11.54917,103.235039],[11.5485,103.235313],[11.54473,103.23539],[11.54185,103.236504],[11.54024,103.237099],[11.53936,103.237282],[11.53716,103.237579],[11.53528,103.237],[11.534,103.236366],[11.53277,103.235626],[11.53164,103.234917],[11.53099,103.234749],[11.52984,103.23455],[11.52888,103.234177],[11.52735,103.233299],[11.52659,103.232536],[11.5262,103.23188],[11.5253,103.230614],[11.52429,103.229973],[11.52392,103.229927],[11.52121,103.229973],[11.51972,103.229561],[11.51893,103.229263],[11.5182,103.229317],[11.51399,103.23159],[11.51297,103.231812],[11.51194,103.231857],[11.51011,103.23188],[11.50902,103.232224],[11.50693,103.233429],[11.50576,103.233551],[11.50494,103.233231],[11.50325,103.23259],[11.50252,103.232422],[11.50093,103.232712],[11.50011,103.232773],[11.49915,103.232857],[11.49806,103.232651],[11.49561,103.231987],[11.49041,103.228378],[11.48962,103.227768],[11.48887,103.227501],[11.48762,103.227386],[11.48165,103.227951],[11.47617,103.227783],[11.47501,103.227638],[11.47367,103.226982],[11.47107,103.225647],[11.46887,103.224922],[11.46673,103.224213],[11.46596,103.224083],[11.46513,103.224503],[11.46288,103.22673],[11.45861,103.229118],[11.45768,103.229927],[11.45594,103.235283],[11.45535,103.235847],[11.45436,103.235909],[11.45231,103.23494],[11.45074,103.234207],[11.44935,103.233437],[11.44882,103.232803],[11.4481,103.231903],[11.44777,103.231461],[11.44646,103.23069],[11.44483,103.229797],[11.44376,103.228737],[11.44315,103.22834],[11.44296,103.228027],[11.44312,103.227257],[11.44294,103.226593],[11.44219,103.225899],[11.44182,103.225731],[11.44121,103.225906],[11.44061,103.226013],[11.43851,103.225807],[11.43649,103.225662],[11.43577,103.225906],[11.43484,103.226486],[11.43371,103.22715],[11.43153,103.228653],[11.43091,103.228668],[11.43053,103.228401],[11.43026,103.22805],[11.42979,103.227699],[11.42935,103.227997],[11.42913,103.228737],[11.42871,103.229958],[11.42834,103.230888],[11.42772,103.232048],[11.42666,103.232628],[11.42512,103.231987],[11.42317,103.23111],[11.41956,103.229424],[11.41809,103.229721],[11.41689,103.230324],[11.41594,103.231331],[11.41515,103.232651],[11.41403,103.233566],[11.41247,103.233757],[11.41083,103.233849],[11.4076,103.234238],[11.40635,103.23497],[11.40458,103.235901],[11.40382,103.23703],[11.40074,103.243408],[11.39951,103.246849],[11.39861,103.247864],[11.39231,103.250717],[11.38318,103.25174],[11.38208,103.252617],[11.38027,103.256081],[11.37877,103.259323],[11.37654,103.260857],[11.37606,103.261749],[11.37449,103.264359],[11.37389,103.264664],[11.3691,103.264771],[11.36836,103.265198],[11.36669,103.267418],[11.35941,103.271683],[11.35284,103.28212],[11.34847,103.285744],[11.34724,103.286469],[11.34553,103.287643],[11.34518,103.288109],[11.34536,103.288788],[11.34643,103.289711],[11.34668,103.290863],[11.34588,103.292938],[11.34509,103.293678],[11.33875,103.295464],[11.33796,103.296097],[11.33729,103.297028],[11.33656,103.297882],[11.33186,103.300552],[11.33066,103.30188],[11.3304,103.302391],[11.33031,103.303093],[11.33047,103.305153],[11.33047,103.306183],[11.32961,103.30854],[11.32908,103.309013],[11.32749,103.309433],[11.32654,103.310249],[11.3261,103.311157],[11.32575,103.312737],[11.32507,103.31424],[11.32294,103.317398],[11.32109,103.320778],[11.32049,103.321167],[11.31987,103.321289],[11.31806,103.321457],[11.31508,103.321899],[11.31325,103.322609],[11.31258,103.322662],[11.3116,103.322113],[11.3109,103.321907],[11.30992,103.321991],[11.30893,103.32225],[11.30779,103.322746],[11.30688,103.323372],[11.3058,103.324211],[11.30497,103.324944],[11.30449,103.325333],[11.30392,103.325691],[11.30293,103.325844],[11.30268,103.325783],[11.29959,103.324966],[11.29905,103.324928],[11.2979,103.324837],[11.29723,103.324654],[11.29601,103.323753],[11.29476,103.323433],[11.29397,103.323624],[11.2925,103.324753],[11.29014,103.325653],[11.28738,103.326508],[11.28699,103.327026],[11.28605,103.32917],[11.28512,103.330017],[11.28327,103.330742],[11.28231,103.330727],[11.27854,103.329353],[11.27771,103.329453],[11.27648,103.330269],[11.27562,103.330856],[11.27447,103.331558],[11.27372,103.332024],[11.27274,103.332283],[11.27011,103.332947],[11.26775,103.333687],[11.26709,103.334099],[11.26572,103.335281],[11.26541,103.335876],[11.26491,103.337448],[11.26399,103.339478],[11.26304,103.341507],[11.26191,103.343407],[11.2606,103.345131],[11.25998,103.345482],[11.25803,103.345978],[11.25598,103.346603],[11.2535,103.347031],[11.25327,103.347191],[11.25276,103.34761],[11.25099,103.351044],[11.24909,103.354622],[11.24879,103.355293],[11.24842,103.355789],[11.24748,103.356209],[11.24567,103.356209],[11.24308,103.356209],[11.24239,103.356491],[11.24009,103.358109],[11.23948,103.358612],[11.23888,103.359482],[11.23785,103.361458],[11.23727,103.361908],[11.23649,103.362137],[11.23424,103.362457],[11.23186,103.36274],[11.23022,103.363487],[11.22925,103.363747],[11.22569,103.364067],[11.22477,103.364693],[11.22408,103.365273],[11.22289,103.366341],[11.22187,103.367439],[11.22114,103.36763],[11.22042,103.367523],[11.22021,103.367577],[11.21984,103.367989],[11.21934,103.368477],[11.21889,103.368767],[11.21749,103.369614],[11.21565,103.371063],[11.21389,103.37262],[11.21215,103.37439],[11.21129,103.375877],[11.21071,103.37722],[11.21017,103.377876],[11.20754,103.379547],[11.20646,103.380302],[11.20535,103.381142],[11.20467,103.382057],[11.20402,103.383331],[11.20299,103.385292],[11.20158,103.387016],[11.20094,103.387779],[11.19945,103.388924],[11.19743,103.390358],[11.19607,103.390877],[11.19556,103.390968],[11.19516,103.391029],[11.19458,103.391098],[11.19393,103.390984],[11.19326,103.390533],[11.19254,103.390106],[11.19202,103.389648],[11.19145,103.388702],[11.19104,103.388496],[11.19063,103.388634],[11.19037,103.389236],[11.19007,103.389633],[11.18963,103.389832],[11.1892,103.389771],[11.18897,103.389664],[11.18855,103.389473],[11.18803,103.389282],[11.1875,103.389397],[11.18686,103.390068],[11.18626,103.390823],[11.18613,103.391403],[11.18627,103.391899],[11.18647,103.392479],[11.18649,103.392998],[11.1864,103.393242],[11.18608,103.393578],[11.18541,103.393738],[11.1844,103.393951],[11.184,103.394127],[11.18359,103.394417],[11.18341,103.394943],[11.18338,103.395569],[11.18366,103.396118],[11.18396,103.396408],[11.18422,103.396881],[11.18416,103.397163],[11.18315,103.398163],[11.18271,103.399933],[11.18287,103.401947],[11.18255,103.403778],[11.18269,103.404312],[11.18305,103.404793],[11.18307,103.405411],[11.18288,103.407066],[11.183,103.407387],[11.18321,103.407898],[11.18416,103.408882],[11.18428,103.409531],[11.18365,103.410843],[11.18349,103.411758],[11.18326,103.414078],[11.18286,103.416344],[11.18285,103.420883],[11.18364,103.424301],[11.1816,103.43045],[11.18061,103.4356],[11.17133,103.445473],[11.17097,103.446518],[11.17128,103.447769],[11.17192,103.449387],[11.17298,103.450996],[11.17648,103.454811],[11.18074,103.458771],[11.18119,103.459801],[11.18182,103.464951],[11.18233,103.465736],[11.18585,103.468758],[11.18979,103.471992],[11.19473,103.474182],[11.19598,103.474953],[11.19772,103.476303],[11.19857,103.476929],[11.19942,103.477669],[11.20113,103.478958],[11.20304,103.480507],[11.20471,103.481773],[11.20656,103.483238],[11.20854,103.484772],[11.20998,103.486183],[11.21027,103.486923],[11.21045,103.487823],[11.21039,103.489372],[11.21008,103.49366],[11.20821,103.51046],[11.20727,103.51165],[11.20585,103.513023],[11.20319,103.515953],[11.20203,103.519188],[11.20101,103.522598],[11.19859,103.532829],[11.19582,103.539001],[11.19552,103.544373],[11.19414,103.549026],[11.19365,103.553429],[11.19193,103.557022],[11.19208,103.559959],[11.19363,103.562714],[11.19476,103.56871],[11.19292,103.574707],[11.19234,103.575996],[11.19049,103.579964],[11.19004,103.581207],[11.18869,103.585373],[11.18686,103.587471],[11.18619,103.589417],[11.18608,103.590813],[11.18591,103.594711],[11.18573,103.595322],[11.1852,103.595947],[11.1827,103.597633],[11.18065,103.598991],[11.1801,103.5998],[11.17972,103.600929],[11.17936,103.602127],[11.17823,103.604088],[11.1776,103.605919],[11.17711,103.607857],[11.17699,103.608253],[11.17684,103.608704],[11.17675,103.609093],[11.17663,103.609612],[11.176,103.611229],[11.17401,103.615463],[11.17314,103.619499],[11.17309,103.620338],[11.17312,103.621239],[11.17308,103.624657],[11.1727,103.631561],[11.17279,103.632179],[11.17314,103.632736],[11.17592,103.635521],[11.17691,103.636276],[11.17731,103.636833],[11.17748,103.637352],[11.1775,103.638008],[11.17767,103.639717],[11.17787,103.640297],[11.17843,103.640999],[11.17895,103.641747],[11.17928,103.642517],[11.17927,103.643646],[11.17883,103.645798],[11.17867,103.646828],[11.17881,103.648117],[11.17961,103.651459],[11.17982,103.652237],[11.18029,103.653122],[11.18186,103.654266],[11.1829,103.655678],[11.1831,103.657021],[11.18229,103.659958],[11.18197,103.661087],[11.18152,103.662033],[11.17997,103.663933],[11.17963,103.66465],[11.17872,103.666634],[11.17818,103.667557],[11.1777,103.668221],[11.17682,103.668671],[11.17575,103.669441],[11.17496,103.670227],[11.17445,103.671227],[11.17418,103.671707],[11.1741,103.673157],[11.17405,103.674454],[11.17397,103.67588],[11.17366,103.676682],[11.17308,103.677841],[11.17065,103.682823],[11.17009,103.686668],[11.16957,103.690979],[11.16915,103.692131],[11.16804,103.693398],[11.16752,103.694008],[11.16648,103.695183],[11.16421,103.697701],[11.15985,103.702187],[11.15614,103.711243],[11.15262,103.720367],[11.15229,103.72171],[11.15202,103.723969],[11.1517,103.726891],[11.15096,103.732788],[11.15073,103.733566],[11.15039,103.734428],[11.14969,103.735809],[11.1481,103.738739],[11.14768,103.74202],[11.14836,103.743347],[11.14942,103.744827],[11.15026,103.745934],[11.15069,103.74662],[11.15106,103.747192],[11.15114,103.747833],[11.15095,103.748703],[11.14987,103.750328],[11.14856,103.752373],[11.14835,103.753464],[11.14851,103.754333],[11.14922,103.756638],[11.14941,103.757294],[11.14952,103.757881],[11.14919,103.758911],[11.14651,103.76133],[11.1442,103.763733],[11.14196,103.766197],[11.13964,103.768623],[11.13886,103.769012],[11.1381,103.76931],[11.13718,103.769592],[11.13477,103.770317],[11.13238,103.771004],[11.13146,103.771141],[11.13038,103.771156],[11.12787,103.771088],[11.12668,103.77153],[11.12241,103.773743],[11.12171,103.773857],[11.12084,103.773911],[11.12001,103.773933],[11.11721,103.773972],[11.10998,103.775299],[11.10607,103.774773],[11.1045,103.775162],[11.10346,103.775337],[11.10286,103.775177],[11.1018,103.774887],[11.09952,103.775078],[11.09706,103.775284],[11.09649,103.775337],[11.09577,103.775627],[11.09525,103.776192],[11.0947,103.777184],[11.09453,103.779541],[11.09447,103.781898],[11.09466,103.783058],[11.09488,103.784233],[11.09502,103.78524],[11.09505,103.785767],[11.09496,103.786369],[11.09466,103.787041],[11.09433,103.787537],[11.09375,103.788277],[11.09328,103.789017],[11.09195,103.791183],[11.09117,103.792397],[11.09022,103.79364],[11.08845,103.796211],[11.08748,103.798477],[11.08641,103.7995],[11.08534,103.79982],[11.08406,103.799927],[11.08297,103.799973],[11.08174,103.799881],[11.07517,103.796448],[11.07028,103.795197],[11.06735,103.795021],[11.06615,103.794579],[11.06494,103.794243],[11.0645,103.794113],[11.06399,103.794029],[11.0629,103.793983],[11.06133,103.793953],[11.06056,103.793938],[11.06005,103.793953],[11.05928,103.794083],[11.05789,103.794296],[11.05707,103.794327],[11.05632,103.793892],[11.0545,103.79258],[11.05322,103.792236],[11.05209,103.792221],[11.05152,103.792267],[11.05095,103.79245],[11.04974,103.793556],[11.04763,103.795731],[11.04724,103.796448],[11.04712,103.797119],[11.04707,103.797707],[11.04714,103.798843],[11.04714,103.800903],[11.04725,103.802391],[11.04753,103.803543],[11.05113,103.81208],[11.05209,103.814003],[11.05402,103.816803],[11.05514,103.818604],[11.05573,103.820747],[11.05638,103.82383],[11.057,103.825287],[11.05763,103.826073],[11.06003,103.828537],[11.06042,103.83004],[11.06021,103.83284],[11.06045,103.833878],[11.06309,103.839684],[11.06362,103.840446],[11.07223,103.848389],[11.07265,103.849403],[11.07273,103.850739],[11.07205,103.852127],[11.07038,103.854652],[11.07001,103.856651],[11.07053,103.858231],[11.0738,103.861671],[11.07438,103.863029],[11.07604,103.867943],[11.08074,103.876663],[11.08276,103.883034],[11.08504,103.887573],[11.08747,103.891853],[11.09351,103.902863],[11.09626,103.907677],[11.09797,103.910271],[11.09986,103.912628],[11.10172,103.914497],[11.11719,103.928207],[11.12314,103.933548],[11.12609,103.937073],[11.12849,103.940979],[11.13351,103.950737],[11.13833,103.960007],[11.14351,103.970093],[11.14877,103.980263],[11.15045,103.983887],[11.15166,103.987389],[11.15335,103.990837],[11.15434,103.992569],[11.16036,104.000847],[11.1649,104.007309],[11.16648,104.00956],[11.17444,104.020821],[11.17617,104.023148],[11.17744,104.024361],[11.1804,104.026291],[11.18675,104.032623],[11.18853,104.034492],[11.18943,104.035606],[11.1903,104.037193],[11.19067,104.038139],[11.19143,104.040947],[11.19232,104.044868],[11.19301,104.049026],[11.19386,104.055923],[11.19406,104.057426],[11.19365,104.060654],[11.19418,104.071198],[11.19437,104.073151],[11.19465,104.074532],[11.19516,104.07576],[11.20094,104.086983],[11.20212,104.08889],[11.20234,104.089523],[11.20257,104.090561],[11.20284,104.091293],[11.20358,104.092796],[11.20381,104.093384],[11.20417,104.094589],[11.20428,104.095154],[11.20439,104.09597],[11.20459,104.096642],[11.20479,104.097198],[11.20496,104.097893],[11.20516,104.099487],[11.20535,104.100258],[11.20553,104.100502],[11.20604,104.10096],[11.20737,104.101891],[11.20792,104.102623],[11.20809,104.103104],[11.20937,104.108627],[11.21023,104.112587],[11.2122,104.117897],[11.21319,104.120369],[11.21763,104.127892],[11.22001,104.131653],[11.22482,104.137657],[11.2308,104.146797],[11.24009,104.161209],[11.24535,104.16938],[11.25656,104.18306],[11.26132,104.188797],[11.26612,104.195312],[11.26954,104.199753],[11.27281,104.205101],[11.27728,104.212517],[11.27887,104.215157],[11.28602,104.227188],[11.29414,104.241119],[11.30092,104.252647],[11.30841,104.265282],[11.31258,104.272278],[11.31552,104.278542],[11.31805,104.282516],[11.32065,104.286133],[11.32409,104.291763],[11.32748,104.297836],[11.33257,104.305969],[11.34071,104.319382],[11.34404,104.324768],[11.34898,104.329353],[11.35067,104.331482],[11.35595,104.340073],[11.35931,104.34671],[11.36522,104.355904],[11.36764,104.358238],[11.37237,104.362923],[11.37664,104.368263],[11.37729,104.369011],[11.38512,104.374298],[11.39029,104.38002],[11.39617,104.38681],[11.3989,104.392479],[11.4047,104.399544],[11.40971,104.409241],[11.41611,104.424797],[11.41866,104.42984],[11.42282,104.446877],[11.4267,104.457939],[11.43018,104.46505],[11.43874,104.476578],[11.44111,104.480171],[11.44412,104.485619],[11.44534,104.487007],[11.44653,104.488136],[11.4482,104.48912],[11.45309,104.491272],[11.45469,104.492531],[11.45604,104.495033],[11.4585,104.504662],[11.45999,104.51059],[11.46157,104.517471],[11.4626,104.521729],[11.46297,104.522919],[11.46348,104.523781],[11.46505,104.525787],[11.46582,104.527733],[11.46739,104.531898],[11.47216,104.544884],[11.47508,104.553177],[11.47558,104.566727],[11.47516,104.57859],[11.47593,104.584923],[11.47684,104.58889],[11.47796,104.591553],[11.4827,104.61026],[11.48373,104.615677],[11.48535,104.624268],[11.48672,104.630508],[11.48914,104.63916],[11.4909,104.647552],[11.49224,104.652893],[11.49312,104.657547],[11.49447,104.66188],[11.49498,104.663223],[11.49638,104.66687],[11.49774,104.670662],[11.49856,104.672638],[11.49964,104.676613],[11.50056,104.679749],[11.50305,104.686951],[11.50356,104.694168],[11.50428,104.699677],[11.50513,104.704674],[11.50695,104.712051],[11.50716,104.715637],[11.5071,104.724953],[11.50695,104.728851],[11.50735,104.733101],[11.50765,104.734657],[11.5088,104.738792],[11.51005,104.744072],[11.51144,104.750343],[11.51393,104.763412],[11.51486,104.767693],[11.51789,104.77317],[11.51962,104.776314],[11.52081,104.778954],[11.52391,104.790916],[11.52485,104.794319],[11.52508,104.794853],[11.52576,104.796127],[11.526,104.796539],[11.5275,104.799171],[11.52917,104.80204],[11.5295,104.802589],[11.52975,104.803032],[11.53017,104.803993],[11.53039,104.804741],[11.53051,104.805389],[11.53062,104.805977],[11.53119,104.809479],[11.53182,104.813492],[11.53254,104.81739],[11.53259,104.817734],[11.53285,104.819397],[11.53309,104.820824],[11.5333,104.822166],[11.53381,104.825127],[11.53402,104.826477],[11.53435,104.828453],[11.53438,104.828537],[11.53437,104.828773],[11.53431,104.829033],[11.5342,104.829201],[11.53414,104.829323],[11.53413,104.829643],[11.53463,104.830093],[11.53414,104.830704],[11.53351,104.831467],[11.53081,104.834793],[11.52835,104.837891],[11.52877,104.841797],[11.52904,104.844307],[11.52908,104.844551],[11.53072,104.855827],[11.53079,104.856331],[11.53114,104.858963],[11.53308,104.873177],[11.53473,104.885193],[11.53474,104.885353],[11.53458,104.885536],[11.53447,104.885757],[11.53425,104.885963],[11.53221,104.886429],[11.53208,104.886452],[11.52989,104.886871],[11.52962,104.886932],[11.52785,104.887291],[11.52576,104.887718],[11.52572,104.888298],[11.52556,104.889893],[11.52537,104.890633],[11.52427,104.894363],[11.52349,104.897171],[11.5231,104.898407],[11.52284,104.899269],[11.52256,104.9002],[11.52215,104.901703],[11.52156,104.903717],[11.52088,104.906128],[11.52042,104.907951],[11.5193,104.913322],[11.51897,104.915192],[11.51894,104.915604],[11.51896,104.916061],[11.51903,104.916496],[11.51917,104.916962],[11.51975,104.91864],[11.51983,104.918854],[11.52025,104.919617],[11.5207,104.920212],[11.52108,104.920509],[11.52147,104.920723],[11.52208,104.920898],[11.52358,104.920998],[11.52505,104.921097],[11.52677,104.921227],[11.527,104.92186],[11.52883,104.926086],[11.52992,104.928574],[11.5299,104.92897],[11.53005,104.929619],[11.5302,104.930206],[11.53026,104.930496],[11.53027,104.930717],[11.53014,104.930946],[11.5296,104.931168],[11.52902,104.931396],[11.52877,104.931587],[11.52823,104.931801],[11.52758,104.931999],[11.52638,104.932114],[11.5239,104.93235],[11.51604,104.935379],[11.51338,104.935677],[11.51252,104.935997],[11.50867,104.937866],[11.50674,104.938766],[11.50388,104.939621],[11.50249,104.940048],[11.49697,104.942436],[11.49289,104.94355],[11.49186,104.94355],[11.49092,104.943123],[11.48942,104.942436],[11.48809,104.941818],[11.48757,104.94165],[11.48726,104.941727],[11.48513,104.942841],[11.48492,104.942963],[11.48385,104.943527],[11.48288,104.944061],[11.48157,104.944771],[11.48138,104.944633],[11.48112,104.944733],[11.48108,104.945053],[11.47857,104.946381],[11.47776,104.946823],[11.47264,104.949509],[11.47149,104.950127],[11.46992,104.950981],[11.46587,104.953209],[11.46406,104.954208],[11.46098,104.955994],[11.46003,104.956543],[11.45616,104.958847],[11.45244,104.961067],[11.45039,104.962288],[11.44289,104.966873],[11.44102,104.968018],[11.43993,104.968681],[11.43116,104.973999],[11.42561,104.977943],[11.4193,104.985237],[11.40634,104.999748],[11.40146,105.004936],[11.40073,105.005623],[11.39999,105.005829],[11.39922,105.005791],[11.39655,105.005074],[11.39496,105.004761],[11.3919,105.00444],[11.38985,105.004044],[11.38363,105.001984],[11.37883,105.001343],[11.37475,105.001892],[11.37105,105.003014],[11.36419,105.000473],[11.35815,105.001381],[11.35153,105.004639],[11.34709,105.007607],[11.34363,105.010948],[11.34161,105.013443],[11.33983,105.016502],[11.33843,105.019676],[11.33641,105.022873],[11.33367,105.025948],[11.32995,105.028282]]; \ No newline at end of file diff --git a/extlib/leaflet/debug/vector/vector-mobile.html b/extlib/leaflet/debug/vector/vector-mobile.html new file mode 100644 index 00000000..519de0c6 --- /dev/null +++ b/extlib/leaflet/debug/vector/vector-mobile.html @@ -0,0 +1,38 @@ + + + + Leaflet debug page + + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/extlib/leaflet/debug/vector/vector.html b/extlib/leaflet/debug/vector/vector.html new file mode 100644 index 00000000..4886f3b4 --- /dev/null +++ b/extlib/leaflet/debug/vector/vector.html @@ -0,0 +1,38 @@ + + + + Leaflet debug page + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/extlib/leaflet/spec/runner.html b/extlib/leaflet/spec/runner.html new file mode 100644 index 00000000..6931d2c9 --- /dev/null +++ b/extlib/leaflet/spec/runner.html @@ -0,0 +1,82 @@ + + + + Jasmine Test Runner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/LeafletSpec.js b/extlib/leaflet/spec/suites/LeafletSpec.js new file mode 100644 index 00000000..c67879cf --- /dev/null +++ b/extlib/leaflet/spec/suites/LeafletSpec.js @@ -0,0 +1,15 @@ +describe('L#noConflict', function() { + it('should restore the previous L value and return Leaflet namespace', function(){ + + expect(L.VERSION).toBeDefined(); + + var L2 = L.noConflict(); + + expect(L).toEqual('test'); + expect(L2.VERSION).toBeDefined(); + + this.after(function() { + window.L = L2; + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/SpecHelper.js b/extlib/leaflet/spec/suites/SpecHelper.js new file mode 100644 index 00000000..8b827041 --- /dev/null +++ b/extlib/leaflet/spec/suites/SpecHelper.js @@ -0,0 +1,5 @@ +function noSpecs() { + it('should have specs', function() { + expect('specs').toBe(); + }); +} \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/core/ClassSpec.js b/extlib/leaflet/spec/suites/core/ClassSpec.js new file mode 100644 index 00000000..7a289154 --- /dev/null +++ b/extlib/leaflet/spec/suites/core/ClassSpec.js @@ -0,0 +1,120 @@ +describe("Class", function() { + + describe("#extend", function() { + var Klass, + constructor, + method; + + beforeEach(function() { + constructor = jasmine.createSpy(), + method = jasmine.createSpy(); + + Klass = L.Class.extend({ + statics: {bla: 1}, + includes: {mixin: true}, + + initialize: constructor, + foo: 5, + bar: method + }); + }); + + it("should create a class with the given constructor & properties", function() { + var a = new Klass(); + + expect(constructor).toHaveBeenCalled(); + expect(a.foo).toEqual(5); + + a.bar(); + + expect(method).toHaveBeenCalled(); + }); + + it("should inherit parent classes' constructor & properties", function() { + var Klass2 = Klass.extend({baz: 2}); + + var b = new Klass2(); + + expect(b instanceof Klass).toBeTruthy(); + expect(b instanceof Klass2).toBeTruthy(); + + expect(constructor).toHaveBeenCalled(); + expect(b.baz).toEqual(2); + + b.bar(); + + expect(method).toHaveBeenCalled(); + }); + + it("should grant the ability to call parent methods, including constructor", function() { + var Klass2 = Klass.extend({ + initialize: function() {}, + bar: function() {} + }); + + var b = new Klass2(); + + expect(constructor).not.toHaveBeenCalled(); + b.superclass.initialize.call(this); + expect(constructor).toHaveBeenCalled(); + + b.superclass.bar.call(this); + expect(method).toHaveBeenCalled(); + }); + + it("should support static properties", function() { + expect(Klass.bla).toEqual(1); + }); + + it("should inherit parent static properties", function() { + var Klass2 = Klass.extend({}); + + expect(Klass2.bla).toEqual(1); + }); + + it("should include the given mixin", function() { + var a = new Klass(); + expect(a.mixin).toBeTruthy(); + }); + + it("should be able to include multiple mixins", function() { + var Klass2 = L.Class.extend({ + includes: [{mixin: true}, {mixin2: true}] + }); + var a = new Klass2(); + + expect(a.mixin).toBeTruthy(); + expect(a.mixin2).toBeTruthy(); + }); + + it("should grant the ability to include the given mixin", function() { + Klass.include({mixin2: true}); + + var a = new Klass(); + expect(a.mixin2).toBeTruthy(); + }); + + it("should merge options instead of replacing them", function() { + var KlassWithOptions1 = L.Class.extend({ + options: { + foo1: 1, + foo2: 2 + } + }); + var KlassWithOptions2 = KlassWithOptions1.extend({ + options: { + foo2: 3, + foo3: 4 + } + }); + + var a = new KlassWithOptions2(); + + expect(a.options).toEqual({ + foo1: 1, + foo2: 3, + foo3: 4 + }); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/core/EventsSpec.js b/extlib/leaflet/spec/suites/core/EventsSpec.js new file mode 100644 index 00000000..be143866 --- /dev/null +++ b/extlib/leaflet/spec/suites/core/EventsSpec.js @@ -0,0 +1,110 @@ +describe('Events', function() { + var Klass; + + beforeEach(function() { + Klass = L.Class.extend({ + includes: L.Mixin.Events + }); + }); + + describe('#fireEvent', function() { + + it('should fire all listeners added through #addEventListener', function() { + var obj = new Klass(), + spy = jasmine.createSpy(), + spy2 = jasmine.createSpy(), + spy3 = jasmine.createSpy(); + + obj.addEventListener('test', spy); + obj.addEventListener('test', spy2); + obj.addEventListener('other', spy3); + + expect(spy).not.toHaveBeenCalled(); + expect(spy2).not.toHaveBeenCalled(); + expect(spy3).not.toHaveBeenCalled(); + + obj.fireEvent('test'); + + expect(spy).toHaveBeenCalled(); + expect(spy2).toHaveBeenCalled(); + expect(spy3).not.toHaveBeenCalled(); + }); + + it('should provide event object to listeners and execute them in the right context', function() { + var obj = new Klass(), + obj2 = new Klass(), + foo = {}; + + function listener1(e) { + expect(e.type).toEqual('test'); + expect(e.target).toEqual(obj); + expect(this).toEqual(obj); + expect(e.bar).toEqual(3); + }; + + function listener2(e) { + expect(e.target).toEqual(obj2); + expect(this).toEqual(foo); + }; + + obj.addEventListener('test', listener1); + obj2.addEventListener('test', listener2, foo); + + obj.fireEvent('test', {bar: 3}); + }); + + it('should not call listeners removed through #removeEventListener', function() { + var obj = new Klass(), + spy = jasmine.createSpy(); + + obj.addEventListener('test', spy); + obj.removeEventListener('test', spy); + + obj.fireEvent('test'); + + expect(spy).not.toHaveBeenCalled(); + }); + }); + + describe('#on, #off & #fire', function() { + + it('should work like #addEventListener && #removeEventListener', function() { + var obj = new Klass(), + spy = jasmine.createSpy(); + + obj.on('test', spy); + obj.fire('test'); + + expect(spy).toHaveBeenCalled(); + + obj.off('test', spy); + obj.fireEvent('test'); + + expect(spy.callCount).toBeLessThan(2); + }); + + it('should not override existing methods with the same name', function() { + var spy1 = jasmine.createSpy(), + spy2 = jasmine.createSpy(), + spy3 = jasmine.createSpy(); + + var Klass2 = L.Class.extend({ + includes: L.Mixin.Events, + on: spy1, + off: spy2, + fire: spy3 + }); + + var obj = new Klass2(); + + obj.on(); + expect(spy1).toHaveBeenCalled(); + + obj.off(); + expect(spy2).toHaveBeenCalled(); + + obj.fire(); + expect(spy3).toHaveBeenCalled(); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/core/UtilSpec.js b/extlib/leaflet/spec/suites/core/UtilSpec.js new file mode 100644 index 00000000..46cb8fba --- /dev/null +++ b/extlib/leaflet/spec/suites/core/UtilSpec.js @@ -0,0 +1,63 @@ +describe('Util', function() { + + describe('#extend', function() { + var a; + + beforeEach(function() { + a = { + foo: 5, + bar: 'asd' + }; + }); + + it('should extend the first argument with the properties of the second', function() { + L.Util.extend(a, { + bar: 7, + baz: 3 + }); + + expect(a).toEqual({ + foo: 5, + bar: 7, + baz: 3 + }); + }); + + it('should work with more than 2 arguments', function() { + L.Util.extend(a, {bar: 7}, {baz: 3}); + + expect(a).toEqual({ + foo: 5, + bar: 7, + baz: 3 + }); + }); + }); + + describe('#bind', function() { + it('should return the given function with the given context', function() { + var fn = function() { + return this; + }; + + var fn2 = L.Util.bind(fn, 5); + + expect(fn2()).toEqual(5); + }); + }); + + describe('#stamp', function() { + it('should set a unique id on the given object and return it', function() { + var a = {}, + id = L.Util.stamp(a); + + expect(typeof id).toEqual('number'); + expect(L.Util.stamp(a)).toEqual(id); + + var b = {}, + id2 = L.Util.stamp(b); + + expect(id2).not.toEqual(id); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/dom/DomEventSpec.js b/extlib/leaflet/spec/suites/dom/DomEventSpec.js new file mode 100644 index 00000000..83d08541 --- /dev/null +++ b/extlib/leaflet/spec/suites/dom/DomEventSpec.js @@ -0,0 +1,102 @@ +describe('DomEvent', function() { + var el; + + function simulateClick(el) { + if (document.createEvent) { + var e = document.createEvent('MouseEvents'); + e.initMouseEvent('click', true, true, window, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + return el.dispatchEvent(e); + } else if (el.fireEvent) { + return el.fireEvent('onclick'); + } + } + + beforeEach(function() { + el = document.createElement('div'); + el.style.position = 'absolute'; + el.style.top = el.style.left = '-10000px'; + document.body.appendChild(el); + }); + + afterEach(function() { + document.body.removeChild(el); + }); + + describe('#addListener', function() { + it('should add a listener and call it on event', function() { + var listener1 = jasmine.createSpy('listener1'), + listener2 = jasmine.createSpy('listener2'); + + L.DomEvent.addListener(el, 'click', listener1); + L.DomEvent.addListener(el, 'click', listener2); + + simulateClick(el); + + expect(listener1).toHaveBeenCalled(); + expect(listener2).toHaveBeenCalled(); + }); + + it('should have "this" keyword point to the given context', function() { + var obj = {foo: 'bar'}, + result; + + L.DomEvent.addListener(el, 'click', function() { + result = this; + }, obj); + + simulateClick(el); + + expect(result).toEqual(obj); + }); + + it('should pass an event object to the listener', function() { + var type; + + L.DomEvent.addListener(el, 'click', function(e) { + type = e && e.type; + }); + simulateClick(el); + + expect(type).toEqual('click'); + }); + }); + + describe('#removeListener', function() { + it('should remove prevously added listener', function() { + var listener = jasmine.createSpy('listener'); + + L.DomEvent.addListener(el, 'click', listener); + L.DomEvent.removeListener(el, 'click', listener); + + simulateClick(el); + + expect(listener).not.toHaveBeenCalled(); + }); + }); + + describe('#stopPropagation', function() { + it('should stop propagation of the given event', function() { + var child = document.createElement('div'), + listener = jasmine.createSpy('listener'); + + el.appendChild(child); + + L.DomEvent.addListener(child, 'click', L.DomEvent.stopPropagation); + L.DomEvent.addListener(el, 'click', listener); + + simulateClick(child); + + expect(listener).not.toHaveBeenCalled(); + + el.removeChild(child); + }); + }); + describe('#preventDefault', function() { + it('should prevent the default action of event', function() { + L.DomEvent.addListener(el, 'click', L.DomEvent.preventDefault); + + expect(simulateClick(el)).toBe(false); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/dom/DomUtilSpec.js b/extlib/leaflet/spec/suites/dom/DomUtilSpec.js new file mode 100644 index 00000000..60de22fe --- /dev/null +++ b/extlib/leaflet/spec/suites/dom/DomUtilSpec.js @@ -0,0 +1,29 @@ +describe('DomUtil', function() { + var el; + + beforeEach(function() { + el = document.createElement('div'); + el.style.position = 'absolute'; + el.style.top = el.style.left = '-10000px'; + document.body.appendChild(el); + }); + + afterEach(function() { + document.body.removeChild(el); + }); + + describe('#get', function() { + it('should get element by id if the given argument is string', function() { + el.id = 'testId'; + expect(L.DomUtil.get(el.id)).toBe(el); + }); + + it('should return the element if it is given as an argument', function() { + expect(L.DomUtil.get(el)).toBe(el); + }); + }); + + describe('#setPosition', noSpecs); + + describe('#getStyle', noSpecs); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/geo/LatLngBoundsSpec.js b/extlib/leaflet/spec/suites/geo/LatLngBoundsSpec.js new file mode 100644 index 00000000..be9bf12b --- /dev/null +++ b/extlib/leaflet/spec/suites/geo/LatLngBoundsSpec.js @@ -0,0 +1 @@ +describe('LatLngBounds', noSpecs); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/geo/LatLngSpec.js b/extlib/leaflet/spec/suites/geo/LatLngSpec.js new file mode 100644 index 00000000..a7498e71 --- /dev/null +++ b/extlib/leaflet/spec/suites/geo/LatLngSpec.js @@ -0,0 +1,70 @@ +describe('LatLng', function() { + describe('constructor', function() { + it("should set lat and lng", function() { + var a = new L.LatLng(25, 74); + expect(a.lat).toEqual(25); + expect(a.lng).toEqual(74); + + var a = new L.LatLng(-25, -74); + expect(a.lat).toEqual(-25); + expect(a.lng).toEqual(-74); + }); + + it("should clamp latitude to lie between -90 and 90", function() { + var a = new L.LatLng(150, 0).lat; + expect(a).toEqual(90); + + var b = new L.LatLng(-230, 0).lat; + expect(b).toEqual(-90); + }); + + it("should clamp longtitude to lie between -180 and 180", function() { + var a = new L.LatLng(0, 190).lng; + expect(a).toEqual(-170); + + var b = new L.LatLng(0, 360).lng; + expect(b).toEqual(0); + + var c = new L.LatLng(0, 380).lng; + expect(c).toEqual(20); + + var d = new L.LatLng(0, -190).lng; + expect(d).toEqual(170); + + var e = new L.LatLng(0, -360).lng; + expect(e).toEqual(0); + + var f = new L.LatLng(0, -380).lng; + expect(f).toEqual(-20); + }); + + it("should not clamp latitude and longtitude if unbounded flag set to true", function() { + var a = new L.LatLng(150, 0, true).lat; + expect(a).toEqual(150); + + var b = new L.LatLng(-230, 0, true).lat; + expect(b).toEqual(-230); + + var c = new L.LatLng(0, 250, true).lng; + expect(c).toEqual(250); + + var d = new L.LatLng(0, -190, true).lng; + expect(d).toEqual(-190); + }); + }); + + describe('#equals', function() { + it("should return true if compared objects are equal within a certain margin", function() { + var a = new L.LatLng(10, 20); + var b = new L.LatLng(10 + 1.0E-10, 20 - 1.0E-10); + expect(a.equals(b)).toBe(true); + }); + + it("should return false if compared objects are not equal within a certain margin", function() { + var a = new L.LatLng(10, 20); + var b = new L.LatLng(10, 23.3); + expect(a.equals(b)).toBe(false); + }); + }); +}); + diff --git a/extlib/leaflet/spec/suites/geo/ProjectionSpec.js b/extlib/leaflet/spec/suites/geo/ProjectionSpec.js new file mode 100644 index 00000000..6b9c7b61 --- /dev/null +++ b/extlib/leaflet/spec/suites/geo/ProjectionSpec.js @@ -0,0 +1,42 @@ +describe("Projection.Mercator", function() { + var p = L.Projection.Mercator; + + beforeEach(function() { + function almostEqual(a, b, p) { + return Math.abs(a - b) <= (p || 1.0E-12); + }; + this.addMatchers({ + toAlmostEqual: function(expected, margin) { + var p1 = this.actual, + p2 = expected; + return almostEqual(p1.x, p2.x, margin) && almostEqual(p1.y, p2.y, margin); + } + }); + }); + + + describe("#project", function() { + it("should do projection properly", function() { + //edge cases + expect(p.project(new L.LatLng(0, 0))).toAlmostEqual(new L.Point(0, 0)); + expect(p.project(new L.LatLng(90, 180))).toAlmostEqual(new L.Point(-Math.PI, Math.PI)); + expect(p.project(new L.LatLng(-90, -180))).toAlmostEqual(new L.Point(-Math.PI, -Math.PI)); + + expect(p.project(new L.LatLng(50, 30))).toAlmostEqual(new L.Point(0.523598775598, 1.010683188683)); + }); + }); + + describe("#unproject", function() { + it("should do unprojection properly", function() { + function pr(point) { + return p.project(p.unproject(point)); + } + + expect(pr(new L.Point(0, 0))).toAlmostEqual(new L.Point(0, 0)); + expect(pr(new L.Point(-Math.PI, Math.PI))).toAlmostEqual(new L.Point(-Math.PI, Math.PI)); + expect(pr(new L.Point(-Math.PI, -Math.PI))).toAlmostEqual(new L.Point(-Math.PI, -Math.PI)); + + expect(pr(new L.Point(0.523598775598, 1.010683188683))).toAlmostEqual(new L.Point(0.523598775598, 1.010683188683)); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/geometry/BoundsSpec.js b/extlib/leaflet/spec/suites/geometry/BoundsSpec.js new file mode 100644 index 00000000..eee05e4b --- /dev/null +++ b/extlib/leaflet/spec/suites/geometry/BoundsSpec.js @@ -0,0 +1,43 @@ +describe('Bounds', function() { + var a, b; + + beforeEach(function() { + a = new L.Bounds( + new L.Point(14, 12), + new L.Point(30, 40)); + b = new L.Bounds([ + new L.Point(20, 12), + new L.Point(14, 20), + new L.Point(30, 40) + ]); + }); + + describe('constructor', function() { + it('should create bounds with proper min & max on (Point, Point)', function() { + expect(a.min).toEqual(new L.Point(14, 12)); + expect(a.max).toEqual(new L.Point(30, 40)); + }); + it('should create bounds with proper min & max on (Point[])', function() { + expect(b.min).toEqual(new L.Point(14, 12)); + expect(b.max).toEqual(new L.Point(30, 40)); + }); + }); + + describe('#extend', function() { + it('should extend the bounds to contain the given point', function() { + a.extend(new L.Point(50, 20)); + expect(a.min).toEqual(new L.Point(14, 12)); + expect(a.max).toEqual(new L.Point(50, 40)); + + b.extend(new L.Point(25, 50)); + expect(b.min).toEqual(new L.Point(14, 12)); + expect(b.max).toEqual(new L.Point(30, 50)); + }); + }); + + describe('#getCenter', function() { + it('should return the center point', function() { + expect(a.getCenter()).toEqual(new L.Point(22, 26)); + }); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/geometry/PointSpec.js b/extlib/leaflet/spec/suites/geometry/PointSpec.js new file mode 100644 index 00000000..d004d60b --- /dev/null +++ b/extlib/leaflet/spec/suites/geometry/PointSpec.js @@ -0,0 +1,45 @@ +describe("Point", function() { + + describe('constructor', function() { + + it("should create a point with the given x and y", function() { + var p = new L.Point(1.5, 2.5); + expect(p.x).toEqual(1.5); + expect(p.y).toEqual(2.5); + }); + + it("should round the given x and y if the third argument is true", function() { + var p = new L.Point(1.3, 2.7, true); + expect(p.x).toEqual(1); + expect(p.y).toEqual(3); + }); + }); + + describe('#subtract', function() { + it('should subtract the given point from this one', function() { + var a = new L.Point(50, 30), + b = new L.Point(20, 10); + expect(a.subtract(b)).toEqual(new L.Point(30, 20)); + }); + }); + + describe('#add', function() { + it('should add the given point to this one', function() { + expect(new L.Point(50, 30).add(new L.Point(20, 10))).toEqual(new L.Point(70, 40)); + }); + }); + + describe('#divideBy', function() { + it('should divide this point by the given amount', function() { + expect(new L.Point(50, 30).divideBy(5)).toEqual(new L.Point(10, 6)); + }); + }); + + describe('#multiplyBy', function() { + it('should multiply this point by the given amount', function() { + expect(new L.Point(50, 30).multiplyBy(2)).toEqual(new L.Point(100, 60)); + }); + }); + + describe('#distanceTo', noSpecs); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/geometry/TransformationSpec.js b/extlib/leaflet/spec/suites/geometry/TransformationSpec.js new file mode 100644 index 00000000..8a945df1 --- /dev/null +++ b/extlib/leaflet/spec/suites/geometry/TransformationSpec.js @@ -0,0 +1,19 @@ +describe("Transformation", function() { + var t, p; + + beforeEach(function() { + t = new L.Transformation(1, 2, 3, 4); + p = new L.Point(10, 20); + }); + + it("#transform should perform a transformation", function() { + var p2 = t.transform(p, 2); + expect(p2).toEqual(new L.Point(24, 128)); + }); + + it("#untransform should perform a reverse transformation", function() { + var p2 = t.transform(p, 2); + var p3 = t.untransform(p2, 2); + expect(p3).toEqual(p); + }); +}); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/layer/TileLayerSpec.js b/extlib/leaflet/spec/suites/layer/TileLayerSpec.js new file mode 100644 index 00000000..28517ad9 --- /dev/null +++ b/extlib/leaflet/spec/suites/layer/TileLayerSpec.js @@ -0,0 +1 @@ +describe('TileLayer', noSpecs); \ No newline at end of file diff --git a/extlib/leaflet/spec/suites/map/MapSpec.js b/extlib/leaflet/spec/suites/map/MapSpec.js new file mode 100644 index 00000000..7908b1a9 --- /dev/null +++ b/extlib/leaflet/spec/suites/map/MapSpec.js @@ -0,0 +1 @@ +describe("Map", noSpecs); \ No newline at end of file diff --git a/extlib/leaflet/src/Leaflet.js b/extlib/leaflet/src/Leaflet.js new file mode 100644 index 00000000..750a4a5f --- /dev/null +++ b/extlib/leaflet/src/Leaflet.js @@ -0,0 +1,35 @@ +/** + * @preserve Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin + * Leaflet is a BSD-licensed JavaScript library for map display and interaction. + * See http://cloudmade.github.com/Leaflet/ for more information. + */ + +(function(root) { + var L = { + VERSION: '0.2', + + ROOT_URL: (function() { + var scripts = document.getElementsByTagName('script'), + leafletRe = /^(.*\/)leaflet-?([\w-]*)\.js.*$/; + for (var i = 0, len = scripts.length; i < len; i++) { + var src = scripts[i].src, + res = src && src.match(leafletRe); + + if (res) { + if (res[2] == 'include') break; + return res[1]; + } + } + return '../../dist/'; + })(), + + noConflict: function() { + root.L = this._originalL; + return this; + }, + + _originalL: root.L + }; + + window.L = L; +}(this)); diff --git a/extlib/leaflet/src/control/Control.Attribution.js b/extlib/leaflet/src/control/Control.Attribution.js new file mode 100644 index 00000000..84b31f52 --- /dev/null +++ b/extlib/leaflet/src/control/Control.Attribution.js @@ -0,0 +1,55 @@ +L.Control.Attribution = L.Class.extend({ + onAdd: function(map) { + this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); + this._map = map; + this._prefix = 'Powered by Leaflet'; + this._attributions = {}; + this._update(); + }, + + getPosition: function() { + return L.Control.Position.BOTTOM_RIGHT; + }, + + getContainer: function() { + return this._container; + }, + + setPrefix: function(prefix) { + this._prefix = prefix; + }, + + addAttribution: function(text) { + if (!text) return; + this._attributions[text] = true; + this._update(); + }, + + removeAttribution: function(text) { + if (!text) return; + delete this._attributions[text]; + this._update(); + }, + + _update: function() { + if (!this._map) return; + + var attribs = []; + + for (var i in this._attributions) { + if (this._attributions.hasOwnProperty(i)) { + attribs.push(i); + } + } + + var prefixAndAttribs = []; + if (this._prefix) { + prefixAndAttribs.push(this._prefix); + } + if (attribs.length) { + prefixAndAttribs.push(attribs.join(', ')); + } + + this._container.innerHTML = prefixAndAttribs.join(' — '); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/control/Control.Zoom.js b/extlib/leaflet/src/control/Control.Zoom.js new file mode 100644 index 00000000..d6964fd6 --- /dev/null +++ b/extlib/leaflet/src/control/Control.Zoom.js @@ -0,0 +1,36 @@ + +L.Control.Zoom = L.Class.extend({ + onAdd: function(map) { + this._map = map; + this._container = L.DomUtil.create('div', 'leaflet-control-zoom'); + + this._zoomInButton = this._createButton( + 'Zoom in', 'leaflet-control-zoom-in', this._map.zoomIn, this._map); + this._zoomOutButton = this._createButton( + 'Zoom out', 'leaflet-control-zoom-out', this._map.zoomOut, this._map); + + this._container.appendChild(this._zoomInButton); + this._container.appendChild(this._zoomOutButton); + }, + + getContainer: function() { + return this._container; + }, + + getPosition: function() { + return L.Control.Position.TOP_LEFT; + }, + + _createButton: function(title, className, fn, context) { + var link = document.createElement('a'); + link.href = '#'; + link.title = title; + link.className = className; + + L.DomEvent.disableClickPropagation(link); + L.DomEvent.addListener(link, 'click', L.DomEvent.preventDefault); + L.DomEvent.addListener(link, 'click', fn, context); + + return link; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/control/Control.js b/extlib/leaflet/src/control/Control.js new file mode 100644 index 00000000..a01c6807 --- /dev/null +++ b/extlib/leaflet/src/control/Control.js @@ -0,0 +1,9 @@ + +L.Control = {}; + +L.Control.Position = { + TOP_LEFT: 'topLeft', + TOP_RIGHT: 'topRight', + BOTTOM_LEFT: 'bottomLeft', + BOTTOM_RIGHT: 'bottomRight' +}; \ No newline at end of file diff --git a/extlib/leaflet/src/core/Browser.js b/extlib/leaflet/src/core/Browser.js new file mode 100644 index 00000000..0604ed6d --- /dev/null +++ b/extlib/leaflet/src/core/Browser.js @@ -0,0 +1,23 @@ +(function() { + var ua = navigator.userAgent.toLowerCase(), + ie = !!window.ActiveXObject, + webkit = ua.indexOf("webkit") != -1, + mobile = ua.indexOf("mobi") != -1, + android = ua.indexOf("android") != -1, + opera = window.opera; + + L.Browser = { + ie: ie, + ie6: ie && !window.XMLHttpRequest, + webkit: webkit, + webkit3d: webkit && ('WebKitCSSMatrix' in window) && ('m11' in new WebKitCSSMatrix()), + mobileWebkit: webkit && (mobile || android), + mobileOpera: mobile && opera, + gecko: ua.indexOf("gecko") != -1, + android: android + }; + + //TODO replace ugly ua sniffing with feature detection + + L.Browser.touch = L.Browser.mobileWebkit || L.Browser.mobileOpera; +})(); \ No newline at end of file diff --git a/extlib/leaflet/src/core/Class.js b/extlib/leaflet/src/core/Class.js new file mode 100644 index 00000000..09a9e539 --- /dev/null +++ b/extlib/leaflet/src/core/Class.js @@ -0,0 +1,66 @@ +/* + * Class powers the OOP facilities of the library. Thanks to John Resig and Dean Edwards for inspiration! + */ + +L.Class = function() {}; + +L.Class.extend = function(/*Object*/ props) /*-> Class*/ { + + // extended class with the new prototype + var NewClass = function() { + if (!L.Class._prototyping && this.initialize) { + this.initialize.apply(this, arguments); + } + }; + + // instantiate class without calling constructor + L.Class._prototyping = true; + var proto = new this(); + L.Class._prototyping = false; + + proto.constructor = NewClass; + NewClass.prototype = proto; + + // add superclass access + proto.superclass = this.prototype; + + // add class name + //proto.className = props; + + // mix static properties into the class + if (props.statics) { + L.Util.extend(NewClass, props.statics); + delete props.statics; + } + + // mix includes into the prototype + if (props.includes) { + L.Util.extend.apply(null, [proto].concat(props.includes)); + delete props.includes; + } + + // merge options + if (props.options && proto.options) { + props.options = L.Util.extend({}, proto.options, props.options); + } + + // mix given properties into the prototype + L.Util.extend(proto, props); + + // allow inheriting further + NewClass.extend = arguments.callee; + + // method for adding properties to prototype + NewClass.include = function(props) { + L.Util.extend(this.prototype, props); + }; + + //inherit parent's statics + for (var i in this) { + if (this.hasOwnProperty(i) && i != 'prototype') { + NewClass[i] = this[i]; + } + } + + return NewClass; +}; \ No newline at end of file diff --git a/extlib/leaflet/src/core/Events.js b/extlib/leaflet/src/core/Events.js new file mode 100644 index 00000000..53ea20fa --- /dev/null +++ b/extlib/leaflet/src/core/Events.js @@ -0,0 +1,58 @@ +/* + * L.Mixin.Events adds custom events functionality to Leaflet classes + */ + +L.Mixin = {}; + +L.Mixin.Events = { + addEventListener: function(/*String*/ type, /*Function*/ fn, /*(optional) Object*/ context) { + var events = this._leaflet_events = this._leaflet_events || {}; + events[type] = events[type] || []; + events[type].push({ + action: fn, + context: context + }); + return this; + }, + + hasEventListeners: function(/*String*/ type) /*-> Boolean*/ { + var k = '_leaflet_events'; + return (k in this) && (type in this[k]) && (this[k][type].length > 0); + }, + + removeEventListener: function(/*String*/ type, /*Function*/ fn, /*(optional) Object*/ context) { + if (!this.hasEventListeners(type)) { return this; } + + for (var i = 0, events = this._leaflet_events, len = events[type].length; i < len; i++) { + if ( + (events[type][i].action === fn) && + (!context || (events[type][i].context === context)) + ) { + events[type].splice(i, 1); + return this; + } + } + return this; + }, + + fireEvent: function(/*String*/ type, /*(optional) Object*/ data) { + if (!this.hasEventListeners(type)) { return; } + + var event = L.Util.extend({ + type: type, + target: this + }, data); + + var listeners = this._leaflet_events[type].slice(); + + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i].action.call(listeners[i].context || this, event); + } + + return this; + } +}; + +L.Mixin.Events.on = L.Mixin.Events.addEventListener; +L.Mixin.Events.off = L.Mixin.Events.removeEventListener; +L.Mixin.Events.fire = L.Mixin.Events.fireEvent; \ No newline at end of file diff --git a/extlib/leaflet/src/core/Util.js b/extlib/leaflet/src/core/Util.js new file mode 100644 index 00000000..28daa284 --- /dev/null +++ b/extlib/leaflet/src/core/Util.js @@ -0,0 +1,96 @@ +/* + * L.Util is a namespace for various utility functions. + */ + +L.Util = { + extend: function(/*Object*/ dest) /*-> Object*/ { // merge src properties into dest + var sources = Array.prototype.slice.call(arguments, 1); + for (var j = 0, len = sources.length, src; j < len; j++) { + src = sources[j] || {}; + for (var i in src) { + if (src.hasOwnProperty(i)) { + dest[i] = src[i]; + } + } + } + return dest; + }, + + bind: function(/*Function*/ fn, /*Object*/ obj) /*-> Object*/ { + return function() { + return fn.apply(obj, arguments); + }; + }, + + stamp: (function() { + var lastId = 0, key = '_leaflet_id'; + return function(/*Object*/ obj) { + obj[key] = obj[key] || ++lastId; + return obj[key]; + }; + })(), + + requestAnimFrame: (function() { + function timeoutDefer(callback) { + window.setTimeout(callback, 1000 / 60); + } + + var requestFn = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + timeoutDefer; + + return function(callback, context, immediate) { + callback = context ? L.Util.bind(callback, context) : context; + if (immediate && requestFn === timeoutDefer) { + callback(); + } else { + requestFn(callback); + } + }; + })(), + + limitExecByInterval: function(fn, time, context) { + var lock, execOnUnlock, args; + function exec(){ + lock = false; + if (execOnUnlock) { + args.callee.apply(context, args); + execOnUnlock = false; + } + } + return function() { + args = arguments; + if (!lock) { + lock = true; + setTimeout(exec, time); + fn.apply(context, args); + } else { + execOnUnlock = true; + } + }; + }, + + falseFn: function() { return false; }, + + formatNum: function(num, digits) { + var pow = Math.pow(10, digits || 5); + return Math.round(num * pow) / pow; + }, + + setOptions: function(obj, options) { + obj.options = L.Util.extend({}, obj.options, options); + }, + + getParamString: function(obj) { + var params = []; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + params.push(i + '=' + obj[i]); + } + } + return '?' + params.join('&'); + } +}; diff --git a/extlib/leaflet/src/dom/DomEvent.DoubleTap.js b/extlib/leaflet/src/dom/DomEvent.DoubleTap.js new file mode 100644 index 00000000..08bd79b9 --- /dev/null +++ b/extlib/leaflet/src/dom/DomEvent.DoubleTap.js @@ -0,0 +1,41 @@ +L.Util.extend(L.DomEvent, { + // inspired by Zepto touch code by Thomas Fuchs + addDoubleTapListener: function(obj, handler, id) { + var last, + doubleTap = false, + delay = 250, + touch, + pre = '_leaflet_', + touchstart = 'touchstart', + touchend = 'touchend'; + + function onTouchStart(e) { + if (e.touches.length != 1) return; + + var now = Date.now(), + delta = now - (last || now); + + touch = e.touches[0]; + doubleTap = (delta > 0 && delta <= delay); + last = now; + } + function onTouchEnd(e) { + if (doubleTap) { + touch.type = 'dblclick'; + handler(touch); + last = null; + } + } + obj[pre + touchstart + id] = onTouchStart; + obj[pre + touchend + id] = onTouchEnd; + + obj.addEventListener(touchstart, onTouchStart, false); + obj.addEventListener(touchend, onTouchEnd, false); + }, + + removeDoubleTapListener: function(obj, id) { + var pre = '_leaflet_'; + obj.removeEventListener(obj, obj[pre + 'touchstart' + id], false); + obj.removeEventListener(obj, obj[pre + 'touchend' + id], false); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/dom/DomEvent.js b/extlib/leaflet/src/dom/DomEvent.js new file mode 100644 index 00000000..bcabebc2 --- /dev/null +++ b/extlib/leaflet/src/dom/DomEvent.js @@ -0,0 +1,132 @@ +/* + * L.DomEvent contains functions for working with DOM events. + */ + +L.DomEvent = { + /* inpired by John Resig, Dean Edwards and YUI addEvent implementations */ + addListener: function(/*HTMLElement*/ obj, /*String*/ type, /*Function*/ fn, /*Object*/ context) { + var id = L.Util.stamp(fn); + + function handler(e) { + return fn.call(context || obj, e || L.DomEvent._getEvent()); + } + + if (L.Browser.touch && (type == 'dblclick') && this.addDoubleTapListener) { + this.addDoubleTapListener(obj, handler, id); + } else if ('addEventListener' in obj) { + if (type == 'mousewheel') { + obj.addEventListener('DOMMouseScroll', handler, false); + obj.addEventListener(type, handler, false); + } else if ((type == 'mouseenter') || (type == 'mouseleave')) { + var originalHandler = handler, + newType = (type == 'mouseenter' ? 'mouseover' : 'mouseout'); + handler = function(e) { + if (!L.DomEvent._checkMouse(obj, e)) return; + return originalHandler(e); + }; + obj.addEventListener(newType, handler, false); + } else { + obj.addEventListener(type, handler, false); + } + } else if ('attachEvent' in obj) { + obj.attachEvent("on" + type, handler); + } + + obj['_leaflet_' + type + id] = handler; + }, + + removeListener: function(/*HTMLElement*/ obj, /*String*/ type, /*Function*/ fn) { + var id = L.Util.stamp(fn), + key = '_leaflet_' + type + id; + handler = obj[key]; + + if (L.Browser.mobileWebkit && (type == 'dblclick') && this.removeDoubleTapListener) { + this.removeDoubleTapListener(obj, id); + } else if ('removeEventListener' in obj) { + if (type == 'mousewheel') { + obj.removeEventListener('DOMMouseScroll', handler, false); + obj.removeEventListener(type, handler, false); + } else if ((type == 'mouseenter') || (type == 'mouseleave')) { + obj.removeEventListener((type == 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false); + } else { + obj.removeEventListener(type, handler, false); + } + } else if ('detachEvent' in obj) { + obj.detachEvent("on" + type, handler); + } + obj[key] = null; + }, + + _checkMouse: function(el, e) { + var related = e.relatedTarget; + + if (!related) return true; + + try { + while (related && (related != el)) { + related = related.parentNode; + } + } catch(err) { return false; } + + return (related != el); + }, + + _getEvent: function()/*->Event*/ { + var e = window.event; + if (!e) { + var caller = arguments.callee.caller; + while (caller) { + e = caller['arguments'][0]; + if (e && Event == e.constructor) { break; } + caller = caller.caller; + } + } + return e; + }, + + stopPropagation: function(/*Event*/ e) { + if (e.stopPropagation) { + e.stopPropagation(); + } else { + e.cancelBubble = true; + } + }, + + disableClickPropagation: function(/*HTMLElement*/ el) { + L.DomEvent.addListener(el, 'mousedown', L.DomEvent.stopPropagation); + L.DomEvent.addListener(el, 'click', L.DomEvent.stopPropagation); + L.DomEvent.addListener(el, 'dblclick', L.DomEvent.stopPropagation); + }, + + preventDefault: function(/*Event*/ e) { + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + }, + + stop: function(e) { + L.DomEvent.preventDefault(e); + L.DomEvent.stopPropagation(e); + }, + + getMousePosition: function(e, container) { + var x = e.pageX ? e.pageX : e.clientX + + document.body.scrollLeft + document.documentElement.scrollLeft, + y = e.pageY ? e.pageY : e.clientY + + document.body.scrollTop + document.documentElement.scrollTop, + pos = new L.Point(x, y); + + return (container ? + pos.subtract(L.DomUtil.getCumulativeOffset(container)) : pos); + }, + + getWheelDelta: function(e) { + var delta = 0; + if (e.wheelDelta) { delta = e.wheelDelta/120; } + if (e.detail) { delta = -e.detail/3; } + return delta; + } +}; + diff --git a/extlib/leaflet/src/dom/DomUtil.js b/extlib/leaflet/src/dom/DomUtil.js new file mode 100644 index 00000000..7672bfba --- /dev/null +++ b/extlib/leaflet/src/dom/DomUtil.js @@ -0,0 +1,124 @@ +/* + * L.DomUtil contains various utility functions for working with DOM + */ + +L.DomUtil = { + get: function(id) { + return (typeof id == 'string' ? document.getElementById(id) : id); + }, + + getStyle: function(el, style) { + var value = el.style[style]; + if (!value && el.currentStyle) { + value = el.currentStyle[style]; + } + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(el, null); + value = css ? css[style] : null; + } + return (value == 'auto' ? null : value); + }, + + getCumulativeOffset: function(el) { + var top = 0, + left = 0; + do { + top += el.offsetTop || 0; + left += el.offsetLeft || 0; + el = el.offsetParent; + } while (el); + return new L.Point(left, top); + }, + + create: function(tagName, className, container) { + var el = document.createElement(tagName); + el.className = className; + if (container) { + container.appendChild(el); + } + return el; + }, + + disableTextSelection: function() { + if (document.selection && document.selection.empty) { + document.selection.empty(); + } + if (!this._onselectstart) { + this._onselectstart = document.onselectstart; + document.onselectstart = L.Util.falseFn; + } + }, + + enableTextSelection: function() { + document.onselectstart = this._onselectstart; + this._onselectstart = null; + }, + + CLASS_RE: /(\\s|^)'+cls+'(\\s|$)/, + + hasClass: function(el, name) { + return (el.className.length > 0) && + new RegExp("(^|\\s)" + name + "(\\s|$)").test(el.className); + }, + + addClass: function(el, name) { + if (!L.DomUtil.hasClass(el, name)) { + el.className += (el.className ? ' ' : '') + name; + } + }, + + setOpacity: function(el, value) { + if (L.Browser.ie) { + el.style.filter = 'alpha(opacity=' + Math.round(value * 100) + ')'; + } else { + el.style.opacity = value; + } + }, + + //TODO refactor away this ugly translate/position mess + + testProp: function(props) { + var style = document.documentElement.style; + + for (var i = 0; i < props.length; i++) { + if (props[i] in style) { + return props[i]; + } + } + return false; + }, + + getTranslateString: function(point) { + return L.DomUtil.TRANSLATE_OPEN + + point.x + 'px,' + point.y + 'px' + + L.DomUtil.TRANSLATE_CLOSE; + }, + + getScaleString: function(scale, origin) { + return L.DomUtil.getTranslateString(origin) + + ' scale(' + scale + ') ' + + L.DomUtil.getTranslateString(origin.multiplyBy(-1)); + }, + + setPosition: function(el, point) { + el._leaflet_pos = point; + if (L.Browser.webkit) { + el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); + } else { + el.style.left = point.x + 'px'; + el.style.top = point.y + 'px'; + } + }, + + getPosition: function(el) { + return el._leaflet_pos; + } +}; + +L.Util.extend(L.DomUtil, { + TRANSITION: L.DomUtil.testProp(['transition', 'webkitTransition', 'OTransition', 'MozTransition', 'msTransition']), + TRANSFORM: L.DomUtil.testProp(['transformProperty', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']), + + TRANSLATE_OPEN: 'translate' + (L.Browser.webkit3d ? '3d(' : '('), + TRANSLATE_CLOSE: L.Browser.webkit3d ? ',0)' : ')' +}); \ No newline at end of file diff --git a/extlib/leaflet/src/dom/Draggable.js b/extlib/leaflet/src/dom/Draggable.js new file mode 100644 index 00000000..c0aea23e --- /dev/null +++ b/extlib/leaflet/src/dom/Draggable.js @@ -0,0 +1,129 @@ +/* + * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too. + */ + +L.Draggable = L.Class.extend({ + includes: L.Mixin.Events, + + statics: { + START: L.Browser.touch ? 'touchstart' : 'mousedown', + END: L.Browser.touch ? 'touchend' : 'mouseup', + MOVE: L.Browser.touch ? 'touchmove' : 'mousemove', + TAP_TOLERANCE: 15 + }, + + initialize: function(element, dragStartTarget) { + this._element = element; + this._dragStartTarget = dragStartTarget || element; + }, + + enable: function() { + if (this._enabled) { return; } + L.DomEvent.addListener(this._dragStartTarget, L.Draggable.START, this._onDown, this); + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + L.DomEvent.removeListener(this._dragStartTarget, L.Draggable.START, this._onDown); + this._enabled = false; + }, + + _onDown: function(e) { + if (e.shiftKey || ((e.which != 1) && (e.button != 1) && !e.touches)) { return; } + + if (e.touches && e.touches.length > 1) { return; } + + var first = (e.touches && e.touches.length == 1 ? e.touches[0] : e); + + L.DomEvent.preventDefault(e); + + if (L.Browser.mobileWebkit) { + first.target.className += ' leaflet-active'; + } + + this._moved = false; + + L.DomUtil.disableTextSelection(); + this._setMovingCursor(); + + this._startPos = this._newPos = L.DomUtil.getPosition(this._element); + this._startPoint = new L.Point(first.clientX, first.clientY); + + L.DomEvent.addListener(document, L.Draggable.MOVE, this._onMove, this); + L.DomEvent.addListener(document, L.Draggable.END, this._onUp, this); + }, + + _onMove: function(e) { + if (e.touches && e.touches.length > 1) { return; } + + L.DomEvent.preventDefault(e); + + var first = (e.touches && e.touches.length == 1 ? e.touches[0] : e); + + if (!this._moved) { + this.fire('dragstart'); + this._moved = true; + } + + var newPoint = new L.Point(first.clientX, first.clientY); + this._newPos = this._startPos.add(newPoint).subtract(this._startPoint); + + L.Util.requestAnimFrame(this._updatePosition, this, true); + + this.fire('drag'); + }, + + _updatePosition: function() { + L.DomUtil.setPosition(this._element, this._newPos); + }, + + _onUp: function(e) { + if (e.changedTouches) { + var first = e.changedTouches[0], + el = first.target, + dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0; + + el.className = el.className.replace(' leaflet-active', ''); + + if (dist < L.Draggable.TAP_TOLERANCE) { + this._simulateEvent('click', first); + } + } + + L.DomUtil.enableTextSelection(); + + this._restoreCursor(); + + L.DomEvent.removeListener(document, L.Draggable.MOVE, this._onMove); + L.DomEvent.removeListener(document, L.Draggable.END, this._onUp); + + if (this._moved) { + this.fire('dragend'); + } + }, + + _removeActiveClass: function(el) { + }, + + _setMovingCursor: function() { + this._bodyCursor = document.body.style.cursor; + document.body.style.cursor = 'move'; + }, + + _restoreCursor: function() { + document.body.style.cursor = this._bodyCursor; + }, + + _simulateEvent: function(type, e) { + var simulatedEvent = document.createEvent('MouseEvent'); + + simulatedEvent.initMouseEvent( + type, true, true, window, 1, + e.screenX, e.screenY, + e.clientX, e.clientY, + false, false, false, false, 0, null); + + e.target.dispatchEvent(simulatedEvent); + } +}); diff --git a/extlib/leaflet/src/dom/transition/Transition.Native.js b/extlib/leaflet/src/dom/transition/Transition.Native.js new file mode 100644 index 00000000..6ce16a67 --- /dev/null +++ b/extlib/leaflet/src/dom/transition/Transition.Native.js @@ -0,0 +1,89 @@ +/* + * L.Transition native implementation that powers Leaflet animation + * in browsers that support CSS3 Transitions + */ + +L.Transition = L.Transition.extend({ + statics: (function() { + var transition = L.DomUtil.TRANSITION, + transitionEnd = (transition == 'webkitTransition' || transition == 'OTransition' ? + transition + 'End' : 'transitionend'); + + return { + NATIVE: !!transition, + + TRANSITION: transition, + PROPERTY: transition + 'Property', + DURATION: transition + 'Duration', + EASING: transition + 'TimingFunction', + END: transitionEnd, + + // transition-property value to use with each particular custom property + CUSTOM_PROPS_PROPERTIES: { + position: L.Browser.webkit ? L.DomUtil.TRANSFORM : 'top, left' + } + }; + })(), + + options: { + fakeStepInterval: 100 + }, + + initialize: function(/*HTMLElement*/ el, /*Object*/ options) { + this._el = el; + L.Util.setOptions(this, options); + + L.DomEvent.addListener(el, L.Transition.END, this._onTransitionEnd, this); + this._onFakeStep = L.Util.bind(this._onFakeStep, this); + }, + + run: function(/*Object*/ props) { + var prop, + propsList = [], + customProp = L.Transition.CUSTOM_PROPS_PROPERTIES; + + for (prop in props) { + if (props.hasOwnProperty(prop)) { + prop = customProp[prop] ? customProp[prop] : prop; + prop = prop.replace(/([A-Z])/g, function(w) { return '-' + w.toLowerCase(); }); + propsList.push(prop); + } + } + + this._el.style[L.Transition.DURATION] = this.options.duration + 's'; + this._el.style[L.Transition.EASING] = this.options.easing; + this._el.style[L.Transition.PROPERTY] = propsList.join(', '); + + for (prop in props) { + if (props.hasOwnProperty(prop)) { + this._setProperty(prop, props[prop]); + } + } + + this._inProgress = true; + + this.fire('start'); + + if (L.Transition.NATIVE) { + this._timer = setInterval(this._onFakeStep, this.options.fakeStepInterval); + } else { + this._onTransitionEnd(); + } + }, + + _onFakeStep: function() { + this.fire('step'); + }, + + _onTransitionEnd: function() { + if (this._inProgress) { + this._inProgress = false; + clearInterval(this._timer); + + this._el.style[L.Transition.PROPERTY] = 'none'; + + this.fire('step'); + this.fire('end'); + } + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/dom/transition/Transition.Timer.js b/extlib/leaflet/src/dom/transition/Transition.Timer.js new file mode 100644 index 00000000..af4e4ef2 --- /dev/null +++ b/extlib/leaflet/src/dom/transition/Transition.Timer.js @@ -0,0 +1,124 @@ +/* + * L.Transition fallback implementation that powers Leaflet animation + * in browsers that don't support CSS3 Transitions + */ + +L.Transition = L.Transition.NATIVE ? L.Transition : L.Transition.extend({ + statics: { + getTime: Date.now || function() { return +new Date(); }, + + TIMER: true, + + EASINGS: { + 'ease': [0.25, 0.1, 0.25, 1.0], + 'linear': [0.0, 0.0, 1.0, 1.0], + 'ease-in': [0.42, 0, 1.0, 1.0], + 'ease-out': [0, 0, 0.58, 1.0], + 'ease-in-out': [0.42, 0, 0.58, 1.0] + }, + + CUSTOM_PROPS_GETTERS: { + position: L.DomUtil.getPosition + }, + + //used to get units from strings like "10.5px" (->px) + UNIT_RE: /^[\d\.]+(\D*)$/ + }, + + options: { + fps: 50 + }, + + initialize: function(el, options) { + this._el = el; + L.Util.extend(this.options, options); + + var easings = L.Transition.EASINGS[this.options.easing] || L.Transition.EASINGS['ease']; + + this._p1 = new L.Point(0, 0); + this._p2 = new L.Point(easings[0], easings[1]); + this._p3 = new L.Point(easings[2], easings[3]); + this._p4 = new L.Point(1, 1); + + this._step = L.Util.bind(this._step, this); + this._interval = Math.round(1000 / this.options.fps); + }, + + run: function(props) { + this._props = {}; + + var getters = L.Transition.CUSTOM_PROPS_GETTERS, + re = L.Transition.UNIT_RE; + + this.fire('start'); + + for (var prop in props) { + if (props.hasOwnProperty(prop)) { + var p = {}; + if (prop in getters) { + p.from = getters[prop](this._el); + } else { + var matches = this._el.style[prop].match(re); + p.from = parseFloat(matches[0]); + p.unit = matches[1]; + } + p.to = props[prop]; + this._props[prop] = p; + } + } + + clearInterval(this._timer); + this._timer = setInterval(this._step, this._interval); + this._startTime = L.Transition.getTime(); + }, + + _step: function() { + var time = L.Transition.getTime(), + elapsed = time - this._startTime, + duration = this.options.duration * 1000; + + if (elapsed < duration) { + this._runFrame(this._cubicBezier(elapsed / duration)); + } else { + this._runFrame(1); + this._complete(); + } + }, + + _runFrame: function(percentComplete) { + var setters = L.Transition.CUSTOM_PROPS_SETTERS, + prop, p, value; + + for (prop in this._props) { + if (this._props.hasOwnProperty(prop)) { + p = this._props[prop]; + if (prop in setters) { + value = p.to.subtract(p.from).multiplyBy(percentComplete).add(p.from); + setters[prop](this._el, value); + } else { + this._el.style[prop] = + ((p.to - p.from) * percentComplete + p.from) + p.unit; + } + } + } + this.fire('step'); + }, + + _complete: function() { + clearInterval(this._timer); + this.fire('end'); + }, + + _cubicBezier: function(t) { + var a = Math.pow(1 - t, 3), + b = 3 * Math.pow(1 - t, 2) * t, + c = 3 * (1 - t) * Math.pow(t, 2), + d = Math.pow(t, 3), + p1 = this._p1.multiplyBy(a), + p2 = this._p2.multiplyBy(b), + p3 = this._p3.multiplyBy(c), + p4 = this._p4.multiplyBy(d); + + return p1.add(p2).add(p3).add(p4).y; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/dom/transition/Transition.js b/extlib/leaflet/src/dom/transition/Transition.js new file mode 100644 index 00000000..ccf48572 --- /dev/null +++ b/extlib/leaflet/src/dom/transition/Transition.js @@ -0,0 +1,28 @@ +L.Transition = L.Class.extend({ + includes: L.Mixin.Events, + + statics: { + CUSTOM_PROPS_SETTERS: { + position: L.DomUtil.setPosition + //TODO transform custom attr + }, + + implemented: function() { + return L.Transition.NATIVE || L.Transition.TIMER; + } + }, + + options: { + easing: 'ease', + duration: 0.5 + }, + + _setProperty: function(prop, value) { + var setters = L.Transition.CUSTOM_PROPS_SETTERS; + if (prop in setters) { + setters[prop](this._el, value); + } else { + this._el.style[prop] = value; + } + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/geo/LatLng.js b/extlib/leaflet/src/geo/LatLng.js new file mode 100644 index 00000000..fb916547 --- /dev/null +++ b/extlib/leaflet/src/geo/LatLng.js @@ -0,0 +1,35 @@ +/* + CM.LatLng represents a geographical point with latitude and longtitude coordinates. +*/ + +L.LatLng = function(/*Number*/ lat, /*Number*/ lng, /*Boolean*/ noWrap) { + if (noWrap !== true) { + lat = Math.max(Math.min(lat, 90), -90); // clamp latitude into -90..90 + lng = (lng + 180) % 360 + (lng < -180 ? 180 : -180); // wrap longtitude into -180..180 + } + + //TODO change to lat() & lng() + this.lat = lat; + this.lng = lng; +}; + +L.Util.extend(L.LatLng, { + DEG_TO_RAD: Math.PI / 180, + RAD_TO_DEG: 180 / Math.PI, + MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check +}); + +L.LatLng.prototype = { + equals: function(/*LatLng*/ obj) { + if (!(obj instanceof L.LatLng)) { return false; } + + var margin = Math.max(Math.abs(this.lat - obj.lat), Math.abs(this.lng - obj.lng)); + return margin <= L.LatLng.MAX_MARGIN; + }, + + toString: function() { + return 'LatLng(' + + L.Util.formatNum(this.lat) + ', ' + + L.Util.formatNum(this.lng) + ')'; + } +}; \ No newline at end of file diff --git a/extlib/leaflet/src/geo/LatLngBounds.js b/extlib/leaflet/src/geo/LatLngBounds.js new file mode 100644 index 00000000..c4e70ec3 --- /dev/null +++ b/extlib/leaflet/src/geo/LatLngBounds.js @@ -0,0 +1,62 @@ +/* + * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. + */ + +L.LatLngBounds = L.Class.extend({ + initialize: function(southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) + if (!southWest) return; + var latlngs = (southWest instanceof Array ? southWest : [southWest, northEast]); + for (var i = 0, len = latlngs.length; i < len; i++) { + this.extend(latlngs[i]); + } + }, + + // extend the bounds to contain the given point + extend: function(/*LatLng*/ latlng) { + if (!this._southWest && !this._northEast) { + this._southWest = new L.LatLng(latlng.lat, latlng.lng); + this._northEast = new L.LatLng(latlng.lat, latlng.lng); + } else { + this._southWest.lat = Math.min(latlng.lat, this._southWest.lat); + this._southWest.lng = Math.min(latlng.lng, this._southWest.lng); + this._northEast.lat = Math.max(latlng.lat, this._northEast.lat); + this._northEast.lng = Math.max(latlng.lng, this._northEast.lng); + } + }, + + getCenter: function() /*-> LatLng*/ { + return new L.LatLng( + (this._southWest.lat + this._northEast.lat) / 2, + (this._southWest.lng + this._northEast.lng) / 2); + }, + + getSouthWest: function() { return this._southWest; }, + + getNorthEast: function() { return this._northEast; }, + + getNorthWest: function() { + return new L.LatLng(this._northEast.lat, this._southWest.lng); + }, + + getSouthEast: function() { + return new L.LatLng(this._southWest.lat, this._northEast.lng); + }, + + contains: function(/*LatLngBounds or LatLng*/ obj) /*-> Boolean*/ { + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof L.LatLngBounds) { + sw2 = obj.getSouthWest(); + ne2 = obj.getNorthEast(); + } else { + sw2 = ne2 = obj; + } + + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); + } +}); + +//TODO International date line? \ No newline at end of file diff --git a/extlib/leaflet/src/geo/crs/CRS.EPSG3395.js b/extlib/leaflet/src/geo/crs/CRS.EPSG3395.js new file mode 100644 index 00000000..426dc73c --- /dev/null +++ b/extlib/leaflet/src/geo/crs/CRS.EPSG3395.js @@ -0,0 +1,13 @@ + +L.CRS.EPSG3395 = L.Util.extend({}, L.CRS, { + code: 'EPSG:3395', + + projection: L.Projection.Mercator, + transformation: (function() { + var m = L.Projection.Mercator, + r = m.R_MAJOR, + r2 = m.R_MINOR; + + return new L.Transformation(0.5/(Math.PI * r), 0.5, -0.5/(Math.PI * r2), 0.5); + })() +}); \ No newline at end of file diff --git a/extlib/leaflet/src/geo/crs/CRS.EPSG3857.js b/extlib/leaflet/src/geo/crs/CRS.EPSG3857.js new file mode 100644 index 00000000..cbdbd03a --- /dev/null +++ b/extlib/leaflet/src/geo/crs/CRS.EPSG3857.js @@ -0,0 +1,17 @@ + +L.CRS.EPSG3857 = L.Util.extend({}, L.CRS, { + code: 'EPSG:3857', + + projection: L.Projection.SphericalMercator, + transformation: new L.Transformation(0.5/Math.PI, 0.5, -0.5/Math.PI, 0.5), + + project: function(/*LatLng*/ latlng)/*-> Point*/ { + var projectedPoint = this.projection.project(latlng), + earthRadius = 6378137; + return projectedPoint.multiplyBy(earthRadius); + } +}); + +L.CRS.EPSG900913 = L.Util.extend({}, L.CRS.EPSG3857, { + code: 'EPSG:900913' +}); \ No newline at end of file diff --git a/extlib/leaflet/src/geo/crs/CRS.EPSG4326.js b/extlib/leaflet/src/geo/crs/CRS.EPSG4326.js new file mode 100644 index 00000000..1550718d --- /dev/null +++ b/extlib/leaflet/src/geo/crs/CRS.EPSG4326.js @@ -0,0 +1,7 @@ + +L.CRS.EPSG4326 = L.Util.extend({}, L.CRS, { + code: 'EPSG:4326', + + projection: L.Projection.LonLat, + transformation: new L.Transformation(1/360, 0.5, -1/360, 0.5) +}); \ No newline at end of file diff --git a/extlib/leaflet/src/geo/crs/CRS.js b/extlib/leaflet/src/geo/crs/CRS.js new file mode 100644 index 00000000..2dc2aa8d --- /dev/null +++ b/extlib/leaflet/src/geo/crs/CRS.js @@ -0,0 +1,17 @@ + +L.CRS = { + latLngToPoint: function(/*LatLng*/ latlng, /*Number*/ scale)/*-> Point*/ { + var projectedPoint = this.projection.project(latlng); + return this.transformation._transform(projectedPoint, scale); + }, + + pointToLatLng: function(/*Point*/ point, /*Number*/ scale, /*(optional) Boolean*/ unbounded)/*-> LatLng*/ { + var untransformedPoint = this.transformation.untransform(point, scale); + return this.projection.unproject(untransformedPoint, unbounded); + //TODO get rid of 'unbounded' everywhere + }, + + project: function(latlng) { + return this.projection.project(latlng); + } +}; \ No newline at end of file diff --git a/extlib/leaflet/src/geo/projection/Projection.LonLat.js b/extlib/leaflet/src/geo/projection/Projection.LonLat.js new file mode 100644 index 00000000..ece29717 --- /dev/null +++ b/extlib/leaflet/src/geo/projection/Projection.LonLat.js @@ -0,0 +1,10 @@ + +L.Projection.LonLat = { + project: function(latlng) { + return new L.Point(latlng.lng, latlng.lat); + }, + + unproject: function(point, unbounded) { + return new L.LatLng(point.y, point.x, unbounded); + } +}; diff --git a/extlib/leaflet/src/geo/projection/Projection.Mercator.js b/extlib/leaflet/src/geo/projection/Projection.Mercator.js new file mode 100644 index 00000000..9eafff18 --- /dev/null +++ b/extlib/leaflet/src/geo/projection/Projection.Mercator.js @@ -0,0 +1,49 @@ + +L.Projection.Mercator = { + MAX_LATITUDE: 85.0840591556, + + R_MINOR: 6356752.3142, + R_MAJOR: 6378137, + + project: function(/*LatLng*/ latlng) /*-> Point*/ { + var d = L.LatLng.DEG_TO_RAD, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + r = this.R_MAJOR, + x = latlng.lng * d * r, + y = lat * d, + tmp = this.R_MINOR / r, + eccent = Math.sqrt(1.0 - tmp * tmp), + con = eccent * Math.sin(y); + + con = Math.pow((1 - con)/(1 + con), eccent * 0.5); + + var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con; + y = -r * Math.log(ts); + + return new L.Point(x, y); + }, + + unproject: function(/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ { + var d = L.LatLng.RAD_TO_DEG, + r = this.R_MAJOR, + lng = point.x * d / r, + tmp = this.R_MINOR / r, + eccent = Math.sqrt(1 - (tmp * tmp)), + ts = Math.exp(- point.y / r), + phi = Math.PI/2 - 2 * Math.atan(ts), + numIter = 15, + tol = 1e-7, + i = numIter, + dphi = 0.1, + con; + + while ((Math.abs(dphi) > tol) && (--i > 0)) { + con = eccent * Math.sin(phi); + dphi = Math.PI/2 - 2 * Math.atan(ts * Math.pow((1.0 - con)/(1.0 + con), 0.5 * eccent)) - phi; + phi += dphi; + } + + return new L.LatLng(phi * d, lng, unbounded); + } +}; diff --git a/extlib/leaflet/src/geo/projection/Projection.SphericalMercator.js b/extlib/leaflet/src/geo/projection/Projection.SphericalMercator.js new file mode 100644 index 00000000..be0532ff --- /dev/null +++ b/extlib/leaflet/src/geo/projection/Projection.SphericalMercator.js @@ -0,0 +1,23 @@ + +L.Projection.SphericalMercator = { + MAX_LATITUDE: 85.0511287798, + + project: function(/*LatLng*/ latlng) /*-> Point*/ { + var d = L.LatLng.DEG_TO_RAD, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + x = latlng.lng * d, + y = lat * d; + y = Math.log(Math.tan(Math.PI/4 + y/2)); + + return new L.Point(x, y); + }, + + unproject: function(/*Point*/ point, /*Boolean*/ unbounded) /*-> LatLng*/ { + var d = L.LatLng.RAD_TO_DEG, + lng = point.x * d, + lat = (2 * Math.atan(Math.exp(point.y)) - Math.PI/2) * d; + + return new L.LatLng(lat, lng, unbounded); + } +}; diff --git a/extlib/leaflet/src/geo/projection/Projection.js b/extlib/leaflet/src/geo/projection/Projection.js new file mode 100644 index 00000000..84316b30 --- /dev/null +++ b/extlib/leaflet/src/geo/projection/Projection.js @@ -0,0 +1,5 @@ +/* + * L.Projection contains various geographical projections used by CRS classes. + */ + +L.Projection = {}; diff --git a/extlib/leaflet/src/geometry/Bounds.js b/extlib/leaflet/src/geometry/Bounds.js new file mode 100644 index 00000000..73448ceb --- /dev/null +++ b/extlib/leaflet/src/geometry/Bounds.js @@ -0,0 +1,48 @@ +/* + * L.Bounds represents a rectangular area on the screen in pixel coordinates. + */ + +L.Bounds = L.Class.extend({ + initialize: function(min, max) { //(Point, Point) or Point[] + if (!min) return; + var points = (min instanceof Array ? min : [min, max]); + for (var i = 0, len = points.length; i < len; i++) { + this.extend(points[i]); + } + }, + + // extend the bounds to contain the given point + extend: function(/*Point*/ point) { + if (!this.min && !this.max) { + this.min = new L.Point(point.x, point.y); + this.max = new L.Point(point.x, point.y); + } else { + this.min.x = Math.min(point.x, this.min.x); + this.max.x = Math.max(point.x, this.max.x); + this.min.y = Math.min(point.y, this.min.y); + this.max.y = Math.max(point.y, this.max.y); + } + }, + + getCenter: function(round)/*->Point*/ { + return new L.Point( + (this.min.x + this.max.x) / 2, + (this.min.y + this.max.y) / 2, round); + }, + + contains: function(/*Bounds or Point*/ obj)/*->Boolean*/ { + var min, max; + + if (obj instanceof L.Bounds) { + min = obj.min; + max = obj.max; + } else { + max = max = obj; + } + + return (min.x >= this.min.x) && + (max.x <= this.max.x) && + (min.y >= this.min.y) && + (max.y <= this.max.y); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/geometry/LineUtil.js b/extlib/leaflet/src/geometry/LineUtil.js new file mode 100644 index 00000000..72a80855 --- /dev/null +++ b/extlib/leaflet/src/geometry/LineUtil.js @@ -0,0 +1,159 @@ +/* + * L.LineUtil contains different utility functions for line segments + * and polylines (clipping, simplification, distances, etc.) + */ + +L.LineUtil = { + /* + * Simplify polyline with vertex reduction and Douglas-Peucker simplification. + * Improves rendering performance dramatically by lessening the number of points to draw. + */ + simplify: function(/*Point[]*/ points, /*Number*/ tolerance) { + if (!tolerance) return points.slice(); + + // stage 1: vertex reduction + points = this.reducePoints(points, tolerance); + + // stage 2: Douglas-Peucker simplification + points = this.simplifyDP(points, tolerance); + + return points; + }, + + // distance from a point to a segment between two points + pointToSegmentDistance: function(/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { + return Math.sqrt(this._sqPointToSegmentDist(p, p1, p2)); + }, + + // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm + simplifyDP: function(points, tol) { + var maxDist2 = 0, + index = 0, + t2 = tol * tol; + + for (var i = 1, len = points.length, dist2; i < len - 1; i++) { + dist2 = this._sqPointToSegmentDist(points[i], points[0], points[len - 1]); + if (dist2 > maxDist2) { + index = i; + maxDist2 = dist2; + } + } + + if (maxDist2 >= t2) { + var part1 = points.slice(0, index), + part2 = points.slice(index), + simplifiedPart1 = this.simplifyDP(part1, tol).slice(0, len - 2), + simplifiedPart2 = this.simplifyDP(part2, tol); + + return simplifiedPart1.concat(simplifiedPart2); + } else { + return [points[0], points[len - 1]]; + } + }, + + // reduce points that are too close to each other to a single point + reducePoints: function(points, tol) { + var reducedPoints = [points[0]], + t2 = tol * tol; + + for (var i = 1, prev = 0, len = points.length; i < len; i++) { + if (this._sqDist(points[i], points[prev]) < t2) continue; + reducedPoints.push(points[i]); + prev = i; + } + if (prev < len - 1) { + reducedPoints.push(points[len - 1]); + } + return reducedPoints; + }, + + /* + * Cohen-Sutherland line clipping algorithm. + * Used to avoid rendering parts of a polyline that are not currently visible. + */ + clipSegment: function(a, b, bounds, useLastCode) { + var min = bounds.min, + max = bounds.max; + + var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds), + codeB = this._getBitCode(b, bounds); + + // save 2nd code to avoid calculating it on the next segment + this._lastCode = codeB; + + while (true) { + // if a,b is inside the clip window (trivial accept) + if (!(codeA | codeB)) { + return [a, b]; + // if a,b is outside the clip window (trivial reject) + } else if (codeA & codeB) { + return false; + // other cases + } else { + var codeOut = codeA || codeB, + p = this._getEdgeIntersection(a, b, codeOut, bounds), + newCode = this._getBitCode(p, bounds); + + if (codeOut == codeA) { + a = p; + codeA = newCode; + } else { + b = p; + codeB = newCode; + } + } + } + }, + + _getEdgeIntersection: function(a, b, code, bounds) { + var dx = b.x - a.x, + dy = b.y - a.y, + min = bounds.min, + max = bounds.max; + + if (code & 8) { // top + return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y); + } else if (code & 4) { // bottom + return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y); + } else if (code & 2){ // right + return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx); + } else if (code & 1) { // left + return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx); + } + }, + + _getBitCode: function(/*Point*/ p, bounds) { + var code = 0; + + if (p.x < bounds.min.x) code |= 1; // left + else if (p.x > bounds.max.x) code |= 2; // right + if (p.y < bounds.min.y) code |= 4; // bottom + else if (p.y > bounds.max.y) code |= 8; // top + + return code; + }, + + // square distance (to avoid unnecessary Math.sqrt calls) + _sqDist: function(p1, p2) { + var dx = p2.x - p1.x, + dy = p2.y - p1.y; + return dx * dx + dy * dy; + }, + + // square distance from point to a segment + _sqPointToSegmentDist: function(p, p1, p2) { + var x2 = p2.x - p1.x, + y2 = p2.y - p1.y; + + if (!x2 && !y2) return this._sqDist(p, p1); + + var dot = (p.x - p1.x) * x2 + (p.y - p1.y) * y2, + t = dot / this._sqDist(p1, p2); + + if (t < 0) return this._sqDist(p, p1); + if (t > 1) return this._sqDist(p, p2); + + var proj = new L.Point(p1.x + x2 * t, p1.y + y2 * t); + return this._sqDist(p, proj); + } +}; \ No newline at end of file diff --git a/extlib/leaflet/src/geometry/Point.js b/extlib/leaflet/src/geometry/Point.js new file mode 100644 index 00000000..d031ffe1 --- /dev/null +++ b/extlib/leaflet/src/geometry/Point.js @@ -0,0 +1,66 @@ +/* + * L.Point represents a point with x and y coordinates. + */ + +L.Point = function(/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { + this.x = (round ? Math.round(x) : x); + this.y = (round ? Math.round(y) : y); +}; + +L.Point.prototype = { + add: function(point) { + return this.clone()._add(point); + }, + + _add: function(point) { + this.x += point.x; + this.y += point.y; + return this; + }, + + subtract: function(point) { + return this.clone()._subtract(point); + }, + + // destructive subtract (faster) + _subtract: function(point) { + this.x -= point.x; + this.y -= point.y; + return this; + }, + + divideBy: function(num, round) { + return new L.Point(this.x/num, this.y/num, round); + }, + + multiplyBy: function(num) { + return new L.Point(this.x * num, this.y * num); + }, + + distanceTo: function(point) { + var x = point.x - this.x, + y = point.y - this.y; + return Math.sqrt(x*x + y*y); + }, + + round: function() { + return this.clone()._round(); + }, + + // destructive round + _round: function() { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + }, + + clone: function() { + return new L.Point(this.x, this.y); + }, + + toString: function() { + return 'Point(' + + L.Util.formatNum(this.x) + ', ' + + L.Util.formatNum(this.y) + ')'; + } +}; \ No newline at end of file diff --git a/extlib/leaflet/src/geometry/PolyUtil.js b/extlib/leaflet/src/geometry/PolyUtil.js new file mode 100644 index 00000000..c5460709 --- /dev/null +++ b/extlib/leaflet/src/geometry/PolyUtil.js @@ -0,0 +1,55 @@ +/* + * L.PolyUtil contains utilify functions for polygons (clipping, etc.). + */ + +L.PolyUtil = {}; + +/* + * Sutherland-Hodgeman polygon clipping algorithm. + * Used to avoid rendering parts of a polygon that are not currently visible. + */ +L.PolyUtil.clipPolygon = function(points, bounds) { + var min = bounds.min, + max = bounds.max, + clippedPoints, + edges = [1, 4, 2, 8], + i, j, k, + a, b, + len, edge, p, + lu = L.LineUtil; + + for (i = 0, len = points.length; i < len; i++) { + points[i]._code = lu._getBitCode(points[i], bounds); + } + + // for each edge (left, bottom, right, top) + for (k = 0; k < 4; k++) { + edge = edges[k]; + clippedPoints = []; + + for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { + a = points[i]; + b = points[j]; + + // if a is inside the clip window + if (!(a._code & edge)) { + // if b is outside the clip window (a->b goes out of screen) + if (b._code & edge) { + p = lu._getEdgeIntersection(b, a, edge, bounds); + p._code = lu._getBitCode(p, bounds); + clippedPoints.push(p); + } + clippedPoints.push(a); + + // else if b is inside the clip window (a->b enters the screen) + } else if (!(b._code & edge)) { + p = lu._getEdgeIntersection(b, a, edge, bounds); + p._code = lu._getBitCode(p, bounds); + clippedPoints.push(p); + } + } + points = clippedPoints; + } + + return points; +}; \ No newline at end of file diff --git a/extlib/leaflet/src/geometry/Transformation.js b/extlib/leaflet/src/geometry/Transformation.js new file mode 100644 index 00000000..37f40968 --- /dev/null +++ b/extlib/leaflet/src/geometry/Transformation.js @@ -0,0 +1,31 @@ +/* + * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. + */ + +L.Transformation = L.Class.extend({ + initialize: function(/*Number*/ a, /*Number*/ b, /*Number*/ c, /*Number*/ d) { + this._a = a; + this._b = b; + this._c = c; + this._d = d; + }, + + transform: function(point, scale) { + return this._transform(point.clone(), scale); + }, + + // destructive transform (faster) + _transform: function(/*Point*/ point, /*Number*/ scale) /*-> Point*/ { + scale = scale || 1; + point.x = scale * (this._a * point.x + this._b); + point.y = scale * (this._c * point.y + this._d); + return point; + }, + + untransform: function(/*Point*/ point, /*Number*/ scale) /*-> Point*/ { + scale = scale || 1; + return new L.Point( + (point.x/scale - this._b) / this._a, + (point.y/scale - this._d) / this._c); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/handler/DoubleClickZoom.js b/extlib/leaflet/src/handler/DoubleClickZoom.js new file mode 100644 index 00000000..121a5e20 --- /dev/null +++ b/extlib/leaflet/src/handler/DoubleClickZoom.js @@ -0,0 +1,21 @@ +/* + * L.Handler.DoubleClickZoom is used internally by L.Map to add double-click zooming. + */ + +L.Handler.DoubleClickZoom = L.Handler.extend({ + enable: function() { + if (this._enabled) { return; } + this._map.on('dblclick', this._onDoubleClick, this._map); + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + this._map.off('dblclick', this._onDoubleClick, this._map); + this._enabled = false; + }, + + _onDoubleClick: function(e) { + this.setView(e.latlng, this._zoom + 1); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/handler/Handler.js b/extlib/leaflet/src/handler/Handler.js new file mode 100644 index 00000000..c38a6b6a --- /dev/null +++ b/extlib/leaflet/src/handler/Handler.js @@ -0,0 +1,13 @@ +/* + * L.Handler classes are used internally to inject interaction features to classes like Map and Marker. + */ + +L.Handler = L.Class.extend({ + initialize: function(map) { + this._map = map; + }, + + enabled: function() { + return !!this._enabled; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/handler/MapDrag.js b/extlib/leaflet/src/handler/MapDrag.js new file mode 100644 index 00000000..1c407269 --- /dev/null +++ b/extlib/leaflet/src/handler/MapDrag.js @@ -0,0 +1,44 @@ +/* + * L.Handler.MapDrag is used internally by L.Map to make the map draggable. + */ + +L.Handler.MapDrag = L.Handler.extend({ + + enable: function() { + if (this._enabled) { return; } + if (!this._draggable) { + this._draggable = new L.Draggable(this._map._mapPane, this._map._container); + + this._draggable.on('dragstart', this._onDragStart, this); + this._draggable.on('drag', this._onDrag, this); + this._draggable.on('dragend', this._onDragEnd, this); + } + this._draggable.enable(); + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + this._draggable.disable(); + this._enabled = false; + }, + + moved: function() { + return this._draggable._moved; + }, + + _onDragStart: function() { + this._map.fire('movestart'); + this._map.fire('dragstart'); + }, + + _onDrag: function() { + this._map.fire('move'); + this._map.fire('drag'); + }, + + _onDragEnd: function() { + this._map.fire('moveend'); + this._map.fire('dragend'); + } +}); diff --git a/extlib/leaflet/src/handler/MarkerDrag.js b/extlib/leaflet/src/handler/MarkerDrag.js new file mode 100644 index 00000000..8e884d50 --- /dev/null +++ b/extlib/leaflet/src/handler/MarkerDrag.js @@ -0,0 +1,54 @@ +/* + * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. + */ + +L.Handler.MarkerDrag = L.Handler.extend({ + initialize: function(marker) { + this._marker = marker; + }, + + enable: function() { + if (this._enabled) { return; } + if (!this._draggable) { + this._draggable = new L.Draggable(this._marker._icon, this._marker._icon); + this._draggable.on('dragstart', this._onDragStart, this); + this._draggable.on('drag', this._onDrag, this); + this._draggable.on('dragend', this._onDragEnd, this); + } + this._draggable.enable(); + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + this._draggable.disable(); + this._enabled = false; + }, + + moved: function() { + return this._draggable && this._draggable._moved; + }, + + _onDragStart: function(e) { + this._marker.closePopup(); + + this._marker.fire('movestart'); + this._marker.fire('dragstart'); + }, + + _onDrag: function(e) { + // update shadow position + var iconPos = L.DomUtil.getPosition(this._marker._icon); + L.DomUtil.setPosition(this._marker._shadow, iconPos); + + this._marker._latlng = this._marker._map.layerPointToLatLng(iconPos); + + this._marker.fire('move'); + this._marker.fire('drag'); + }, + + _onDragEnd: function() { + this._marker.fire('moveend'); + this._marker.fire('dragend'); + } +}); diff --git a/extlib/leaflet/src/handler/ScrollWheelZoom.js b/extlib/leaflet/src/handler/ScrollWheelZoom.js new file mode 100644 index 00000000..dc877e17 --- /dev/null +++ b/extlib/leaflet/src/handler/ScrollWheelZoom.js @@ -0,0 +1,50 @@ +/* + * L.Handler.ScrollWheelZoom is used internally by L.Map to enable mouse scroll wheel zooming on the map. + */ + +L.Handler.ScrollWheelZoom = L.Handler.extend({ + enable: function() { + if (this._enabled) { return; } + L.DomEvent.addListener(this._map._container, 'mousewheel', this._onWheelScroll, this); + this._delta = 0; + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + L.DomEvent.removeListener(this._map._container, 'mousewheel', this._onWheelScroll); + this._enabled = false; + }, + + _onWheelScroll: function(e) { + this._delta += L.DomEvent.getWheelDelta(e); + this._lastMousePos = this._map.mouseEventToContainerPoint(e); + + clearTimeout(this._timer); + this._timer = setTimeout(L.Util.bind(this._performZoom, this), 50); + + L.DomEvent.preventDefault(e); + }, + + _performZoom: function() { + var delta = Math.round(this._delta); + this._delta = 0; + + if (!delta) { return; } + + var center = this._getCenterForScrollWheelZoom(this._lastMousePos, delta), + zoom = this._map.getZoom() + delta; + + if (this._map._limitZoom(zoom) == this._map._zoom) { return; } + + this._map.setView(center, zoom); + }, + + _getCenterForScrollWheelZoom: function(mousePos, delta) { + var centerPoint = this._map.getPixelBounds().getCenter(), + viewHalf = this._map.getSize().divideBy(2), + centerOffset = mousePos.subtract(viewHalf).multiplyBy(1 - Math.pow(2, -delta)), + newCenterPoint = centerPoint.add(centerOffset); + return this._map.unproject(newCenterPoint, this._map._zoom, true); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/handler/ShiftDragZoom.js b/extlib/leaflet/src/handler/ShiftDragZoom.js new file mode 100644 index 00000000..ba216109 --- /dev/null +++ b/extlib/leaflet/src/handler/ShiftDragZoom.js @@ -0,0 +1,79 @@ +/* + * L.Handler.ShiftDragZoom is used internally by L.Map to add shift-drag zoom (zoom to a selected bounding box). + */ + +L.Handler.ShiftDragZoom = L.Handler.extend({ + initialize: function(map) { + this._map = map; + this._container = map._container; + this._pane = map._panes.overlayPane; + }, + + enable: function() { + if (this._enabled) { return; } + + L.DomEvent.addListener(this._container, 'mousedown', this._onMouseDown, this); + + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + + L.DomEvent.removeListener(this._container, 'mousedown', this._onMouseDown); + + this._enabled = false; + }, + + _onMouseDown: function(e) { + if (!e.shiftKey || ((e.which != 1) && (e.button != 1))) { return false; } + + L.DomUtil.disableTextSelection(); + + this._startLayerPoint = this._map.mouseEventToLayerPoint(e); + + this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane); + L.DomUtil.setPosition(this._box, this._startLayerPoint); + + //TODO move cursor to styles + this._container.style.cursor = 'crosshair'; + + L.DomEvent.addListener(document, 'mousemove', this._onMouseMove, this); + L.DomEvent.addListener(document, 'mouseup', this._onMouseUp, this); + + L.DomEvent.preventDefault(e); + }, + + _onMouseMove: function(e) { + var layerPoint = this._map.mouseEventToLayerPoint(e), + dx = layerPoint.x - this._startLayerPoint.x, + dy = layerPoint.y - this._startLayerPoint.y; + + var newX = Math.min(layerPoint.x, this._startLayerPoint.x), + newY = Math.min(layerPoint.y, this._startLayerPoint.y), + newPos = new L.Point(newX, newY); + + L.DomUtil.setPosition(this._box, newPos); + + this._box.style.width = (Math.abs(dx) - 4) + 'px'; + this._box.style.height = (Math.abs(dy) - 4) + 'px'; + }, + + _onMouseUp: function(e) { + this._pane.removeChild(this._box); + this._container.style.cursor = ''; + + L.DomUtil.enableTextSelection(); + + L.DomEvent.removeListener(document, 'mousemove', this._onMouseMove); + L.DomEvent.removeListener(document, 'mouseup', this._onMouseUp); + + var layerPoint = this._map.mouseEventToLayerPoint(e); + + var bounds = new L.LatLngBounds( + this._map.layerPointToLatLng(this._startLayerPoint), + this._map.layerPointToLatLng(layerPoint)); + + this._map.fitBounds(bounds); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/handler/TouchZoom.js b/extlib/leaflet/src/handler/TouchZoom.js new file mode 100644 index 00000000..cc2ec73f --- /dev/null +++ b/extlib/leaflet/src/handler/TouchZoom.js @@ -0,0 +1,87 @@ +/* + * L.Handler.TouchZoom is used internally by L.Map to add touch-zooming on Webkit-powered mobile browsers. + */ + +L.Handler.TouchZoom = L.Handler.extend({ + enable: function() { + if (!L.Browser.mobileWebkit || this._enabled) { return; } + L.DomEvent.addListener(this._map._container, 'touchstart', this._onTouchStart, this); + this._enabled = true; + }, + + disable: function() { + if (!this._enabled) { return; } + L.DomEvent.removeListener(this._map._container, 'touchstart', this._onTouchStart, this); + this._enabled = false; + }, + + _onTouchStart: function(e) { + if (!e.touches || e.touches.length != 2 || this._map._animatingZoom) { return; } + + var p1 = this._map.mouseEventToLayerPoint(e.touches[0]), + p2 = this._map.mouseEventToLayerPoint(e.touches[1]), + viewCenter = this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2)); + + this._startCenter = p1.add(p2).divideBy(2, true); + this._startDist = p1.distanceTo(p2); + //this._startTransform = this._map._mapPane.style.webkitTransform; + + this._moved = false; + this._zooming = true; + + this._centerOffset = viewCenter.subtract(this._startCenter); + + L.DomEvent.addListener(document, 'touchmove', this._onTouchMove, this); + L.DomEvent.addListener(document, 'touchend', this._onTouchEnd, this); + + L.DomEvent.preventDefault(e); + }, + + _onTouchMove: function(e) { + if (!e.touches || e.touches.length != 2) { return; } + + if (!this._moved) { + this._map._mapPane.className += ' leaflet-zoom-anim'; + this._map._prepareTileBg(); + this._moved = true; + } + + var p1 = this._map.mouseEventToLayerPoint(e.touches[0]), + p2 = this._map.mouseEventToLayerPoint(e.touches[1]); + + this._scale = p1.distanceTo(p2) / this._startDist; + this._delta = p1.add(p2).divideBy(2, true).subtract(this._startCenter); + + /* + * Used 2 translates instead of transform-origin because of a very strange bug - + * it didn't count the origin on the first touch-zoom but worked correctly afterwards + */ + this._map._tileBg.style.webkitTransform = [ + L.DomUtil.getTranslateString(this._delta), + L.DomUtil.getScaleString(this._scale, this._startCenter) + ].join(" "); + + L.DomEvent.preventDefault(e); + }, + + _onTouchEnd: function(e) { + if (!this._moved || !this._zooming) { return; } + this._zooming = false; + + var oldZoom = this._map.getZoom(), + floatZoomDelta = Math.log(this._scale)/Math.LN2, + roundZoomDelta = (floatZoomDelta > 0 ? Math.ceil(floatZoomDelta) : Math.floor(floatZoomDelta)), + zoom = this._map._limitZoom(oldZoom + roundZoomDelta), + zoomDelta = zoom - oldZoom, + centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale), + centerPoint = this._map.getPixelOrigin().add(this._startCenter).add(centerOffset), + center = this._map.unproject(centerPoint); + + L.DomEvent.removeListener(document, 'touchmove', this._onTouchMove); + L.DomEvent.removeListener(document, 'touchend', this._onTouchEnd); + + var finalScale = Math.pow(2, zoomDelta); + + this._map._runAnimation(center, zoom, finalScale / this._scale, this._startCenter.add(centerOffset)); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/FeatureGroup.js b/extlib/leaflet/src/layer/FeatureGroup.js new file mode 100644 index 00000000..6e45d84c --- /dev/null +++ b/extlib/leaflet/src/layer/FeatureGroup.js @@ -0,0 +1,40 @@ +/* + * L.FeatureGroup extends L.LayerGroup by introducing mouse events and bindPopup method shared between a group of layers. + */ + +L.FeatureGroup = L.LayerGroup.extend({ + includes: L.Mixin.Events, + + addLayer: function(layer) { + this._initEvents(layer); + L.LayerGroup.prototype.addLayer.call(this, layer); + + if (this._popupContent && layer.bindPopup) { + layer.bindPopup(this._popupContent); + } + }, + + bindPopup: function(content) { + this._popupContent = content; + + for (var i in this._layers) { + if (this._layers.hasOwnProperty(i) && this._layers[i].bindPopup) { + this._layers[i].bindPopup(content); + } + } + }, + + _events: ['click', 'dblclick', 'mouseover', 'mouseout'], + + _initEvents: function(layer) { + for (var i = 0, len = this._events.length; i < len; i++) { + layer.on(this._events[i], this._propagateEvent, this); + } + }, + + _propagateEvent: function(e) { + e.layer = e.target; + e.target = this; + this.fire(e.type, e); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/GeoJSON.js b/extlib/leaflet/src/layer/GeoJSON.js new file mode 100644 index 00000000..6cbd4193 --- /dev/null +++ b/extlib/leaflet/src/layer/GeoJSON.js @@ -0,0 +1,106 @@ + +L.GeoJSON = L.LayerGroup.extend({ + includes: L.Mixin.Events, + + initialize: function(geojson, options) { + L.Util.setOptions(this, options); + this._geojson = geojson; + this._layers = {}; + + if (geojson) { + this.addGeoJSON(geojson); + } + }, + + addGeoJSON: function(geojson) { + if (geojson.features) { + for (var i = 0, len = geojson.features.length; i < len; i++) { + this.addGeoJSON(geojson.features[i]); + } + return; + } + + var isFeature = (geojson.type == 'Feature'), + geometry = (isFeature ? geojson.geometry : geojson), + layer = L.GeoJSON.geometryToLayer(geometry, this.options.pointToLayer); + + this.fire('featureparse', { + layer: layer, + properties: geojson.properties, + geometryType: geometry.type, + bbox: geojson.bbox, + id: geojson.id + }); + + this.addLayer(layer); + } +}); + +L.Util.extend(L.GeoJSON, { + geometryToLayer: function(geometry, pointToLayer) { + var coords = geometry.coordinates, + latlng, latlngs, + i, len, + layer, + layers = []; + + switch (geometry.type) { + case 'Point': + latlng = this.coordsToLatLng(coords); + return pointToLayer ? pointToLayer(latlng) : new L.Marker(latlng); + + case 'MultiPoint': + for (i = 0, len = coords.length; i < len; i++) { + latlng = this.coordsToLatLng(coords[i]); + layer = pointToLayer ? pointToLayer(latlng) : new L.Marker(latlng); + layers.push(layer); + } + return new L.FeatureGroup(layers); + + case 'LineString': + latlngs = this.coordsToLatLngs(coords); + return new L.Polyline(latlngs); + + case 'Polygon': + latlngs = this.coordsToLatLngs(coords, 1); + return new L.Polygon(latlngs); + + case 'MultiLineString': + latlngs = this.coordsToLatLngs(coords, 1); + return new L.MultiPolyline(latlngs); + + case "MultiPolygon": + latlngs = this.coordsToLatLngs(coords, 2); + return new L.MultiPolygon(latlngs); + + case "GeometryCollection": + for (i = 0, len = geometry.geometries.length; i < len; i++) { + layer = this.geometryToLayer(geometry.geometries[i]); + layers.push(layer); + } + return new L.FeatureGroup(layers); + + default: + throw new Error('Invalid GeoJSON object.'); + } + }, + + coordsToLatLng: function(/*Array*/ coords, /*Boolean*/ reverse)/*: LatLng*/ { + var lat = parseFloat(coords[reverse ? 0 : 1]), + lng = parseFloat(coords[reverse ? 1 : 0]); + return new L.LatLng(lat, lng); + }, + + coordsToLatLngs: function(/*Array*/ coords, /*Number*/ levelsDeep, /*Boolean*/ reverse)/*: Array*/ { + var latlng, latlngs = [], + i, len = coords.length; + + for (i = 0; i < len; i++) { + latlng = levelsDeep ? + this.coordsToLatLngs(coords[i], levelsDeep - 1, reverse) : + this.coordsToLatLng(coords[i], reverse); + latlngs.push(latlng); + } + return latlngs; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/ImageOverlay.js b/extlib/leaflet/src/layer/ImageOverlay.js new file mode 100644 index 00000000..4551b2e3 --- /dev/null +++ b/extlib/leaflet/src/layer/ImageOverlay.js @@ -0,0 +1,58 @@ +L.ImageOverlay = L.Class.extend({ + includes: L.Mixin.Events, + + initialize: function(/*String*/ url, /*LatLngBounds*/ bounds) { + this._url = url; + this._bounds = bounds; + }, + + onAdd: function(map) { + this._map = map; + + if (!this._image) { + this._initImage(); + } + + map.getPanes().overlayPane.appendChild(this._image); + + map.on('viewreset', this._reset, this); + this._reset(); + }, + + onRemove: function(map) { + map.getPanes().overlayPane.removeChild(this._image); + map.off('viewreset', this._reset, this); + }, + + _initImage: function() { + this._image = L.DomUtil.create('img', 'leaflet-image-layer'); + + this._image.style.visibility = 'hidden'; + //TODO opacity option + + //TODO createImage util method to remove duplication + L.Util.extend(this._image, { + galleryimg: 'no', + onselectstart: L.Util.falseFn, + onmousemove: L.Util.falseFn, + onload: this._onImageLoad, + src: this._url + }); + }, + + _reset: function() { + var topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), + bottomRight = this._map.latLngToLayerPoint(this._bounds.getSouthEast()), + size = bottomRight.subtract(topLeft); + + L.DomUtil.setPosition(this._image, topLeft); + + this._image.style.width = size.x + 'px'; + this._image.style.height = size.y + 'px'; + }, + + _onImageLoad: function() { + this.style.visibility = ''; + //TODO fire layerload + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/LayerGroup.js b/extlib/leaflet/src/layer/LayerGroup.js new file mode 100644 index 00000000..58940d40 --- /dev/null +++ b/extlib/leaflet/src/layer/LayerGroup.js @@ -0,0 +1,58 @@ +/* + * L.LayerGroup is a class to combine several layers so you can manipulate the group (e.g. add/remove it) as one layer. + */ + +L.LayerGroup = L.Class.extend({ + initialize: function(layers) { + this._layers = {}; + + if (layers) { + for (var i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + } + }, + + addLayer: function(layer) { + var id = L.Util.stamp(layer); + this._layers[id] = layer; + + if (this._map) { + this._map.addLayer(layer); + } + return this; + }, + + removeLayer: function(layer) { + var id = L.Util.stamp(layer); + delete this._layers[id]; + + if (this._map) { + this._map.removeLayer(layer); + } + return this; + }, + + clearLayers: function() { + this._iterateLayers(this.removeLayer, this); + return this; + }, + + onAdd: function(map) { + this._map = map; + this._iterateLayers(map.addLayer, map); + }, + + onRemove: function(map) { + this._iterateLayers(map.removeLayer, map); + delete this._map; + }, + + _iterateLayers: function(method, context) { + for (var i in this._layers) { + if (this._layers.hasOwnProperty(i)) { + method.call(context, this._layers[i]); + } + } + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/Popup.js b/extlib/leaflet/src/layer/Popup.js new file mode 100644 index 00000000..4cb14e3c --- /dev/null +++ b/extlib/leaflet/src/layer/Popup.js @@ -0,0 +1,165 @@ + +L.Popup = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + maxWidth: 300, + autoPan: true, + closeButton: true, + + offset: new L.Point(0, 2), + autoPanPadding: new L.Point(5, 5) + }, + + initialize: function(options) { + L.Util.setOptions(this, options); + }, + + onAdd: function(map) { + this._map = map; + if (!this._container) { + this._initLayout(); + } + this._updateContent(); + + this._container.style.opacity = '0'; + + this._map._panes.popupPane.appendChild(this._container); + this._map.on('viewreset', this._updatePosition, this); + if (this._map.options.closePopupOnClick) { + this._map.on('preclick', this._close, this); + } + this._update(); + + this._container.style.opacity = '1'; //TODO fix ugly opacity hack + + this._opened = true; + }, + + onRemove: function(map) { + map._panes.popupPane.removeChild(this._container); + map.off('viewreset', this._updatePosition, this); + map.off('click', this._close, this); + + this._container.style.opacity = '0'; + + this._opened = false; + }, + + setLatLng: function(latlng) { + this._latlng = latlng; + if (this._opened) { + this._update(); + } + return this; + }, + + setContent: function(content) { + this._content = content; + if (this._opened) { + this._update(); + } + return this; + }, + + _close: function() { + if (this._opened) { + this._map.removeLayer(this); + } + }, + + _initLayout: function() { + this._container = L.DomUtil.create('div', 'leaflet-popup'); + + this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container); + this._closeButton.href = '#close'; + this._closeButton.onclick = L.Util.bind(this._onCloseButtonClick, this); + + this._wrapper = L.DomUtil.create('div', 'leaflet-popup-content-wrapper', this._container); + L.DomEvent.disableClickPropagation(this._wrapper); + this._contentNode = L.DomUtil.create('div', 'leaflet-popup-content', this._wrapper); + + this._tipContainer = L.DomUtil.create('div', 'leaflet-popup-tip-container', this._container); + this._tip = L.DomUtil.create('div', 'leaflet-popup-tip', this._tipContainer); + }, + + _update: function() { + this._container.style.visibility = 'hidden'; + + this._updateContent(); + this._updateLayout(); + this._updatePosition(); + + this._container.style.visibility = ''; + + this._adjustPan(); + }, + + _updateContent: function() { + if (!this._content) return; + + if (typeof this._content == 'string') { + this._contentNode.innerHTML = this._content; + } else { + this._contentNode.innerHTML = ''; + this._contentNode.appendChild(this._content); + } + }, + + _updateLayout: function() { + this._container.style.width = ''; + this._container.style.whiteSpace = 'nowrap'; + + var width = this._container.offsetWidth; + + this._container.style.width = (width > this.options.maxWidth ? this.options.maxWidth : width) + 'px'; + this._container.style.whiteSpace = ''; + + this._containerWidth = this._container.offsetWidth; + }, + + _updatePosition: function() { + var pos = this._map.latLngToLayerPoint(this._latlng); + + this._containerBottom = -pos.y - this.options.offset.y; + this._containerLeft = pos.x - Math.round(this._containerWidth/2) + this.options.offset.x; + + this._container.style.bottom = this._containerBottom + 'px'; + this._container.style.left = this._containerLeft + 'px'; + }, + + _adjustPan: function() { + if (!this.options.autoPan) { return; } + + var containerHeight = this._container.offsetHeight, + layerPos = new L.Point( + this._containerLeft, + -containerHeight - this._containerBottom), + containerPos = this._map.layerPointToContainerPoint(layerPos), + adjustOffset = new L.Point(0, 0), + padding = this.options.autoPanPadding, + size = this._map.getSize(); + + if (containerPos.x < 0) { + adjustOffset.x = containerPos.x - padding.x; + } + if (containerPos.x + this._containerWidth > size.x) { + adjustOffset.x = containerPos.x + this._containerWidth - size.x + padding.x; + } + if (containerPos.y < 0) { + adjustOffset.y = containerPos.y - padding.y; + } + if (containerPos.y + containerHeight > size.y) { + adjustOffset.y = containerPos.y + containerHeight - size.y + padding.y; + } + + if (adjustOffset.x || adjustOffset.y) { + this._map.panBy(adjustOffset); + } + }, + + _onCloseButtonClick: function(e) { + this._close(); + L.DomEvent.stop(e); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/marker/Icon.js b/extlib/leaflet/src/layer/marker/Icon.js new file mode 100644 index 00000000..6df036e4 --- /dev/null +++ b/extlib/leaflet/src/layer/marker/Icon.js @@ -0,0 +1,56 @@ +L.Icon = L.Class.extend({ + iconUrl: L.ROOT_URL + 'images/marker.png', + shadowUrl: L.ROOT_URL + 'images/marker-shadow.png', + + iconSize: new L.Point(25, 41), + shadowSize: new L.Point(41, 41), + + iconAnchor: new L.Point(13, 41), + popupAnchor: new L.Point(0, -33), + + initialize: function(iconUrl) { + if (iconUrl) { + this.iconUrl = iconUrl; + } + }, + + createIcon: function() { + return this._createIcon('icon'); + }, + + createShadow: function() { + return this._createIcon('shadow'); + }, + + _createIcon: function(name) { + var size = this[name + 'Size'], + src = this[name + 'Url'], + img = this._createImg(src); + + if (!src) { return null; } + + img.className = 'leaflet-marker-' + name; + + img.style.marginLeft = (-this.iconAnchor.x) + 'px'; + img.style.marginTop = (-this.iconAnchor.y) + 'px'; + + if (size) { + img.style.width = size.x + 'px'; + img.style.height = size.y + 'px'; + } + + return img; + }, + + _createImg: function(src) { + var el; + if (!L.Browser.ie6) { + el = document.createElement('img'); + el.src = src; + } else { + el = document.createElement('div'); + el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; + } + return el; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/marker/Marker.Popup.js b/extlib/leaflet/src/layer/marker/Marker.Popup.js new file mode 100644 index 00000000..4c5cad04 --- /dev/null +++ b/extlib/leaflet/src/layer/marker/Marker.Popup.js @@ -0,0 +1,28 @@ +/* + * Popup extension to L.Marker, adding openPopup & bindPopup methods. + */ + +L.Marker.include({ + openPopup: function() { + this._popup.setLatLng(this._latlng); + this._map.openPopup(this._popup); + + return this; + }, + + closePopup: function() { + if (this._popup) { + this._popup._close(); + } + }, + + bindPopup: function(content, options) { + options = L.Util.extend({offset: this.options.icon.popupAnchor}, options); + + this._popup = new L.Popup(options); + this._popup.setContent(content); + this.on('click', this.openPopup, this); + + return this; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/marker/Marker.js b/extlib/leaflet/src/layer/marker/Marker.js new file mode 100644 index 00000000..b98bec4e --- /dev/null +++ b/extlib/leaflet/src/layer/marker/Marker.js @@ -0,0 +1,123 @@ +/* + * L.Marker is used to display clickable/draggable icons on the map. + */ + +L.Marker = L.Class.extend({ + + includes: L.Mixin.Events, + + options: { + icon: new L.Icon(), + title: '', + clickable: true, + draggable: false + }, + + initialize: function(latlng, options) { + L.Util.setOptions(this, options); + this._latlng = latlng; + }, + + onAdd: function(map) { + this._map = map; + + this._initIcon(); + + map.on('viewreset', this._reset, this); + this._reset(); + }, + + onRemove: function(map) { + this._removeIcon(); + + map.off('viewreset', this._reset, this); + }, + + getLatLng: function() { + return this._latlng; + }, + + setLatLng: function(latlng) { + this._latlng = latlng; + this._reset(); + }, + + setIcon: function(icon) { + this._removeIcon(); + + this._icon = this._shadow = null; + this.options.icon = icon; + + this._initIcon(); + }, + + _initIcon: function() { + if (!this._icon) { + this._icon = this.options.icon.createIcon(); + + if (this.options.title) { + this._icon.title = this.options.title; + } + + this._initInteraction(); + } + if (!this._shadow) { + this._shadow = this.options.icon.createShadow(); + } + + this._map._panes.markerPane.appendChild(this._icon); + if (this._shadow) { + this._map._panes.shadowPane.appendChild(this._shadow); + } + }, + + _removeIcon: function() { + this._map._panes.markerPane.removeChild(this._icon); + if (this._shadow) { + this._map._panes.shadowPane.removeChild(this._shadow); + } + }, + + _reset: function() { + var pos = this._map.latLngToLayerPoint(this._latlng).round(); + + L.DomUtil.setPosition(this._icon, pos); + if (this._shadow) { + L.DomUtil.setPosition(this._shadow, pos); + } + + this._icon.style.zIndex = pos.y; + }, + + _initInteraction: function() { + if (this.options.clickable) { + this._icon.className += ' leaflet-clickable'; + + L.DomEvent.addListener(this._icon, 'click', this._onMouseClick, this); + + var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout']; + for (var i = 0; i < events.length; i++) { + L.DomEvent.addListener(this._icon, events[i], this._fireMouseEvent, this); + } + } + + if (L.Handler.MarkerDrag) { + this.dragging = new L.Handler.MarkerDrag(this); + + if (this.options.draggable) { + this.dragging.enable(); + } + } + }, + + _onMouseClick: function(e) { + L.DomEvent.stopPropagation(e); + if (this.dragging && this.dragging.moved()) { return; } + this.fire(e.type); + }, + + _fireMouseEvent: function(e) { + this.fire(e.type); + L.DomEvent.stopPropagation(e); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/tile/TileLayer.Canvas.js b/extlib/leaflet/src/layer/tile/TileLayer.Canvas.js new file mode 100644 index 00000000..08bbaae2 --- /dev/null +++ b/extlib/leaflet/src/layer/tile/TileLayer.Canvas.js @@ -0,0 +1,41 @@ +L.TileLayer.Canvas = L.TileLayer.extend({ + options: { + async: false + }, + + initialize: function(options) { + L.Util.setOptions(this, options); + }, + + _createTileProto: function() { + this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); + + var tileSize = this.options.tileSize; + this._canvasProto.width = tileSize; + this._canvasProto.height = tileSize; + }, + + _createTile: function() { + var tile = this._canvasProto.cloneNode(false); + tile.onselectstart = tile.onmousemove = L.Util.falseFn; + return tile; + }, + + _loadTile: function(tile, tilePoint, zoom) { + tile._layer = this; + + this.drawTile(tile, tilePoint, zoom); + + if (!this.options.async) { + this.tileDrawn(tile); + } + }, + + drawTile: function(tile, tilePoint, zoom) { + // override with rendering code + }, + + tileDrawn: function(tile) { + this._tileOnLoad.call(tile); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/tile/TileLayer.WMS.js b/extlib/leaflet/src/layer/tile/TileLayer.WMS.js new file mode 100644 index 00000000..2f4ad05a --- /dev/null +++ b/extlib/leaflet/src/layer/tile/TileLayer.WMS.js @@ -0,0 +1,47 @@ +L.TileLayer.WMS = L.TileLayer.extend({ + defaultWmsParams: { + service: 'WMS', + request: 'GetMap', + version: '1.1.1', + layers: '', + styles: '', + format: 'image/jpeg', + transparent: false + }, + + initialize: function(/*String*/ url, /*Object*/ options) { + this._url = url; + + this.wmsParams = L.Util.extend({}, this.defaultWmsParams); + this.wmsParams.width = this.wmsParams.height = this.options.tileSize; + + for (var i in options) { + // all keys that are not TileLayer options go to WMS params + if (!this.options.hasOwnProperty(i)) { + this.wmsParams[i] = options[i]; + } + } + + L.Util.setOptions(this, options); + }, + + onAdd: function(map) { + var projectionKey = (parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs'); + this.wmsParams[projectionKey] = map.options.crs.code; + + L.TileLayer.prototype.onAdd.call(this, map); + }, + + getTileUrl: function(/*Point*/ tilePoint, /*Number*/ zoom)/*-> String*/ { + var tileSize = this.options.tileSize, + nwPoint = tilePoint.multiplyBy(tileSize), + sePoint = nwPoint.add(new L.Point(tileSize, tileSize)), + nwMap = this._map.unproject(nwPoint, this._zoom, true), + seMap = this._map.unproject(sePoint, this._zoom, true), + nw = this._map.options.crs.project(nwMap), + se = this._map.options.crs.project(seMap), + bbox = [nw.x, se.y, se.x, nw.y].join(','); + + return this._url + L.Util.getParamString(this.wmsParams) + "&bbox=" + bbox; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/tile/TileLayer.js b/extlib/leaflet/src/layer/tile/TileLayer.js new file mode 100644 index 00000000..68072ee9 --- /dev/null +++ b/extlib/leaflet/src/layer/tile/TileLayer.js @@ -0,0 +1,262 @@ +/* + * L.TileLayer is used for standard xyz-numbered tile layers. + */ + +L.TileLayer = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + minZoom: 0, + maxZoom: 18, + tileSize: 256, + subdomains: 'abc', + errorTileUrl: '', + attribution: '', + opacity: 1, + scheme: 'xyz', + noWrap: false, + + unloadInvisibleTiles: L.Browser.mobileWebkit, + updateWhenIdle: L.Browser.mobileWebkit + }, + + initialize: function(url, options) { + L.Util.setOptions(this, options); + + this._url = url; + + if (typeof this.options.subdomains == 'string') { + this.options.subdomains = this.options.subdomains.split(''); + } + }, + + onAdd: function(map) { + this._map = map; + + // create a container div for tiles + this._initContainer(); + + // create an image to clone for tiles + this._createTileProto(); + + // set up events + map.on('viewreset', this._reset, this); + + if (this.options.updateWhenIdle) { + map.on('moveend', this._update, this); + } else { + this._limitedUpdate = L.Util.limitExecByInterval(this._update, 100, this); + map.on('move', this._limitedUpdate, this); + } + + this._reset(); + this._update(); + }, + + onRemove: function(map) { + this._map.getPanes().tilePane.removeChild(this._container); + this._container = null; + + this._map.off('viewreset', this._reset, this); + + if (this.options.updateWhenIdle) { + this._map.off('moveend', this._update, this); + } else { + this._map.off('move', this._limitedUpdate, this); + } + }, + + getAttribution: function() { + return this.options.attribution; + }, + + setOpacity: function(opacity) { + this.options.opacity = opacity; + + this._setOpacity(opacity); + + // stupid webkit hack to force redrawing of tiles + if (L.Browser.webkit) { + for (i in this._tiles) { + this._tiles[i].style.webkitTransform += ' translate(0,0)'; + } + } + }, + + _setOpacity: function(opacity) { + if (opacity < 1) { + L.DomUtil.setOpacity(this._container, opacity); + } + }, + + _initContainer: function() { + var tilePane = this._map.getPanes().tilePane; + + if (!this._container || tilePane.empty) { + this._container = L.DomUtil.create('div', 'leaflet-layer', tilePane); + + this._setOpacity(this.options.opacity); + } + }, + + _reset: function() { + this._tiles = {}; + this._initContainer(); + this._container.innerHTML = ''; + }, + + _update: function() { + var bounds = this._map.getPixelBounds(), + tileSize = this.options.tileSize; + + var nwTilePoint = new L.Point( + Math.floor(bounds.min.x / tileSize), + Math.floor(bounds.min.y / tileSize)), + seTilePoint = new L.Point( + Math.floor(bounds.max.x / tileSize), + Math.floor(bounds.max.y / tileSize)), + tileBounds = new L.Bounds(nwTilePoint, seTilePoint); + + this._addTilesFromCenterOut(tileBounds); + + if (this.options.unloadInvisibleTiles) { + this._removeOtherTiles(tileBounds); + } + }, + + _addTilesFromCenterOut: function(bounds) { + var queue = [], + center = bounds.getCenter(); + + for (var j = bounds.min.y; j <= bounds.max.y; j++) { + for (var i = bounds.min.x; i <= bounds.max.x; i++) { + if ((i + ':' + j) in this._tiles) { continue; } + queue.push(new L.Point(i, j)); + } + } + + // load tiles in order of their distance to center + queue.sort(function(a, b) { + return a.distanceTo(center) - b.distanceTo(center); + }); + + this._tilesToLoad = queue.length; + for (var k = 0, len = this._tilesToLoad; k < len; k++) { + this._addTile(queue[k]); + } + }, + + _removeOtherTiles: function(bounds) { + var kArr, x, y, key; + + for (key in this._tiles) { + if (this._tiles.hasOwnProperty(key)) { + kArr = key.split(':'); + x = parseInt(kArr[0], 10); + y = parseInt(kArr[1], 10); + + // remove tile if it's out of bounds + if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { + this._tiles[key].src = ''; + if (this._tiles[key].parentNode == this._container) { + this._container.removeChild(this._tiles[key]); + } + delete this._tiles[key]; + } + } + } + }, + + _addTile: function(tilePoint) { + var tilePos = this._getTilePos(tilePoint), + zoom = this._map.getZoom(), + key = tilePoint.x + ':' + tilePoint.y; + + // wrap tile coordinates + var tileLimit = (1 << zoom); + if (!this.options.noWrap) { + tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit; + } + if (tilePoint.y < 0 || tilePoint.y >= tileLimit) { return; } + + // create tile + var tile = this._createTile(); + L.DomUtil.setPosition(tile, tilePos); + + this._tiles[key] = tile; + + if (this.options.scheme == 'tms') { + tilePoint.y = tileLimit - tilePoint.y - 1; + } + + this._loadTile(tile, tilePoint, zoom); + + this._container.appendChild(tile); + }, + + _getTilePos: function(tilePoint) { + var origin = this._map.getPixelOrigin(), + tileSize = this.options.tileSize; + + return tilePoint.multiplyBy(tileSize).subtract(origin); + }, + + // image-specific code (override to implement e.g. Canvas or SVG tile layer) + + getTileUrl: function(tilePoint, zoom) { + var subdomains = this.options.subdomains, + s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length]; + + return this._url + .replace('{s}', s) + .replace('{z}', zoom) + .replace('{x}', tilePoint.x) + .replace('{y}', tilePoint.y); + }, + + _createTileProto: function() { + this._tileImg = L.DomUtil.create('img', 'leaflet-tile'); + this._tileImg.galleryimg = 'no'; + + var tileSize = this.options.tileSize; + this._tileImg.style.width = tileSize + 'px'; + this._tileImg.style.height = tileSize + 'px'; + }, + + _createTile: function() { + var tile = this._tileImg.cloneNode(false); + tile.onselectstart = tile.onmousemove = L.Util.falseFn; + return tile; + }, + + _loadTile: function(tile, tilePoint, zoom) { + tile._layer = this; + tile.onload = this._tileOnLoad; + tile.onerror = this._tileOnError; + tile.src = this.getTileUrl(tilePoint, zoom); + }, + + _tileOnLoad: function(e) { + var layer = this._layer; + + this.className += ' leaflet-tile-loaded'; + + layer.fire('tileload', {tile: this, url: this.src}); + + layer._tilesToLoad--; + if (!layer._tilesToLoad) { + layer.fire('load'); + } + }, + + _tileOnError: function(e) { + var layer = this._layer; + + layer.fire('tileerror', {tile: this, url: this.src}); + + var newUrl = layer.options.errorTileUrl; + if (newUrl) { + this.src = newUrl; + } + } +}); diff --git a/extlib/leaflet/src/layer/vector/Circle.js b/extlib/leaflet/src/layer/vector/Circle.js new file mode 100644 index 00000000..c737c191 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Circle.js @@ -0,0 +1,51 @@ +/* + * L.Circle is a circle overlay (with a certain radius in meters). + */ + +L.Circle = L.Path.extend({ + initialize: function(latlng, radius, options) { + L.Path.prototype.initialize.call(this, options); + + this._latlng = latlng; + this._mRadius = radius; + }, + + options: { + fill: true + }, + + setLatLng: function(latlng) { + this._latlng = latlng; + this._redraw(); + return this; + }, + + setRadius: function(radius) { + this._mRadius = radius; + this._redraw(); + return this; + }, + + projectLatlngs: function() { + var equatorLength = 40075017, + scale = this._map.options.scale(this._map._zoom); + + this._point = this._map.latLngToLayerPoint(this._latlng); + this._radius = (this._mRadius / equatorLength) * scale; + }, + + getPathString: function() { + var p = this._point, + r = this._radius; + + if (L.Path.SVG) { + return "M" + p.x + "," + (p.y - r) + + "A" + r + "," + r + ",0,1,1," + + (p.x - 0.1) + "," + (p.y - r) + " z"; + } else { + p._round(); + r = Math.round(r); + return "AL " + p.x + "," + p.y + " " + r + "," + r + " 0," + (65535 * 360); + } + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/CircleMarker.js b/extlib/leaflet/src/layer/vector/CircleMarker.js new file mode 100644 index 00000000..fa4bacf0 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/CircleMarker.js @@ -0,0 +1,25 @@ +/* + * L.CircleMarker is a circle overlay with a permanent pixel radius. + */ + +L.CircleMarker = L.Circle.extend({ + options: { + radius: 10, + weight: 2 + }, + + initialize: function(latlng, options) { + L.Circle.prototype.initialize.call(this, latlng, null, options); + this._radius = this.options.radius; + }, + + projectLatlngs: function() { + this._point = this._map.latLngToLayerPoint(this._latlng); + }, + + setRadius: function(radius) { + this._radius = radius; + this._redraw(); + return this; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/MultiPoly.js b/extlib/leaflet/src/layer/vector/MultiPoly.js new file mode 100644 index 00000000..60d6de68 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/MultiPoly.js @@ -0,0 +1,27 @@ +/* + * Contains L.MultiPolyline and L.MultiPolygon layers. + */ + +(function() { + function createMulti(klass) { + return L.FeatureGroup.extend({ + initialize: function(latlngs, options) { + this._layers = {}; + for (var i = 0, len = latlngs.length; i < len; i++) { + this.addLayer(new klass(latlngs[i], options)); + } + }, + + setStyle: function(style) { + for (var i in this._layers) { + if (this._layers.hasOwnProperty(i) && this._layers[i].setStyle) { + this._layers[i].setStyle(style); + } + } + } + }); + } + + L.MultiPolyline = createMulti(L.Polyline); + L.MultiPolygon = createMulti(L.Polygon); +}()); diff --git a/extlib/leaflet/src/layer/vector/Path.Popup.js b/extlib/leaflet/src/layer/vector/Path.Popup.js new file mode 100644 index 00000000..b82a4920 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Path.Popup.js @@ -0,0 +1,24 @@ +/* + * Popup extension to L.Path (polylines, polygons, circles), adding bindPopup method. + */ + +L.Path.include({ + bindPopup: function(content, options) { + if (!this._popup || this._popup.options !== options) { + this._popup = new L.Popup(options); + } + this._popup.setContent(content); + + if (!this._openPopupAdded) { + this.on('click', this._openPopup, this); + this._openPopupAdded = true; + } + + return this; + }, + + _openPopup: function(e) { + this._popup.setLatLng(e.latlng); + this._map.openPopup(this._popup); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/Path.VML.js b/extlib/leaflet/src/layer/vector/Path.VML.js new file mode 100644 index 00000000..8481d994 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Path.VML.js @@ -0,0 +1,91 @@ +/* + * Vector rendering for IE6-8 through VML. + * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! + */ + +L.Path.VML = (function() { + var d = document.createElement('div'), s; + d.innerHTML = ''; + s = d.firstChild; + s.style.behavior = 'url(#default#VML)'; + + return (s && (typeof s.adj == 'object')); +})(); + +L.Path = L.Path.SVG || !L.Path.VML ? L.Path : L.Path.extend({ + statics: { + CLIP_PADDING: 0.02 + }, + + _createElement: (function() { + try { + document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); + return function(name) { + return document.createElement(''); + }; + } catch (e) { + return function(name) { + return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); + }; + } + })(), + + _initRoot: function() { + if (!this._map._pathRoot) { + this._map._pathRoot = document.createElement('div'); + this._map._pathRoot.className = 'leaflet-vml-container'; + this._map._panes.overlayPane.appendChild(this._map._pathRoot); + + this._map.on('moveend', this._updateViewport, this); + this._updateViewport(); + } + }, + + _initPath: function() { + this._container = this._createElement('shape'); + this._container.className += ' leaflet-vml-shape' + + (this.options.clickable ? ' leaflet-clickable' : ''); + this._container.coordsize = '1 1'; + + this._path = this._createElement('path'); + this._container.appendChild(this._path); + + this._map._pathRoot.appendChild(this._container); + }, + + _initStyle: function() { + if (this.options.stroke) { + this._stroke = this._createElement('stroke'); + this._stroke.endcap = 'round'; + this._container.appendChild(this._stroke); + } else { + this._container.stroked = false; + } + if (this.options.fill) { + this._container.filled = true; + this._fill = this._createElement('fill'); + this._container.appendChild(this._fill); + } else { + this._container.filled = false; + } + this._updateStyle(); + }, + + _updateStyle: function() { + if (this.options.stroke) { + this._stroke.weight = this.options.weight + 'px'; + this._stroke.color = this.options.color; + this._stroke.opacity = this.options.opacity; + } + if (this.options.fill) { + this._fill.color = this.options.fillColor || this.options.color; + this._fill.opacity = this.options.fillOpacity; + } + }, + + _updatePath: function() { + this._container.style.display = 'none'; + this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug + this._container.style.display = ''; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/Path.js b/extlib/leaflet/src/layer/vector/Path.js new file mode 100644 index 00000000..3d4837cc --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Path.js @@ -0,0 +1,207 @@ +/* + * L.Path is a base class for rendering vector paths on a map. It's inherited by Polyline, Circle, etc. + */ + +L.Path = L.Class.extend({ + includes: [L.Mixin.Events], + + statics: (function() { + var svgns = 'http://www.w3.org/2000/svg', + ce = 'createElementNS'; + + return { + SVG_NS: svgns, + SVG: !!(document[ce] && document[ce](svgns, 'svg').createSVGRect), + + // how much to extend the clip area around the map view + // (relative to its size, e.g. 0.5 is half the screen in each direction) + CLIP_PADDING: 0.5 + }; + })(), + + options: { + stroke: true, + color: '#0033ff', + weight: 5, + opacity: 0.5, + + fill: false, + fillColor: null, //same as color by default + fillOpacity: 0.2, + + clickable: true, + + updateOnMoveEnd: false + }, + + initialize: function(options) { + L.Util.setOptions(this, options); + }, + + onAdd: function(map) { + this._map = map; + + this._initElements(); + this._initEvents(); + this.projectLatlngs(); + this._updatePath(); + + map.on('viewreset', this.projectLatlngs, this); + + this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset'; + map.on(this._updateTrigger, this._updatePath, this); + }, + + onRemove: function(map) { + map._pathRoot.removeChild(this._container); + map.off('viewreset', this._projectLatlngs, this); + map.off(this._updateTrigger, this._updatePath, this); + }, + + projectLatlngs: function() { + // do all projection stuff here + }, + + getPathString: function() { + // form path string here + }, + + setStyle: function(style) { + L.Util.setOptions(this, style); + if (this._path) { + this._updateStyle(); + } + }, + + _initElements: function() { + this._initRoot(); + this._initPath(); + this._initStyle(); + }, + + _initRoot: function() { + if (!this._map._pathRoot) { + this._map._pathRoot = this._createElement('svg'); + this._map._panes.overlayPane.appendChild(this._map._pathRoot); + + this._map.on('moveend', this._updateSvgViewport, this); + this._updateSvgViewport(); + } + }, + + _updateSvgViewport: function() { + this._updateViewport(); + + var vp = this._map._pathViewport, + min = vp.min, + max = vp.max, + width = max.x - min.x, + height = max.y - min.y, + root = this._map._pathRoot, + pane = this._map._panes.overlayPane; + + // Hack to make flicker on drag end on mobile webkit less irritating + // Unfortunately I haven't found a good workaround for this yet + if (L.Browser.mobileWebkit) { pane.removeChild(root); } + + L.DomUtil.setPosition(root, min); + root.setAttribute('width', width); + root.setAttribute('height', height); + root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); + + if (L.Browser.mobileWebkit) { pane.appendChild(root); } + }, + + _updateViewport: function() { + var p = L.Path.CLIP_PADDING, + size = this._map.getSize(), + //TODO this._map._getMapPanePos() + panePos = L.DomUtil.getPosition(this._map._mapPane), + min = panePos.multiplyBy(-1).subtract(size.multiplyBy(p)), + max = min.add(size.multiplyBy(1 + p * 2)); + + this._map._pathViewport = new L.Bounds(min, max); + }, + + _initPath: function() { + this._container = this._createElement('g'); + + this._path = this._createElement('path'); + this._container.appendChild(this._path); + + this._map._pathRoot.appendChild(this._container); + }, + + _initStyle: function() { + if (this.options.stroke) { + this._path.setAttribute('stroke-linejoin', 'round'); + this._path.setAttribute('stroke-linecap', 'round'); + } + if (this.options.fill) { + this._path.setAttribute('fill-rule', 'evenodd'); + } else { + this._path.setAttribute('fill', 'none'); + } + this._updateStyle(); + }, + + _updateStyle: function() { + if (this.options.stroke) { + this._path.setAttribute('stroke', this.options.color); + this._path.setAttribute('stroke-opacity', this.options.opacity); + this._path.setAttribute('stroke-width', this.options.weight); + } + if (this.options.fill) { + this._path.setAttribute('fill', this.options.fillColor || this.options.color); + this._path.setAttribute('fill-opacity', this.options.fillOpacity); + } + }, + + _updatePath: function() { + var str = this.getPathString(); + if (!str) { + // fix webkit empty string parsing bug + str = 'M0 0'; + } + this._path.setAttribute('d', str); + }, + + _createElement: function(name) { + return document.createElementNS(L.Path.SVG_NS, name); + }, + + // TODO remove duplication with L.Map + _initEvents: function() { + if (this.options.clickable) { + if (!L.Path.VML) { + this._path.setAttribute('class', 'leaflet-clickable'); + } + + L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this); + + var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout']; + for (var i = 0; i < events.length; i++) { + L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this); + } + } + }, + + _onMouseClick: function(e) { + if (this._map.dragging && this._map.dragging.moved()) { return; } + this._fireMouseEvent(e); + }, + + _fireMouseEvent: function(e) { + if (!this.hasEventListeners(e.type)) { return; } + this.fire(e.type, { + latlng: this._map.mouseEventToLatLng(e), + layerPoint: this._map.mouseEventToLayerPoint(e) + }); + L.DomEvent.stopPropagation(e); + }, + + _redraw: function() { + this.projectLatlngs(); + this._updatePath(); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/Polygon.js b/extlib/leaflet/src/layer/vector/Polygon.js new file mode 100644 index 00000000..52bf2d6b --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Polygon.js @@ -0,0 +1,58 @@ +/* + * L.Polygon is used to display polygons on a map. + */ + +L.Polygon = L.Polyline.extend({ + options: { + fill: true + }, + + initialize: function(latlngs, options) { + L.Polyline.prototype.initialize.call(this, latlngs, options); + + if (latlngs[0] instanceof Array) { + this._latlngs = latlngs[0]; + this._holes = latlngs.slice(1); + } + }, + + projectLatlngs: function() { + L.Polyline.prototype.projectLatlngs.call(this); + + // project polygon holes points + // TODO move this logic to Polyline to get rid of duplication + this._holePoints = []; + + if (!this._holes) return; + + for (var i = 0, len = this._holes.length, hole; i < len; i++) { + this._holePoints[i] = []; + + for(var j = 0, len2 = this._holes[i].length; j < len2; j++) { + this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]); + } + } + }, + + _clipPoints: function() { + var points = this._originalPoints, + newParts = []; + + this._parts = [points].concat(this._holePoints); + + if (this.options.noClip) return; + + for (var i = 0, len = this._parts.length; i < len; i++) { + var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport); + if (!clipped.length) continue; + newParts.push(clipped); + } + + this._parts = newParts; + }, + + _getPathPartStr: function(points) { + var str = L.Polyline.prototype._getPathPartStr.call(this, points); + return str + (L.Path.SVG ? 'z' : 'x'); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/layer/vector/Polyline.js b/extlib/leaflet/src/layer/vector/Polyline.js new file mode 100644 index 00000000..606d7d71 --- /dev/null +++ b/extlib/leaflet/src/layer/vector/Polyline.js @@ -0,0 +1,112 @@ + +L.Polyline = L.Path.extend({ + initialize: function(latlngs, options) { + L.Path.prototype.initialize.call(this, options); + this._latlngs = latlngs; + }, + + options: { + // how much to simplify the polyline on each zoom level + // more = better performance and smoother look, less = more accurate + smoothFactor: 1.0, + noClip: false, + + updateOnMoveEnd: true + }, + + projectLatlngs: function() { + this._originalPoints = []; + + for (var i = 0, len = this._latlngs.length; i < len; i++) { + this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]); + } + }, + + getPathString: function() { + for (var i = 0, len = this._parts.length, str = ''; i < len; i++) { + str += this._getPathPartStr(this._parts[i]); + } + return str; + }, + + getLatLngs: function() { + return this._latlngs; + }, + + setLatLngs: function(latlngs) { + this._latlngs = latlngs; + this._redraw(); + return this; + }, + + addLatLng: function(latlng) { + this._latlngs.push(latlng); + this._redraw(); + return this; + }, + + spliceLatLngs: function(index, howMany) { + var removed = [].splice.apply(this._latlngs, arguments); + this._redraw(); + return removed; + }, + + _getPathPartStr: function(points) { + var round = L.Path.VML; + + for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) { + p = points[j]; + if (round) p._round(); + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; + } + return str; + }, + + _clipPoints: function() { + var points = this._originalPoints, + len = points.length, + i, k, segment; + + if (this.options.noClip) { + this._parts = [points]; + return; + } + + this._parts = []; + + var parts = this._parts, + vp = this._map._pathViewport, + lu = L.LineUtil; + + for (i = 0, k = 0; i < len - 1; i++) { + segment = lu.clipSegment(points[i], points[i+1], vp, i); + if (!segment) continue; + + parts[k] = parts[k] || []; + parts[k].push(segment[0]); + + // if segment goes out of screen, or it's the last one, it's the end of the line part + if ((segment[1] != points[i+1]) || (i == len - 2)) { + parts[k].push(segment[1]); + k++; + } + } + }, + + // simplify each clipped part of the polyline + _simplifyPoints: function() { + var parts = this._parts, + lu = L.LineUtil; + + for (var i = 0, len = parts.length; i < len; i++) { + parts[i] = lu.simplify(parts[i], this.options.smoothFactor); + } + }, + + _updatePath: function() { + this._clipPoints(); + this._simplifyPoints(); + + L.Path.prototype._updatePath.call(this); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/map/Map.js b/extlib/leaflet/src/map/Map.js new file mode 100644 index 00000000..d460048e --- /dev/null +++ b/extlib/leaflet/src/map/Map.js @@ -0,0 +1,464 @@ +/* + * L.Map is the central class of the API - it is used to create a map. + */ + +L.Map = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + // projection + crs: L.CRS.EPSG3857 || L.CRS.EPSG4326, + scale: function(zoom) { return 256 * (1 << zoom); }, + + // state + center: null, + zoom: null, + layers: [], + + // interaction + dragging: true, + touchZoom: L.Browser.mobileWebkit && !L.Browser.android, + scrollWheelZoom: !L.Browser.mobileWebkit, + doubleClickZoom: true, + shiftDragZoom: true, + + // controls + zoomControl: true, + attributionControl: true, + + // animation + fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android, + zoomAnimation: L.DomUtil.TRANSITION && !L.Browser.android && !L.Browser.mobileOpera, + + // misc + trackResize: true, + closePopupOnClick: true + }, + + + // constructor + + initialize: function(/*HTMLElement or String*/ id, /*Object*/ options) { + L.Util.setOptions(this, options); + + this._container = L.DomUtil.get(id); + + this._initLayout(); + + if (L.DomEvent) { + this._initEvents(); + if (L.Handler) { this._initInteraction(); } + if (L.Control) { this._initControls(); } + } + + var center = this.options.center, + zoom = this.options.zoom; + + if (center !== null && zoom !== null) { + this.setView(center, zoom, true); + } + + var layers = this.options.layers; + layers = (layers instanceof Array ? layers : [layers]); + this._tileLayersNum = 0; + this._initLayers(layers); + }, + + + // public methods that modify map state + + // replaced by animation-powered implementation in Map.PanAnimation.js + setView: function(center, zoom, forceReset) { + // reset the map view + this._resetView(center, this._limitZoom(zoom)); + return this; + }, + + setZoom: function(/*Number*/ zoom) { + return this.setView(this.getCenter(), zoom); + }, + + zoomIn: function() { + return this.setZoom(this._zoom + 1); + }, + + zoomOut: function() { + return this.setZoom(this._zoom - 1); + }, + + fitBounds: function(/*LatLngBounds*/ bounds) { + var zoom = this.getBoundsZoom(bounds); + return this.setView(bounds.getCenter(), zoom); + }, + + fitWorld: function() { + var sw = new L.LatLng(-60, -170), + ne = new L.LatLng(85, 179); + return this.fitBounds(new L.LatLngBounds(sw, ne)); + }, + + panTo: function(/*LatLng*/ center) { + return this.setView(center, this._zoom); + }, + + panBy: function(/*Point*/ offset) { + // replaced with animated panBy in Map.Animation.js + this.fire('movestart'); + + this._rawPanBy(offset); + + this.fire('move'); + this.fire('moveend'); + + return this; + }, + + addLayer: function(layer) { + var id = L.Util.stamp(layer); + + if (this._layers[id]) return this; + + this._layers[id] = layer; + + if (layer.options && !isNaN(layer.options.maxZoom)) { + this._layersMaxZoom = Math.max(this._layersMaxZoom || 0, layer.options.maxZoom); + } + if (layer.options && !isNaN(layer.options.minZoom)) { + this._layersMinZoom = Math.min(this._layersMinZoom || Infinity, layer.options.minZoom); + } + //TODO getMaxZoom, getMinZoom in ILayer (instead of options) + + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { + this._tileLayersNum++; + layer.on('load', this._onTileLayerLoad, this); + } + if (this.attributionControl && layer.getAttribution) { + this.attributionControl.addAttribution(layer.getAttribution()); + } + + var onMapLoad = function() { + layer.onAdd(this); + this.fire('layeradd', {layer: layer}); + }; + + if (this._loaded) { + onMapLoad.call(this); + } else { + this.on('load', onMapLoad, this); + } + + return this; + }, + + removeLayer: function(layer) { + var id = L.Util.stamp(layer); + + if (this._layers[id]) { + layer.onRemove(this); + delete this._layers[id]; + + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { + this._tileLayersNum--; + layer.off('load', this._onTileLayerLoad, this); + } + if (this.attributionControl && layer.getAttribution) { + this.attributionControl.removeAttribution(layer.getAttribution()); + } + + this.fire('layerremove', {layer: layer}); + } + return this; + }, + + invalidateSize: function() { + this._sizeChanged = true; + + this.fire('move'); + + clearTimeout(this._sizeTimer); + this._sizeTimer = setTimeout(L.Util.bind(function() { + this.fire('moveend'); + }, this), 200); + + return this; + }, + + + // public methods for getting map state + + getCenter: function(/*Boolean*/ unbounded) { + var viewHalf = this.getSize().divideBy(2), + centerPoint = this._getTopLeftPoint().add(viewHalf); + return this.unproject(centerPoint, this._zoom, unbounded); + }, + + getZoom: function() { + return this._zoom; + }, + + getBounds: function() { + var bounds = this.getPixelBounds(), + sw = this.unproject(new L.Point(bounds.min.x, bounds.max.y)), + ne = this.unproject(new L.Point(bounds.max.x, bounds.min.y)); + return new L.LatLngBounds(sw, ne); + }, + + getMinZoom: function() { + return isNaN(this.options.minZoom) ? this._layersMinZoom || 0 : this.options.minZoom; + }, + + getMaxZoom: function() { + return isNaN(this.options.maxZoom) ? this._layersMaxZoom || Infinity : this.options.maxZoom; + }, + + getBoundsZoom: function(/*LatLngBounds*/ bounds) { + var size = this.getSize(), + zoom = this.getMinZoom(), + maxZoom = this.getMaxZoom(), + ne = bounds.getNorthEast(), + sw = bounds.getSouthWest(), + boundsSize, + nePoint, swPoint; + do { + zoom++; + nePoint = this.project(ne, zoom); + swPoint = this.project(sw, zoom); + boundsSize = new L.Point(nePoint.x - swPoint.x, swPoint.y - nePoint.y); + } while ((boundsSize.x <= size.x) && + (boundsSize.y <= size.y) && (zoom <= maxZoom)); + + return zoom - 1; + }, + + getSize: function() { + if (!this._size || this._sizeChanged) { + this._size = new L.Point(this._container.clientWidth, this._container.clientHeight); + this._sizeChanged = false; + } + return this._size; + }, + + getPixelBounds: function() { + var topLeftPoint = this._getTopLeftPoint(), + size = this.getSize(); + return new L.Bounds(topLeftPoint, topLeftPoint.add(size)); + }, + + getPixelOrigin: function() { + return this._initialTopLeftPoint; + }, + + getPanes: function() { + return this._panes; + }, + + + // conversion methods + + mouseEventToContainerPoint: function(/*MouseEvent*/ e) { + return L.DomEvent.getMousePosition(e, this._container); + }, + + mouseEventToLayerPoint: function(/*MouseEvent*/ e) { + return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); + }, + + mouseEventToLatLng: function(/*MouseEvent*/ e) { + return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); + }, + + containerPointToLayerPoint: function(/*Point*/ point) { + return point.subtract(L.DomUtil.getPosition(this._mapPane)); + }, + + layerPointToContainerPoint: function(/*Point*/ point) { + return point.add(L.DomUtil.getPosition(this._mapPane)); + }, + + layerPointToLatLng: function(/*Point*/ point) { + return this.unproject(point.add(this._initialTopLeftPoint)); + }, + + latLngToLayerPoint: function(/*LatLng*/ latlng) { + return this.project(latlng)._subtract(this._initialTopLeftPoint); + }, + + project: function(/*LatLng*/ latlng, /*(optional) Number*/ zoom)/*-> Point*/ { + zoom = (typeof zoom == 'undefined' ? this._zoom : zoom); + return this.options.crs.latLngToPoint(latlng, this.options.scale(zoom)); + }, + + unproject: function(/*Point*/ point, /*(optional) Number*/ zoom, /*(optional) Boolean*/ unbounded)/*-> Object*/ { + zoom = (typeof zoom == 'undefined' ? this._zoom : zoom); + return this.options.crs.pointToLatLng(point, this.options.scale(zoom), unbounded); + }, + + + // private methods that modify map state + + _initLayout: function() { + var container = this._container; + + container.className += ' leaflet-container'; + + if (this.options.fadeAnimation) { + container.className += ' leaflet-fade-anim'; + } + + var position = L.DomUtil.getStyle(container, 'position'); + if (position != 'absolute' && position != 'relative') { + container.style.position = 'relative'; + } + + this._initPanes(); + + if (this._initControlPos) this._initControlPos(); + }, + + _initPanes: function() { + var panes = this._panes = {}; + + this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container); + + this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); + this._objectsPane = panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); + + panes.shadowPane = this._createPane('leaflet-shadow-pane'); + panes.overlayPane = this._createPane('leaflet-overlay-pane'); + panes.markerPane = this._createPane('leaflet-marker-pane'); + panes.popupPane = this._createPane('leaflet-popup-pane'); + }, + + _createPane: function(className, container) { + return L.DomUtil.create('div', className, container || this._objectsPane); + }, + + _resetView: function(center, zoom, preserveMapOffset) { + var zoomChanged = (this._zoom != zoom); + + this.fire('movestart'); + + this._zoom = zoom; + + this._initialTopLeftPoint = this._getNewTopLeftPoint(center); + + if (!preserveMapOffset) { + L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); + } else { + var offset = L.DomUtil.getPosition(this._mapPane); + this._initialTopLeftPoint._add(offset); + } + + this._tileLayersToLoad = this._tileLayersNum; + this.fire('viewreset'); + + this.fire('move'); + if (zoomChanged) { this.fire('zoomend'); } + this.fire('moveend'); + + if (!this._loaded) { + this._loaded = true; + this.fire('load'); + } + }, + + _initLayers: function(layers) { + this._layers = {}; + for (var i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + }, + + _initControls: function() { + if (this.options.zoomControl) { + this.addControl(new L.Control.Zoom()); + } + if (this.options.attributionControl) { + this.attributionControl = new L.Control.Attribution(); + this.addControl(this.attributionControl); + } + }, + + _rawPanBy: function(offset) { + var mapPaneOffset = L.DomUtil.getPosition(this._mapPane); + L.DomUtil.setPosition(this._mapPane, mapPaneOffset.subtract(offset)); + }, + + + // map events + + _initEvents: function() { + L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this); + + var events = ['dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove']; + for (var i = 0; i < events.length; i++) { + L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this); + } + + if (this.options.trackResize) { + L.DomEvent.addListener(window, 'resize', this.invalidateSize, this); + } + }, + + _onMouseClick: function(e) { + if (this.dragging && this.dragging.moved()) { return; } + + this.fire('pre' + e.type); + this._fireMouseEvent(e); + }, + + _fireMouseEvent: function(e) { + var type = e.type; + type = (type == 'mouseenter' ? 'mouseover' : (type == 'mouseleave' ? 'mouseout' : type)); + if (!this.hasEventListeners(type)) { return; } + this.fire(type, { + latlng: this.mouseEventToLatLng(e), + layerPoint: this.mouseEventToLayerPoint(e) + }); + }, + + _initInteraction: function() { + var handlers = { + dragging: L.Handler.MapDrag, + touchZoom: L.Handler.TouchZoom, + doubleClickZoom: L.Handler.DoubleClickZoom, + scrollWheelZoom: L.Handler.ScrollWheelZoom, + shiftDragZoom: L.Handler.ShiftDragZoom + }; + for (var i in handlers) { + if (handlers.hasOwnProperty(i) && handlers[i]) { + this[i] = new handlers[i](this); + if (this.options[i]) this[i].enable(); + } + } + }, + + _onTileLayerLoad: function() { + // clear scaled tiles after all new tiles are loaded (for performance) + this._tileLayersToLoad--; + if (this._tileLayersNum && !this._tileLayersToLoad && this._tileBg) { + clearTimeout(this._clearTileBgTimer); + this._clearTileBgTimer = setTimeout(L.Util.bind(this._clearTileBg, this), 500); + } + }, + + + // private methods for getting map state + + _getTopLeftPoint: function() { + if (!this._loaded) throw new Error('Set map center and zoom first.'); + var offset = L.DomUtil.getPosition(this._mapPane); + return this._initialTopLeftPoint.subtract(offset); + }, + + _getNewTopLeftPoint: function(center) { + var viewHalf = this.getSize().divideBy(2); + return this.project(center).subtract(viewHalf).round(); + }, + + _limitZoom: function(zoom) { + var min = this.getMinZoom(); + var max = this.getMaxZoom(); + return Math.max(min, Math.min(max, zoom)); + } +}); diff --git a/extlib/leaflet/src/map/ext/Map.Control.js b/extlib/leaflet/src/map/ext/Map.Control.js new file mode 100644 index 00000000..46711a82 --- /dev/null +++ b/extlib/leaflet/src/map/ext/Map.Control.js @@ -0,0 +1,50 @@ +L.Map.include({ + addControl: function(control) { + control.onAdd(this); + + var pos = control.getPosition(), + corner = this._controlCorners[pos], + container = control.getContainer(); + + L.DomUtil.addClass(container, 'leaflet-control'); + + if (pos.indexOf('bottom') != -1) { + corner.insertBefore(container, corner.firstChild); + } else { + corner.appendChild(container); + } + return this; + }, + + removeControl: function(control) { + var pos = control.getPosition(), + corner = this._controlCorners[pos], + container = control.getContainer(); + + corner.removeChild(container); + + if (control.onRemove) { + control.onRemove(this); + } + return this; + }, + + _initControlPos: function() { + var corners = this._controlCorners = {}, + classPart = 'leaflet-', + top = classPart + 'top', + bottom = classPart + 'bottom', + left = classPart + 'left', + right = classPart + 'right', + controlContainer = L.DomUtil.create('div', classPart + 'control-container', this._container); + + if (L.Browser.mobileWebkit) { + controlContainer.className += ' ' + classPart + 'big-buttons'; + } + + corners.topLeft = L.DomUtil.create('div', top + ' ' + left, controlContainer); + corners.topRight = L.DomUtil.create('div', top + ' ' + right, controlContainer); + corners.bottomLeft = L.DomUtil.create('div', bottom + ' ' + left, controlContainer); + corners.bottomRight = L.DomUtil.create('div', bottom + ' ' + right, controlContainer); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/map/ext/Map.Geolocation.js b/extlib/leaflet/src/map/ext/Map.Geolocation.js new file mode 100644 index 00000000..328662b9 --- /dev/null +++ b/extlib/leaflet/src/map/ext/Map.Geolocation.js @@ -0,0 +1,69 @@ +/* + * Provides L.Map with convenient shortcuts for W3C geolocation. + */ + +L.Map.include({ + locate: function(/*Object*/ options) { + // W3C Geolocation API Spec position options, http://dev.w3.org/geo/api/spec-source.html#position-options + var opts = {timeout: 10000}; + L.Util.extend(opts, options); + + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + L.Util.bind(this._handleGeolocationResponse, this), + L.Util.bind(this._handleGeolocationError, this), + opts); + } else { + this.fire('locationerror', { + code: 0, + message: "Geolocation not supported." + }); + } + return this; + }, + + locateAndSetView: function(maxZoom, options) { + this._setViewOnLocate = true; + this._maxLocateZoom = maxZoom || Infinity; + return this.locate(options); + }, + + _handleGeolocationError: function(error) { + var c = error.code, + message = (c == 1 ? "permission denied" : + (c == 2 ? "position unavailable" : "timeout")); + + if (this._setViewOnLocate) { + this.fitWorld(); + this._setViewOnLocate = false; + } + + this.fire('locationerror', { + code: c, + message: "Geolocation error: " + message + "." + }); + }, + + _handleGeolocationResponse: function(pos) { + var latAccuracy = 180 * pos.coords.accuracy / 4e7, + lngAccuracy = latAccuracy * 2, + lat = pos.coords.latitude, + lng = pos.coords.longitude; + + var sw = new L.LatLng(lat - latAccuracy, lng - lngAccuracy), + ne = new L.LatLng(lat + latAccuracy, lng + lngAccuracy), + bounds = new L.LatLngBounds(sw, ne); + + if (this._setViewOnLocate) { + var zoom = Math.min(this.getBoundsZoom(bounds), this._maxLocateZoom); + this.setView(bounds.getCenter(), zoom); + this._setViewOnLocate = false; + } + + this.fire('locationfound', { + latlng: new L.LatLng(lat, lng), + bounds: bounds, + accuracy: pos.coords.accuracy + }); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/map/ext/Map.PanAnimation.js b/extlib/leaflet/src/map/ext/Map.PanAnimation.js new file mode 100644 index 00000000..02ccfd15 --- /dev/null +++ b/extlib/leaflet/src/map/ext/Map.PanAnimation.js @@ -0,0 +1,62 @@ +L.Map.include(!(L.Transition && L.Transition.implemented()) ? {} : { + setView: function(center, zoom, forceReset) { + zoom = this._limitZoom(zoom); + var zoomChanged = (this._zoom != zoom); + + if (this._loaded && !forceReset && this._layers) { + // difference between the new and current centers in pixels + var offset = this._getNewTopLeftPoint(center).subtract(this._getTopLeftPoint()); + + var done = (zoomChanged ? + !!this._zoomToIfCenterInView && this._zoomToIfCenterInView(center, zoom, offset) : + this._panByIfClose(offset)); + + // exit if animated pan or zoom started + if (done) { return this; } + } + + // reset the map view + this._resetView(center, zoom); + + return this; + }, + + panBy: function(offset) { + if (!this._panTransition) { + this._panTransition = new L.Transition(this._mapPane, {duration: 0.3}); + + this._panTransition.on('step', this._onPanTransitionStep, this); + this._panTransition.on('end', this._onPanTransitionEnd, this); + } + this.fire(this, 'movestart'); + + this._panTransition.run({ + position: L.DomUtil.getPosition(this._mapPane).subtract(offset) + }); + + return this; + }, + + _onPanTransitionStep: function() { + this.fire('move'); + }, + + _onPanTransitionEnd: function() { + this.fire('moveend'); + }, + + _panByIfClose: function(offset) { + if (this._offsetIsWithinView(offset)) { + this.panBy(offset); + return true; + } + return false; + }, + + _offsetIsWithinView: function(offset, multiplyFactor) { + var m = multiplyFactor || 1, + size = this.getSize(); + return (Math.abs(offset.x) <= size.x * m) && + (Math.abs(offset.y) <= size.y * m); + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/map/ext/Map.Popup.js b/extlib/leaflet/src/map/ext/Map.Popup.js new file mode 100644 index 00000000..8b8de937 --- /dev/null +++ b/extlib/leaflet/src/map/ext/Map.Popup.js @@ -0,0 +1,15 @@ + +L.Map.include({ + openPopup: function(popup) { + this.closePopup(); + this._popup = popup; + return this.addLayer(popup); + }, + + closePopup: function() { + if (this._popup) { + this.removeLayer(this._popup); + } + return this; + } +}); \ No newline at end of file diff --git a/extlib/leaflet/src/map/ext/Map.ZoomAnimation.js b/extlib/leaflet/src/map/ext/Map.ZoomAnimation.js new file mode 100644 index 00000000..4bf7b9bf --- /dev/null +++ b/extlib/leaflet/src/map/ext/Map.ZoomAnimation.js @@ -0,0 +1,124 @@ +L.Map.include(!L.DomUtil.TRANSITION ? {} : { + _zoomToIfCenterInView: function(center, zoom, centerOffset) { + + if (this._animatingZoom) { return true; } + if (!this.options.zoomAnimation) { return false; } + + var zoomDelta = zoom - this._zoom, + scale = Math.pow(2, zoomDelta), + offset = centerOffset.divideBy(1 - 1/scale); + + //if offset does not exceed half of the view + if (!this._offsetIsWithinView(offset, 1)) { return false; } + + this._mapPane.className += ' leaflet-zoom-anim'; + + var centerPoint = this.containerPointToLayerPoint(this.getSize().divideBy(2)), + origin = centerPoint.add(offset); + + this._prepareTileBg(); + + this._runAnimation(center, zoom, scale, origin); + + return true; + }, + + + _runAnimation: function(center, zoom, scale, origin) { + this._animatingZoom = true; + + this._animateToCenter = center; + this._animateToZoom = zoom; + + var transform = L.DomUtil.TRANSFORM; + + //dumb FireFox hack, I have no idea why this magic zero translate fixes the scale transition problem + if (L.Browser.gecko || window.opera) { + this._tileBg.style[transform] += ' translate(0,0)'; + } + + var scaleStr; + + // Android doesn't like translate/scale chains, transformOrigin + scale works better but + // it breaks touch zoom which Anroid doesn't support anyway, so that's a really ugly hack + // TODO work around this prettier + if (L.Browser.android) { + this._tileBg.style[transform + 'Origin'] = origin.x + 'px ' + origin.y + 'px'; + scaleStr = 'scale(' + scale + ')'; + } else { + scaleStr = L.DomUtil.getScaleString(scale, origin); + } + + L.Util.falseFn(this._tileBg.offsetWidth); //hack to make sure transform is updated before running animation + + var options = {}; + options[transform] = this._tileBg.style[transform] + ' ' + scaleStr; + this._tileBg.transition.run(options); + }, + + _prepareTileBg: function() { + if (!this._tileBg) { + this._tileBg = this._createPane('leaflet-tile-pane', this._mapPane); + this._tileBg.style.zIndex = 1; + } + + var tilePane = this._tilePane, + tileBg = this._tileBg; + + // prepare the background pane to become the main tile pane + //tileBg.innerHTML = ''; + tileBg.style[L.DomUtil.TRANSFORM] = ''; + tileBg.style.visibility = 'hidden'; + + // tells tile layers to reinitialize their containers + tileBg.empty = true; + tilePane.empty = false; + + this._tilePane = this._panes.tilePane = tileBg; + this._tileBg = tilePane; + + if (!this._tileBg.transition) { + this._tileBg.transition = new L.Transition(this._tileBg, {duration: 0.3, easing: 'cubic-bezier(0.25,0.1,0.25,0.75)'}); + this._tileBg.transition.on('end', this._onZoomTransitionEnd, this); + } + + this._stopLoadingBgTiles(); + }, + + // stops loading all tiles in the background layer + _stopLoadingBgTiles: function() { + var tiles = [].slice.call(this._tileBg.getElementsByTagName('img')); + + for (var i = 0, len = tiles.length; i < len; i++) { + if (!tiles[i].complete) { + tiles[i].src = ''; + tiles[i].parentNode.removeChild(tiles[i]); + } + } + }, + + _onZoomTransitionEnd: function() { + this._restoreTileFront(); + + L.Util.falseFn(this._tileBg.offsetWidth); + this._resetView(this._animateToCenter, this._animateToZoom, true); + + //TODO clear tileBg on map layersload + + this._mapPane.className = this._mapPane.className.replace(' leaflet-zoom-anim', ''); //TODO toggleClass util + this._animatingZoom = false; + }, + + _restoreTileFront: function() { + this._tilePane.innerHTML = ''; + this._tilePane.style.visibility = ''; + this._tilePane.style.zIndex = 2; + this._tileBg.style.zIndex = 1; + }, + + _clearTileBg: function() { + if (!this._animatingZoom && !this.touchZoom._zooming) { + this._tileBg.innerHTML = ''; + } + } +}); \ No newline at end of file diff --git a/mediagoblin/static/extlib/leaflet b/mediagoblin/static/extlib/leaflet new file mode 120000 index 00000000..b47e2b1b --- /dev/null +++ b/mediagoblin/static/extlib/leaflet @@ -0,0 +1 @@ +../../../extlib/leaflet/dist/ \ No newline at end of file -- cgit v1.2.3 From 9bf7563d4c4c263fb6e5345bd1185aebb1c6ef8f Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 02:14:37 +0100 Subject: Installed EXIF.py in extlibs/ --- extlib/exif/EXIF.py | 1767 +++++++++++++++++++++++++++++++++ mediagoblin/media_types/image/EXIF.py | 1 + 2 files changed, 1768 insertions(+) create mode 100755 extlib/exif/EXIF.py create mode 120000 mediagoblin/media_types/image/EXIF.py diff --git a/extlib/exif/EXIF.py b/extlib/exif/EXIF.py new file mode 100755 index 00000000..ed4192af --- /dev/null +++ b/extlib/exif/EXIF.py @@ -0,0 +1,1767 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Library to extract EXIF information from digital camera image files +# http://sourceforge.net/projects/exif-py/ +# +# VERSION 1.1.0 +# +# To use this library call with: +# f = open(path_name, 'rb') +# tags = EXIF.process_file(f) +# +# To ignore MakerNote tags, pass the -q or --quick +# command line arguments, or as +# tags = EXIF.process_file(f, details=False) +# +# To stop processing after a certain tag is retrieved, +# pass the -t TAG or --stop-tag TAG argument, or as +# tags = EXIF.process_file(f, stop_tag='TAG') +# +# where TAG is a valid tag name, ex 'DateTimeOriginal' +# +# These 2 are useful when you are retrieving a large list of images +# +# +# To return an error on invalid tags, +# pass the -s or --strict argument, or as +# tags = EXIF.process_file(f, strict=True) +# +# Otherwise these tags will be ignored +# +# Returned tags will be a dictionary mapping names of EXIF tags to their +# values in the file named by path_name. You can process the tags +# as you wish. In particular, you can iterate through all the tags with: +# for tag in tags.keys(): +# if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', +# 'EXIF MakerNote'): +# print "Key: %s, value %s" % (tag, tags[tag]) +# (This code uses the if statement to avoid printing out a few of the +# tags that tend to be long or boring.) +# +# The tags dictionary will include keys for all of the usual EXIF +# tags, and will also include keys for Makernotes used by some +# cameras, for which we have a good specification. +# +# Note that the dictionary keys are the IFD name followed by the +# tag name. For example: +# 'EXIF DateTimeOriginal', 'Image Orientation', 'MakerNote FocusMode' +# +# Copyright (c) 2002-2007 Gene Cash All rights reserved +# Copyright (c) 2007-2008 Ianaré Sévi All rights reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. Neither the name of the authors nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# ----- See 'changes.txt' file for all contributors and changes ----- # +# + + +# Don't throw an exception when given an out of range character. +def make_string(seq): + str = '' + for c in seq: + # Screen out non-printing characters + if 32 <= c and c < 256: + str += chr(c) + # If no printing chars + if not str: + return seq + return str + +# Special version to deal with the code in the first 8 bytes of a user comment. +# First 8 bytes gives coding system e.g. ASCII vs. JIS vs Unicode +def make_string_uc(seq): + code = seq[0:8] + seq = seq[8:] + # Of course, this is only correct if ASCII, and the standard explicitly + # allows JIS and Unicode. + return make_string(seq) + +# field type descriptions as (length, abbreviation, full name) tuples +FIELD_TYPES = ( + (0, 'X', 'Proprietary'), # no such type + (1, 'B', 'Byte'), + (1, 'A', 'ASCII'), + (2, 'S', 'Short'), + (4, 'L', 'Long'), + (8, 'R', 'Ratio'), + (1, 'SB', 'Signed Byte'), + (1, 'U', 'Undefined'), + (2, 'SS', 'Signed Short'), + (4, 'SL', 'Signed Long'), + (8, 'SR', 'Signed Ratio'), + ) + +# dictionary of main EXIF tag names +# first element of tuple is tag name, optional second element is +# another dictionary giving names to values +EXIF_TAGS = { + 0x0100: ('ImageWidth', ), + 0x0101: ('ImageLength', ), + 0x0102: ('BitsPerSample', ), + 0x0103: ('Compression', + {1: 'Uncompressed', + 2: 'CCITT 1D', + 3: 'T4/Group 3 Fax', + 4: 'T6/Group 4 Fax', + 5: 'LZW', + 6: 'JPEG (old-style)', + 7: 'JPEG', + 8: 'Adobe Deflate', + 9: 'JBIG B&W', + 10: 'JBIG Color', + 32766: 'Next', + 32769: 'Epson ERF Compressed', + 32771: 'CCIRLEW', + 32773: 'PackBits', + 32809: 'Thunderscan', + 32895: 'IT8CTPAD', + 32896: 'IT8LW', + 32897: 'IT8MP', + 32898: 'IT8BL', + 32908: 'PixarFilm', + 32909: 'PixarLog', + 32946: 'Deflate', + 32947: 'DCS', + 34661: 'JBIG', + 34676: 'SGILog', + 34677: 'SGILog24', + 34712: 'JPEG 2000', + 34713: 'Nikon NEF Compressed', + 65000: 'Kodak DCR Compressed', + 65535: 'Pentax PEF Compressed'}), + 0x0106: ('PhotometricInterpretation', ), + 0x0107: ('Thresholding', ), + 0x010A: ('FillOrder', ), + 0x010D: ('DocumentName', ), + 0x010E: ('ImageDescription', ), + 0x010F: ('Make', ), + 0x0110: ('Model', ), + 0x0111: ('StripOffsets', ), + 0x0112: ('Orientation', + {1: 'Horizontal (normal)', + 2: 'Mirrored horizontal', + 3: 'Rotated 180', + 4: 'Mirrored vertical', + 5: 'Mirrored horizontal then rotated 90 CCW', + 6: 'Rotated 90 CW', + 7: 'Mirrored horizontal then rotated 90 CW', + 8: 'Rotated 90 CCW'}), + 0x0115: ('SamplesPerPixel', ), + 0x0116: ('RowsPerStrip', ), + 0x0117: ('StripByteCounts', ), + 0x011A: ('XResolution', ), + 0x011B: ('YResolution', ), + 0x011C: ('PlanarConfiguration', ), + 0x011D: ('PageName', make_string), + 0x0128: ('ResolutionUnit', + {1: 'Not Absolute', + 2: 'Pixels/Inch', + 3: 'Pixels/Centimeter'}), + 0x012D: ('TransferFunction', ), + 0x0131: ('Software', ), + 0x0132: ('DateTime', ), + 0x013B: ('Artist', ), + 0x013E: ('WhitePoint', ), + 0x013F: ('PrimaryChromaticities', ), + 0x0156: ('TransferRange', ), + 0x0200: ('JPEGProc', ), + 0x0201: ('JPEGInterchangeFormat', ), + 0x0202: ('JPEGInterchangeFormatLength', ), + 0x0211: ('YCbCrCoefficients', ), + 0x0212: ('YCbCrSubSampling', ), + 0x0213: ('YCbCrPositioning', + {1: 'Centered', + 2: 'Co-sited'}), + 0x0214: ('ReferenceBlackWhite', ), + + 0x4746: ('Rating', ), + + 0x828D: ('CFARepeatPatternDim', ), + 0x828E: ('CFAPattern', ), + 0x828F: ('BatteryLevel', ), + 0x8298: ('Copyright', ), + 0x829A: ('ExposureTime', ), + 0x829D: ('FNumber', ), + 0x83BB: ('IPTC/NAA', ), + 0x8769: ('ExifOffset', ), + 0x8773: ('InterColorProfile', ), + 0x8822: ('ExposureProgram', + {0: 'Unidentified', + 1: 'Manual', + 2: 'Program Normal', + 3: 'Aperture Priority', + 4: 'Shutter Priority', + 5: 'Program Creative', + 6: 'Program Action', + 7: 'Portrait Mode', + 8: 'Landscape Mode'}), + 0x8824: ('SpectralSensitivity', ), + 0x8825: ('GPSInfo', ), + 0x8827: ('ISOSpeedRatings', ), + 0x8828: ('OECF', ), + 0x9000: ('ExifVersion', make_string), + 0x9003: ('DateTimeOriginal', ), + 0x9004: ('DateTimeDigitized', ), + 0x9101: ('ComponentsConfiguration', + {0: '', + 1: 'Y', + 2: 'Cb', + 3: 'Cr', + 4: 'Red', + 5: 'Green', + 6: 'Blue'}), + 0x9102: ('CompressedBitsPerPixel', ), + 0x9201: ('ShutterSpeedValue', ), + 0x9202: ('ApertureValue', ), + 0x9203: ('BrightnessValue', ), + 0x9204: ('ExposureBiasValue', ), + 0x9205: ('MaxApertureValue', ), + 0x9206: ('SubjectDistance', ), + 0x9207: ('MeteringMode', + {0: 'Unidentified', + 1: 'Average', + 2: 'CenterWeightedAverage', + 3: 'Spot', + 4: 'MultiSpot', + 5: 'Pattern'}), + 0x9208: ('LightSource', + {0: 'Unknown', + 1: 'Daylight', + 2: 'Fluorescent', + 3: 'Tungsten', + 9: 'Fine Weather', + 10: 'Flash', + 11: 'Shade', + 12: 'Daylight Fluorescent', + 13: 'Day White Fluorescent', + 14: 'Cool White Fluorescent', + 15: 'White Fluorescent', + 17: 'Standard Light A', + 18: 'Standard Light B', + 19: 'Standard Light C', + 20: 'D55', + 21: 'D65', + 22: 'D75', + 255: 'Other'}), + 0x9209: ('Flash', + {0: 'No', + 1: 'Fired', + 5: 'Fired (?)', # no return sensed + 7: 'Fired (!)', # return sensed + 9: 'Fill Fired', + 13: 'Fill Fired (?)', + 15: 'Fill Fired (!)', + 16: 'Off', + 24: 'Auto Off', + 25: 'Auto Fired', + 29: 'Auto Fired (?)', + 31: 'Auto Fired (!)', + 32: 'Not Available'}), + 0x920A: ('FocalLength', ), + 0x9214: ('SubjectArea', ), + 0x927C: ('MakerNote', ), + 0x9286: ('UserComment', make_string_uc), + 0x9290: ('SubSecTime', ), + 0x9291: ('SubSecTimeOriginal', ), + 0x9292: ('SubSecTimeDigitized', ), + + # used by Windows Explorer + 0x9C9B: ('XPTitle', ), + 0x9C9C: ('XPComment', ), + 0x9C9D: ('XPAuthor', ), #(ignored by Windows Explorer if Artist exists) + 0x9C9E: ('XPKeywords', ), + 0x9C9F: ('XPSubject', ), + + 0xA000: ('FlashPixVersion', make_string), + 0xA001: ('ColorSpace', + {1: 'sRGB', + 2: 'Adobe RGB', + 65535: 'Uncalibrated'}), + 0xA002: ('ExifImageWidth', ), + 0xA003: ('ExifImageLength', ), + 0xA005: ('InteroperabilityOffset', ), + 0xA20B: ('FlashEnergy', ), # 0x920B in TIFF/EP + 0xA20C: ('SpatialFrequencyResponse', ), # 0x920C + 0xA20E: ('FocalPlaneXResolution', ), # 0x920E + 0xA20F: ('FocalPlaneYResolution', ), # 0x920F + 0xA210: ('FocalPlaneResolutionUnit', ), # 0x9210 + 0xA214: ('SubjectLocation', ), # 0x9214 + 0xA215: ('ExposureIndex', ), # 0x9215 + 0xA217: ('SensingMethod', # 0x9217 + {1: 'Not defined', + 2: 'One-chip color area', + 3: 'Two-chip color area', + 4: 'Three-chip color area', + 5: 'Color sequential area', + 7: 'Trilinear', + 8: 'Color sequential linear'}), + 0xA300: ('FileSource', + {1: 'Film Scanner', + 2: 'Reflection Print Scanner', + 3: 'Digital Camera'}), + 0xA301: ('SceneType', + {1: 'Directly Photographed'}), + 0xA302: ('CVAPattern', ), + 0xA401: ('CustomRendered', + {0: 'Normal', + 1: 'Custom'}), + 0xA402: ('ExposureMode', + {0: 'Auto Exposure', + 1: 'Manual Exposure', + 2: 'Auto Bracket'}), + 0xA403: ('WhiteBalance', + {0: 'Auto', + 1: 'Manual'}), + 0xA404: ('DigitalZoomRatio', ), + 0xA405: ('FocalLengthIn35mmFilm', ), + 0xA406: ('SceneCaptureType', + {0: 'Standard', + 1: 'Landscape', + 2: 'Portrait', + 3: 'Night)'}), + 0xA407: ('GainControl', + {0: 'None', + 1: 'Low gain up', + 2: 'High gain up', + 3: 'Low gain down', + 4: 'High gain down'}), + 0xA408: ('Contrast', + {0: 'Normal', + 1: 'Soft', + 2: 'Hard'}), + 0xA409: ('Saturation', + {0: 'Normal', + 1: 'Soft', + 2: 'Hard'}), + 0xA40A: ('Sharpness', + {0: 'Normal', + 1: 'Soft', + 2: 'Hard'}), + 0xA40B: ('DeviceSettingDescription', ), + 0xA40C: ('SubjectDistanceRange', ), + 0xA500: ('Gamma', ), + 0xC4A5: ('PrintIM', ), + 0xEA1C: ('Padding', ), + } + +# interoperability tags +INTR_TAGS = { + 0x0001: ('InteroperabilityIndex', ), + 0x0002: ('InteroperabilityVersion', ), + 0x1000: ('RelatedImageFileFormat', ), + 0x1001: ('RelatedImageWidth', ), + 0x1002: ('RelatedImageLength', ), + } + +# GPS tags (not used yet, haven't seen camera with GPS) +GPS_TAGS = { + 0x0000: ('GPSVersionID', ), + 0x0001: ('GPSLatitudeRef', ), + 0x0002: ('GPSLatitude', ), + 0x0003: ('GPSLongitudeRef', ), + 0x0004: ('GPSLongitude', ), + 0x0005: ('GPSAltitudeRef', ), + 0x0006: ('GPSAltitude', ), + 0x0007: ('GPSTimeStamp', ), + 0x0008: ('GPSSatellites', ), + 0x0009: ('GPSStatus', ), + 0x000A: ('GPSMeasureMode', ), + 0x000B: ('GPSDOP', ), + 0x000C: ('GPSSpeedRef', ), + 0x000D: ('GPSSpeed', ), + 0x000E: ('GPSTrackRef', ), + 0x000F: ('GPSTrack', ), + 0x0010: ('GPSImgDirectionRef', ), + 0x0011: ('GPSImgDirection', ), + 0x0012: ('GPSMapDatum', ), + 0x0013: ('GPSDestLatitudeRef', ), + 0x0014: ('GPSDestLatitude', ), + 0x0015: ('GPSDestLongitudeRef', ), + 0x0016: ('GPSDestLongitude', ), + 0x0017: ('GPSDestBearingRef', ), + 0x0018: ('GPSDestBearing', ), + 0x0019: ('GPSDestDistanceRef', ), + 0x001A: ('GPSDestDistance', ), + 0x001D: ('GPSDate', ), + } + +# Ignore these tags when quick processing +# 0x927C is MakerNote Tags +# 0x9286 is user comment +IGNORE_TAGS=(0x9286, 0x927C) + +# http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp +def nikon_ev_bias(seq): + # First digit seems to be in steps of 1/6 EV. + # Does the third value mean the step size? It is usually 6, + # but it is 12 for the ExposureDifference. + # + # Check for an error condition that could cause a crash. + # This only happens if something has gone really wrong in + # reading the Nikon MakerNote. + if len( seq ) < 4 : return "" + # + if seq == [252, 1, 6, 0]: + return "-2/3 EV" + if seq == [253, 1, 6, 0]: + return "-1/2 EV" + if seq == [254, 1, 6, 0]: + return "-1/3 EV" + if seq == [0, 1, 6, 0]: + return "0 EV" + if seq == [2, 1, 6, 0]: + return "+1/3 EV" + if seq == [3, 1, 6, 0]: + return "+1/2 EV" + if seq == [4, 1, 6, 0]: + return "+2/3 EV" + # Handle combinations not in the table. + a = seq[0] + # Causes headaches for the +/- logic, so special case it. + if a == 0: + return "0 EV" + if a > 127: + a = 256 - a + ret_str = "-" + else: + ret_str = "+" + b = seq[2] # Assume third value means the step size + whole = a / b + a = a % b + if whole != 0: + ret_str = ret_str + str(whole) + " " + if a == 0: + ret_str = ret_str + "EV" + else: + r = Ratio(a, b) + ret_str = ret_str + r.__repr__() + " EV" + return ret_str + +# Nikon E99x MakerNote Tags +MAKERNOTE_NIKON_NEWER_TAGS={ + 0x0001: ('MakernoteVersion', make_string), # Sometimes binary + 0x0002: ('ISOSetting', make_string), + 0x0003: ('ColorMode', ), + 0x0004: ('Quality', ), + 0x0005: ('Whitebalance', ), + 0x0006: ('ImageSharpening', ), + 0x0007: ('FocusMode', ), + 0x0008: ('FlashSetting', ), + 0x0009: ('AutoFlashMode', ), + 0x000B: ('WhiteBalanceBias', ), + 0x000C: ('WhiteBalanceRBCoeff', ), + 0x000D: ('ProgramShift', nikon_ev_bias), + # Nearly the same as the other EV vals, but step size is 1/12 EV (?) + 0x000E: ('ExposureDifference', nikon_ev_bias), + 0x000F: ('ISOSelection', ), + 0x0011: ('NikonPreview', ), + 0x0012: ('FlashCompensation', nikon_ev_bias), + 0x0013: ('ISOSpeedRequested', ), + 0x0016: ('PhotoCornerCoordinates', ), + # 0x0017: Unknown, but most likely an EV value + 0x0018: ('FlashBracketCompensationApplied', nikon_ev_bias), + 0x0019: ('AEBracketCompensationApplied', ), + 0x001A: ('ImageProcessing', ), + 0x001B: ('CropHiSpeed', ), + 0x001D: ('SerialNumber', ), # Conflict with 0x00A0 ? + 0x001E: ('ColorSpace', ), + 0x001F: ('VRInfo', ), + 0x0020: ('ImageAuthentication', ), + 0x0022: ('ActiveDLighting', ), + 0x0023: ('PictureControl', ), + 0x0024: ('WorldTime', ), + 0x0025: ('ISOInfo', ), + 0x0080: ('ImageAdjustment', ), + 0x0081: ('ToneCompensation', ), + 0x0082: ('AuxiliaryLens', ), + 0x0083: ('LensType', ), + 0x0084: ('LensMinMaxFocalMaxAperture', ), + 0x0085: ('ManualFocusDistance', ), + 0x0086: ('DigitalZoomFactor', ), + 0x0087: ('FlashMode', + {0x00: 'Did Not Fire', + 0x01: 'Fired, Manual', + 0x07: 'Fired, External', + 0x08: 'Fired, Commander Mode ', + 0x09: 'Fired, TTL Mode'}), + 0x0088: ('AFFocusPosition', + {0x0000: 'Center', + 0x0100: 'Top', + 0x0200: 'Bottom', + 0x0300: 'Left', + 0x0400: 'Right'}), + 0x0089: ('BracketingMode', + {0x00: 'Single frame, no bracketing', + 0x01: 'Continuous, no bracketing', + 0x02: 'Timer, no bracketing', + 0x10: 'Single frame, exposure bracketing', + 0x11: 'Continuous, exposure bracketing', + 0x12: 'Timer, exposure bracketing', + 0x40: 'Single frame, white balance bracketing', + 0x41: 'Continuous, white balance bracketing', + 0x42: 'Timer, white balance bracketing'}), + 0x008A: ('AutoBracketRelease', ), + 0x008B: ('LensFStops', ), + 0x008C: ('NEFCurve1', ), # ExifTool calls this 'ContrastCurve' + 0x008D: ('ColorMode', ), + 0x008F: ('SceneMode', ), + 0x0090: ('LightingType', ), + 0x0091: ('ShotInfo', ), # First 4 bytes are a version number in ASCII + 0x0092: ('HueAdjustment', ), + # ExifTool calls this 'NEFCompression', should be 1-4 + 0x0093: ('Compression', ), + 0x0094: ('Saturation', + {-3: 'B&W', + -2: '-2', + -1: '-1', + 0: '0', + 1: '1', + 2: '2'}), + 0x0095: ('NoiseReduction', ), + 0x0096: ('NEFCurve2', ), # ExifTool calls this 'LinearizationTable' + 0x0097: ('ColorBalance', ), # First 4 bytes are a version number in ASCII + 0x0098: ('LensData', ), # First 4 bytes are a version number in ASCII + 0x0099: ('RawImageCenter', ), + 0x009A: ('SensorPixelSize', ), + 0x009C: ('Scene Assist', ), + 0x009E: ('RetouchHistory', ), + 0x00A0: ('SerialNumber', ), + 0x00A2: ('ImageDataSize', ), + # 00A3: unknown - a single byte 0 + # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200') + 0x00A5: ('ImageCount', ), + 0x00A6: ('DeletedImageCount', ), + 0x00A7: ('TotalShutterReleases', ), + # First 4 bytes are a version number in ASCII, with version specific + # info to follow. Its hard to treat it as a string due to embedded nulls. + 0x00A8: ('FlashInfo', ), + 0x00A9: ('ImageOptimization', ), + 0x00AA: ('Saturation', ), + 0x00AB: ('DigitalVariProgram', ), + 0x00AC: ('ImageStabilization', ), + 0x00AD: ('Responsive AF', ), # 'AFResponse' + 0x00B0: ('MultiExposure', ), + 0x00B1: ('HighISONoiseReduction', ), + 0x00B7: ('AFInfo', ), + 0x00B8: ('FileInfo', ), + # 00B9: unknown + 0x0100: ('DigitalICE', ), + 0x0103: ('PreviewCompression', + {1: 'Uncompressed', + 2: 'CCITT 1D', + 3: 'T4/Group 3 Fax', + 4: 'T6/Group 4 Fax', + 5: 'LZW', + 6: 'JPEG (old-style)', + 7: 'JPEG', + 8: 'Adobe Deflate', + 9: 'JBIG B&W', + 10: 'JBIG Color', + 32766: 'Next', + 32769: 'Epson ERF Compressed', + 32771: 'CCIRLEW', + 32773: 'PackBits', + 32809: 'Thunderscan', + 32895: 'IT8CTPAD', + 32896: 'IT8LW', + 32897: 'IT8MP', + 32898: 'IT8BL', + 32908: 'PixarFilm', + 32909: 'PixarLog', + 32946: 'Deflate', + 32947: 'DCS', + 34661: 'JBIG', + 34676: 'SGILog', + 34677: 'SGILog24', + 34712: 'JPEG 2000', + 34713: 'Nikon NEF Compressed', + 65000: 'Kodak DCR Compressed', + 65535: 'Pentax PEF Compressed',}), + 0x0201: ('PreviewImageStart', ), + 0x0202: ('PreviewImageLength', ), + 0x0213: ('PreviewYCbCrPositioning', + {1: 'Centered', + 2: 'Co-sited'}), + 0x0010: ('DataDump', ), + } + +MAKERNOTE_NIKON_OLDER_TAGS = { + 0x0003: ('Quality', + {1: 'VGA Basic', + 2: 'VGA Normal', + 3: 'VGA Fine', + 4: 'SXGA Basic', + 5: 'SXGA Normal', + 6: 'SXGA Fine'}), + 0x0004: ('ColorMode', + {1: 'Color', + 2: 'Monochrome'}), + 0x0005: ('ImageAdjustment', + {0: 'Normal', + 1: 'Bright+', + 2: 'Bright-', + 3: 'Contrast+', + 4: 'Contrast-'}), + 0x0006: ('CCDSpeed', + {0: 'ISO 80', + 2: 'ISO 160', + 4: 'ISO 320', + 5: 'ISO 100'}), + 0x0007: ('WhiteBalance', + {0: 'Auto', + 1: 'Preset', + 2: 'Daylight', + 3: 'Incandescent', + 4: 'Fluorescent', + 5: 'Cloudy', + 6: 'Speed Light'}), + } + +# decode Olympus SpecialMode tag in MakerNote +def olympus_special_mode(v): + a={ + 0: 'Normal', + 1: 'Unknown', + 2: 'Fast', + 3: 'Panorama'} + b={ + 0: 'Non-panoramic', + 1: 'Left to right', + 2: 'Right to left', + 3: 'Bottom to top', + 4: 'Top to bottom'} + if v[0] not in a or v[2] not in b: + return v + return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]]) + +MAKERNOTE_OLYMPUS_TAGS={ + # ah HAH! those sneeeeeaky bastids! this is how they get past the fact + # that a JPEG thumbnail is not allowed in an uncompressed TIFF file + 0x0100: ('JPEGThumbnail', ), + 0x0200: ('SpecialMode', olympus_special_mode), + 0x0201: ('JPEGQual', + {1: 'SQ', + 2: 'HQ', + 3: 'SHQ'}), + 0x0202: ('Macro', + {0: 'Normal', + 1: 'Macro', + 2: 'SuperMacro'}), + 0x0203: ('BWMode', + {0: 'Off', + 1: 'On'}), + 0x0204: ('DigitalZoom', ), + 0x0205: ('FocalPlaneDiagonal', ), + 0x0206: ('LensDistortionParams', ), + 0x0207: ('SoftwareRelease', ), + 0x0208: ('PictureInfo', ), + 0x0209: ('CameraID', make_string), # print as string + 0x0F00: ('DataDump', ), + 0x0300: ('PreCaptureFrames', ), + 0x0404: ('SerialNumber', ), + 0x1000: ('ShutterSpeedValue', ), + 0x1001: ('ISOValue', ), + 0x1002: ('ApertureValue', ), + 0x1003: ('BrightnessValue', ), + 0x1004: ('FlashMode', ), + 0x1004: ('FlashMode', + {2: 'On', + 3: 'Off'}), + 0x1005: ('FlashDevice', + {0: 'None', + 1: 'Internal', + 4: 'External', + 5: 'Internal + External'}), + 0x1006: ('ExposureCompensation', ), + 0x1007: ('SensorTemperature', ), + 0x1008: ('LensTemperature', ), + 0x100b: ('FocusMode', + {0: 'Auto', + 1: 'Manual'}), + 0x1017: ('RedBalance', ), + 0x1018: ('BlueBalance', ), + 0x101a: ('SerialNumber', ), + 0x1023: ('FlashExposureComp', ), + 0x1026: ('ExternalFlashBounce', + {0: 'No', + 1: 'Yes'}), + 0x1027: ('ExternalFlashZoom', ), + 0x1028: ('ExternalFlashMode', ), + 0x1029: ('Contrast int16u', + {0: 'High', + 1: 'Normal', + 2: 'Low'}), + 0x102a: ('SharpnessFactor', ), + 0x102b: ('ColorControl', ), + 0x102c: ('ValidBits', ), + 0x102d: ('CoringFilter', ), + 0x102e: ('OlympusImageWidth', ), + 0x102f: ('OlympusImageHeight', ), + 0x1034: ('CompressionRatio', ), + 0x1035: ('PreviewImageValid', + {0: 'No', + 1: 'Yes'}), + 0x1036: ('PreviewImageStart', ), + 0x1037: ('PreviewImageLength', ), + 0x1039: ('CCDScanMode', + {0: 'Interlaced', + 1: 'Progressive'}), + 0x103a: ('NoiseReduction', + {0: 'Off', + 1: 'On'}), + 0x103b: ('InfinityLensStep', ), + 0x103c: ('NearLensStep', ), + + # TODO - these need extra definitions + # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html + 0x2010: ('Equipment', ), + 0x2020: ('CameraSettings', ), + 0x2030: ('RawDevelopment', ), + 0x2040: ('ImageProcessing', ), + 0x2050: ('FocusInfo', ), + 0x3000: ('RawInfo ', ), + } + +# 0x2020 CameraSettings +MAKERNOTE_OLYMPUS_TAG_0x2020={ + 0x0100: ('PreviewImageValid', + {0: 'No', + 1: 'Yes'}), + 0x0101: ('PreviewImageStart', ), + 0x0102: ('PreviewImageLength', ), + 0x0200: ('ExposureMode', + {1: 'Manual', + 2: 'Program', + 3: 'Aperture-priority AE', + 4: 'Shutter speed priority AE', + 5: 'Program-shift'}), + 0x0201: ('AELock', + {0: 'Off', + 1: 'On'}), + 0x0202: ('MeteringMode', + {2: 'Center Weighted', + 3: 'Spot', + 5: 'ESP', + 261: 'Pattern+AF', + 515: 'Spot+Highlight control', + 1027: 'Spot+Shadow control'}), + 0x0300: ('MacroMode', + {0: 'Off', + 1: 'On'}), + 0x0301: ('FocusMode', + {0: 'Single AF', + 1: 'Sequential shooting AF', + 2: 'Continuous AF', + 3: 'Multi AF', + 10: 'MF'}), + 0x0302: ('FocusProcess', + {0: 'AF Not Used', + 1: 'AF Used'}), + 0x0303: ('AFSearch', + {0: 'Not Ready', + 1: 'Ready'}), + 0x0304: ('AFAreas', ), + 0x0401: ('FlashExposureCompensation', ), + 0x0500: ('WhiteBalance2', + {0: 'Auto', + 16: '7500K (Fine Weather with Shade)', + 17: '6000K (Cloudy)', + 18: '5300K (Fine Weather)', + 20: '3000K (Tungsten light)', + 21: '3600K (Tungsten light-like)', + 33: '6600K (Daylight fluorescent)', + 34: '4500K (Neutral white fluorescent)', + 35: '4000K (Cool white fluorescent)', + 48: '3600K (Tungsten light-like)', + 256: 'Custom WB 1', + 257: 'Custom WB 2', + 258: 'Custom WB 3', + 259: 'Custom WB 4', + 512: 'Custom WB 5400K', + 513: 'Custom WB 2900K', + 514: 'Custom WB 8000K', }), + 0x0501: ('WhiteBalanceTemperature', ), + 0x0502: ('WhiteBalanceBracket', ), + 0x0503: ('CustomSaturation', ), # (3 numbers: 1. CS Value, 2. Min, 3. Max) + 0x0504: ('ModifiedSaturation', + {0: 'Off', + 1: 'CM1 (Red Enhance)', + 2: 'CM2 (Green Enhance)', + 3: 'CM3 (Blue Enhance)', + 4: 'CM4 (Skin Tones)'}), + 0x0505: ('ContrastSetting', ), # (3 numbers: 1. Contrast, 2. Min, 3. Max) + 0x0506: ('SharpnessSetting', ), # (3 numbers: 1. Sharpness, 2. Min, 3. Max) + 0x0507: ('ColorSpace', + {0: 'sRGB', + 1: 'Adobe RGB', + 2: 'Pro Photo RGB'}), + 0x0509: ('SceneMode', + {0: 'Standard', + 6: 'Auto', + 7: 'Sport', + 8: 'Portrait', + 9: 'Landscape+Portrait', + 10: 'Landscape', + 11: 'Night scene', + 13: 'Panorama', + 16: 'Landscape+Portrait', + 17: 'Night+Portrait', + 19: 'Fireworks', + 20: 'Sunset', + 22: 'Macro', + 25: 'Documents', + 26: 'Museum', + 28: 'Beach&Snow', + 30: 'Candle', + 35: 'Underwater Wide1', + 36: 'Underwater Macro', + 39: 'High Key', + 40: 'Digital Image Stabilization', + 44: 'Underwater Wide2', + 45: 'Low Key', + 46: 'Children', + 48: 'Nature Macro'}), + 0x050a: ('NoiseReduction', + {0: 'Off', + 1: 'Noise Reduction', + 2: 'Noise Filter', + 3: 'Noise Reduction + Noise Filter', + 4: 'Noise Filter (ISO Boost)', + 5: 'Noise Reduction + Noise Filter (ISO Boost)'}), + 0x050b: ('DistortionCorrection', + {0: 'Off', + 1: 'On'}), + 0x050c: ('ShadingCompensation', + {0: 'Off', + 1: 'On'}), + 0x050d: ('CompressionFactor', ), + 0x050f: ('Gradation', + {'-1 -1 1': 'Low Key', + '0 -1 1': 'Normal', + '1 -1 1': 'High Key'}), + 0x0520: ('PictureMode', + {1: 'Vivid', + 2: 'Natural', + 3: 'Muted', + 256: 'Monotone', + 512: 'Sepia'}), + 0x0521: ('PictureModeSaturation', ), + 0x0522: ('PictureModeHue?', ), + 0x0523: ('PictureModeContrast', ), + 0x0524: ('PictureModeSharpness', ), + 0x0525: ('PictureModeBWFilter', + {0: 'n/a', + 1: 'Neutral', + 2: 'Yellow', + 3: 'Orange', + 4: 'Red', + 5: 'Green'}), + 0x0526: ('PictureModeTone', + {0: 'n/a', + 1: 'Neutral', + 2: 'Sepia', + 3: 'Blue', + 4: 'Purple', + 5: 'Green'}), + 0x0600: ('Sequence', ), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits + 0x0601: ('PanoramaMode', ), # (2 numbers: 1. Mode, 2. Shot number) + 0x0603: ('ImageQuality2', + {1: 'SQ', + 2: 'HQ', + 3: 'SHQ', + 4: 'RAW'}), + 0x0901: ('ManometerReading', ), + } + + +MAKERNOTE_CASIO_TAGS={ + 0x0001: ('RecordingMode', + {1: 'Single Shutter', + 2: 'Panorama', + 3: 'Night Scene', + 4: 'Portrait', + 5: 'Landscape'}), + 0x0002: ('Quality', + {1: 'Economy', + 2: 'Normal', + 3: 'Fine'}), + 0x0003: ('FocusingMode', + {2: 'Macro', + 3: 'Auto Focus', + 4: 'Manual Focus', + 5: 'Infinity'}), + 0x0004: ('FlashMode', + {1: 'Auto', + 2: 'On', + 3: 'Off', + 4: 'Red Eye Reduction'}), + 0x0005: ('FlashIntensity', + {11: 'Weak', + 13: 'Normal', + 15: 'Strong'}), + 0x0006: ('Object Distance', ), + 0x0007: ('WhiteBalance', + {1: 'Auto', + 2: 'Tungsten', + 3: 'Daylight', + 4: 'Fluorescent', + 5: 'Shade', + 129: 'Manual'}), + 0x000B: ('Sharpness', + {0: 'Normal', + 1: 'Soft', + 2: 'Hard'}), + 0x000C: ('Contrast', + {0: 'Normal', + 1: 'Low', + 2: 'High'}), + 0x000D: ('Saturation', + {0: 'Normal', + 1: 'Low', + 2: 'High'}), + 0x0014: ('CCDSpeed', + {64: 'Normal', + 80: 'Normal', + 100: 'High', + 125: '+1.0', + 244: '+3.0', + 250: '+2.0'}), + } + +MAKERNOTE_FUJIFILM_TAGS={ + 0x0000: ('NoteVersion', make_string), + 0x1000: ('Quality', ), + 0x1001: ('Sharpness', + {1: 'Soft', + 2: 'Soft', + 3: 'Normal', + 4: 'Hard', + 5: 'Hard'}), + 0x1002: ('WhiteBalance', + {0: 'Auto', + 256: 'Daylight', + 512: 'Cloudy', + 768: 'DaylightColor-Fluorescent', + 769: 'DaywhiteColor-Fluorescent', + 770: 'White-Fluorescent', + 1024: 'Incandescent', + 3840: 'Custom'}), + 0x1003: ('Color', + {0: 'Normal', + 256: 'High', + 512: 'Low'}), + 0x1004: ('Tone', + {0: 'Normal', + 256: 'High', + 512: 'Low'}), + 0x1010: ('FlashMode', + {0: 'Auto', + 1: 'On', + 2: 'Off', + 3: 'Red Eye Reduction'}), + 0x1011: ('FlashStrength', ), + 0x1020: ('Macro', + {0: 'Off', + 1: 'On'}), + 0x1021: ('FocusMode', + {0: 'Auto', + 1: 'Manual'}), + 0x1030: ('SlowSync', + {0: 'Off', + 1: 'On'}), + 0x1031: ('PictureMode', + {0: 'Auto', + 1: 'Portrait', + 2: 'Landscape', + 4: 'Sports', + 5: 'Night', + 6: 'Program AE', + 256: 'Aperture Priority AE', + 512: 'Shutter Priority AE', + 768: 'Manual Exposure'}), + 0x1100: ('MotorOrBracket', + {0: 'Off', + 1: 'On'}), + 0x1300: ('BlurWarning', + {0: 'Off', + 1: 'On'}), + 0x1301: ('FocusWarning', + {0: 'Off', + 1: 'On'}), + 0x1302: ('AEWarning', + {0: 'Off', + 1: 'On'}), + } + +MAKERNOTE_CANON_TAGS = { + 0x0006: ('ImageType', ), + 0x0007: ('FirmwareVersion', ), + 0x0008: ('ImageNumber', ), + 0x0009: ('OwnerName', ), + } + +# this is in element offset, name, optional value dictionary format +MAKERNOTE_CANON_TAG_0x001 = { + 1: ('Macromode', + {1: 'Macro', + 2: 'Normal'}), + 2: ('SelfTimer', ), + 3: ('Quality', + {2: 'Normal', + 3: 'Fine', + 5: 'Superfine'}), + 4: ('FlashMode', + {0: 'Flash Not Fired', + 1: 'Auto', + 2: 'On', + 3: 'Red-Eye Reduction', + 4: 'Slow Synchro', + 5: 'Auto + Red-Eye Reduction', + 6: 'On + Red-Eye Reduction', + 16: 'external flash'}), + 5: ('ContinuousDriveMode', + {0: 'Single Or Timer', + 1: 'Continuous'}), + 7: ('FocusMode', + {0: 'One-Shot', + 1: 'AI Servo', + 2: 'AI Focus', + 3: 'MF', + 4: 'Single', + 5: 'Continuous', + 6: 'MF'}), + 10: ('ImageSize', + {0: 'Large', + 1: 'Medium', + 2: 'Small'}), + 11: ('EasyShootingMode', + {0: 'Full Auto', + 1: 'Manual', + 2: 'Landscape', + 3: 'Fast Shutter', + 4: 'Slow Shutter', + 5: 'Night', + 6: 'B&W', + 7: 'Sepia', + 8: 'Portrait', + 9: 'Sports', + 10: 'Macro/Close-Up', + 11: 'Pan Focus'}), + 12: ('DigitalZoom', + {0: 'None', + 1: '2x', + 2: '4x'}), + 13: ('Contrast', + {0xFFFF: 'Low', + 0: 'Normal', + 1: 'High'}), + 14: ('Saturation', + {0xFFFF: 'Low', + 0: 'Normal', + 1: 'High'}), + 15: ('Sharpness', + {0xFFFF: 'Low', + 0: 'Normal', + 1: 'High'}), + 16: ('ISO', + {0: 'See ISOSpeedRatings Tag', + 15: 'Auto', + 16: '50', + 17: '100', + 18: '200', + 19: '400'}), + 17: ('MeteringMode', + {3: 'Evaluative', + 4: 'Partial', + 5: 'Center-weighted'}), + 18: ('FocusType', + {0: 'Manual', + 1: 'Auto', + 3: 'Close-Up (Macro)', + 8: 'Locked (Pan Mode)'}), + 19: ('AFPointSelected', + {0x3000: 'None (MF)', + 0x3001: 'Auto-Selected', + 0x3002: 'Right', + 0x3003: 'Center', + 0x3004: 'Left'}), + 20: ('ExposureMode', + {0: 'Easy Shooting', + 1: 'Program', + 2: 'Tv-priority', + 3: 'Av-priority', + 4: 'Manual', + 5: 'A-DEP'}), + 23: ('LongFocalLengthOfLensInFocalUnits', ), + 24: ('ShortFocalLengthOfLensInFocalUnits', ), + 25: ('FocalUnitsPerMM', ), + 28: ('FlashActivity', + {0: 'Did Not Fire', + 1: 'Fired'}), + 29: ('FlashDetails', + {14: 'External E-TTL', + 13: 'Internal Flash', + 11: 'FP Sync Used', + 7: '2nd("Rear")-Curtain Sync Used', + 4: 'FP Sync Enabled'}), + 32: ('FocusMode', + {0: 'Single', + 1: 'Continuous'}), + } + +MAKERNOTE_CANON_TAG_0x004 = { + 7: ('WhiteBalance', + {0: 'Auto', + 1: 'Sunny', + 2: 'Cloudy', + 3: 'Tungsten', + 4: 'Fluorescent', + 5: 'Flash', + 6: 'Custom'}), + 9: ('SequenceNumber', ), + 14: ('AFPointUsed', ), + 15: ('FlashBias', + {0xFFC0: '-2 EV', + 0xFFCC: '-1.67 EV', + 0xFFD0: '-1.50 EV', + 0xFFD4: '-1.33 EV', + 0xFFE0: '-1 EV', + 0xFFEC: '-0.67 EV', + 0xFFF0: '-0.50 EV', + 0xFFF4: '-0.33 EV', + 0x0000: '0 EV', + 0x000C: '0.33 EV', + 0x0010: '0.50 EV', + 0x0014: '0.67 EV', + 0x0020: '1 EV', + 0x002C: '1.33 EV', + 0x0030: '1.50 EV', + 0x0034: '1.67 EV', + 0x0040: '2 EV'}), + 19: ('SubjectDistance', ), + } + +# extract multibyte integer in Motorola format (little endian) +def s2n_motorola(str): + x = 0 + for c in str: + x = (x << 8) | ord(c) + return x + +# extract multibyte integer in Intel format (big endian) +def s2n_intel(str): + x = 0 + y = 0L + for c in str: + x = x | (ord(c) << y) + y = y + 8 + return x + +# ratio object that eventually will be able to reduce itself to lowest +# common denominator for printing +def gcd(a, b): + if b == 0: + return a + else: + return gcd(b, a % b) + +class Ratio: + def __init__(self, num, den): + self.num = num + self.den = den + + def __repr__(self): + self.reduce() + if self.den == 1: + return str(self.num) + return '%d/%d' % (self.num, self.den) + + def reduce(self): + div = gcd(self.num, self.den) + if div > 1: + self.num = self.num / div + self.den = self.den / div + +# for ease of dealing with tags +class IFD_Tag: + def __init__(self, printable, tag, field_type, values, field_offset, + field_length): + # printable version of data + self.printable = printable + # tag ID number + self.tag = tag + # field type as index into FIELD_TYPES + self.field_type = field_type + # offset of start of field in bytes from beginning of IFD + self.field_offset = field_offset + # length of data field in bytes + self.field_length = field_length + # either a string or array of data items + self.values = values + + def __str__(self): + return self.printable + + def __repr__(self): + return '(0x%04X) %s=%s @ %d' % (self.tag, + FIELD_TYPES[self.field_type][2], + self.printable, + self.field_offset) + +# class that handles an EXIF header +class EXIF_header: + def __init__(self, file, endian, offset, fake_exif, strict, debug=0): + self.file = file + self.endian = endian + self.offset = offset + self.fake_exif = fake_exif + self.strict = strict + self.debug = debug + self.tags = {} + + # convert slice to integer, based on sign and endian flags + # usually this offset is assumed to be relative to the beginning of the + # start of the EXIF information. For some cameras that use relative tags, + # this offset may be relative to some other starting point. + def s2n(self, offset, length, signed=0): + self.file.seek(self.offset+offset) + slice=self.file.read(length) + if self.endian == 'I': + val=s2n_intel(slice) + else: + val=s2n_motorola(slice) + # Sign extension ? + if signed: + msb=1L << (8*length-1) + if val & msb: + val=val-(msb << 1) + return val + + # convert offset to string + def n2s(self, offset, length): + s = '' + for dummy in range(length): + if self.endian == 'I': + s = s + chr(offset & 0xFF) + else: + s = chr(offset & 0xFF) + s + offset = offset >> 8 + return s + + # return first IFD + def first_IFD(self): + return self.s2n(4, 4) + + # return pointer to next IFD + def next_IFD(self, ifd): + entries=self.s2n(ifd, 2) + return self.s2n(ifd+2+12*entries, 4) + + # return list of IFDs in header + def list_IFDs(self): + i=self.first_IFD() + a=[] + while i: + a.append(i) + i=self.next_IFD(i) + return a + + # return list of entries in this IFD + def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0, stop_tag='UNDEF'): + entries=self.s2n(ifd, 2) + for i in range(entries): + # entry is index of start of this IFD in the file + entry = ifd + 2 + 12 * i + tag = self.s2n(entry, 2) + + # get tag name early to avoid errors, help debug + tag_entry = dict.get(tag) + if tag_entry: + tag_name = tag_entry[0] + else: + tag_name = 'Tag 0x%04X' % tag + + # ignore certain tags for faster processing + if not (not detailed and tag in IGNORE_TAGS): + field_type = self.s2n(entry + 2, 2) + + # unknown field type + if not 0 < field_type < len(FIELD_TYPES): + if not self.strict: + continue + else: + raise ValueError('unknown type %d in tag 0x%04X' % (field_type, tag)) + + typelen = FIELD_TYPES[field_type][0] + count = self.s2n(entry + 4, 4) + # Adjust for tag id/type/count (2+2+4 bytes) + # Now we point at either the data or the 2nd level offset + offset = entry + 8 + + # If the value fits in 4 bytes, it is inlined, else we + # need to jump ahead again. + if count * typelen > 4: + # offset is not the value; it's a pointer to the value + # if relative we set things up so s2n will seek to the right + # place when it adds self.offset. Note that this 'relative' + # is for the Nikon type 3 makernote. Other cameras may use + # other relative offsets, which would have to be computed here + # slightly differently. + if relative: + tmp_offset = self.s2n(offset, 4) + offset = tmp_offset + ifd - 8 + if self.fake_exif: + offset = offset + 18 + else: + offset = self.s2n(offset, 4) + + field_offset = offset + if field_type == 2: + # special case: null-terminated ASCII string + # XXX investigate + # sometimes gets too big to fit in int value + if count != 0 and count < (2**31): + self.file.seek(self.offset + offset) + values = self.file.read(count) + #print values + # Drop any garbage after a null. + values = values.split('\x00', 1)[0] + else: + values = '' + else: + values = [] + signed = (field_type in [6, 8, 9, 10]) + + # XXX investigate + # some entries get too big to handle could be malformed + # file or problem with self.s2n + if count < 1000: + for dummy in range(count): + if field_type in (5, 10): + # a ratio + value = Ratio(self.s2n(offset, 4, signed), + self.s2n(offset + 4, 4, signed)) + else: + value = self.s2n(offset, typelen, signed) + values.append(value) + offset = offset + typelen + # The test above causes problems with tags that are + # supposed to have long values! Fix up one important case. + elif tag_name == 'MakerNote' : + for dummy in range(count): + value = self.s2n(offset, typelen, signed) + values.append(value) + offset = offset + typelen + #else : + # print "Warning: dropping large tag:", tag, tag_name + + # now 'values' is either a string or an array + if count == 1 and field_type != 2: + printable=str(values[0]) + elif count > 50 and len(values) > 20 : + printable=str( values[0:20] )[0:-1] + ", ... ]" + else: + printable=str(values) + + # compute printable version of values + if tag_entry: + if len(tag_entry) != 1: + # optional 2nd tag element is present + if callable(tag_entry[1]): + # call mapping function + printable = tag_entry[1](values) + else: + printable = '' + for i in values: + # use lookup table for this tag + printable += tag_entry[1].get(i, repr(i)) + + self.tags[ifd_name + ' ' + tag_name] = IFD_Tag(printable, tag, + field_type, + values, field_offset, + count * typelen) + if self.debug: + print ' debug: %s: %s' % (tag_name, + repr(self.tags[ifd_name + ' ' + tag_name])) + + if tag_name == stop_tag: + break + + # extract uncompressed TIFF thumbnail (like pulling teeth) + # we take advantage of the pre-existing layout in the thumbnail IFD as + # much as possible + def extract_TIFF_thumbnail(self, thumb_ifd): + entries = self.s2n(thumb_ifd, 2) + # this is header plus offset to IFD ... + if self.endian == 'M': + tiff = 'MM\x00*\x00\x00\x00\x08' + else: + tiff = 'II*\x00\x08\x00\x00\x00' + # ... plus thumbnail IFD data plus a null "next IFD" pointer + self.file.seek(self.offset+thumb_ifd) + tiff += self.file.read(entries*12+2)+'\x00\x00\x00\x00' + + # fix up large value offset pointers into data area + for i in range(entries): + entry = thumb_ifd + 2 + 12 * i + tag = self.s2n(entry, 2) + field_type = self.s2n(entry+2, 2) + typelen = FIELD_TYPES[field_type][0] + count = self.s2n(entry+4, 4) + oldoff = self.s2n(entry+8, 4) + # start of the 4-byte pointer area in entry + ptr = i * 12 + 18 + # remember strip offsets location + if tag == 0x0111: + strip_off = ptr + strip_len = count * typelen + # is it in the data area? + if count * typelen > 4: + # update offset pointer (nasty "strings are immutable" crap) + # should be able to say "tiff[ptr:ptr+4]=newoff" + newoff = len(tiff) + tiff = tiff[:ptr] + self.n2s(newoff, 4) + tiff[ptr+4:] + # remember strip offsets location + if tag == 0x0111: + strip_off = newoff + strip_len = 4 + # get original data and store it + self.file.seek(self.offset + oldoff) + tiff += self.file.read(count * typelen) + + # add pixel strips and update strip offset info + old_offsets = self.tags['Thumbnail StripOffsets'].values + old_counts = self.tags['Thumbnail StripByteCounts'].values + for i in range(len(old_offsets)): + # update offset pointer (more nasty "strings are immutable" crap) + offset = self.n2s(len(tiff), strip_len) + tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:] + strip_off += strip_len + # add pixel strip to end + self.file.seek(self.offset + old_offsets[i]) + tiff += self.file.read(old_counts[i]) + + self.tags['TIFFThumbnail'] = tiff + + # decode all the camera-specific MakerNote formats + + # Note is the data that comprises this MakerNote. The MakerNote will + # likely have pointers in it that point to other parts of the file. We'll + # use self.offset as the starting point for most of those pointers, since + # they are relative to the beginning of the file. + # + # If the MakerNote is in a newer format, it may use relative addressing + # within the MakerNote. In that case we'll use relative addresses for the + # pointers. + # + # As an aside: it's not just to be annoying that the manufacturers use + # relative offsets. It's so that if the makernote has to be moved by the + # picture software all of the offsets don't have to be adjusted. Overall, + # this is probably the right strategy for makernotes, though the spec is + # ambiguous. (The spec does not appear to imagine that makernotes would + # follow EXIF format internally. Once they did, it's ambiguous whether + # the offsets should be from the header at the start of all the EXIF info, + # or from the header at the start of the makernote.) + def decode_maker_note(self): + note = self.tags['EXIF MakerNote'] + + # Some apps use MakerNote tags but do not use a format for which we + # have a description, so just do a raw dump for these. + #if self.tags.has_key('Image Make'): + make = self.tags['Image Make'].printable + #else: + # make = '' + + # model = self.tags['Image Model'].printable # unused + + # Nikon + # The maker note usually starts with the word Nikon, followed by the + # type of the makernote (1 or 2, as a short). If the word Nikon is + # not at the start of the makernote, it's probably type 2, since some + # cameras work that way. + if 'NIKON' in make: + if note.values[0:7] == [78, 105, 107, 111, 110, 0, 1]: + if self.debug: + print "Looks like a type 1 Nikon MakerNote." + self.dump_IFD(note.field_offset+8, 'MakerNote', + dict=MAKERNOTE_NIKON_OLDER_TAGS) + elif note.values[0:7] == [78, 105, 107, 111, 110, 0, 2]: + if self.debug: + print "Looks like a labeled type 2 Nikon MakerNote" + if note.values[12:14] != [0, 42] and note.values[12:14] != [42L, 0L]: + raise ValueError("Missing marker tag '42' in MakerNote.") + # skip the Makernote label and the TIFF header + self.dump_IFD(note.field_offset+10+8, 'MakerNote', + dict=MAKERNOTE_NIKON_NEWER_TAGS, relative=1) + else: + # E99x or D1 + if self.debug: + print "Looks like an unlabeled type 2 Nikon MakerNote" + self.dump_IFD(note.field_offset, 'MakerNote', + dict=MAKERNOTE_NIKON_NEWER_TAGS) + return + + # Olympus + if make.startswith('OLYMPUS'): + self.dump_IFD(note.field_offset+8, 'MakerNote', + dict=MAKERNOTE_OLYMPUS_TAGS) + # XXX TODO + #for i in (('MakerNote Tag 0x2020', MAKERNOTE_OLYMPUS_TAG_0x2020),): + # self.decode_olympus_tag(self.tags[i[0]].values, i[1]) + #return + + # Casio + if 'CASIO' in make or 'Casio' in make: + self.dump_IFD(note.field_offset, 'MakerNote', + dict=MAKERNOTE_CASIO_TAGS) + return + + # Fujifilm + if make == 'FUJIFILM': + # bug: everything else is "Motorola" endian, but the MakerNote + # is "Intel" endian + endian = self.endian + self.endian = 'I' + # bug: IFD offsets are from beginning of MakerNote, not + # beginning of file header + offset = self.offset + self.offset += note.field_offset + # process note with bogus values (note is actually at offset 12) + self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS) + # reset to correct values + self.endian = endian + self.offset = offset + return + + # Canon + if make == 'Canon': + self.dump_IFD(note.field_offset, 'MakerNote', + dict=MAKERNOTE_CANON_TAGS) + for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001), + ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)): + self.canon_decode_tag(self.tags[i[0]].values, i[1]) + return + + + # XXX TODO decode Olympus MakerNote tag based on offset within tag + def olympus_decode_tag(self, value, dict): + pass + + # decode Canon MakerNote tag based on offset within tag + # see http://www.burren.cx/david/canon.html by David Burren + def canon_decode_tag(self, value, dict): + for i in range(1, len(value)): + x=dict.get(i, ('Unknown', )) + if self.debug: + print i, x + name=x[0] + if len(x) > 1: + val=x[1].get(value[i], 'Unknown') + else: + val=value[i] + # it's not a real IFD Tag but we fake one to make everybody + # happy. this will have a "proprietary" type + self.tags['MakerNote '+name]=IFD_Tag(str(val), None, 0, None, + None, None) + +# process an image file (expects an open file object) +# this is the function that has to deal with all the arbitrary nasty bits +# of the EXIF standard +def process_file(f, stop_tag='UNDEF', details=True, strict=False, debug=False): + # yah it's cheesy... + global detailed + detailed = details + + # by default do not fake an EXIF beginning + fake_exif = 0 + + # determine whether it's a JPEG or TIFF + data = f.read(12) + if data[0:4] in ['II*\x00', 'MM\x00*']: + # it's a TIFF file + f.seek(0) + endian = f.read(1) + f.read(1) + offset = 0 + elif data[0:2] == '\xFF\xD8': + # it's a JPEG file + while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM', 'Phot'): + length = ord(data[4])*256+ord(data[5]) + f.read(length-8) + # fake an EXIF beginning of file + data = '\xFF\x00'+f.read(10) + fake_exif = 1 + if data[2] == '\xFF' and data[6:10] == 'Exif': + # detected EXIF header + offset = f.tell() + endian = f.read(1) + else: + # no EXIF information + return {} + else: + # file format not recognized + return {} + + # deal with the EXIF info we found + if debug: + print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format' + hdr = EXIF_header(f, endian, offset, fake_exif, strict, debug) + ifd_list = hdr.list_IFDs() + ctr = 0 + for i in ifd_list: + if ctr == 0: + IFD_name = 'Image' + elif ctr == 1: + IFD_name = 'Thumbnail' + thumb_ifd = i + else: + IFD_name = 'IFD %d' % ctr + if debug: + print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i) + hdr.dump_IFD(i, IFD_name, stop_tag=stop_tag) + # EXIF IFD + exif_off = hdr.tags.get(IFD_name+' ExifOffset') + if exif_off: + if debug: + print ' EXIF SubIFD at offset %d:' % exif_off.values[0] + hdr.dump_IFD(exif_off.values[0], 'EXIF', stop_tag=stop_tag) + # Interoperability IFD contained in EXIF IFD + intr_off = hdr.tags.get('EXIF SubIFD InteroperabilityOffset') + if intr_off: + if debug: + print ' EXIF Interoperability SubSubIFD at offset %d:' \ + % intr_off.values[0] + hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability', + dict=INTR_TAGS, stop_tag=stop_tag) + # GPS IFD + gps_off = hdr.tags.get(IFD_name+' GPSInfo') + if gps_off: + if debug: + print ' GPS SubIFD at offset %d:' % gps_off.values[0] + hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS, stop_tag=stop_tag) + ctr += 1 + + # extract uncompressed TIFF thumbnail + thumb = hdr.tags.get('Thumbnail Compression') + if thumb and thumb.printable == 'Uncompressed TIFF': + hdr.extract_TIFF_thumbnail(thumb_ifd) + + # JPEG thumbnail (thankfully the JPEG data is stored as a unit) + thumb_off = hdr.tags.get('Thumbnail JPEGInterchangeFormat') + if thumb_off: + f.seek(offset+thumb_off.values[0]) + size = hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0] + hdr.tags['JPEGThumbnail'] = f.read(size) + + # deal with MakerNote contained in EXIF IFD + # (Some apps use MakerNote tags but do not use a format for which we + # have a description, do not process these). + if 'EXIF MakerNote' in hdr.tags and 'Image Make' in hdr.tags and detailed: + hdr.decode_maker_note() + + # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote + # since it's not allowed in a uncompressed TIFF IFD + if 'JPEGThumbnail' not in hdr.tags: + thumb_off=hdr.tags.get('MakerNote JPEGThumbnail') + if thumb_off: + f.seek(offset+thumb_off.values[0]) + hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length) + + return hdr.tags + + +# show command line usage +def usage(exit_status): + msg = 'Usage: EXIF.py [OPTIONS] file1 [file2 ...]\n' + msg += 'Extract EXIF information from digital camera image files.\n\nOptions:\n' + msg += '-q --quick Do not process MakerNotes.\n' + msg += '-t TAG --stop-tag TAG Stop processing when this tag is retrieved.\n' + msg += '-s --strict Run in strict mode (stop on errors).\n' + msg += '-d --debug Run in debug mode (display extra info).\n' + print msg + sys.exit(exit_status) + +# library test/debug function (dump given files) +if __name__ == '__main__': + import sys + import getopt + + # parse command line options/arguments + try: + opts, args = getopt.getopt(sys.argv[1:], "hqsdt:v", ["help", "quick", "strict", "debug", "stop-tag="]) + except getopt.GetoptError: + usage(2) + if args == []: + usage(2) + detailed = True + stop_tag = 'UNDEF' + debug = False + strict = False + for o, a in opts: + if o in ("-h", "--help"): + usage(0) + if o in ("-q", "--quick"): + detailed = False + if o in ("-t", "--stop-tag"): + stop_tag = a + if o in ("-s", "--strict"): + strict = True + if o in ("-d", "--debug"): + debug = True + + # output info for each file + for filename in args: + try: + file=open(filename, 'rb') + except: + print "'%s' is unreadable\n"%filename + continue + print filename + ':' + # get the tags + data = process_file(file, stop_tag=stop_tag, details=detailed, strict=strict, debug=debug) + if not data: + print 'No EXIF information found' + continue + + x=data.keys() + x.sort() + for i in x: + if i in ('JPEGThumbnail', 'TIFFThumbnail'): + continue + try: + print ' %s (%s): %s' % \ + (i, FIELD_TYPES[data[i].field_type][2], data[i].printable) + except: + print 'error', i, '"', data[i], '"' + if 'JPEGThumbnail' in data: + print 'File has JPEG thumbnail' + print + diff --git a/mediagoblin/media_types/image/EXIF.py b/mediagoblin/media_types/image/EXIF.py new file mode 120000 index 00000000..82a2fb30 --- /dev/null +++ b/mediagoblin/media_types/image/EXIF.py @@ -0,0 +1 @@ +../../../extlib/exif/EXIF.py \ No newline at end of file -- cgit v1.2.3 From 836df45dbecbaa5c8156dbbdb93c1c23bee44be4 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 02:53:46 +0100 Subject: Added code for leaflet geolocation map --- mediagoblin/static/js/extlib/leaflet | 1 + mediagoblin/static/js/geolocation-map.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 120000 mediagoblin/static/js/extlib/leaflet create mode 100644 mediagoblin/static/js/geolocation-map.js diff --git a/mediagoblin/static/js/extlib/leaflet b/mediagoblin/static/js/extlib/leaflet new file mode 120000 index 00000000..2fc302d7 --- /dev/null +++ b/mediagoblin/static/js/extlib/leaflet @@ -0,0 +1 @@ +../../../../extlib/leaflet/dist/ \ No newline at end of file diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js new file mode 100644 index 00000000..22cbe2f3 --- /dev/null +++ b/mediagoblin/static/js/geolocation-map.js @@ -0,0 +1,29 @@ +$(document).ready(function () { + var longitude = Number( + $('#tile-map #gps-longitude').val()); + var latitude = Number( + $('#tile-map #gps-latitude').val()); + + console.log(longitude, latitude); + + var map = new L.Map('tile-map'); + + var mqtileUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg'; + var mqtileAttrib = 'Map data © ' + + String(new Date().getFullYear()) + + ' OpenStreetMap contributors, CC-BY-SA.' + + ' Imaging © ' + + String(new Date().getFullYear()) + + ' MapQuest.'; + var mqtile = new L.TileLayer( + mqtileUrl, + {maxZoom: 18, + attribution: mqtileAttrib, + subdomains: '1234'}); + + var location = new L.LatLng(latitude, longitude); // geographical point (longitude and latitude) + map.setView(location, 13).addLayer(mqtile); + + var marker = new L.Marker(location); + map.addLayer(marker); +}); -- cgit v1.2.3 From e8e444a85e2b16583587ff5a074f0ab1ffbaca85 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 02:59:07 +0100 Subject: EXIF extraction, geolocation map, image rotation - Images are now rotated based on EXIF image orientation (in case the image isn't flipped on X or Y axis or correctly oriented, then we do nothing) - *Always* create a medium.jpg in image.processing, for the sake of rotation of display image - Extract EXIF and GPS tags from images and insert them into media_data - Geolocation map display added to media.html - EXIF display added, then removed. It is not in this revision, although some of it is (the "EXIF" h4 header). Need to make it presentable, filtering out purely robotical tags, perhaps. --- mediagoblin/media_types/image/processing.py | 161 ++++++++++++++++++--- .../templates/mediagoblin/user_pages/media.html | 43 ++++++ 2 files changed, 185 insertions(+), 19 deletions(-) diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index cf90388f..9eb8fa16 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -18,14 +18,10 @@ import Image import os from mediagoblin import mg_globals as mgg - from mediagoblin.processing import BadMediaFail, \ create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE - -################################ -# Media processing initial steps -################################ - +from mediagoblin.media_types.image.EXIF import process_file +from mediagoblin.tools.translate import pass_to_ugettext as _ def process_image(entry): """ @@ -46,11 +42,17 @@ def process_image(entry): basename = os.path.split(filename_bits[0])[1] extension = filename_bits[1].lower() + # EXIF extraction + exif_tags = extract_exif(queued_filename) + gps_data = get_gps_data(exif_tags) + try: thumb = Image.open(queued_filename) except IOError: raise BadMediaFail() + thumb = exif_fix_image_orientation(thumb, exif_tags) + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) # Copy the thumb to the conversion subdir, then remotely. @@ -67,23 +69,22 @@ def process_image(entry): # file, a `medium.jpg` files is created and later associated with the media # entry. medium = Image.open(queued_filename) - medium_processed = False + # Fox orientation + medium = exif_fix_image_orientation(medium, exif_tags) if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) - medium_filename = 'medium' + extension - medium_filepath = create_pub_filepath(entry, medium_filename) - tmp_medium_filename = os.path.join( - conversions_subdir, medium_filename) - - with file(tmp_medium_filename, 'w') as medium_file: - medium.save(medium_file) + medium_filename = 'medium' + extension + medium_filepath = create_pub_filepath(entry, medium_filename) + tmp_medium_filename = os.path.join( + conversions_subdir, medium_filename) - mgg.public_store.copy_local_to_storage( - tmp_medium_filename, medium_filepath) + with file(tmp_medium_filename, 'w') as medium_file: + medium.save(medium_file) - medium_processed = True + mgg.public_store.copy_local_to_storage( + tmp_medium_filename, medium_filepath) # we have to re-read because unlike PIL, not everything reads # things in string representation :) @@ -97,13 +98,135 @@ def process_image(entry): as original_file: original_file.write(queued_file.read()) + # Remove queued media file from storage and database mgg.queue_store.delete_file(queued_filepath) entry.queued_media_file = [] + + # Insert media file information into database media_files_dict = entry.setdefault('media_files', {}) media_files_dict['thumb'] = thumb_filepath media_files_dict['original'] = original_filepath - if medium_processed: - media_files_dict['medium'] = medium_filepath + media_files_dict['medium'] = medium_filepath + + # Insert exif data into database + media_data = entry.setdefault('media_data', {}) + media_data['exif'] = clean_exif(exif_tags) + media_data['gps'] = gps_data # clean up workbench workbench.destroy_self() + +def exif_fix_image_orientation(im, exif_tags): + """ + Translate any EXIF orientation to raw orientation + + Cons: + - REDUCES IMAGE QUALITY by recompressig it + + Pros: + - Cures my neck pain + """ + # Rotate image + if 'Image Orientation' in exif_tags: + rotation_map = { + 3: 180, + 6: 270, + 8: 90} + orientation = exif_tags['Image Orientation'].values[0] + if orientation in rotation_map.keys(): + im = im.rotate( + rotation_map[orientation]) + + return im + +def extract_exif(filename): + """ + Returns EXIF tags found in file at ``filename`` + """ + exif_tags = {} + + try: + image = open(filename) + exif_tags = process_file(image) + except IOError: + BadMediaFail(_('Could not read the image file.')) + + return exif_tags + +def clean_exif(exif): + # Clean the result from anything the database cannot handle + + # Discard any JPEG thumbnail, for database compatibility + # and that I cannot see a case when we would use it. + # It takes up some space too. + disabled_tags = [ + 'Thumbnail JPEGInterchangeFormatLength', + 'JPEGThumbnail', + 'Thumbnail JPEGInterchangeFormat'] + + clean_exif = {} + + for key, value in exif.items(): + if not key in disabled_tags: + clean_exif[key] = str(value) + + return clean_exif + + +def get_gps_data(exif): + """ + Processes EXIF data returned by EXIF.py + """ + if not 'Image GPSInfo' in exif: + return False + + gps_data = {} + + try: + dms_data = { + 'latitude': exif['GPS GPSLatitude'], + 'longitude': exif['GPS GPSLongitude']} + + for key, dat in dms_data.items(): + gps_data[key] = ( + lambda v: + float(v[0].num) / float(v[0].den) \ + + (float(v[1].num) / float(v[1].den) / 60 )\ + + (float(v[2].num) / float(v[2].den) / (60 * 60)) + )(dat.values) + except KeyError: + pass + + try: + gps_data['direction'] = ( + lambda d: + float(d.num) / float(d.den) + )(exif['GPS GPSImgDirection'].values[0]) + except KeyError: + pass + + try: + gps_data['altitude'] = ( + lambda a: + float(a.num) / float(a.den) + )(exif['GPS GPSAltitude'].values[0]) + except KeyError: + pass + + return gps_data + + +if __name__ == '__main__': + import sys + import pprint + + pp = pprint.PrettyPrinter() + + result = extract_exif(sys.argv[1]) + gps = get_gps_data(result) + + import pdb + pdb.set_trace() + + print pp.pprint( + result) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index cbe26cbf..944d7f6e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -23,8 +23,16 @@ {% block title %}{{ media.title }} — {{ super() }}{% endblock %} {% block mediagoblin_head %} + + + + {% endblock mediagoblin_head %} {% block mediagoblin_content %} @@ -72,6 +80,21 @@ media= media._id) %} {% trans %}Delete{% endtrans %} {% endif %} + {% if media.media_data.exif %} + {#- + TODO: + - Render GPS data in a human-readable format + +

EXIF

+
{{ media_entry['title'] }}{{ media_entry['created'].strftime("%m-%d-%Y %I:%M %p") }}{{ media_entry.created.strftime("%m-%d-%Y %I:%M %p") }}
{{ media_entry['title'] }}{{ media_entry.title }} {{ media_entry.created.strftime("%m-%d-%Y %I:%M %p") }}
{{ media_entry['title'] }}{{ media_entry.title }} {{ media_entry['created'].strftime("%m-%d-%Y %I:%M %p") }} {{ media_entry.get_fail_exception().general_message }}
+ {% for tag, value in media.media_data.exif.items() %} + + + + + {% endfor %} +
{{ tag }}{{ value }}
#} + {% endif %}

{% if comments %}

@@ -171,6 +194,26 @@ {% include "mediagoblin/utils/tags.html" %} {% endif %} + {% if media.media_data.gps %} +

Map

+
+ {% set gps = media.media_data.gps %} +
+ + +
+

+ + View on + + OpenStreetMap + + +

+
+ {% endif %} {% include "mediagoblin/utils/license.html" %}
{% endblock %} -- cgit v1.2.3 From a020391d908ec685d4fc1b14956d1abec6701a77 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 16 Jan 2012 03:25:57 +0100 Subject: Removed link to EXIF.py in media_types.image --- mediagoblin/media_types/image/EXIF.py | 1 - 1 file changed, 1 deletion(-) delete mode 120000 mediagoblin/media_types/image/EXIF.py diff --git a/mediagoblin/media_types/image/EXIF.py b/mediagoblin/media_types/image/EXIF.py deleted file mode 120000 index 82a2fb30..00000000 --- a/mediagoblin/media_types/image/EXIF.py +++ /dev/null @@ -1 +0,0 @@ -../../../extlib/exif/EXIF.py \ No newline at end of file -- cgit v1.2.3 From a180ca264e937f7f862c09c30ce3fe7f819ff515 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 16 Jan 2012 03:45:58 +0100 Subject: EXIF fixes - Moved exif functions from mediagoblin.media_types.image.processing to mediagoblin.tools.exif - Moved EXIF.py link from mediagoblin.media_types to mediagoblin.tools.extlib - Refractored and updated EXIF exctraction and presentation --- mediagoblin/media_types/image/processing.py | 113 ++------------ .../templates/mediagoblin/user_pages/media.html | 16 +- mediagoblin/tools/exif.py | 168 +++++++++++++++++++++ mediagoblin/tools/extlib/EXIF.py | 1 + mediagoblin/tools/extlib/__init__.py | 0 5 files changed, 187 insertions(+), 111 deletions(-) create mode 100644 mediagoblin/tools/exif.py create mode 120000 mediagoblin/tools/extlib/EXIF.py create mode 100644 mediagoblin/tools/extlib/__init__.py diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 9eb8fa16..f669e1a5 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -20,8 +20,8 @@ import os from mediagoblin import mg_globals as mgg from mediagoblin.processing import BadMediaFail, \ create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE -from mediagoblin.media_types.image.EXIF import process_file -from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.exif import exif_fix_image_orientation, \ + extract_exif, clean_exif, get_gps_data, get_useful def process_image(entry): """ @@ -110,112 +110,15 @@ def process_image(entry): # Insert exif data into database media_data = entry.setdefault('media_data', {}) - media_data['exif'] = clean_exif(exif_tags) + media_data['exif'] = { + 'clean': clean_exif(exif_tags)} + media_data['exif']['useful'] = get_useful( + media_data['exif']['clean']) media_data['gps'] = gps_data # clean up workbench workbench.destroy_self() -def exif_fix_image_orientation(im, exif_tags): - """ - Translate any EXIF orientation to raw orientation - - Cons: - - REDUCES IMAGE QUALITY by recompressig it - - Pros: - - Cures my neck pain - """ - # Rotate image - if 'Image Orientation' in exif_tags: - rotation_map = { - 3: 180, - 6: 270, - 8: 90} - orientation = exif_tags['Image Orientation'].values[0] - if orientation in rotation_map.keys(): - im = im.rotate( - rotation_map[orientation]) - - return im - -def extract_exif(filename): - """ - Returns EXIF tags found in file at ``filename`` - """ - exif_tags = {} - - try: - image = open(filename) - exif_tags = process_file(image) - except IOError: - BadMediaFail(_('Could not read the image file.')) - - return exif_tags - -def clean_exif(exif): - # Clean the result from anything the database cannot handle - - # Discard any JPEG thumbnail, for database compatibility - # and that I cannot see a case when we would use it. - # It takes up some space too. - disabled_tags = [ - 'Thumbnail JPEGInterchangeFormatLength', - 'JPEGThumbnail', - 'Thumbnail JPEGInterchangeFormat'] - - clean_exif = {} - - for key, value in exif.items(): - if not key in disabled_tags: - clean_exif[key] = str(value) - - return clean_exif - - -def get_gps_data(exif): - """ - Processes EXIF data returned by EXIF.py - """ - if not 'Image GPSInfo' in exif: - return False - - gps_data = {} - - try: - dms_data = { - 'latitude': exif['GPS GPSLatitude'], - 'longitude': exif['GPS GPSLongitude']} - - for key, dat in dms_data.items(): - gps_data[key] = ( - lambda v: - float(v[0].num) / float(v[0].den) \ - + (float(v[1].num) / float(v[1].den) / 60 )\ - + (float(v[2].num) / float(v[2].den) / (60 * 60)) - )(dat.values) - except KeyError: - pass - - try: - gps_data['direction'] = ( - lambda d: - float(d.num) / float(d.den) - )(exif['GPS GPSImgDirection'].values[0]) - except KeyError: - pass - - try: - gps_data['altitude'] = ( - lambda a: - float(a.num) / float(a.den) - )(exif['GPS GPSAltitude'].values[0]) - except KeyError: - pass - - return gps_data - - if __name__ == '__main__': import sys import pprint @@ -224,9 +127,11 @@ if __name__ == '__main__': result = extract_exif(sys.argv[1]) gps = get_gps_data(result) + clean = clean_exif(result) + useful = get_useful(clean) import pdb pdb.set_trace() print pp.pprint( - result) + clean) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 944d7f6e..60fca710 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -80,20 +80,21 @@ media= media._id) %} {% trans %}Delete{% endtrans %} {% endif %} - {% if media.media_data.exif %} + {% if media.media_data.has_key('exif') + and media.media_data.exif.has_key('useful') %} {#- TODO: - Render GPS data in a human-readable format - + #}

EXIF

- {% for tag, value in media.media_data.exif.items() %} + {% for key, tag in media.media_data.exif.useful.items() %} - - + + {% endfor %} -
{{ tag }}{{ value }}{{ key }}{{ tag.printable }}
#} + {% endif %}

{% if comments %} @@ -194,7 +195,8 @@ {% include "mediagoblin/utils/tags.html" %} {% endif %} - {% if media.media_data.gps %} + {% if media.media_data.has_key('gps') + and media.media_data.gps %}

Map

{% set gps = media.media_data.gps %} diff --git a/mediagoblin/tools/exif.py b/mediagoblin/tools/exif.py new file mode 100644 index 00000000..445907ba --- /dev/null +++ b/mediagoblin/tools/exif.py @@ -0,0 +1,168 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.tools.extlib.EXIF import process_file, Ratio +from mediagoblin.processing import BadMediaFail +from mediagoblin.tools.translate import pass_to_ugettext as _ + +from collections import OrderedDict + +# A list of tags that should be stored for faster access +USEFUL_TAGS = [ + 'Image Make', + 'Image Model', + 'EXIF FNumber', + 'EXIF Flash', + 'EXIF FocalLength', + 'EXIF ExposureTime', + 'EXIF ApertureValue', + 'EXIF ExposureMode', + 'EXIF ISOSpeedRatings', + 'EXIF UserComment', + ] + +def exif_fix_image_orientation(im, exif_tags): + """ + Translate any EXIF orientation to raw orientation + + Cons: + - REDUCES IMAGE QUALITY by recompressig it + + Pros: + - Cures my neck pain + """ + # Rotate image + if 'Image Orientation' in exif_tags: + rotation_map = { + 3: 180, + 6: 270, + 8: 90} + orientation = exif_tags['Image Orientation'].values[0] + if orientation in rotation_map.keys(): + im = im.rotate( + rotation_map[orientation]) + + return im + +def extract_exif(filename): + """ + Returns EXIF tags found in file at ``filename`` + """ + exif_tags = {} + + try: + image = open(filename) + exif_tags = process_file(image) + except IOError: + raise BadMediaFail(_('Could not read the image file.')) + + return exif_tags + +def clean_exif(exif): + ''' + Clean the result from anyt +hing the database cannot handle + ''' + # Discard any JPEG thumbnail, for database compatibility + # and that I cannot see a case when we would use it. + # It takes up some space too. + disabled_tags = [ + 'Thumbnail JPEGInterchangeFormatLength', + 'JPEGThumbnail', + 'Thumbnail JPEGInterchangeFormat'] + + clean_exif = {} + + for key, value in exif.items(): + if not key in disabled_tags: + clean_exif[key] = _ifd_tag_to_dict(value) + + return clean_exif + +def _ifd_tag_to_dict(tag): + data = { + 'printable': tag.printable, + 'tag': tag.tag, + 'field_type': tag.field_type, + 'field_offset': tag.field_offset, + 'field_length': tag.field_length, + 'values': None} + if type(tag.values) == list: + data['values'] = [] + for val in tag.values: + if isinstance(val, Ratio): + data['values'].append( + _ratio_to_list(val)) + else: + data['values'].append(val) + else: + data['values'] = tag.values + + return data + +def _ratio_to_list(ratio): + return [ratio.num, ratio.den] + +def get_useful(tags): + useful = {} + for key, tag in tags.items(): + if key in USEFUL_TAGS: + useful[key] = tag + + return useful + + +def get_gps_data(tags): + """ + Processes EXIF data returned by EXIF.py + """ + if not 'Image GPSInfo' in tags: + return False + + gps_data = {} + + try: + dms_data = { + 'latitude': tags['GPS GPSLatitude'], + 'longitude': tags['GPS GPSLongitude']} + + for key, dat in dms_data.items(): + gps_data[key] = ( + lambda v: + float(v[0].num) / float(v[0].den) \ + + (float(v[1].num) / float(v[1].den) / 60 )\ + + (float(v[2].num) / float(v[2].den) / (60 * 60)) + )(dat.values) + except KeyError: + pass + + try: + gps_data['direction'] = ( + lambda d: + float(d.num) / float(d.den) + )(tags['GPS GPSImgDirection'].values[0]) + except KeyError: + pass + + try: + gps_data['altitude'] = ( + lambda a: + float(a.num) / float(a.den) + )(tags['GPS GPSAltitude'].values[0]) + except KeyError: + pass + + return gps_data diff --git a/mediagoblin/tools/extlib/EXIF.py b/mediagoblin/tools/extlib/EXIF.py new file mode 120000 index 00000000..82a2fb30 --- /dev/null +++ b/mediagoblin/tools/extlib/EXIF.py @@ -0,0 +1 @@ +../../../extlib/exif/EXIF.py \ No newline at end of file diff --git a/mediagoblin/tools/extlib/__init__.py b/mediagoblin/tools/extlib/__init__.py new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 5907222c0b5b1fb25b93de3b5cf5751de2da3013 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 20 Jan 2012 02:31:29 +0100 Subject: Added exif_visisble and geolocation_map_visible to config_spec --- mediagoblin/config_spec.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index dc286a27..2d410899 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -53,6 +53,9 @@ csrf_cookie_name = string(default='mediagoblin_csrftoken') # Push stuff push_urls = string_list(default=list()) +exif_visible = boolean(default=False) +geolocation_map_visible = boolean(default=False) + [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/public") -- cgit v1.2.3 From 6d9ce47f5c90fffdac33c32dfcb9dd5c6fa37b11 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 20 Jan 2012 10:27:26 +0100 Subject: Moved EXIF to sidebar, added conditions for visibility configuration settings --- .../templates/mediagoblin/user_pages/media.html | 37 ++++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 60fca710..446c9f85 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -80,22 +80,6 @@ media= media._id) %} {% trans %}Delete{% endtrans %} {% endif %} - {% if media.media_data.has_key('exif') - and media.media_data.exif.has_key('useful') %} - {#- - TODO: - - Render GPS data in a human-readable format - #} -

EXIF

- - {% for key, tag in media.media_data.exif.useful.items() %} - - - - - {% endfor %} -
{{ key }}{{ tag.printable }}
- {% endif %}

{% if comments %}

@@ -195,7 +179,10 @@ {% include "mediagoblin/utils/tags.html" %} {% endif %} + {% include "mediagoblin/utils/license.html" %} + {% if media.media_data.has_key('gps') + and app_config['geolocation_map_visible'] and media.media_data.gps %}

Map

@@ -216,6 +203,22 @@

{% endif %} - {% include "mediagoblin/utils/license.html" %} + {% if media.media_data.has_key('exif') + and app_config['exif_visible'] + and media.media_data.exif.has_key('useful') %} + {#- + TODO: + - Render GPS data in a human-readable format + #} +

EXIF

+ + {% for key, tag in media.media_data.exif.useful.items() %} + + + + + {% endfor %} +
{{ key }}{{ tag.printable }}
+ {% endif %}
{% endblock %} -- cgit v1.2.3 From 63bd7c04bdc11cfd6d5805005b4e421f832106bb Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 25 Jan 2012 23:05:47 +0100 Subject: Acts on feedback from Chris - Added EXIF tests - Removed pdb from image processing "ifmain" - Fixed comment typo in image processing - Removed unused import in tools.exif --- mediagoblin/media_types/image/processing.py | 10 +- mediagoblin/tests/test_exif.py | 189 ++++++++++++++++++++++++++++ mediagoblin/tests/test_exif/bad.jpg | 18 +++ mediagoblin/tests/test_exif/empty.jpg | Bin 0 -> 26636 bytes mediagoblin/tests/test_exif/good.jpg | Bin 0 -> 207590 bytes mediagoblin/tests/test_exif/has-gps.jpg | Bin 0 -> 1933121 bytes mediagoblin/tools/exif.py | 11 +- 7 files changed, 217 insertions(+), 11 deletions(-) create mode 100644 mediagoblin/tests/test_exif.py create mode 100644 mediagoblin/tests/test_exif/bad.jpg create mode 100644 mediagoblin/tests/test_exif/empty.jpg create mode 100644 mediagoblin/tests/test_exif/good.jpg create mode 100644 mediagoblin/tests/test_exif/has-gps.jpg diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index f669e1a5..78f64be0 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -58,10 +58,13 @@ def process_image(entry): # Copy the thumb to the conversion subdir, then remotely. thumb_filename = 'thumbnail' + extension thumb_filepath = create_pub_filepath(entry, thumb_filename) + tmp_thumb_filename = os.path.join( conversions_subdir, thumb_filename) + with file(tmp_thumb_filename, 'w') as thumb_file: thumb.save(thumb_file) + mgg.public_store.copy_local_to_storage( tmp_thumb_filename, thumb_filepath) @@ -69,7 +72,8 @@ def process_image(entry): # file, a `medium.jpg` files is created and later associated with the media # entry. medium = Image.open(queued_filename) - # Fox orientation + + # Fix orientation medium = exif_fix_image_orientation(medium, exif_tags) if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]: @@ -77,6 +81,7 @@ def process_image(entry): medium_filename = 'medium' + extension medium_filepath = create_pub_filepath(entry, medium_filename) + tmp_medium_filename = os.path.join( conversions_subdir, medium_filename) @@ -130,8 +135,5 @@ if __name__ == '__main__': clean = clean_exif(result) useful = get_useful(clean) - import pdb - pdb.set_trace() - print pp.pprint( clean) diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py new file mode 100644 index 00000000..9f2219c0 --- /dev/null +++ b/mediagoblin/tests/test_exif.py @@ -0,0 +1,189 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import pkg_resources +import Image + +from mediagoblin.tools.exif import exif_fix_image_orientation, \ + extract_exif, clean_exif, get_gps_data, get_useful + +GOOD_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', + os.path.join( + 'test_exif', + 'good.jpg')) +EMPTY_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', + os.path.join( + 'test_exif', + 'empty.jpg')) +BAD_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', + os.path.join( + 'test_exif', + 'bad.jpg')) +GPS_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', + os.path.join( + 'test_exif', + 'has-gps.jpg')) + +def test_exif_extraction(): + ''' + Test EXIF extraction from a good image + ''' + result = extract_exif(GOOD_JPG) + clean = clean_exif(result) + useful = get_useful(clean) + gps = get_gps_data(result) + + # Do we have the result? + assert len(result) == 108 + + # Do we have clean data? + assert len(clean) == 105 + + # GPS data? + assert gps == {} + + # Do we have the "useful" tags? + assert useful == { + 'EXIF Flash': { + 'field_type': 3, + 'printable': 'No', + 'field_offset': 380, + 'tag': 37385, + 'values': [0], + 'field_length': 2}, + 'EXIF ExposureTime': { + 'field_type': 5, + 'printable': '1/125', + 'field_offset': 700, + 'tag': 33434, + 'values': [[1, 125]], + 'field_length': 8}, + 'EXIF FocalLength': { + 'field_type': 5, + 'printable': '18', + 'field_offset': 780, + 'tag': 37386, + 'values': [[18, 1]], + 'field_length': 8}, + 'Image Model': { + 'field_type': 2, + 'printable': 'NIKON D80', + 'field_offset': 152, + 'tag': 272, + 'values': 'NIKON D80', + 'field_length': 10}, + 'Image Make': { + 'field_type': 2, + 'printable': 'NIKON CORPORATION', + 'field_offset': 134, + 'tag': 271, + 'values': 'NIKON CORPORATION', + 'field_length': 18}, + 'EXIF ExposureMode': { + 'field_type': 3, + 'printable': 'Manual Exposure', + 'field_offset': 584, + 'tag': 41986, + 'values': [1], + 'field_length': 2}, + 'EXIF ISOSpeedRatings': { + 'field_type': 3, + 'printable': '100', + 'field_offset': 260, + 'tag': 34855, + 'values': [100], + 'field_length': 2}, + 'EXIF FNumber': { + 'field_type': 5, + 'printable': '10', + 'field_offset': 708, + 'tag': 33437, + 'values': [[10, 1]], + 'field_length': 8}, + 'EXIF UserComment': { + 'field_type': 7, + 'printable': 'Joar Wandborg ', + 'field_offset': 26180, + 'tag': 37510, + 'values': [ + 65, 83, 67, 73, 73, 0, 0, 0, 74, 111, 97, 114, 32, 87, + 97, 110, 100, 98, 111, 114, 103, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32], + 'field_length': 44}} + +def test_exif_image_orientation(): + ''' + Test image reorientation based on EXIF data + ''' + result = extract_exif(GOOD_JPG) + + image = exif_fix_image_orientation( + Image.open(GOOD_JPG), + result) + + # Are the dimensions correct? + assert image.size == (428, 640) + + # If this pixel looks right, the rest of the image probably will too. + assert image.getdata()[10000] == (41, 28, 11) + +def test_exif_no_exif(): + ''' + Test an image without exif + ''' + result = extract_exif(EMPTY_JPG) + clean = clean_exif(result) + useful = get_useful(clean) + gps = get_gps_data(result) + + assert result == {} + assert clean == {} + assert gps == {} + assert useful == {} + +def test_exif_bad_image(): + ''' + Test EXIF extraction from a faithful, but bad image + ''' + result = extract_exif(BAD_JPG) + clean = clean_exif(result) + useful = get_useful(clean) + gps = get_gps_data(result) + + assert result == {} + assert clean == {} + assert gps == {} + assert useful == {} + +def test_exif_gps_data(): + ''' + Test extractiion of GPS data + ''' + result = extract_exif(GPS_JPG) + gps = get_gps_data(result) + + assert gps == { + 'latitude': 59.336666666666666, + 'direction': 25.674046740467404, + 'altitude': 37.64365671641791, + 'longitude': 18.016166666666667} + diff --git a/mediagoblin/tests/test_exif/bad.jpg b/mediagoblin/tests/test_exif/bad.jpg new file mode 100644 index 00000000..4cde23cd --- /dev/null +++ b/mediagoblin/tests/test_exif/bad.jpg @@ -0,0 +1,18 @@ +V2UncmUgbm8gc3RyYW5nZXJzIHRvIGxvdmUKWW91IGtub3cgdGhlIHJ1bGVzIGFuZCBzbyBkbyBJ +CkEgZnVsbCBjb21taXRtZW50J3Mgd2hhdCBJJ20gdGhpbmtpbicgb2YKWW91IHdvdWxkbid0IGdl +dCB0aGlzIGZyb20gYW55IG90aGVyIGd1eQpJIGp1c3Qgd2FubmEgdGVsbCB5b3UgaG93IEknbSBm +ZWVsaW4nCkdvdHRhIG1ha2UgeW91IHVuZGVyc3RhbmQKCihDaG9ydXMpCk5ldmVyIGdvbm5hIGdp +dmUgeW91IHVwCk5ldmVyIGdvbm5hIGxldCB5b3UgZG93bgpOZXZlciBnb25uYSBydW4gYXJvdW5k +IGFuZCBkZXNlcnQgeW91Ck5ldmVyIGdvbm5hIG1ha2UgeW91IGNyeQpOZXZlciBnb25uYSBzYXkg +Z29vZGJ5ZQpOZXZlciBnb25uYSB0ZWxsIGEgbGllIGFuZCBodXJ0IHlvdQoKV2UndmUga25vdyBl +YWNoIG90aGVyIGZvciBzbyBsb25nCllvdXIgaGVhcnQncyBiZWVuIGFjaGluJyBidXQgeW91J3Jl +IHRvbyBzaHkgdG8gc2F5IGl0Ckluc2lkZSB3ZSBib3RoIGtub3cgd2hhdCdzIGJlZW4gZ29pbmcg +b24KV2Uga25vdyB0aGUgZ2FtZSBhbmQgd2UncmUgZ29ubmEgcGxheSBpdApBbmQgaWYgeW91IGFz +ayBtZSBob3cgSSdtIGZlZWxpbicKRG9uJ3QgdGVsbCBtZSB5b3UncmUgdG9vIGJsaW5kIHRvIHNl +ZQoKKENob3J1cyB4MikKCihHaXZlIHlvdSB1cCwgZ2l2ZSB5b3UgdXApCk5ldmVyIGdvbm5hIGdp +dmUsIG5ldmVyIGdvbm5hIGdpdmUKKEdpdmUgeW91IHVwKQpOZXZlciBnb25uYSBnaXZlLCBuZXZl +ciBnb25uYSBnaXZlCihHaXZlIHlvdSB1cCkKCldlJ3ZlIGtub3cgZWFjaCBvdGhlciBmb3Igc28g +bG9uZwpZb3VyIGhlYXJ0J3MgYmVlbiBhY2hpbicgYnV0IHlvdSdyZSB0b28gc2h5IHRvIHNheSBp +dApJbnNpZGUgd2UgYm90aCBrbm93IHdoYXQncyBiZWVuIGdvaW5nIG9uCldlIGtub3cgdGhlIGdh +bWUgYW5kIHdlJ3JlIGdvbm5hIHBsYXkgaXQKSSBqdXN0IHdhbm5hIHRlbGwgeW91IGhvdyBJJ20g +ZmVlbGluJwpHb3R0YSBtYWtlIHlvdSB1bmRlcnN0YW5kCgooQ2hvcnVzIHgzKQo= diff --git a/mediagoblin/tests/test_exif/empty.jpg b/mediagoblin/tests/test_exif/empty.jpg new file mode 100644 index 00000000..37533af5 Binary files /dev/null and b/mediagoblin/tests/test_exif/empty.jpg differ diff --git a/mediagoblin/tests/test_exif/good.jpg b/mediagoblin/tests/test_exif/good.jpg new file mode 100644 index 00000000..0ee956fe Binary files /dev/null and b/mediagoblin/tests/test_exif/good.jpg differ diff --git a/mediagoblin/tests/test_exif/has-gps.jpg b/mediagoblin/tests/test_exif/has-gps.jpg new file mode 100644 index 00000000..c7d2cc93 Binary files /dev/null and b/mediagoblin/tests/test_exif/has-gps.jpg differ diff --git a/mediagoblin/tools/exif.py b/mediagoblin/tools/exif.py index 445907ba..3c1aebe5 100644 --- a/mediagoblin/tools/exif.py +++ b/mediagoblin/tools/exif.py @@ -18,8 +18,6 @@ from mediagoblin.tools.extlib.EXIF import process_file, Ratio from mediagoblin.processing import BadMediaFail from mediagoblin.tools.translate import pass_to_ugettext as _ -from collections import OrderedDict - # A list of tags that should be stored for faster access USEFUL_TAGS = [ 'Image Make', @@ -73,8 +71,7 @@ def extract_exif(filename): def clean_exif(exif): ''' - Clean the result from anyt -hing the database cannot handle + Clean the result from anything the database cannot handle ''' # Discard any JPEG thumbnail, for database compatibility # and that I cannot see a case when we would use it. @@ -129,11 +126,11 @@ def get_gps_data(tags): """ Processes EXIF data returned by EXIF.py """ - if not 'Image GPSInfo' in tags: - return False - gps_data = {} + if not 'Image GPSInfo' in tags: + return gps_data + try: dms_data = { 'latitude': tags['GPS GPSLatitude'], -- cgit v1.2.3 From cc7ca4da73890e4ab0af0b3d3bdde7d985637076 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 25 Jan 2012 23:53:02 +0100 Subject: Refractored media.html template and related includes - Added

around license part to separate it properly from other sidebar content - Moved exif part to mediagoblin/utils/exif.html - Moved geolocation map to mediagoblin/utils/geolocation_map.html --- .../templates/mediagoblin/user_pages/media.html | 42 ++-------------------- mediagoblin/templates/mediagoblin/utils/exif.html | 33 +++++++++++++++++ .../mediagoblin/utils/geolocation_map.html | 42 ++++++++++++++++++++++ .../templates/mediagoblin/utils/license.html | 14 ++++---- 4 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 mediagoblin/templates/mediagoblin/utils/exif.html create mode 100644 mediagoblin/templates/mediagoblin/utils/geolocation_map.html diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 446c9f85..a2ad117e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -181,44 +181,8 @@ {% include "mediagoblin/utils/license.html" %} - {% if media.media_data.has_key('gps') - and app_config['geolocation_map_visible'] - and media.media_data.gps %} -

Map

-
- {% set gps = media.media_data.gps %} -
- - -
-

- - View on - - OpenStreetMap - - -

-
- {% endif %} - {% if media.media_data.has_key('exif') - and app_config['exif_visible'] - and media.media_data.exif.has_key('useful') %} - {#- - TODO: - - Render GPS data in a human-readable format - #} -

EXIF

- - {% for key, tag in media.media_data.exif.useful.items() %} - - - - - {% endfor %} -
{{ key }}{{ tag.printable }}
- {% endif %} + {% include "mediagoblin/utils/geolocation_map.html" %} + + {% include "mediagoblin/utils/exif.html" %}
{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html new file mode 100644 index 00000000..9962dd65 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/exif.html @@ -0,0 +1,33 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block exif_content %} + {% if media.media_data.has_key('exif') + and app_config['exif_visible'] + and media.media_data.exif.has_key('useful') %} +

EXIF

+ + {% for key, tag in media.media_data.exif.useful.items() %} + + + + + {% endfor %} +
{{ key }}{{ tag.printable }}
+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html new file mode 100644 index 00000000..ce1edc39 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html @@ -0,0 +1,42 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block geolocation_map %} + {% if media.media_data.has_key('gps') + and app_config['geolocation_map_visible'] + and media.media_data.gps %} +

Map

+
+ {% set gps = media.media_data.gps %} +
+ + +
+

+ + View on + + OpenStreetMap + + +

+
+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 056c356e..5a268e39 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,10 +17,12 @@ #} {% block license_content -%} - {% trans %}License:{% endtrans %} - {% if media.license %} - {{ media.get_license_data().abbreviation }} - {% else %} - {% trans %}All rights reserved{% endtrans %} - {% endif %} +

+ {% trans %}License:{% endtrans %} + {% if media.license %} + {{ media.get_license_data().abbreviation }} + {% else %} + {% trans %}All rights reserved{% endtrans %} + {% endif %} +

{% endblock %} -- cgit v1.2.3 From d595374d180afef2f468e75b50331ea8e1e621ed Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 26 Jan 2012 21:33:49 +0100 Subject: Packaging improvement by Clint Byrum from Debian/Ubuntu 1) MANIFEST.in missed a bunch of things, especially config_spec.ini. 2) You need to specify include_package_data=True in setup.py to actually activate MANIFEST.in it seems. Thanks go to Clint Byrum! --- MANIFEST.in | 4 ++-- setup.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index b1f93dba..956f44c9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ recursive-include mediagoblin/templates *.html -recursive-include mediagoblin/static *.js *.css *.png *.svg +recursive-include mediagoblin/static *.js *.css *.png *.svg *.ico recursive-include mediagoblin/tests *.ini recursive-include docs *.rst *.html - +include mediagoblin/config_spec.ini diff --git a/setup.py b/setup.py index 293f3f03..ca7d4ae2 100644 --- a/setup.py +++ b/setup.py @@ -38,6 +38,7 @@ setup( version=get_version(), packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), zip_safe=False, + include_package_data = True, # scripts and dependencies install_requires=[ 'setuptools', -- cgit v1.2.3 From 10196c681164afe6fde807459befa9252f62e39f Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 26 Jan 2012 22:10:46 +0100 Subject: Drop all buildout things virtualenv is working for everyone. No need for the buildout stuff any more. --- bootstrap.py | 260 ---------------------------------------- buildout.cfg | 19 --- mediagoblin/buildout_recipes.py | 50 -------- 3 files changed, 329 deletions(-) delete mode 100644 bootstrap.py delete mode 100644 buildout.cfg delete mode 100644 mediagoblin/buildout_recipes.py diff --git a/bootstrap.py b/bootstrap.py deleted file mode 100644 index 5f2cb083..00000000 --- a/bootstrap.py +++ /dev/null @@ -1,260 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 Zope Foundation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Bootstrap a buildout-based project - -Simply run this script in a directory containing a buildout.cfg. -The script accepts buildout command-line options, so you can -use the -c option to specify an alternate configuration file. -""" - -import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess -from optparse import OptionParser - -if sys.platform == 'win32': - def quote(c): - if ' ' in c: - return '"%s"' % c # work around spawn lamosity on windows - else: - return c -else: - quote = str - -# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. -stdout, stderr = subprocess.Popen( - [sys.executable, '-Sc', - 'try:\n' - ' import ConfigParser\n' - 'except ImportError:\n' - ' print 1\n' - 'else:\n' - ' print 0\n'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() -has_broken_dash_S = bool(int(stdout.strip())) - -# In order to be more robust in the face of system Pythons, we want to -# run without site-packages loaded. This is somewhat tricky, in -# particular because Python 2.6's distutils imports site, so starting -# with the -S flag is not sufficient. However, we'll start with that: -if not has_broken_dash_S and 'site' in sys.modules: - # We will restart with python -S. - args = sys.argv[:] - args[0:0] = [sys.executable, '-S'] - args = map(quote, args) - os.execv(sys.executable, args) -# Now we are running with -S. We'll get the clean sys.path, import site -# because distutils will do it later, and then reset the path and clean -# out any namespace packages from site-packages that might have been -# loaded by .pth files. -clean_path = sys.path[:] -import site -sys.path[:] = clean_path -for k, v in sys.modules.items(): - if k in ('setuptools', 'pkg_resources') or ( - hasattr(v, '__path__') and - len(v.__path__)==1 and - not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): - # This is a namespace package. Remove it. - sys.modules.pop(k) - -is_jython = sys.platform.startswith('java') - -setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' -distribute_source = 'http://python-distribute.org/distribute_setup.py' - -# parsing arguments -def normalize_to_url(option, opt_str, value, parser): - if value: - if '://' not in value: # It doesn't smell like a URL. - value = 'file://%s' % ( - urllib.pathname2url( - os.path.abspath(os.path.expanduser(value))),) - if opt_str == '--download-base' and not value.endswith('/'): - # Download base needs a trailing slash to make the world happy. - value += '/' - else: - value = None - name = opt_str[2:].replace('-', '_') - setattr(parser.values, name, value) - -usage = '''\ -[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] - -Bootstraps a buildout-based project. - -Simply run this script in a directory containing a buildout.cfg, using the -Python that you want bin/buildout to use. - -Note that by using --setup-source and --download-base to point to -local resources, you can keep this script from going over the network. -''' - -parser = OptionParser(usage=usage) -parser.add_option("-v", "--version", dest="version", - help="use a specific zc.buildout version") -parser.add_option("-d", "--distribute", - action="store_true", dest="use_distribute", default=False, - help="Use Distribute rather than Setuptools.") -parser.add_option("--setup-source", action="callback", dest="setup_source", - callback=normalize_to_url, nargs=1, type="string", - help=("Specify a URL or file location for the setup file. " - "If you use Setuptools, this will default to " + - setuptools_source + "; if you use Distribute, this " - "will default to " + distribute_source +".")) -parser.add_option("--download-base", action="callback", dest="download_base", - callback=normalize_to_url, nargs=1, type="string", - help=("Specify a URL or directory for downloading " - "zc.buildout and either Setuptools or Distribute. " - "Defaults to PyPI.")) -parser.add_option("--eggs", - help=("Specify a directory for storing eggs. Defaults to " - "a temporary directory that is deleted when the " - "bootstrap script completes.")) -parser.add_option("-t", "--accept-buildout-test-releases", - dest='accept_buildout_test_releases', - action="store_true", default=False, - help=("Normally, if you do not specify a --version, the " - "bootstrap script and buildout gets the newest " - "*final* versions of zc.buildout and its recipes and " - "extensions for you. If you use this flag, " - "bootstrap and buildout will get the newest releases " - "even if they are alphas or betas.")) -parser.add_option("-c", None, action="store", dest="config_file", - help=("Specify the path to the buildout configuration " - "file to be used.")) - -options, args = parser.parse_args() - -# if -c was provided, we push it back into args for buildout's main function -if options.config_file is not None: - args += ['-c', options.config_file] - -if options.eggs: - eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) -else: - eggs_dir = tempfile.mkdtemp() - -if options.setup_source is None: - if options.use_distribute: - options.setup_source = distribute_source - else: - options.setup_source = setuptools_source - -if options.accept_buildout_test_releases: - args.append('buildout:accept-buildout-test-releases=true') -args.append('bootstrap') - -try: - import pkg_resources - import setuptools # A flag. Sometimes pkg_resources is installed alone. - if not hasattr(pkg_resources, '_distribute'): - raise ImportError -except ImportError: - ez_code = urllib2.urlopen( - options.setup_source).read().replace('\r\n', '\n') - ez = {} - exec ez_code in ez - setup_args = dict(to_dir=eggs_dir, download_delay=0) - if options.download_base: - setup_args['download_base'] = options.download_base - if options.use_distribute: - setup_args['no_fake'] = True - ez['use_setuptools'](**setup_args) - if 'pkg_resources' in sys.modules: - reload(sys.modules['pkg_resources']) - import pkg_resources - # This does not (always?) update the default working set. We will - # do it. - for path in sys.path: - if path not in pkg_resources.working_set.entries: - pkg_resources.working_set.add_entry(path) - -cmd = [quote(sys.executable), - '-c', - quote('from setuptools.command.easy_install import main; main()'), - '-mqNxd', - quote(eggs_dir)] - -if not has_broken_dash_S: - cmd.insert(1, '-S') - -find_links = options.download_base -if not find_links: - find_links = os.environ.get('bootstrap-testing-find-links') -if find_links: - cmd.extend(['-f', quote(find_links)]) - -if options.use_distribute: - setup_requirement = 'distribute' -else: - setup_requirement = 'setuptools' -ws = pkg_resources.working_set -setup_requirement_path = ws.find( - pkg_resources.Requirement.parse(setup_requirement)).location -env = dict( - os.environ, - PYTHONPATH=setup_requirement_path) - -requirement = 'zc.buildout' -version = options.version -if version is None and not options.accept_buildout_test_releases: - # Figure out the most recent final version of zc.buildout. - import setuptools.package_index - _final_parts = '*final-', '*final' - def _final_version(parsed_version): - for part in parsed_version: - if (part[:1] == '*') and (part not in _final_parts): - return False - return True - index = setuptools.package_index.PackageIndex( - search_path=[setup_requirement_path]) - if find_links: - index.add_find_links((find_links,)) - req = pkg_resources.Requirement.parse(requirement) - if index.obtain(req) is not None: - best = [] - bestv = None - for dist in index[req.project_name]: - distv = dist.parsed_version - if _final_version(distv): - if bestv is None or distv > bestv: - best = [dist] - bestv = distv - elif distv == bestv: - best.append(dist) - if best: - best.sort() - version = best[-1].version -if version: - requirement = '=='.join((requirement, version)) -cmd.append(requirement) - -if is_jython: - import subprocess - exitcode = subprocess.Popen(cmd, env=env).wait() -else: # Windows prefers this, apparently; otherwise we would prefer subprocess - exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) -if exitcode != 0: - sys.stdout.flush() - sys.stderr.flush() - print ("An error occurred when trying to install zc.buildout. " - "Look above this message for any errors that " - "were output by easy_install.") - sys.exit(exitcode) - -ws.add_entry(eggs_dir) -ws.require(requirement) -import zc.buildout.buildout -zc.buildout.buildout.main(args) -if not options.eggs: # clean up temporary egg directory - shutil.rmtree(eggs_dir) diff --git a/buildout.cfg b/buildout.cfg deleted file mode 100644 index a77bf93c..00000000 --- a/buildout.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[buildout] -develop = . -parts = mediagoblin make_user_dev_dirs - -[mediagoblin] -recipe=zc.recipe.egg -interpreter=python -dependent-scripts = true -eggs= - python-dateutil>=1.5.0,<2.0.0 - mediagoblin -entry-points = - nosetests=nose:run_exit - paster=paste.script.command:run - - -[make_user_dev_dirs] -recipe = mediagoblin:make_user_dev_dirs -path = user_dev \ No newline at end of file diff --git a/mediagoblin/buildout_recipes.py b/mediagoblin/buildout_recipes.py deleted file mode 100644 index f3d0362f..00000000 --- a/mediagoblin/buildout_recipes.py +++ /dev/null @@ -1,50 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - - -import logging -import os - - -MAKE_SUBDIRECTORIES = ['media/queue', 'media/public', 'beaker'] - - -class MakeUserDevDirs(object): - """ - Simple recipe for making subdirectories for user buildout convenience - """ - def __init__(self, buildout, name, options): - self.buildout, self.name, self.options = buildout, name, options - - if self.options['path'].startswith('/'): - self.path = self.options['path'] - else: - self.path = os.path.join( - self.buildout['buildout']['directory'], - self.options['path']) - - def install(self): - for make_subdir in MAKE_SUBDIRECTORIES: - fulldir = os.path.join(self.path, make_subdir) - - if not os.path.exists(fulldir): - logging.getLogger(self.name).info( - 'Creating directory %s' % fulldir) - os.makedirs(fulldir) - - return () - - update = install -- cgit v1.2.3 From 997b419fe304427d587fceaae28f9a4652fb5f1a Mon Sep 17 00:00:00 2001 From: Elrond Date: Thu, 26 Jan 2012 22:14:48 +0100 Subject: Add "mediagoblin/templates *.txt" to packaging Again thanks to Clint Byrum! --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 956f44c9..9300c698 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -recursive-include mediagoblin/templates *.html +recursive-include mediagoblin/templates *.html *.txt recursive-include mediagoblin/static *.js *.css *.png *.svg *.ico recursive-include mediagoblin/tests *.ini recursive-include docs *.rst *.html -- cgit v1.2.3 From 3c43cfc9f91b487d52ff7868f821fe920f676d90 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 22 Jan 2012 20:17:43 +0100 Subject: Move declarative_base Base into base.py The base class of all models "Base" should be in base.py. --- mediagoblin/db/sql/base.py | 4 ++++ mediagoblin/db/sql/models.py | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 6f45b21b..1db53c56 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -15,6 +15,7 @@ # along with this program. If not, see . +from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, sessionmaker, object_session from sqlalchemy.orm.query import Query from sqlalchemy.sql.expression import desc @@ -73,3 +74,6 @@ class GMGTableBase(object): sess = Session() sess.add(self) sess.commit() + + +Base = declarative_base(cls=GMGTableBase) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 57444c2c..95147d50 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -17,7 +17,6 @@ import datetime -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import ( Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint) @@ -27,13 +26,10 @@ from sqlalchemy.sql.expression import desc from sqlalchemy.ext.associationproxy import association_proxy from mediagoblin.db.sql.extratypes import PathTupleWithSlashes -from mediagoblin.db.sql.base import GMGTableBase +from mediagoblin.db.sql.base import Base from mediagoblin.db.mixin import UserMixin, MediaEntryMixin -Base = declarative_base(cls=GMGTableBase) - - class SimpleFieldAlias(object): """An alias for any field""" def __init__(self, fieldname): -- cgit v1.2.3 From a8382a3a866bd20892e4c0081a7dac020acd0f9f Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 27 Jan 2012 01:52:57 +0100 Subject: Updated .gitignore due to it blacking out the extlib/leaflet/dist/ directory --- .gitignore | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 9e8d958a..b46ec38a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,27 @@ -dist/ -bin/ -develop-eggs/ -build/ -eggs/ -lib/ -include/ -parts/ +# / means repository root, not filesystem root + +# Top-level files and directories +/dist/ +/bin/ +/develop-eggs/ +/build/ +/eggs/ +/lib/ +/include/ +/parts/ +/mediagoblin.egg-info +/docs/_build/ +/docs/build +/user_dev/ +/paste_local.ini +/mediagoblin_local.ini +/server-log.txt + +# Tests +/mediagoblin/tests/user_dev/ + .installed.cfg -mediagoblin.egg-info *.pyc *.pyo -docs/_build/ -docs/build -user_dev/ -paste_local.ini -mediagoblin_local.ini -server-log.txt *~ *.swp -- cgit v1.2.3 From 184dbcdacc0404b6fb979995f11732ce0782df04 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 27 Jan 2012 01:55:50 +0100 Subject: Adding previously erroneously gitignored extlib/leaflet/{lib,dist,build}/ files --- extlib/leaflet/build/Makefile | 65 + extlib/leaflet/build/build.bat | 65 + extlib/leaflet/build/build.html | 208 ++ extlib/leaflet/build/deps.js | 211 ++ extlib/leaflet/dist/images/marker-shadow.png | Bin 0 -> 1649 bytes extlib/leaflet/dist/images/marker.png | Bin 0 -> 2519 bytes extlib/leaflet/dist/images/popup-close.png | Bin 0 -> 1125 bytes extlib/leaflet/dist/images/zoom-in.png | Bin 0 -> 963 bytes extlib/leaflet/dist/images/zoom-out.png | Bin 0 -> 959 bytes extlib/leaflet/dist/leaflet.css | 273 +++ extlib/leaflet/dist/leaflet.ie.css | 46 + extlib/leaflet/dist/leaflet.js | 114 + extlib/leaflet/lib/closure-compiler/COPYING | 202 ++ extlib/leaflet/lib/closure-compiler/README | 278 +++ extlib/leaflet/lib/closure-compiler/compiler.jar | Bin 0 -> 4332498 bytes extlib/leaflet/lib/jasmine/jasmine-html.js | 182 ++ extlib/leaflet/lib/jasmine/jasmine.css | 166 ++ extlib/leaflet/lib/jasmine/jasmine.js | 2421 ++++++++++++++++++++++ 18 files changed, 4231 insertions(+) create mode 100644 extlib/leaflet/build/Makefile create mode 100644 extlib/leaflet/build/build.bat create mode 100644 extlib/leaflet/build/build.html create mode 100644 extlib/leaflet/build/deps.js create mode 100644 extlib/leaflet/dist/images/marker-shadow.png create mode 100644 extlib/leaflet/dist/images/marker.png create mode 100644 extlib/leaflet/dist/images/popup-close.png create mode 100644 extlib/leaflet/dist/images/zoom-in.png create mode 100644 extlib/leaflet/dist/images/zoom-out.png create mode 100644 extlib/leaflet/dist/leaflet.css create mode 100644 extlib/leaflet/dist/leaflet.ie.css create mode 100644 extlib/leaflet/dist/leaflet.js create mode 100644 extlib/leaflet/lib/closure-compiler/COPYING create mode 100644 extlib/leaflet/lib/closure-compiler/README create mode 100644 extlib/leaflet/lib/closure-compiler/compiler.jar create mode 100644 extlib/leaflet/lib/jasmine/jasmine-html.js create mode 100644 extlib/leaflet/lib/jasmine/jasmine.css create mode 100644 extlib/leaflet/lib/jasmine/jasmine.js diff --git a/extlib/leaflet/build/Makefile b/extlib/leaflet/build/Makefile new file mode 100644 index 00000000..22d65483 --- /dev/null +++ b/extlib/leaflet/build/Makefile @@ -0,0 +1,65 @@ +../dist/leaflet.js: Makefile + java -jar ../lib/closure-compiler/compiler.jar \ + --js ../src/Leaflet.js \ + --js ../src/core/Util.js \ + --js ../src/core/Class.js \ + --js ../src/core/Events.js \ + --js ../src/core/Browser.js \ + --js ../src/geometry/Point.js \ + --js ../src/geometry/Bounds.js \ + --js ../src/geometry/Transformation.js \ + --js ../src/geometry/LineUtil.js \ + --js ../src/geometry/PolyUtil.js \ + --js ../src/dom/DomEvent.js \ + --js ../src/dom/DomEvent.DoubleTap.js \ + --js ../src/dom/DomUtil.js \ + --js ../src/dom/Draggable.js \ + --js ../src/dom/transition/Transition.js \ + --js ../src/dom/transition/Transition.Native.js \ + --js ../src/dom/transition/Transition.Timer.js \ + --js ../src/geo/LatLng.js \ + --js ../src/geo/LatLngBounds.js \ + --js ../src/geo/projection/Projection.js \ + --js ../src/geo/projection/Projection.SphericalMercator.js \ + --js ../src/geo/projection/Projection.LonLat.js \ + --js ../src/geo/projection/Projection.Mercator.js \ + --js ../src/geo/crs/CRS.js \ + --js ../src/geo/crs/CRS.EPSG3857.js \ + --js ../src/geo/crs/CRS.EPSG4326.js \ + --js ../src/geo/crs/CRS.EPSG3395.js \ + --js ../src/layer/LayerGroup.js \ + --js ../src/layer/FeatureGroup.js \ + --js ../src/layer/tile/TileLayer.js \ + --js ../src/layer/tile/TileLayer.WMS.js \ + --js ../src/layer/tile/TileLayer.Canvas.js \ + --js ../src/layer/ImageOverlay.js \ + --js ../src/layer/Popup.js \ + --js ../src/layer/marker/Icon.js \ + --js ../src/layer/marker/Marker.js \ + --js ../src/layer/marker/Marker.Popup.js \ + --js ../src/layer/vector/Path.js \ + --js ../src/layer/vector/Path.VML.js \ + --js ../src/layer/vector/Path.Popup.js \ + --js ../src/layer/vector/Polyline.js \ + --js ../src/layer/vector/Polygon.js \ + --js ../src/layer/vector/MultiPoly.js \ + --js ../src/layer/vector/Circle.js \ + --js ../src/layer/vector/CircleMarker.js \ + --js ../src/layer/GeoJSON.js \ + --js ../src/handler/Handler.js \ + --js ../src/handler/MapDrag.js \ + --js ../src/handler/TouchZoom.js \ + --js ../src/handler/ScrollWheelZoom.js \ + --js ../src/handler/DoubleClickZoom.js \ + --js ../src/handler/ShiftDragZoom.js \ + --js ../src/handler/MarkerDrag.js \ + --js ../src/control/Control.js \ + --js ../src/control/Control.Zoom.js \ + --js ../src/control/Control.Attribution.js \ + --js ../src/map/Map.js \ + --js ../src/map/ext/Map.Geolocation.js \ + --js ../src/map/ext/Map.Popup.js \ + --js ../src/map/ext/Map.PanAnimation.js \ + --js ../src/map/ext/Map.ZoomAnimation.js \ + --js ../src/map/ext/Map.Control.js \ + --js_output_file ../dist/leaflet.js diff --git a/extlib/leaflet/build/build.bat b/extlib/leaflet/build/build.bat new file mode 100644 index 00000000..a09d2259 --- /dev/null +++ b/extlib/leaflet/build/build.bat @@ -0,0 +1,65 @@ +@echo off +java -jar ../lib/closure-compiler/compiler.jar ^ +--js ../src/Leaflet.js ^ +--js ../src/core/Util.js ^ +--js ../src/core/Class.js ^ +--js ../src/core/Events.js ^ +--js ../src/core/Browser.js ^ +--js ../src/geometry/Point.js ^ +--js ../src/geometry/Bounds.js ^ +--js ../src/geometry/Transformation.js ^ +--js ../src/geometry/LineUtil.js ^ +--js ../src/geometry/PolyUtil.js ^ +--js ../src/dom/DomEvent.js ^ +--js ../src/dom/DomEvent.DoubleTap.js ^ +--js ../src/dom/DomUtil.js ^ +--js ../src/dom/Draggable.js ^ +--js ../src/dom/transition/Transition.js ^ +--js ../src/dom/transition/Transition.Native.js ^ +--js ../src/dom/transition/Transition.Timer.js ^ +--js ../src/geo/LatLng.js ^ +--js ../src/geo/LatLngBounds.js ^ +--js ../src/geo/projection/Projection.js ^ +--js ../src/geo/projection/Projection.SphericalMercator.js ^ +--js ../src/geo/projection/Projection.LonLat.js ^ +--js ../src/geo/projection/Projection.Mercator.js ^ +--js ../src/geo/crs/CRS.js ^ +--js ../src/geo/crs/CRS.EPSG3857.js ^ +--js ../src/geo/crs/CRS.EPSG4326.js ^ +--js ../src/geo/crs/CRS.EPSG3395.js ^ +--js ../src/layer/LayerGroup.js ^ +--js ../src/layer/FeatureGroup.js ^ +--js ../src/layer/tile/TileLayer.js ^ +--js ../src/layer/tile/TileLayer.WMS.js ^ +--js ../src/layer/tile/TileLayer.Canvas.js ^ +--js ../src/layer/ImageOverlay.js ^ +--js ../src/layer/Popup.js ^ +--js ../src/layer/marker/Icon.js ^ +--js ../src/layer/marker/Marker.js ^ +--js ../src/layer/marker/Marker.Popup.js ^ +--js ../src/layer/vector/Path.js ^ +--js ../src/layer/vector/Path.VML.js ^ +--js ../src/layer/vector/Path.Popup.js ^ +--js ../src/layer/vector/Polyline.js ^ +--js ../src/layer/vector/Polygon.js ^ +--js ../src/layer/vector/MultiPoly.js ^ +--js ../src/layer/vector/Circle.js ^ +--js ../src/layer/vector/CircleMarker.js ^ +--js ../src/layer/GeoJSON.js ^ +--js ../src/handler/Handler.js ^ +--js ../src/handler/MapDrag.js ^ +--js ../src/handler/TouchZoom.js ^ +--js ../src/handler/ScrollWheelZoom.js ^ +--js ../src/handler/DoubleClickZoom.js ^ +--js ../src/handler/ShiftDragZoom.js ^ +--js ../src/handler/MarkerDrag.js ^ +--js ../src/control/Control.js ^ +--js ../src/control/Control.Zoom.js ^ +--js ../src/control/Control.Attribution.js ^ +--js ../src/map/Map.js ^ +--js ../src/map/ext/Map.Geolocation.js ^ +--js ../src/map/ext/Map.Popup.js ^ +--js ../src/map/ext/Map.PanAnimation.js ^ +--js ../src/map/ext/Map.ZoomAnimation.js ^ +--js ../src/map/ext/Map.Control.js ^ +--js_output_file ../dist/leaflet.js \ No newline at end of file diff --git a/extlib/leaflet/build/build.html b/extlib/leaflet/build/build.html new file mode 100644 index 00000000..c60e5f31 --- /dev/null +++ b/extlib/leaflet/build/build.html @@ -0,0 +1,208 @@ + + + + Leaflet Build Helper + + + + + + +
+

Leaflet Build Helper

+ +

+ Select All | + Deselect All +

+ +
    + +

    + Run this command in the build directory:
    + +

    +
    + + + + \ No newline at end of file diff --git a/extlib/leaflet/build/deps.js b/extlib/leaflet/build/deps.js new file mode 100644 index 00000000..42735648 --- /dev/null +++ b/extlib/leaflet/build/deps.js @@ -0,0 +1,211 @@ +var deps = { + Core: { + src: ['Leaflet.js', + 'core/Browser.js', + 'core/Class.js', + 'core/Events.js', + 'core/Util.js', + 'dom/DomUtil.js', + 'geo/LatLng.js', + 'geo/LatLngBounds.js', + 'geo/projection/Projection.js', + 'geo/projection/Projection.SphericalMercator.js', + 'geo/projection/Projection.LonLat.js', + 'geo/crs/CRS.js', + 'geo/crs/CRS.EPSG3857.js', + 'geo/crs/CRS.EPSG4326.js', + 'geometry/Bounds.js', + 'geometry/Point.js', + 'geometry/Transformation.js', + 'map/Map.js'], + desc: 'The core of the library, including OOP, events, DOM facilities, basic units, projections (EPSG:3857 and EPSG:4326) and the base Map class.' + }, + + + EPSG3395: { + src: ['geo/projection/Projection.Mercator.js', + 'geo/crs/CRS.EPSG3395.js'], + desc: 'EPSG:3395 projection (used by some map providers).', + heading: 'Additional projections' + }, + + TileLayer: { + src: ['layer/tile/TileLayer.js'], + desc: 'The base class for displaying tile layers on the map.', + heading: 'Layers' + }, + + TileLayerWMS: { + src: ['layer/tile/TileLayer.WMS.js'], + desc: 'WMS tile layer.', + deps: ['TileLayer'] + }, + + TileLayerCanvas: { + src: ['layer/tile/TileLayer.Canvas.js'], + desc: 'Tile layer made from canvases (for custom drawing purposes).', + deps: ['TileLayer'] + }, + + ImageOverlay: { + src: ['layer/ImageOverlay.js'], + desc: 'Used to display an image over a particular rectangular area of the map.' + }, + + Marker: { + src: ['layer/marker/Icon.js', 'layer/marker/Marker.js'], + desc: 'Markers to put on the map.' + }, + + Popup: { + src: ['layer/Popup.js', 'layer/marker/Marker.Popup.js', 'map/ext/Map.Popup.js'], + deps: ['Marker'], + desc: 'Used to display the map popup (used mostly for binding HTML data to markers and paths on click).' + }, + + LayerGroup: { + src: ['layer/LayerGroup.js'], + desc: 'Allows grouping several layers to handle them as one.' + }, + + FeatureGroup: { + src: ['layer/FeatureGroup.js'], + deps: ['LayerGroup', 'Popup'], + desc: 'Extends LayerGroup with mouse events and bindPopup method shared between layers.' + }, + + + Path: { + src: ['layer/vector/Path.js', 'layer/vector/Path.Popup.js'], + desc: 'Vector rendering core (SVG-powered), enables overlaying the map with SVG paths.', + heading: 'Vector layers' + }, + + PathVML: { + src: ['layer/vector/Path.VML.js'], + desc: 'VML fallback for vector rendering core (IE 6-8).' + }, + + Polyline: { + src: ['geometry/LineUtil.js', 'layer/vector/Polyline.js'], + deps: ['Path'], + desc: 'Polyline overlays.' + }, + + Polygon: { + src: ['geometry/PolyUtil.js', 'layer/vector/Polygon.js'], + deps: ['Polyline'], + desc: 'Polygon overlays.' + }, + + MultiPoly: { + src: ['layer/vector/MultiPoly.js'], + deps: ['FeatureGroup', 'Polyline', 'Polygon'], + desc: 'MultiPolygon and MultyPolyline layers.' + }, + + Circle: { + src: ['layer/vector/Circle.js'], + deps: ['Path'], + desc: 'Circle overlays (with radius in meters).' + }, + + CircleMarker: { + src: ['layer/vector/CircleMarker.js'], + deps: ['Circle'], + desc: 'Circle overlays with a constant pixel radius.' + }, + + GeoJSON: { + src: ['layer/GeoJSON.js'], + deps: ['Marker', 'MultiPoly', 'FeatureGroup'], + desc: 'GeoJSON layer, parses the data and adds corresponding layers above.' + }, + + + MapDrag: { + src: ['dom/DomEvent.js', + 'dom/Draggable.js', + 'handler/Handler.js', + 'handler/MapDrag.js'], + desc: 'Makes the map draggable (by mouse or touch).', + heading: 'Interaction' + }, + + MouseZoom: { + src: ['dom/DomEvent.js', + 'handler/Handler.js', + 'handler/DoubleClickZoom.js', + 'handler/ScrollWheelZoom.js'], + desc: 'Scroll wheel zoom and double click zoom on the map.' + }, + + TouchZoom: { + src: ['dom/DomEvent.js', + 'dom/DomEvent.DoubleTap.js', + 'handler/Handler.js', + 'handler/TouchZoom.js'], + deps: ['MapAnimationZoom'], + desc: 'Enables smooth touch zooming on iOS and double tap on iOS/Android.' + }, + + ShiftDragZoom: { + src: ['handler/ShiftDragZoom.js'], + desc: 'Enables zooming to bounding box by shift-dragging the map.' + }, + + MarkerDrag: { + src: ['handler/MarkerDrag.js'], + desc: 'Makes markers draggable (by mouse or touch).' + }, + + + ControlZoom: { + src: ['control/Control.js', + 'map/ext/Map.Control.js', + 'control/Control.Zoom.js'], + heading: 'Controls', + desc: 'Basic zoom control with two buttons (zoom in / zoom out).' + }, + + ControlZoom: { + src: ['control/Control.js', + 'map/ext/Map.Control.js', + 'control/Control.Attribution.js'], + desc: 'Attribution control.' + }, + + + MapAnimationNative: { + src: ['dom/DomEvent.js', + 'dom/transition/Transition.js', + 'dom/transition/Transition.Native.js'], + desc: 'Animation core that uses CSS3 Transitions (for powering pan & zoom animations). Works on mobile webkit-powered browsers and some modern desktop browsers.', + heading: 'Visual effects' + }, + + MapAnimationFallback: { + src: ['dom/transition/Transition.Timer.js'], + deps: ['MapAnimationNative'], + desc: 'Timer-based animation fallback for browsers that don\'t support CSS3 transitions.' + }, + + MapAnimationPan: { + src: ['map/ext/Map.PanAnimation.js'], + deps: ['MapAnimationNative'], + desc: 'Panning animation. Can use both native and timer-based animation.' + }, + + MapAnimationZoom: { + src: ['map/ext/Map.ZoomAnimation.js'], + deps: ['MapAnimationPan', 'MapAnimationNative'], + desc: 'Smooth zooming animation. So far it works only on browsers that support CSS3 Transitions.' + }, + + + MapGeolocation: { + src: ['map/ext/Map.Geolocation.js'], + desc: 'Adds Map#locate method and related events to make geolocation easier.', + heading: 'Misc' + } +}; \ No newline at end of file diff --git a/extlib/leaflet/dist/images/marker-shadow.png b/extlib/leaflet/dist/images/marker-shadow.png new file mode 100644 index 00000000..a64f6a67 Binary files /dev/null and b/extlib/leaflet/dist/images/marker-shadow.png differ diff --git a/extlib/leaflet/dist/images/marker.png b/extlib/leaflet/dist/images/marker.png new file mode 100644 index 00000000..bef032e6 Binary files /dev/null and b/extlib/leaflet/dist/images/marker.png differ diff --git a/extlib/leaflet/dist/images/popup-close.png b/extlib/leaflet/dist/images/popup-close.png new file mode 100644 index 00000000..c8faec5e Binary files /dev/null and b/extlib/leaflet/dist/images/popup-close.png differ diff --git a/extlib/leaflet/dist/images/zoom-in.png b/extlib/leaflet/dist/images/zoom-in.png new file mode 100644 index 00000000..9f473d64 Binary files /dev/null and b/extlib/leaflet/dist/images/zoom-in.png differ diff --git a/extlib/leaflet/dist/images/zoom-out.png b/extlib/leaflet/dist/images/zoom-out.png new file mode 100644 index 00000000..f0a5b5d6 Binary files /dev/null and b/extlib/leaflet/dist/images/zoom-out.png differ diff --git a/extlib/leaflet/dist/leaflet.css b/extlib/leaflet/dist/leaflet.css new file mode 100644 index 00000000..4bc0b769 --- /dev/null +++ b/extlib/leaflet/dist/leaflet.css @@ -0,0 +1,273 @@ +/* required styles */ + +.leaflet-map-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-pane, +.leaflet-overlay-pane, +.leaflet-shadow-pane, +.leaflet-marker-pane, +.leaflet-popup-pane, +.leaflet-overlay-pane svg, +.leaflet-zoom-box, +.leaflet-image-layer { /* TODO optimize classes */ + position: absolute; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile-pane { + -webkit-transform: translate3d(0,0,0); + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +.leaflet-clickable { + cursor: pointer; + } +.leaflet-container img { + max-width: auto; + } + +.leaflet-tile-pane { z-index: 2; } +.leaflet-overlay-pane { z-index: 3; } +.leaflet-shadow-pane { z-index: 4; } +.leaflet-marker-pane { z-index: 5; } +.leaflet-popup-pane { z-index: 6; } + +.leaflet-zoom-box { + width: 0; + height: 0; + } + +.leaflet-tile { + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } + +a.leaflet-active { + outline: 2px solid orange; + } + + +/* Leaflet controls */ + +.leaflet-control { + position: relative; + z-index: 7; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + +.leaflet-control-zoom { + padding: 5px; + background: rgba(0, 0, 0, 0.25); + + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + border-radius: 7px; + } +.leaflet-control-zoom a { + display: block; + width: 19px; + height: 19px; + background-position: 50% 50%; + background-repeat: no-repeat; + background-color: rgba(255, 255, 255, 0.75); + + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + } +.leaflet-control-zoom a:hover { + background-color: #fff; + } +.leaflet-big-buttons .leaflet-control-zoom a { + width: 27px; + height: 27px; + } +.leaflet-control-zoom-in { + background-image: url(images/zoom-in.png); + margin-bottom: 5px; + } +.leaflet-control-zoom-out { + background-image: url(images/zoom-out.png); + } + +.leaflet-container .leaflet-control-attribution { + margin: 0; + padding: 0 5px; + + font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + color: #333; + + background-color: rgba(255, 255, 255, 0.7); + + -moz-box-shadow: 0 0 7px #ccc; + -webkit-box-shadow: 0 0 7px #ccc; + box-shadow: 0 0 7px #ccc; + } + + +/* Fade animations */ + +.leaflet-fade-anim .leaflet-tile { + opacity: 0; + + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-tile-loaded { + opacity: 1; + } + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } + +.leaflet-zoom-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-objects-pane { + visibility: hidden; + } + + +/* Popup layout */ + +.leaflet-popup { + position: absolute; + text-align: center; + -webkit-transform: translate3d(0,0,0); + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + } +.leaflet-popup-content { + margin: 19px; + } +.leaflet-popup-tip-container { + margin: 0 auto; + width: 40px; + height: 16px; + position: relative; + overflow: hidden; + } +.leaflet-popup-tip { + width: 15px; + height: 15px; + padding: 1px; + + margin: -8px auto 0; + + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-close-button { + position: absolute; + top: 9px; + right: 9px; + + width: 10px; + height: 10px; + + overflow: hidden; + } +.leaflet-popup-content p { + margin: 18px 0; + } + + +/* Visual appearance */ + +.leaflet-container { + background: #ddd; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #05f; + background: white; + opacity: 0.5; + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background: white; + + box-shadow: 0 1px 10px #888; + -moz-box-shadow: 0 1px 10px #888; + -webkit-box-shadow: 0 1px 14px #999; + } +.leaflet-popup-content-wrapper { + -moz-border-radius: 20px; + -webkit-border-radius: 20px; + border-radius: 20px; + } +.leaflet-popup-content { + font: 12px/1.4 "Helvetica Neue", Arial, Helvetica, sans-serif; + } +.leaflet-popup-close-button { + background: white url(images/popup-close.png); + } \ No newline at end of file diff --git a/extlib/leaflet/dist/leaflet.ie.css b/extlib/leaflet/dist/leaflet.ie.css new file mode 100644 index 00000000..141a16f5 --- /dev/null +++ b/extlib/leaflet/dist/leaflet.ie.css @@ -0,0 +1,46 @@ +.leaflet-tile { + filter: inherit; + } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + +.leaflet-control { + display: inline; + } + +.leaflet-popup-tip { + width: 21px; + _width: 27px; + margin: 0 auto; + _margin-top: -3px; + + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + } +.leaflet-popup-tip-container { + margin-top: -1px; + } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + border: 1px solid #bbb; + } + +.leaflet-control-zoom { + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#3F000000',EndColorStr='#3F000000'); + } +.leaflet-control-zoom a { + background-color: #eee; + } +.leaflet-control-zoom a:hover { + background-color: #fff; + } +.leaflet-control-attribution { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#B2FFFFFF,endColorstr=#B2FFFFFF); + } \ No newline at end of file diff --git a/extlib/leaflet/dist/leaflet.js b/extlib/leaflet/dist/leaflet.js new file mode 100644 index 00000000..d4ed26a4 --- /dev/null +++ b/extlib/leaflet/dist/leaflet.js @@ -0,0 +1,114 @@ +/* + Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin + Leaflet is a BSD-licensed JavaScript library for map display and interaction. + See http://cloudmade.github.com/Leaflet/ for more information. +*/ +(function(a){var b={VERSION:"0.2",ROOT_URL:function(){for(var a=document.getElementsByTagName("script"),b=/^(.*\/)leaflet-?([\w-]*)\.js.*$/,e=0,f=a.length;e0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&a.x<=this.max.x&&b.y>=this.min.y&&a.y<=this.max.y}});L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a;this._b=b;this._c=c;this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){b=b||1;a.x=b*(this._a*a.x+this._b);a.y=b*(this._c*a.y+this._d);return a},untransform:function(a,b){b=b||1;return new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}});L.LineUtil={simplify:function(a,b){if(!b)return a.slice();a=this.reducePoints(a,b);return a=this.simplifyDP(a,b)},pointToSegmentDistance:function(a,b,c){return Math.sqrt(this._sqPointToSegmentDist(a,b,c))},simplifyDP:function(a,b){for(var c=0,d=0,e=b*b,f=1,g=a.length,h;fc&&(d=f,c=h);return c>=e?(c=a.slice(0,d),d=a.slice(d),g=this.simplifyDP(c,b).slice(0,g-2),d=this.simplifyDP(d,b),g.concat(d)):[a[0],a[g-1]]},reducePoints:function(a,b){for(var c= +[a[0]],d=b*b,e=1,f=0,g=a.length;eb.max.x&&(c|=2);a.yb.max.y&&(c|=8);return c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqPointToSegmentDist:function(a,b,c){var d=c.x-b.x,e=c.y-b.y;if(!d&&!e)return this._sqDist(a,b);var f=((a.x-b.x)*d+(a.y-b.y)*e)/this._sqDist(b,c);if(f< +0)return this._sqDist(a,b);if(f>1)return this._sqDist(a,c);b=new L.Point(b.x+d*f,b.y+e*f);return this._sqDist(a,b)}};L.PolyUtil={};L.PolyUtil.clipPolygon=function(a,b){var c,d=[1,4,2,8],e,f,g,h,j,k,l=L.LineUtil;e=0;for(j=a.length;e0&&c<=h;f=b}}function e(){if(g)j.type="dblclick",b(j),f=null}var f,g=!1,h=250,j;a["_leaflet_touchstart"+c]=d;a["_leaflet_touchend"+c]=e;a.addEventListener("touchstart",d,!1);a.addEventListener("touchend",e,!1)},removeDoubleTapListener:function(a,b){a.removeEventListener(a,a["_leaflet_touchstart"+b],!1);a.removeEventListener(a,a["_leaflet_touchend"+b], +!1)}});L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c=="auto")c=(c=document.defaultView.getComputedStyle(a,null))?c[b]:null;return c=="auto"?null:c},getCumulativeOffset:function(a){var b=0,c=0;do b+=a.offsetTop||0,c+=a.offsetLeft||0,a=a.offsetParent;while(a);return new L.Point(c,b)},create:function(a,b,c){a=document.createElement(a);a.className=b;c&&c.appendChild(a);return a},disableTextSelection:function(){document.selection&& +document.selection.empty&&document.selection.empty();if(!this._onselectstart)this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn},enableTextSelection:function(){document.onselectstart=this._onselectstart;this._onselectstart=null},CLASS_RE:/(\\s|^)'+cls+'(\\s|$)/,hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},setOpacity:function(a, +b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){for(var b=document.documentElement.style,c=0;c1)){var b=a.touches&&a.touches.length==1?a.touches[0]:a;L.DomEvent.preventDefault(a);L.Browser.mobileWebkit&&(b.target.className+=" leaflet-active");this._moved=!1;L.DomUtil.disableTextSelection();this._setMovingCursor();this._startPos=this._newPos=L.DomUtil.getPosition(this._element);this._startPoint=new L.Point(b.clientX,b.clientY);L.DomEvent.addListener(document, +L.Draggable.MOVE,this._onMove,this);L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)}},_onMove:function(a){if(!(a.touches&&a.touches.length>1)){L.DomEvent.preventDefault(a);a=a.touches&&a.touches.length==1?a.touches[0]:a;if(!this._moved)this.fire("dragstart"),this._moved=!0;this._newPos=this._startPos.add(new L.Point(a.clientX,a.clientY)).subtract(this._startPoint);L.Util.requestAnimFrame(this._updatePosition,this,!0);this.fire("drag")}},_updatePosition:function(){L.DomUtil.setPosition(this._element, +this._newPos)},_onUp:function(a){if(a.changedTouches){var a=a.changedTouches[0],b=a.target,c=this._newPos&&this._newPos.distanceTo(this._startPos)||0;b.className=b.className.replace(" leaflet-active","");c=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng}});L.Projection={};L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}};L.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.3142,R_MAJOR:6378137,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=this.R_MAJOR,e=a.lng*b*d,a=Math.max(Math.min(c,a.lat),-c)*b,b=this.R_MINOR/d,b=Math.sqrt(1-b*b),c=b*Math.sin(a),c=Math.pow((1-c)/(1+c),b*0.5),a=-d*Math.log(Math.tan(0.5*(Math.PI*0.5-a))/c);return new L.Point(e,a)},unproject:function(a,b){for(var c=L.LatLng.RAD_TO_DEG,d=this.R_MAJOR,e=a.x*c/d,f=this.R_MINOR/d,f=Math.sqrt(1-f*f),d=Math.exp(-a.y/d), +g=Math.PI/2-2*Math.atan(d),h=15,j=0.1;Math.abs(j)>1.0E-7&&--h>0;)j=f*Math.sin(g),j=Math.PI/2-2*Math.atan(d*Math.pow((1-j)/(1+j),0.5*f))-g,g+=j;return new L.LatLng(g*c,e,b)}};L.CRS={latLngToPoint:function(a,b){return this.transformation._transform(this.projection.project(a),b)},pointToLatLng:function(a,b,c){return this.projection.unproject(this.transformation.untransform(a,b),c)},project:function(a){return this.projection.project(a)}};L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(0.5/Math.PI,0.5,-0.5/Math.PI,0.5),project:function(a){return this.projection.project(a).multiplyBy(6378137)}});L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"});L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,0.5,-1/360,0.5)});L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator;return new L.Transformation(0.5/(Math.PI*a.R_MAJOR),0.5,-0.5/(Math.PI*a.R_MINOR),0.5)}()});L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;ba.max.x||ba.max.y))this._tiles[d].src="",this._tiles[d].parentNode==this._container&&this._container.removeChild(this._tiles[d]),delete this._tiles[d]},_addTile:function(a){var b= +this._getTilePos(a),c=this._map.getZoom(),d=a.x+":"+a.y,e=1<=e)){var f=this._createTile();L.DomUtil.setPosition(f,b);this._tiles[d]=f;if(this.options.scheme=="tms")a.y=e-a.y-1;this._loadTile(f,a,c);this._container.appendChild(f)}},_getTilePos:function(a){var b=this._map.getPixelOrigin();return a.multiplyBy(this.options.tileSize).subtract(b)},getTileUrl:function(a,b){return this._url.replace("{s}",this.options.subdomains[(a.x+a.y)%this.options.subdomains.length]).replace("{z}", +b).replace("{x}",a.x).replace("{y}",a.y)},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile");this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px";this._tileImg.style.height=a+"px"},_createTile:function(){var a=this._tileImg.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;a.onload=this._tileOnLoad;a.onerror=this._tileOnError;a.src=this.getTileUrl(b,c)},_tileOnLoad:function(){var a= +this._layer;this.className+=" leaflet-tile-loaded";a.fire("tileload",{tile:this,url:this.src});a._tilesToLoad--;a._tilesToLoad||a.fire("load")},_tileOnError:function(){var a=this._layer;a.fire("tileerror",{tile:this,url:this.src});if(a=a.options.errorTileUrl)this.src=a}});L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a;this.wmsParams=L.Util.extend({},this.defaultWmsParams);this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){this.wmsParams[parseFloat(this.wmsParams.version)>=1.3?"crs":"srs"]=a.options.crs.code; +L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a){var b=this.options.tileSize,a=a.multiplyBy(b),b=a.add(new L.Point(b,b)),a=this._map.unproject(a,this._zoom,!0),b=this._map.unproject(b,this._zoom,!0),a=this._map.options.crs.project(a),b=this._map.options.crs.project(b),b=[a.x,b.y,b.x,a.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+b}});L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a;this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a._layer=this;this.drawTile(a,b,c);this.options.async||this.tileDrawn(a)},drawTile:function(){}, +tileDrawn:function(a){this._tileOnLoad.call(a)}});L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a;this._bounds=b},onAdd:function(a){this._map=a;this._image||this._initImage();a.getPanes().overlayPane.appendChild(this._image);a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image);a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer");this._image.style.visibility="hidden";L.Util.extend(this._image, +{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:this._onImageLoad,src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(a);L.DomUtil.setPosition(this._image,a);this._image.style.width=b.x+"px";this._image.style.height=b.y+"px"},_onImageLoad:function(){this.style.visibility=""}});L.Popup=L.Class.extend({includes:L.Mixin.Events,options:{maxWidth:300,autoPan:!0,closeButton:!0,offset:new L.Point(0,2),autoPanPadding:new L.Point(5,5)},initialize:function(a){L.Util.setOptions(this,a)},onAdd:function(a){this._map=a;this._container||this._initLayout();this._updateContent();this._container.style.opacity="0";this._map._panes.popupPane.appendChild(this._container);this._map.on("viewreset",this._updatePosition,this);if(this._map.options.closePopupOnClick)this._map.on("preclick",this._close, +this);this._update();this._container.style.opacity="1";this._opened=!0},onRemove:function(a){a._panes.popupPane.removeChild(this._container);a.off("viewreset",this._updatePosition,this);a.off("click",this._close,this);this._container.style.opacity="0";this._opened=!1},setLatLng:function(a){this._latlng=a;this._opened&&this._update();return this},setContent:function(a){this._content=a;this._opened&&this._update();return this},_close:function(){this._opened&&this._map.removeLayer(this)},_initLayout:function(){this._container= +L.DomUtil.create("div","leaflet-popup");this._closeButton=L.DomUtil.create("a","leaflet-popup-close-button",this._container);this._closeButton.href="#close";this._closeButton.onclick=L.Util.bind(this._onCloseButtonClick,this);this._wrapper=L.DomUtil.create("div","leaflet-popup-content-wrapper",this._container);L.DomEvent.disableClickPropagation(this._wrapper);this._contentNode=L.DomUtil.create("div","leaflet-popup-content",this._wrapper);this._tipContainer=L.DomUtil.create("div","leaflet-popup-tip-container", +this._container);this._tip=L.DomUtil.create("div","leaflet-popup-tip",this._tipContainer)},_update:function(){this._container.style.visibility="hidden";this._updateContent();this._updateLayout();this._updatePosition();this._container.style.visibility="";this._adjustPan()},_updateContent:function(){if(this._content)typeof this._content=="string"?this._contentNode.innerHTML=this._content:(this._contentNode.innerHTML="",this._contentNode.appendChild(this._content))},_updateLayout:function(){this._container.style.width= +"";this._container.style.whiteSpace="nowrap";var a=this._container.offsetWidth;this._container.style.width=(a>this.options.maxWidth?this.options.maxWidth:a)+"px";this._container.style.whiteSpace="";this._containerWidth=this._container.offsetWidth},_updatePosition:function(){var a=this._map.latLngToLayerPoint(this._latlng);this._containerBottom=-a.y-this.options.offset.y;this._containerLeft=a.x-Math.round(this._containerWidth/2)+this.options.offset.x;this._container.style.bottom=this._containerBottom+ +"px";this._container.style.left=this._containerLeft+"px"},_adjustPan:function(){if(this.options.autoPan){var a=this._container.offsetHeight,b=this._map.layerPointToContainerPoint(new L.Point(this._containerLeft,-a-this._containerBottom)),c=new L.Point(0,0),d=this.options.autoPanPadding,e=this._map.getSize();if(b.x<0)c.x=b.x-d.x;if(b.x+this._containerWidth>e.x)c.x=b.x+this._containerWidth-e.x+d.x;if(b.y<0)c.y=b.y-d.y;if(b.y+a>e.y)c.y=b.y+a-e.y+d.y;(c.x||c.y)&&this._map.panBy(c)}},_onCloseButtonClick:function(a){this._close(); +L.DomEvent.stop(a)}});L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){if(a)this.iconUrl=a},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"],d=this._createImg(c);if(!c)return null;d.className="leaflet-marker-"+ +a;d.style.marginLeft=-this.iconAnchor.x+"px";d.style.marginTop=-this.iconAnchor.y+"px";if(b)d.style.width=b.x+"px",d.style.height=b.y+"px";return d},_createImg:function(a){var b;L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a);return b}});L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1},initialize:function(a,b){L.Util.setOptions(this,b);this._latlng=a},onAdd:function(a){this._map=a;this._initIcon();a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){this._removeIcon();a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a;this._reset()},setIcon:function(a){this._removeIcon();this._icon=this._shadow= +null;this.options.icon=a;this._initIcon()},_initIcon:function(){if(!this._icon){this._icon=this.options.icon.createIcon();if(this.options.title)this._icon.title=this.options.title;this._initInteraction()}if(!this._shadow)this._shadow=this.options.icon.createShadow();this._map._panes.markerPane.appendChild(this._icon);this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon);this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow)}, +_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a);this._shadow&&L.DomUtil.setPosition(this._shadow,a);this._icon.style.zIndex=a.y},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable";L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);for(var a=["dblclick","mousedown","mouseover","mouseout"],b=0;b';a=a.firstChild;a.style.behavior="url(#default#VML)";return a&&typeof a.adj=="object"}(); +L.Path=L.Path.SVG||!L.Path.VML?L.Path:L.Path.extend({statics:{CLIP_PADDING:0.02},_createElement:function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(a){return document.createElement("')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initRoot:function(){if(!this._map._pathRoot)this._map._pathRoot=document.createElement("div"),this._map._pathRoot.className= +"leaflet-vml-container",this._map._panes.overlayPane.appendChild(this._map._pathRoot),this._map.on("moveend",this._updateViewport,this),this._updateViewport()},_initPath:function(){this._container=this._createElement("shape");this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":"");this._container.coordsize="1 1";this._path=this._createElement("path");this._container.appendChild(this._path);this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke? +(this._stroke=this._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1;this.options.fill?(this._container.filled=!0,this._fill=this._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1;this._updateStyle()},_updateStyle:function(){if(this.options.stroke)this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity;if(this.options.fill)this._fill.color= +this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity},_updatePath:function(){this._container.style.display="none";this._path.v=this.getPathString()+" ";this._container.style.display=""}});L.Path.include({bindPopup:function(a,b){if(!this._popup||this._popup.options!==b)this._popup=new L.Popup(b);this._popup.setContent(a);if(!this._openPopupAdded)this.on("click",this._openPopup,this),this._openPopupAdded=!0;return this},_openPopup:function(a){this._popup.setLatLng(a.latlng);this._map.openPopup(this._popup)}});L.Polyline=L.Path.extend({initialize:function(a,b){L.Path.prototype.initialize.call(this,b);this._latlngs=a},options:{smoothFactor:1,noClip:!1,updateOnMoveEnd:!0},projectLatlngs:function(){this._originalPoints=[];for(var a=0,b=this._latlngs.length;a0?Math.ceil(b):Math.floor(b))),a=b-a,c=this._centerOffset.subtract(this._delta).divideBy(this._scale),d=this._map.unproject(this._map.getPixelOrigin().add(this._startCenter).add(c));L.DomEvent.removeListener(document,"touchmove",this._onTouchMove);L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);this._map._runAnimation(d,b,Math.pow(2,a)/this._scale,this._startCenter.add(c))}}});L.Handler.ScrollWheelZoom=L.Handler.extend({enable:function(){if(!this._enabled)L.DomEvent.addListener(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0,this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._map._container,"mousewheel",this._onWheelScroll),this._enabled=!1},_onWheelScroll:function(a){this._delta+=L.DomEvent.getWheelDelta(a);this._lastMousePos=this._map.mouseEventToContainerPoint(a);clearTimeout(this._timer);this._timer=setTimeout(L.Util.bind(this._performZoom, +this),50);L.DomEvent.preventDefault(a)},_performZoom:function(){var a=Math.round(this._delta);this._delta=0;if(a){var b=this._getCenterForScrollWheelZoom(this._lastMousePos,a),a=this._map.getZoom()+a;this._map._limitZoom(a)!=this._map._zoom&&this._map.setView(b,a)}},_getCenterForScrollWheelZoom:function(a,b){var c=this._map.getPixelBounds().getCenter(),d=this._map.getSize().divideBy(2),d=a.subtract(d).multiplyBy(1-Math.pow(2,-b));return this._map.unproject(c.add(d),this._map._zoom,!0)}});L.Handler.DoubleClickZoom=L.Handler.extend({enable:function(){if(!this._enabled)this._map.on("dblclick",this._onDoubleClick,this._map),this._enabled=!0},disable:function(){if(this._enabled)this._map.off("dblclick",this._onDoubleClick,this._map),this._enabled=!1},_onDoubleClick:function(a){this.setView(a.latlng,this._zoom+1)}});L.Handler.ShiftDragZoom=L.Handler.extend({initialize:function(a){this._map=a;this._container=a._container;this._pane=a._panes.overlayPane},enable:function(){if(!this._enabled)L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this),this._enabled=!0},disable:function(){if(this._enabled)L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown),this._enabled=!1},_onMouseDown:function(a){if(!a.shiftKey||a.which!=1&&a.button!=1)return!1;L.DomUtil.disableTextSelection(); +this._startLayerPoint=this._map.mouseEventToLayerPoint(a);this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane);L.DomUtil.setPosition(this._box,this._startLayerPoint);this._container.style.cursor="crosshair";L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this);L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this);L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),a=b.x-this._startLayerPoint.x,c=b.y-this._startLayerPoint.y, +b=new L.Point(Math.min(b.x,this._startLayerPoint.x),Math.min(b.y,this._startLayerPoint.y));L.DomUtil.setPosition(this._box,b);this._box.style.width=Math.abs(a)-4+"px";this._box.style.height=Math.abs(c)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box);this._container.style.cursor="";L.DomUtil.enableTextSelection();L.DomEvent.removeListener(document,"mousemove",this._onMouseMove);L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);a=this._map.mouseEventToLayerPoint(a);this._map.fitBounds(new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint), +this._map.layerPointToLatLng(a)))}});L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},enable:function(){if(!this._enabled){if(!this._draggable)this._draggable=new L.Draggable(this._marker._icon,this._marker._icon),this._draggable.on("dragstart",this._onDragStart,this),this._draggable.on("drag",this._onDrag,this),this._draggable.on("dragend",this._onDragEnd,this);this._draggable.enable();this._enabled=!0}},disable:function(){if(this._enabled)this._draggable.disable(),this._enabled=!1},moved:function(){return this._draggable&& +this._draggable._moved},_onDragStart:function(){this._marker.closePopup();this._marker.fire("movestart");this._marker.fire("dragstart")},_onDrag:function(){var a=L.DomUtil.getPosition(this._marker._icon);L.DomUtil.setPosition(this._marker._shadow,a);this._marker._latlng=this._marker._map.layerPointToLatLng(a);this._marker.fire("move");this._marker.fire("drag")},_onDragEnd:function(){this._marker.fire("moveend");this._marker.fire("dragend")}});L.Control={};L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"};L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a;this._container=L.DomUtil.create("div","leaflet-control-zoom");this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map);this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map);this._container.appendChild(this._zoomInButton);this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT}, +_createButton:function(a,b,c,d){var e=document.createElement("a");e.href="#";e.title=a;e.className=b;L.DomEvent.disableClickPropagation(e);L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault);L.DomEvent.addListener(e,"click",c,d);return e}});L.Control.Attribution=L.Class.extend({onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution");this._map=a;this._prefix='Powered by Leaflet';this._attributions={};this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a},addAttribution:function(a){a&&(this._attributions[a]=!0,this._update())},removeAttribution:function(a){a&& +(delete this._attributions[a],this._update())},_update:function(){if(this._map){var a=[],b;for(b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);b=[];this._prefix&&b.push(this._prefix);a.length&&b.push(a.join(", "));this._container.innerHTML=b.join(" — ")}}});L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*(1< Project ..." and create a +"Java Project." You will see an options screen. Give the project a +name, select "Create project from existing source," and choose the +root of the checked-out source tree as the existing directory. Verify +that you are using JRE version 6 or higher. + +Eclipse can use the build.xml file to discover rules. When you +navigate to the build.xml file, you will see all the build rules in +the "Outline" pane. Run the "jar" rule to build the compiler in +build/compiler.jar. + + +// +// Running The Closure Compiler +// + +Once you have the jar binary, running the Closure Compiler is straightforward. + +On the command line, type + +java -jar compiler.jar + +This starts the compiler in interactive mode. Type + +var x = 17 + 25; + +then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux) +and "Enter" again. The Compiler will respond: + +var x=42; + +The Closure Compiler has many options for reading input from a file, +writing output to a file, checking your code, and running +optimizations. To learn more, type + +java -jar compiler.jar --help + +You can read more detailed documentation about the many flags at +http://code.google.com/closure/compiler/docs/gettingstarted_app.html + + +// +// Compiling Multiple Scripts +// + +If you have multiple scripts, you should compile them all together with +one compile command. + +java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js + +The Closure Compiler will concatenate the files in the order they're +passed at the command line. + +If you need to compile many, many scripts together, you may start to +run into problems with managing dependencies between scripts. You +should check out the Closure Library. It contains functions for +enforcing dependencies between scripts, and a tool called calcdeps.py +that knows how to give scripts to the Closure Compiler in the right +order. + +http://code.google.com/p/closure-library/ + +// +// Licensing +// + +Unless otherwise stated, all source files are licensed under +the Apache License, Version 2.0. + + +----- +Code under: +src/com/google/javascript/rhino +test/com/google/javascript/rhino + +URL: http://www.mozilla.org/rhino +Version: 1.5R3, with heavy modifications +License: Netscape Public License and MPL / GPL dual license + +Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an +implementation of JavaScript for the JVM. The JavaScript parser and +the parse tree data structures were extracted and modified +significantly for use by Google's JavaScript compiler. + +Local Modifications: The packages have been renamespaced. All code not +relavant to parsing has been removed. A JSDoc parser and static typing +system have been added. + + +----- +Code in: +lib/libtrunk_rhino_parser_jarjared.jar + +Rhino +URL: http://www.mozilla.org/rhino +Version: Trunk +License: Netscape Public License and MPL / GPL dual license + +Description: Mozilla Rhino is an implementation of JavaScript for the JVM. + +Local Modifications: None. We've used JarJar to renamespace the code +post-compilation. See: +http://code.google.com/p/jarjar/ + + +----- +Code in: +lib/args4j.jar + +Args4j +URL: https://args4j.dev.java.net/ +Version: 2.0.12 +License: MIT + +Description: +args4j is a small Java class library that makes it easy to parse command line +options/arguments in your CUI application. + +Local Modifications: None. + + +----- +Code in: +lib/guava.jar + +Guava Libraries +URL: http://code.google.com/p/guava-libraries/ +Version: r08 +License: Apache License 2.0 + +Description: Google's core Java libraries. + +Local Modifications: None. + + +----- +Code in: +lib/jsr305.jar + +Annotations for software defect detection +URL: http://code.google.com/p/jsr-305/ +Version: svn revision 47 +License: BSD License + +Description: Annotations for software defect detection. + +Local Modifications: None. + + +---- +Code in: +lib/junit.jar + +JUnit +URL: http://sourceforge.net/projects/junit/ +Version: 4.8.2 +License: Common Public License 1.0 + +Description: A framework for writing and running automated tests in Java. + +Local Modifications: None. + + +--- +Code in: +lib/protobuf-java.jar + +Protocol Buffers +URL: http://code.google.com/p/protobuf/ +Version: 2.3.0 +License: New BSD License + +Description: Supporting libraries for protocol buffers, +an encoding of structured data. + +Local Modifications: None + + +--- +Code in: +lib/ant.jar +lib/ant-launcher.jar + +URL: http://ant.apache.org/bindownload.cgi +Version: 1.8.1 +License: Apache License 2.0 +Description: + Ant is a Java based build tool. In theory it is kind of like "make" + without make's wrinkles and with the full portability of pure java code. + +Local Modifications: None + + +--- +Code in: +lib/json.jar +URL: http://json.org/java/index.html +Version: JSON version 20090211 +License: MIT license +Description: +JSON is a set of java files for use in transmitting data in JSON format. + +Local Modifications: None + +--- +Code in: +tools/maven-ant-tasks-2.1.1.jar +URL: http://maven.apache.org +Version 2.1.1 +License: Apache License 2.0 +Description: + Maven Ant tasks are used to manage dependencies and to install/deploy to + maven repositories. + +Local Modifications: None diff --git a/extlib/leaflet/lib/closure-compiler/compiler.jar b/extlib/leaflet/lib/closure-compiler/compiler.jar new file mode 100644 index 00000000..2f6837d3 Binary files /dev/null and b/extlib/leaflet/lib/closure-compiler/compiler.jar differ diff --git a/extlib/leaflet/lib/jasmine/jasmine-html.js b/extlib/leaflet/lib/jasmine/jasmine-html.js new file mode 100644 index 00000000..b4058216 --- /dev/null +++ b/extlib/leaflet/lib/jasmine/jasmine-html.js @@ -0,0 +1,182 @@ +jasmine.TrivialReporter = function(doc) { + this.document = doc || document; + this.suiteDivs = {}; + this.logRunningSpecs = false; +}; + +jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { + var el = document.createElement(type); + + for (var i = 2; i < arguments.length; i++) { + var child = arguments[i]; + + if (typeof child === 'string') { + el.appendChild(document.createTextNode(child)); + } else { + if (child) { el.appendChild(child); } + } + } + + for (var attr in attrs) { + if (attr == "className") { + el[attr] = attrs[attr]; + } else { + el.setAttribute(attr, attrs[attr]); + } + } + + return el; +}; + +jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { + var showPassed, showSkipped; + + this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, + this.createDom('div', { className: 'banner' }, + this.createDom('div', { className: 'logo' }, + "Jasmine", + this.createDom('span', { className: 'version' }, runner.env.versionString())), + this.createDom('div', { className: 'options' }, + "Show ", + showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), + this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), + showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), + this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") + ) + ), + + this.runnerDiv = this.createDom('div', { className: 'runner running' }, + this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), + this.runnerMessageSpan = this.createDom('span', {}, "Running..."), + this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) + ); + + this.document.body.appendChild(this.outerDiv); + + var suites = runner.suites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; + var suiteDiv = this.createDom('div', { className: 'suite' }, + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), + this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); + this.suiteDivs[suite.id] = suiteDiv; + var parentDiv = this.outerDiv; + if (suite.parentSuite) { + parentDiv = this.suiteDivs[suite.parentSuite.id]; + } + parentDiv.appendChild(suiteDiv); + } + + this.startedAt = new Date(); + + var self = this; + showPassed.onchange = function(evt) { + if (evt.target.checked) { + self.outerDiv.className += ' show-passed'; + } else { + self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); + } + }; + + showSkipped.onchange = function(evt) { + if (evt.target.checked) { + self.outerDiv.className += ' show-skipped'; + } else { + self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); + } + }; +}; + +jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { + var results = runner.results(); + var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; + this.runnerDiv.setAttribute("class", className); + //do it twice for IE + this.runnerDiv.setAttribute("className", className); + var specs = runner.specs(); + var specCount = 0; + for (var i = 0; i < specs.length; i++) { + if (this.specFilter(specs[i])) { + specCount++; + } + } + var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); + message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; + this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); + + this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); +}; + +jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { + var results = suite.results(); + var status = results.passed() ? 'passed' : 'failed'; + if (results.totalCount == 0) { // todo: change this to check results.skipped + status = 'skipped'; + } + this.suiteDivs[suite.id].className += " " + status; +}; + +jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { + if (this.logRunningSpecs) { + this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); + } +}; + +jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { + var results = spec.results(); + var status = results.passed() ? 'passed' : 'failed'; + if (results.skipped) { + status = 'skipped'; + } + var specDiv = this.createDom('div', { className: 'spec ' + status }, + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), + this.createDom('a', { + className: 'description', + href: '?spec=' + encodeURIComponent(spec.getFullName()), + title: spec.getFullName() + }, spec.description)); + + + var resultItems = results.getItems(); + var messagesDiv = this.createDom('div', { className: 'messages' }); + for (var i = 0; i < resultItems.length; i++) { + var result = resultItems[i]; + + if (result.type == 'log') { + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); + } else if (result.type == 'expect' && result.passed && !result.passed()) { + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); + + if (result.trace.stack) { + messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); + } + } + } + + if (messagesDiv.childNodes.length > 0) { + specDiv.appendChild(messagesDiv); + } + + this.suiteDivs[spec.suite.id].appendChild(specDiv); +}; + +jasmine.TrivialReporter.prototype.log = function() { + var console = jasmine.getGlobal().console; + if (console && console.log) console.log.apply(console, arguments); +}; + +jasmine.TrivialReporter.prototype.getLocation = function() { + return this.document.location; +}; + +jasmine.TrivialReporter.prototype.specFilter = function(spec) { + var paramMap = {}; + var params = this.getLocation().search.substring(1).split('&'); + for (var i = 0; i < params.length; i++) { + var p = params[i].split('='); + paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); + } + + if (!paramMap["spec"]) return true; + return spec.getFullName().indexOf(paramMap["spec"]) == 0; +}; diff --git a/extlib/leaflet/lib/jasmine/jasmine.css b/extlib/leaflet/lib/jasmine/jasmine.css new file mode 100644 index 00000000..6583fe7c --- /dev/null +++ b/extlib/leaflet/lib/jasmine/jasmine.css @@ -0,0 +1,166 @@ +body { + font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; +} + + +.jasmine_reporter a:visited, .jasmine_reporter a { + color: #303; +} + +.jasmine_reporter a:hover, .jasmine_reporter a:active { + color: blue; +} + +.run_spec { + float:right; + padding-right: 5px; + font-size: .8em; + text-decoration: none; +} + +.jasmine_reporter { + margin: 0 5px; +} + +.banner { + color: #303; + background-color: #fef; + padding: 5px; +} + +.logo { + float: left; + font-size: 1.1em; + padding-left: 5px; +} + +.logo .version { + font-size: .6em; + padding-left: 1em; +} + +.runner.running { + background-color: yellow; +} + + +.options { + text-align: right; + font-size: .8em; +} + + + + +.suite { + border: 1px outset gray; + margin: 5px 0; + padding-left: 1em; +} + +.suite .suite { + margin: 5px; +} + +.suite.passed { + background-color: #dfd; +} + +.suite.failed { + background-color: #fdd; +} + +.spec { + margin: 5px; + padding-left: 1em; + clear: both; +} + +.spec.failed, .spec.passed, .spec.skipped { + padding-bottom: 5px; + border: 1px solid gray; +} + +.spec.failed { + background-color: #fbb; + border-color: red; +} + +.spec.passed { + background-color: #bfb; + border-color: green; +} + +.spec.skipped { + background-color: #bbb; +} + +.messages { + border-left: 1px dashed gray; + padding-left: 1em; + padding-right: 1em; +} + +.passed { + background-color: #cfc; + display: none; +} + +.failed { + background-color: #fbb; +} + +.skipped { + color: #777; + background-color: #eee; + display: none; +} + + +/*.resultMessage {*/ + /*white-space: pre;*/ +/*}*/ + +.resultMessage span.result { + display: block; + line-height: 2em; + color: black; +} + +.resultMessage .mismatch { + color: black; +} + +.stackTrace { + white-space: pre; + font-size: .8em; + margin-left: 10px; + max-height: 5em; + overflow: auto; + border: 1px inset red; + padding: 1em; + background: #eef; +} + +.finished-at { + padding-left: 1em; + font-size: .6em; +} + +.show-passed .passed, +.show-skipped .skipped { + display: block; +} + + +#jasmine_content { + position:fixed; + right: 100%; +} + +.runner { + border: 1px solid gray; + display: block; + margin: 5px 0; + padding: 2px 0 2px 10px; +} diff --git a/extlib/leaflet/lib/jasmine/jasmine.js b/extlib/leaflet/lib/jasmine/jasmine.js new file mode 100644 index 00000000..3ace3bc4 --- /dev/null +++ b/extlib/leaflet/lib/jasmine/jasmine.js @@ -0,0 +1,2421 @@ +/** + * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. + * + * @namespace + */ +var jasmine = {}; + +/** + * @private + */ +jasmine.unimplementedMethod_ = function() { + throw new Error("unimplemented method"); +}; + +/** + * Use jasmine.undefined instead of undefined, since undefined is just + * a plain old variable and may be redefined by somebody else. + * + * @private + */ +jasmine.undefined = jasmine.___undefined___; + +/** + * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. + * + */ +jasmine.DEFAULT_UPDATE_INTERVAL = 250; + +/** + * Default timeout interval in milliseconds for waitsFor() blocks. + */ +jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; + +jasmine.getGlobal = function() { + function getGlobal() { + return this; + } + + return getGlobal(); +}; + +/** + * Allows for bound functions to be compared. Internal use only. + * + * @ignore + * @private + * @param base {Object} bound 'this' for the function + * @param name {Function} function to find + */ +jasmine.bindOriginal_ = function(base, name) { + var original = base[name]; + if (original.apply) { + return function() { + return original.apply(base, arguments); + }; + } else { + // IE support + return jasmine.getGlobal()[name]; + } +}; + +jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); +jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); +jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); +jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); + +jasmine.MessageResult = function(values) { + this.type = 'log'; + this.values = values; + this.trace = new Error(); // todo: test better +}; + +jasmine.MessageResult.prototype.toString = function() { + var text = ""; + for(var i = 0; i < this.values.length; i++) { + if (i > 0) text += " "; + if (jasmine.isString_(this.values[i])) { + text += this.values[i]; + } else { + text += jasmine.pp(this.values[i]); + } + } + return text; +}; + +jasmine.ExpectationResult = function(params) { + this.type = 'expect'; + this.matcherName = params.matcherName; + this.passed_ = params.passed; + this.expected = params.expected; + this.actual = params.actual; + + this.message = this.passed_ ? 'Passed.' : params.message; + this.trace = this.passed_ ? '' : new Error(this.message); +}; + +jasmine.ExpectationResult.prototype.toString = function () { + return this.message; +}; + +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; + +/** + * Getter for the Jasmine environment. Ensures one gets created + */ +jasmine.getEnv = function() { + return jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isArray_ = function(value) { + return jasmine.isA_("Array", value); +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isString_ = function(value) { + return jasmine.isA_("String", value); +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isNumber_ = function(value) { + return jasmine.isA_("Number", value); +}; + +/** + * @ignore + * @private + * @param {String} typeName + * @param value + * @returns {Boolean} + */ +jasmine.isA_ = function(typeName, value) { + return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; +}; + +/** + * Pretty printer for expecations. Takes any object and turns it into a human-readable string. + * + * @param value {Object} an object to be outputted + * @returns {String} + */ +jasmine.pp = function(value) { + var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); + stringPrettyPrinter.format(value); + return stringPrettyPrinter.string; +}; + +/** + * Returns true if the object is a DOM Node. + * + * @param {Object} obj object to check + * @returns {Boolean} + */ +jasmine.isDomNode = function(obj) { + return obj['nodeType'] > 0; +}; + +/** + * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. + * + * @example + * // don't care about which function is passed in, as long as it's a function + * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); + * + * @param {Class} clazz + * @returns matchable object of the type clazz + */ +jasmine.any = function(clazz) { + return new jasmine.Matchers.Any(clazz); +}; + +/** + * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. + * + * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine + * expectation syntax. Spies can be checked if they were called or not and what the calling params were. + * + * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). + * + * Spies are torn down at the end of every spec. + * + * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. + * + * @example + * // a stub + * var myStub = jasmine.createSpy('myStub'); // can be used anywhere + * + * // spy example + * var foo = { + * not: function(bool) { return !bool; } + * } + * + * // actual foo.not will not be called, execution stops + * spyOn(foo, 'not'); + + // foo.not spied upon, execution will continue to implementation + * spyOn(foo, 'not').andCallThrough(); + * + * // fake example + * var foo = { + * not: function(bool) { return !bool; } + * } + * + * // foo.not(val) will return val + * spyOn(foo, 'not').andCallFake(function(value) {return value;}); + * + * // mock example + * foo.not(7 == 7); + * expect(foo.not).toHaveBeenCalled(); + * expect(foo.not).toHaveBeenCalledWith(true); + * + * @constructor + * @see spyOn, jasmine.createSpy, jasmine.createSpyObj + * @param {String} name + */ +jasmine.Spy = function(name) { + /** + * The name of the spy, if provided. + */ + this.identity = name || 'unknown'; + /** + * Is this Object a spy? + */ + this.isSpy = true; + /** + * The actual function this spy stubs. + */ + this.plan = function() { + }; + /** + * Tracking of the most recent call to the spy. + * @example + * var mySpy = jasmine.createSpy('foo'); + * mySpy(1, 2); + * mySpy.mostRecentCall.args = [1, 2]; + */ + this.mostRecentCall = {}; + + /** + * Holds arguments for each call to the spy, indexed by call count + * @example + * var mySpy = jasmine.createSpy('foo'); + * mySpy(1, 2); + * mySpy(7, 8); + * mySpy.mostRecentCall.args = [7, 8]; + * mySpy.argsForCall[0] = [1, 2]; + * mySpy.argsForCall[1] = [7, 8]; + */ + this.argsForCall = []; + this.calls = []; +}; + +/** + * Tells a spy to call through to the actual implemenatation. + * + * @example + * var foo = { + * bar: function() { // do some stuff } + * } + * + * // defining a spy on an existing property: foo.bar + * spyOn(foo, 'bar').andCallThrough(); + */ +jasmine.Spy.prototype.andCallThrough = function() { + this.plan = this.originalValue; + return this; +}; + +/** + * For setting the return value of a spy. + * + * @example + * // defining a spy from scratch: foo() returns 'baz' + * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); + * + * // defining a spy on an existing property: foo.bar() returns 'baz' + * spyOn(foo, 'bar').andReturn('baz'); + * + * @param {Object} value + */ +jasmine.Spy.prototype.andReturn = function(value) { + this.plan = function() { + return value; + }; + return this; +}; + +/** + * For throwing an exception when a spy is called. + * + * @example + * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' + * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); + * + * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' + * spyOn(foo, 'bar').andThrow('baz'); + * + * @param {String} exceptionMsg + */ +jasmine.Spy.prototype.andThrow = function(exceptionMsg) { + this.plan = function() { + throw exceptionMsg; + }; + return this; +}; + +/** + * Calls an alternate implementation when a spy is called. + * + * @example + * var baz = function() { + * // do some stuff, return something + * } + * // defining a spy from scratch: foo() calls the function baz + * var foo = jasmine.createSpy('spy on foo').andCall(baz); + * + * // defining a spy on an existing property: foo.bar() calls an anonymnous function + * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); + * + * @param {Function} fakeFunc + */ +jasmine.Spy.prototype.andCallFake = function(fakeFunc) { + this.plan = fakeFunc; + return this; +}; + +/** + * Resets all of a spy's the tracking variables so that it can be used again. + * + * @example + * spyOn(foo, 'bar'); + * + * foo.bar(); + * + * expect(foo.bar.callCount).toEqual(1); + * + * foo.bar.reset(); + * + * expect(foo.bar.callCount).toEqual(0); + */ +jasmine.Spy.prototype.reset = function() { + this.wasCalled = false; + this.callCount = 0; + this.argsForCall = []; + this.calls = []; + this.mostRecentCall = {}; +}; + +jasmine.createSpy = function(name) { + + var spyObj = function() { + spyObj.wasCalled = true; + spyObj.callCount++; + var args = jasmine.util.argsToArray(arguments); + spyObj.mostRecentCall.object = this; + spyObj.mostRecentCall.args = args; + spyObj.argsForCall.push(args); + spyObj.calls.push({object: this, args: args}); + return spyObj.plan.apply(this, arguments); + }; + + var spy = new jasmine.Spy(name); + + for (var prop in spy) { + spyObj[prop] = spy[prop]; + } + + spyObj.reset(); + + return spyObj; +}; + +/** + * Determines whether an object is a spy. + * + * @param {jasmine.Spy|Object} putativeSpy + * @returns {Boolean} + */ +jasmine.isSpy = function(putativeSpy) { + return putativeSpy && putativeSpy.isSpy; +}; + +/** + * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something + * large in one call. + * + * @param {String} baseName name of spy class + * @param {Array} methodNames array of names of methods to make spies + */ +jasmine.createSpyObj = function(baseName, methodNames) { + if (!jasmine.isArray_(methodNames) || methodNames.length == 0) { + throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); + } + var obj = {}; + for (var i = 0; i < methodNames.length; i++) { + obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); + } + return obj; +}; + +/** + * All parameters are pretty-printed and concatenated together, then written to the current spec's output. + * + * Be careful not to leave calls to jasmine.log in production code. + */ +jasmine.log = function() { + var spec = jasmine.getEnv().currentSpec; + spec.log.apply(spec, arguments); +}; + +/** + * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. + * + * @example + * // spy example + * var foo = { + * not: function(bool) { return !bool; } + * } + * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops + * + * @see jasmine.createSpy + * @param obj + * @param methodName + * @returns a Jasmine spy that can be chained with all spy methods + */ +var spyOn = function(obj, methodName) { + return jasmine.getEnv().currentSpec.spyOn(obj, methodName); +}; + +/** + * Creates a Jasmine spec that will be added to the current suite. + * + * // TODO: pending tests + * + * @example + * it('should be true', function() { + * expect(true).toEqual(true); + * }); + * + * @param {String} desc description of this specification + * @param {Function} func defines the preconditions and expectations of the spec + */ +var it = function(desc, func) { + return jasmine.getEnv().it(desc, func); +}; + +/** + * Creates a disabled Jasmine spec. + * + * A convenience method that allows existing specs to be disabled temporarily during development. + * + * @param {String} desc description of this specification + * @param {Function} func defines the preconditions and expectations of the spec + */ +var xit = function(desc, func) { + return jasmine.getEnv().xit(desc, func); +}; + +/** + * Starts a chain for a Jasmine expectation. + * + * It is passed an Object that is the actual value and should chain to one of the many + * jasmine.Matchers functions. + * + * @param {Object} actual Actual value to test against and expected value + */ +var expect = function(actual) { + return jasmine.getEnv().currentSpec.expect(actual); +}; + +/** + * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. + * + * @param {Function} func Function that defines part of a jasmine spec. + */ +var runs = function(func) { + jasmine.getEnv().currentSpec.runs(func); +}; + +/** + * Waits a fixed time period before moving to the next block. + * + * @deprecated Use waitsFor() instead + * @param {Number} timeout milliseconds to wait + */ +var waits = function(timeout) { + jasmine.getEnv().currentSpec.waits(timeout); +}; + +/** + * Waits for the latchFunction to return true before proceeding to the next block. + * + * @param {Function} latchFunction + * @param {String} optional_timeoutMessage + * @param {Number} optional_timeout + */ +var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { + jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); +}; + +/** + * A function that is called before each spec in a suite. + * + * Used for spec setup, including validating assumptions. + * + * @param {Function} beforeEachFunction + */ +var beforeEach = function(beforeEachFunction) { + jasmine.getEnv().beforeEach(beforeEachFunction); +}; + +/** + * A function that is called after each spec in a suite. + * + * Used for restoring any state that is hijacked during spec execution. + * + * @param {Function} afterEachFunction + */ +var afterEach = function(afterEachFunction) { + jasmine.getEnv().afterEach(afterEachFunction); +}; + +/** + * Defines a suite of specifications. + * + * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared + * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization + * of setup in some tests. + * + * @example + * // TODO: a simple suite + * + * // TODO: a simple suite with a nested describe block + * + * @param {String} description A string, usually the class under test. + * @param {Function} specDefinitions function that defines several specs. + */ +var describe = function(description, specDefinitions) { + return jasmine.getEnv().describe(description, specDefinitions); +}; + +/** + * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. + * + * @param {String} description A string, usually the class under test. + * @param {Function} specDefinitions function that defines several specs. + */ +var xdescribe = function(description, specDefinitions) { + return jasmine.getEnv().xdescribe(description, specDefinitions); +}; + + +// Provide the XMLHttpRequest class for IE 5.x-6.x: +jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { + try { + return new ActiveXObject("Msxml2.XMLHTTP.6.0"); + } catch(e) { + } + try { + return new ActiveXObject("Msxml2.XMLHTTP.3.0"); + } catch(e) { + } + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch(e) { + } + try { + return new ActiveXObject("Microsoft.XMLHTTP"); + } catch(e) { + } + throw new Error("This browser does not support XMLHttpRequest."); +} : XMLHttpRequest; +/** + * @namespace + */ +jasmine.util = {}; + +/** + * Declare that a child class inherit it's prototype from the parent class. + * + * @private + * @param {Function} childClass + * @param {Function} parentClass + */ +jasmine.util.inherit = function(childClass, parentClass) { + /** + * @private + */ + var subclass = function() { + }; + subclass.prototype = parentClass.prototype; + childClass.prototype = new subclass; +}; + +jasmine.util.formatException = function(e) { + var lineNumber; + if (e.line) { + lineNumber = e.line; + } + else if (e.lineNumber) { + lineNumber = e.lineNumber; + } + + var file; + + if (e.sourceURL) { + file = e.sourceURL; + } + else if (e.fileName) { + file = e.fileName; + } + + var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); + + if (file && lineNumber) { + message += ' in ' + file + ' (line ' + lineNumber + ')'; + } + + return message; +}; + +jasmine.util.htmlEscape = function(str) { + if (!str) return str; + return str.replace(/&/g, '&') + .replace(//g, '>'); +}; + +jasmine.util.argsToArray = function(args) { + var arrayOfArgs = []; + for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); + return arrayOfArgs; +}; + +jasmine.util.extend = function(destination, source) { + for (var property in source) destination[property] = source[property]; + return destination; +}; + +/** + * Environment for Jasmine + * + * @constructor + */ +jasmine.Env = function() { + this.currentSpec = null; + this.currentSuite = null; + this.currentRunner_ = new jasmine.Runner(this); + + this.reporter = new jasmine.MultiReporter(); + + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; + this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; + this.lastUpdate = 0; + this.specFilter = function() { + return true; + }; + + this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; + this.equalityTesters_ = []; + + // wrap matchers + this.matchersClass = function() { + jasmine.Matchers.apply(this, arguments); + }; + jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); +}; + + +jasmine.Env.prototype.setTimeout = jasmine.setTimeout; +jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; +jasmine.Env.prototype.setInterval = jasmine.setInterval; +jasmine.Env.prototype.clearInterval = jasmine.clearInterval; + +/** + * @returns an object containing jasmine version build info, if set. + */ +jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); + } +}; + +/** + * @returns string containing jasmine version build info, if set. + */ +jasmine.Env.prototype.versionString = function() { + if (jasmine.version_) { + var version = this.version(); + return version.major + "." + version.minor + "." + version.build + " revision " + version.revision; + } else { + return "version unknown"; + } +}; + +/** + * @returns a sequential integer starting at 0 + */ +jasmine.Env.prototype.nextSpecId = function () { + return this.nextSpecId_++; +}; + +/** + * @returns a sequential integer starting at 0 + */ +jasmine.Env.prototype.nextSuiteId = function () { + return this.nextSuiteId_++; +}; + +/** + * Register a reporter to receive status updates from Jasmine. + * @param {jasmine.Reporter} reporter An object which will receive status updates. + */ +jasmine.Env.prototype.addReporter = function(reporter) { + this.reporter.addReporter(reporter); +}; + +jasmine.Env.prototype.execute = function() { + this.currentRunner_.execute(); +}; + +jasmine.Env.prototype.describe = function(description, specDefinitions) { + var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); + + var parentSuite = this.currentSuite; + if (parentSuite) { + parentSuite.add(suite); + } else { + this.currentRunner_.add(suite); + } + + this.currentSuite = suite; + + var declarationError = null; + try { + specDefinitions.call(suite); + } catch(e) { + declarationError = e; + } + + this.currentSuite = parentSuite; + + if (declarationError) { + this.it("encountered a declaration exception", function() { + throw declarationError; + }); + } + + return suite; +}; + +jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + if (this.currentSuite) { + this.currentSuite.beforeEach(beforeEachFunction); + } else { + this.currentRunner_.beforeEach(beforeEachFunction); + } +}; + +jasmine.Env.prototype.currentRunner = function () { + return this.currentRunner_; +}; + +jasmine.Env.prototype.afterEach = function(afterEachFunction) { + if (this.currentSuite) { + this.currentSuite.afterEach(afterEachFunction); + } else { + this.currentRunner_.afterEach(afterEachFunction); + } + +}; + +jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { + return { + execute: function() { + } + }; +}; + +jasmine.Env.prototype.it = function(description, func) { + var spec = new jasmine.Spec(this, this.currentSuite, description); + this.currentSuite.add(spec); + this.currentSpec = spec; + + if (func) { + spec.runs(func); + } + + return spec; +}; + +jasmine.Env.prototype.xit = function(desc, func) { + return { + id: this.nextSpecId(), + runs: function() { + } + }; +}; + +jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { + return true; + } + + a.__Jasmine_been_here_before__ = b; + b.__Jasmine_been_here_before__ = a; + + var hasKey = function(obj, keyName) { + return obj != null && obj[keyName] !== jasmine.undefined; + }; + + for (var property in b) { + if (!hasKey(a, property) && hasKey(b, property)) { + mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + } + } + for (property in a) { + if (!hasKey(b, property) && hasKey(a, property)) { + mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + } + } + for (property in b) { + if (property == '__Jasmine_been_here_before__') continue; + if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { + mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + } + } + + if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { + mismatchValues.push("arrays were not the same length"); + } + + delete a.__Jasmine_been_here_before__; + delete b.__Jasmine_been_here_before__; + return (mismatchKeys.length == 0 && mismatchValues.length == 0); +}; + +jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { + mismatchKeys = mismatchKeys || []; + mismatchValues = mismatchValues || []; + + for (var i = 0; i < this.equalityTesters_.length; i++) { + var equalityTester = this.equalityTesters_[i]; + var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); + if (result !== jasmine.undefined) return result; + } + + if (a === b) return true; + + if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { + return (a == jasmine.undefined && b == jasmine.undefined); + } + + if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { + return a === b; + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() == b.getTime(); + } + + if (a instanceof jasmine.Matchers.Any) { + return a.matches(b); + } + + if (b instanceof jasmine.Matchers.Any) { + return b.matches(a); + } + + if (jasmine.isString_(a) && jasmine.isString_(b)) { + return (a == b); + } + + if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { + return (a == b); + } + + if (typeof a === "object" && typeof b === "object") { + return this.compareObjects_(a, b, mismatchKeys, mismatchValues); + } + + //Straight check + return (a === b); +}; + +jasmine.Env.prototype.contains_ = function(haystack, needle) { + if (jasmine.isArray_(haystack)) { + for (var i = 0; i < haystack.length; i++) { + if (this.equals_(haystack[i], needle)) return true; + } + return false; + } + return haystack.indexOf(needle) >= 0; +}; + +jasmine.Env.prototype.addEqualityTester = function(equalityTester) { + this.equalityTesters_.push(equalityTester); +}; +/** No-op base class for Jasmine reporters. + * + * @constructor + */ +jasmine.Reporter = function() { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportRunnerResults = function(runner) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSuiteResults = function(suite) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSpecStarting = function(spec) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSpecResults = function(spec) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.log = function(str) { +}; + +/** + * Blocks are functions with executable code that make up a spec. + * + * @constructor + * @param {jasmine.Env} env + * @param {Function} func + * @param {jasmine.Spec} spec + */ +jasmine.Block = function(env, func, spec) { + this.env = env; + this.func = func; + this.spec = spec; +}; + +jasmine.Block.prototype.execute = function(onComplete) { + try { + this.func.apply(this.spec); + } catch (e) { + this.spec.fail(e); + } + onComplete(); +}; +/** JavaScript API reporter. + * + * @constructor + */ +jasmine.JsApiReporter = function() { + this.started = false; + this.finished = false; + this.suites_ = []; + this.results_ = {}; +}; + +jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { + this.started = true; + var suites = runner.topLevelSuites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; + this.suites_.push(this.summarize_(suite)); + } +}; + +jasmine.JsApiReporter.prototype.suites = function() { + return this.suites_; +}; + +jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { + var isSuite = suiteOrSpec instanceof jasmine.Suite; + var summary = { + id: suiteOrSpec.id, + name: suiteOrSpec.description, + type: isSuite ? 'suite' : 'spec', + children: [] + }; + + if (isSuite) { + var children = suiteOrSpec.children(); + for (var i = 0; i < children.length; i++) { + summary.children.push(this.summarize_(children[i])); + } + } + return summary; +}; + +jasmine.JsApiReporter.prototype.results = function() { + return this.results_; +}; + +jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { + return this.results_[specId]; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { + this.finished = true; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { + this.results_[spec.id] = { + messages: spec.results().getItems(), + result: spec.results().failedCount > 0 ? "failed" : "passed" + }; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.log = function(str) { +}; + +jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ + var results = {}; + for (var i = 0; i < specIds.length; i++) { + var specId = specIds[i]; + results[specId] = this.summarizeResult_(this.results_[specId]); + } + return results; +}; + +jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ + var summaryMessages = []; + var messagesLength = result.messages.length; + for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { + var resultMessage = result.messages[messageIndex]; + summaryMessages.push({ + text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, + passed: resultMessage.passed ? resultMessage.passed() : true, + type: resultMessage.type, + message: resultMessage.message, + trace: { + stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined + } + }); + } + + return { + result : result.result, + messages : summaryMessages + }; +}; + +/** + * @constructor + * @param {jasmine.Env} env + * @param actual + * @param {jasmine.Spec} spec + */ +jasmine.Matchers = function(env, actual, spec, opt_isNot) { + this.env = env; + this.actual = actual; + this.spec = spec; + this.isNot = opt_isNot || false; + this.reportWasCalled_ = false; +}; + +// todo: @deprecated as of Jasmine 0.11, remove soon [xw] +jasmine.Matchers.pp = function(str) { + throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); +}; + +// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] +jasmine.Matchers.prototype.report = function(result, failing_message, details) { + throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); +}; + +jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { + for (var methodName in prototype) { + if (methodName == 'report') continue; + var orig = prototype[methodName]; + matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); + } +}; + +jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { + return function() { + var matcherArgs = jasmine.util.argsToArray(arguments); + var result = matcherFunction.apply(this, arguments); + + if (this.isNot) { + result = !result; + } + + if (this.reportWasCalled_) return result; + + var message; + if (!result) { + if (this.message) { + message = this.message.apply(this, arguments); + if (jasmine.isArray_(message)) { + message = message[this.isNot ? 1 : 0]; + } + } else { + var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); + message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; + if (matcherArgs.length > 0) { + for (var i = 0; i < matcherArgs.length; i++) { + if (i > 0) message += ","; + message += " " + jasmine.pp(matcherArgs[i]); + } + } + message += "."; + } + } + var expectationResult = new jasmine.ExpectationResult({ + matcherName: matcherName, + passed: result, + expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], + actual: this.actual, + message: message + }); + this.spec.addMatcherResult(expectationResult); + return jasmine.undefined; + }; +}; + + + + +/** + * toBe: compares the actual to the expected using === + * @param expected + */ +jasmine.Matchers.prototype.toBe = function(expected) { + return this.actual === expected; +}; + +/** + * toNotBe: compares the actual to the expected using !== + * @param expected + * @deprecated as of 1.0. Use not.toBe() instead. + */ +jasmine.Matchers.prototype.toNotBe = function(expected) { + return this.actual !== expected; +}; + +/** + * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. + * + * @param expected + */ +jasmine.Matchers.prototype.toEqual = function(expected) { + return this.env.equals_(this.actual, expected); +}; + +/** + * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual + * @param expected + * @deprecated as of 1.0. Use not.toNotEqual() instead. + */ +jasmine.Matchers.prototype.toNotEqual = function(expected) { + return !this.env.equals_(this.actual, expected); +}; + +/** + * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes + * a pattern or a String. + * + * @param expected + */ +jasmine.Matchers.prototype.toMatch = function(expected) { + return new RegExp(expected).test(this.actual); +}; + +/** + * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch + * @param expected + * @deprecated as of 1.0. Use not.toMatch() instead. + */ +jasmine.Matchers.prototype.toNotMatch = function(expected) { + return !(new RegExp(expected).test(this.actual)); +}; + +/** + * Matcher that compares the actual to jasmine.undefined. + */ +jasmine.Matchers.prototype.toBeDefined = function() { + return (this.actual !== jasmine.undefined); +}; + +/** + * Matcher that compares the actual to jasmine.undefined. + */ +jasmine.Matchers.prototype.toBeUndefined = function() { + return (this.actual === jasmine.undefined); +}; + +/** + * Matcher that compares the actual to null. + */ +jasmine.Matchers.prototype.toBeNull = function() { + return (this.actual === null); +}; + +/** + * Matcher that boolean not-nots the actual. + */ +jasmine.Matchers.prototype.toBeTruthy = function() { + return !!this.actual; +}; + + +/** + * Matcher that boolean nots the actual. + */ +jasmine.Matchers.prototype.toBeFalsy = function() { + return !this.actual; +}; + + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was called. + */ +jasmine.Matchers.prototype.toHaveBeenCalled = function() { + if (arguments.length > 0) { + throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); + } + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy " + this.actual.identity + " to have been called.", + "Expected spy " + this.actual.identity + " not to have been called." + ]; + }; + + return this.actual.wasCalled; +}; + +/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ +jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was not called. + * + * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead + */ +jasmine.Matchers.prototype.wasNotCalled = function() { + if (arguments.length > 0) { + throw new Error('wasNotCalled does not take arguments'); + } + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy " + this.actual.identity + " to not have been called.", + "Expected spy " + this.actual.identity + " to have been called." + ]; + }; + + return !this.actual.wasCalled; +}; + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. + * + * @example + * + */ +jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { + var expectedArgs = jasmine.util.argsToArray(arguments); + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + this.message = function() { + if (this.actual.callCount == 0) { + // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] + return [ + "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", + "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was." + ]; + } else { + return [ + "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), + "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) + ]; + } + }; + + return this.env.contains_(this.actual.argsForCall, expectedArgs); +}; + +/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ +jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; + +/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ +jasmine.Matchers.prototype.wasNotCalledWith = function() { + var expectedArgs = jasmine.util.argsToArray(arguments); + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", + "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" + ] + }; + + return !this.env.contains_(this.actual.argsForCall, expectedArgs); +}; + +/** + * Matcher that checks that the expected item is an element in the actual Array. + * + * @param {Object} expected + */ +jasmine.Matchers.prototype.toContain = function(expected) { + return this.env.contains_(this.actual, expected); +}; + +/** + * Matcher that checks that the expected item is NOT an element in the actual Array. + * + * @param {Object} expected + * @deprecated as of 1.0. Use not.toNotContain() instead. + */ +jasmine.Matchers.prototype.toNotContain = function(expected) { + return !this.env.contains_(this.actual, expected); +}; + +jasmine.Matchers.prototype.toBeLessThan = function(expected) { + return this.actual < expected; +}; + +jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { + return this.actual > expected; +}; + +/** + * Matcher that checks that the expected exception was thrown by the actual. + * + * @param {String} expected + */ +jasmine.Matchers.prototype.toThrow = function(expected) { + var result = false; + var exception; + if (typeof this.actual != 'function') { + throw new Error('Actual is not a function'); + } + try { + this.actual(); + } catch (e) { + exception = e; + } + if (exception) { + result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); + } + + var not = this.isNot ? "not " : ""; + + this.message = function() { + if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { + return ["Expected function " + not + "to throw", expected ? expected.message || expected : " an exception", ", but it threw", exception.message || exception].join(' '); + } else { + return "Expected function to throw an exception."; + } + }; + + return result; +}; + +jasmine.Matchers.Any = function(expectedClass) { + this.expectedClass = expectedClass; +}; + +jasmine.Matchers.Any.prototype.matches = function(other) { + if (this.expectedClass == String) { + return typeof other == 'string' || other instanceof String; + } + + if (this.expectedClass == Number) { + return typeof other == 'number' || other instanceof Number; + } + + if (this.expectedClass == Function) { + return typeof other == 'function' || other instanceof Function; + } + + if (this.expectedClass == Object) { + return typeof other == 'object'; + } + + return other instanceof this.expectedClass; +}; + +jasmine.Matchers.Any.prototype.toString = function() { + return ''; +}; + +/** + * @constructor + */ +jasmine.MultiReporter = function() { + this.subReporters_ = []; +}; +jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); + +jasmine.MultiReporter.prototype.addReporter = function(reporter) { + this.subReporters_.push(reporter); +}; + +(function() { + var functionNames = [ + "reportRunnerStarting", + "reportRunnerResults", + "reportSuiteResults", + "reportSpecStarting", + "reportSpecResults", + "log" + ]; + for (var i = 0; i < functionNames.length; i++) { + var functionName = functionNames[i]; + jasmine.MultiReporter.prototype[functionName] = (function(functionName) { + return function() { + for (var j = 0; j < this.subReporters_.length; j++) { + var subReporter = this.subReporters_[j]; + if (subReporter[functionName]) { + subReporter[functionName].apply(subReporter, arguments); + } + } + }; + })(functionName); + } +})(); +/** + * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults + * + * @constructor + */ +jasmine.NestedResults = function() { + /** + * The total count of results + */ + this.totalCount = 0; + /** + * Number of passed results + */ + this.passedCount = 0; + /** + * Number of failed results + */ + this.failedCount = 0; + /** + * Was this suite/spec skipped? + */ + this.skipped = false; + /** + * @ignore + */ + this.items_ = []; +}; + +/** + * Roll up the result counts. + * + * @param result + */ +jasmine.NestedResults.prototype.rollupCounts = function(result) { + this.totalCount += result.totalCount; + this.passedCount += result.passedCount; + this.failedCount += result.failedCount; +}; + +/** + * Adds a log message. + * @param values Array of message parts which will be concatenated later. + */ +jasmine.NestedResults.prototype.log = function(values) { + this.items_.push(new jasmine.MessageResult(values)); +}; + +/** + * Getter for the results: message & results. + */ +jasmine.NestedResults.prototype.getItems = function() { + return this.items_; +}; + +/** + * Adds a result, tracking counts (total, passed, & failed) + * @param {jasmine.ExpectationResult|jasmine.NestedResults} result + */ +jasmine.NestedResults.prototype.addResult = function(result) { + if (result.type != 'log') { + if (result.items_) { + this.rollupCounts(result); + } else { + this.totalCount++; + if (result.passed()) { + this.passedCount++; + } else { + this.failedCount++; + } + } + } + this.items_.push(result); +}; + +/** + * @returns {Boolean} True if everything below passed + */ +jasmine.NestedResults.prototype.passed = function() { + return this.passedCount === this.totalCount; +}; +/** + * Base class for pretty printing for expectation results. + */ +jasmine.PrettyPrinter = function() { + this.ppNestLevel_ = 0; +}; + +/** + * Formats a value in a nice, human-readable string. + * + * @param value + */ +jasmine.PrettyPrinter.prototype.format = function(value) { + if (this.ppNestLevel_ > 40) { + throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); + } + + this.ppNestLevel_++; + try { + if (value === jasmine.undefined) { + this.emitScalar('undefined'); + } else if (value === null) { + this.emitScalar('null'); + } else if (value === jasmine.getGlobal()) { + this.emitScalar(''); + } else if (value instanceof jasmine.Matchers.Any) { + this.emitScalar(value.toString()); + } else if (typeof value === 'string') { + this.emitString(value); + } else if (jasmine.isSpy(value)) { + this.emitScalar("spy on " + value.identity); + } else if (value instanceof RegExp) { + this.emitScalar(value.toString()); + } else if (typeof value === 'function') { + this.emitScalar('Function'); + } else if (typeof value.nodeType === 'number') { + this.emitScalar('HTMLNode'); + } else if (value instanceof Date) { + this.emitScalar('Date(' + value + ')'); + } else if (value.__Jasmine_been_here_before__) { + this.emitScalar(''); + } else if (jasmine.isArray_(value) || typeof value == 'object') { + value.__Jasmine_been_here_before__ = true; + if (jasmine.isArray_(value)) { + this.emitArray(value); + } else { + this.emitObject(value); + } + delete value.__Jasmine_been_here_before__; + } else { + this.emitScalar(value.toString()); + } + } finally { + this.ppNestLevel_--; + } +}; + +jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { + for (var property in obj) { + if (property == '__Jasmine_been_here_before__') continue; + fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false); + } +}; + +jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; + +jasmine.StringPrettyPrinter = function() { + jasmine.PrettyPrinter.call(this); + + this.string = ''; +}; +jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); + +jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { + this.append(value); +}; + +jasmine.StringPrettyPrinter.prototype.emitString = function(value) { + this.append("'" + value + "'"); +}; + +jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + this.append('[ '); + for (var i = 0; i < array.length; i++) { + if (i > 0) { + this.append(', '); + } + this.format(array[i]); + } + this.append(' ]'); +}; + +jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + var self = this; + this.append('{ '); + var first = true; + + this.iterateObject(obj, function(property, isGetter) { + if (first) { + first = false; + } else { + self.append(', '); + } + + self.append(property); + self.append(' : '); + if (isGetter) { + self.append(''); + } else { + self.format(obj[property]); + } + }); + + this.append(' }'); +}; + +jasmine.StringPrettyPrinter.prototype.append = function(value) { + this.string += value; +}; +jasmine.Queue = function(env) { + this.env = env; + this.blocks = []; + this.running = false; + this.index = 0; + this.offset = 0; + this.abort = false; +}; + +jasmine.Queue.prototype.addBefore = function(block) { + this.blocks.unshift(block); +}; + +jasmine.Queue.prototype.add = function(block) { + this.blocks.push(block); +}; + +jasmine.Queue.prototype.insertNext = function(block) { + this.blocks.splice((this.index + this.offset + 1), 0, block); + this.offset++; +}; + +jasmine.Queue.prototype.start = function(onComplete) { + this.running = true; + this.onComplete = onComplete; + this.next_(); +}; + +jasmine.Queue.prototype.isRunning = function() { + return this.running; +}; + +jasmine.Queue.LOOP_DONT_RECURSE = true; + +jasmine.Queue.prototype.next_ = function() { + var self = this; + var goAgain = true; + + while (goAgain) { + goAgain = false; + + if (self.index < self.blocks.length && !this.abort) { + var calledSynchronously = true; + var completedSynchronously = false; + + var onComplete = function () { + if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { + completedSynchronously = true; + return; + } + + if (self.blocks[self.index].abort) { + self.abort = true; + } + + self.offset = 0; + self.index++; + + var now = new Date().getTime(); + if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { + self.env.lastUpdate = now; + self.env.setTimeout(function() { + self.next_(); + }, 0); + } else { + if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { + goAgain = true; + } else { + self.next_(); + } + } + }; + self.blocks[self.index].execute(onComplete); + + calledSynchronously = false; + if (completedSynchronously) { + onComplete(); + } + + } else { + self.running = false; + if (self.onComplete) { + self.onComplete(); + } + } + } +}; + +jasmine.Queue.prototype.results = function() { + var results = new jasmine.NestedResults(); + for (var i = 0; i < this.blocks.length; i++) { + if (this.blocks[i].results) { + results.addResult(this.blocks[i].results()); + } + } + return results; +}; + + +/** + * Runner + * + * @constructor + * @param {jasmine.Env} env + */ +jasmine.Runner = function(env) { + var self = this; + self.env = env; + self.queue = new jasmine.Queue(env); + self.before_ = []; + self.after_ = []; + self.suites_ = []; +}; + +jasmine.Runner.prototype.execute = function() { + var self = this; + if (self.env.reporter.reportRunnerStarting) { + self.env.reporter.reportRunnerStarting(this); + } + self.queue.start(function () { + self.finishCallback(); + }); +}; + +jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { + beforeEachFunction.typeName = 'beforeEach'; + this.before_.splice(0,0,beforeEachFunction); +}; + +jasmine.Runner.prototype.afterEach = function(afterEachFunction) { + afterEachFunction.typeName = 'afterEach'; + this.after_.splice(0,0,afterEachFunction); +}; + + +jasmine.Runner.prototype.finishCallback = function() { + this.env.reporter.reportRunnerResults(this); +}; + +jasmine.Runner.prototype.addSuite = function(suite) { + this.suites_.push(suite); +}; + +jasmine.Runner.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.addSuite(block); + } + this.queue.add(block); +}; + +jasmine.Runner.prototype.specs = function () { + var suites = this.suites(); + var specs = []; + for (var i = 0; i < suites.length; i++) { + specs = specs.concat(suites[i].specs()); + } + return specs; +}; + +jasmine.Runner.prototype.suites = function() { + return this.suites_; +}; + +jasmine.Runner.prototype.topLevelSuites = function() { + var topLevelSuites = []; + for (var i = 0; i < this.suites_.length; i++) { + if (!this.suites_[i].parentSuite) { + topLevelSuites.push(this.suites_[i]); + } + } + return topLevelSuites; +}; + +jasmine.Runner.prototype.results = function() { + return this.queue.results(); +}; +/** + * Internal representation of a Jasmine specification, or test. + * + * @constructor + * @param {jasmine.Env} env + * @param {jasmine.Suite} suite + * @param {String} description + */ +jasmine.Spec = function(env, suite, description) { + if (!env) { + throw new Error('jasmine.Env() required'); + } + if (!suite) { + throw new Error('jasmine.Suite() required'); + } + var spec = this; + spec.id = env.nextSpecId ? env.nextSpecId() : null; + spec.env = env; + spec.suite = suite; + spec.description = description; + spec.queue = new jasmine.Queue(env); + + spec.afterCallbacks = []; + spec.spies_ = []; + + spec.results_ = new jasmine.NestedResults(); + spec.results_.description = description; + spec.matchersClass = null; +}; + +jasmine.Spec.prototype.getFullName = function() { + return this.suite.getFullName() + ' ' + this.description + '.'; +}; + + +jasmine.Spec.prototype.results = function() { + return this.results_; +}; + +/** + * All parameters are pretty-printed and concatenated together, then written to the spec's output. + * + * Be careful not to leave calls to jasmine.log in production code. + */ +jasmine.Spec.prototype.log = function() { + return this.results_.log(arguments); +}; + +jasmine.Spec.prototype.runs = function (func) { + var block = new jasmine.Block(this.env, func, this); + this.addToQueue(block); + return this; +}; + +jasmine.Spec.prototype.addToQueue = function (block) { + if (this.queue.isRunning()) { + this.queue.insertNext(block); + } else { + this.queue.add(block); + } +}; + +/** + * @param {jasmine.ExpectationResult} result + */ +jasmine.Spec.prototype.addMatcherResult = function(result) { + this.results_.addResult(result); +}; + +jasmine.Spec.prototype.expect = function(actual) { + var positive = new (this.getMatchersClass_())(this.env, actual, this); + positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); + return positive; +}; + +/** + * Waits a fixed time period before moving to the next block. + * + * @deprecated Use waitsFor() instead + * @param {Number} timeout milliseconds to wait + */ +jasmine.Spec.prototype.waits = function(timeout) { + var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); + this.addToQueue(waitsFunc); + return this; +}; + +/** + * Waits for the latchFunction to return true before proceeding to the next block. + * + * @param {Function} latchFunction + * @param {String} optional_timeoutMessage + * @param {Number} optional_timeout + */ +jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { + var latchFunction_ = null; + var optional_timeoutMessage_ = null; + var optional_timeout_ = null; + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + switch (typeof arg) { + case 'function': + latchFunction_ = arg; + break; + case 'string': + optional_timeoutMessage_ = arg; + break; + case 'number': + optional_timeout_ = arg; + break; + } + } + + var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); + this.addToQueue(waitsForFunc); + return this; +}; + +jasmine.Spec.prototype.fail = function (e) { + var expectationResult = new jasmine.ExpectationResult({ + passed: false, + message: e ? jasmine.util.formatException(e) : 'Exception' + }); + this.results_.addResult(expectationResult); +}; + +jasmine.Spec.prototype.getMatchersClass_ = function() { + return this.matchersClass || this.env.matchersClass; +}; + +jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { + var parent = this.getMatchersClass_(); + var newMatchersClass = function() { + parent.apply(this, arguments); + }; + jasmine.util.inherit(newMatchersClass, parent); + jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); + this.matchersClass = newMatchersClass; +}; + +jasmine.Spec.prototype.finishCallback = function() { + this.env.reporter.reportSpecResults(this); +}; + +jasmine.Spec.prototype.finish = function(onComplete) { + this.removeAllSpies(); + this.finishCallback(); + if (onComplete) { + onComplete(); + } +}; + +jasmine.Spec.prototype.after = function(doAfter) { + if (this.queue.isRunning()) { + this.queue.add(new jasmine.Block(this.env, doAfter, this)); + } else { + this.afterCallbacks.unshift(doAfter); + } +}; + +jasmine.Spec.prototype.execute = function(onComplete) { + var spec = this; + if (!spec.env.specFilter(spec)) { + spec.results_.skipped = true; + spec.finish(onComplete); + return; + } + + this.env.reporter.reportSpecStarting(this); + + spec.env.currentSpec = spec; + + spec.addBeforesAndAftersToQueue(); + + spec.queue.start(function () { + spec.finish(onComplete); + }); +}; + +jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { + var runner = this.env.currentRunner(); + var i; + + for (var suite = this.suite; suite; suite = suite.parentSuite) { + for (i = 0; i < suite.before_.length; i++) { + this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); + } + } + for (i = 0; i < runner.before_.length; i++) { + this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); + } + for (i = 0; i < this.afterCallbacks.length; i++) { + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); + } + for (suite = this.suite; suite; suite = suite.parentSuite) { + for (i = 0; i < suite.after_.length; i++) { + this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); + } + } + for (i = 0; i < runner.after_.length; i++) { + this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); + } +}; + +jasmine.Spec.prototype.explodes = function() { + throw 'explodes function should not have been called'; +}; + +jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { + if (obj == jasmine.undefined) { + throw "spyOn could not find an object to spy upon for " + methodName + "()"; + } + + if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { + throw methodName + '() method does not exist'; + } + + if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { + throw new Error(methodName + ' has already been spied upon'); + } + + var spyObj = jasmine.createSpy(methodName); + + this.spies_.push(spyObj); + spyObj.baseObj = obj; + spyObj.methodName = methodName; + spyObj.originalValue = obj[methodName]; + + obj[methodName] = spyObj; + + return spyObj; +}; + +jasmine.Spec.prototype.removeAllSpies = function() { + for (var i = 0; i < this.spies_.length; i++) { + var spy = this.spies_[i]; + spy.baseObj[spy.methodName] = spy.originalValue; + } + this.spies_ = []; +}; + +/** + * Internal representation of a Jasmine suite. + * + * @constructor + * @param {jasmine.Env} env + * @param {String} description + * @param {Function} specDefinitions + * @param {jasmine.Suite} parentSuite + */ +jasmine.Suite = function(env, description, specDefinitions, parentSuite) { + var self = this; + self.id = env.nextSuiteId ? env.nextSuiteId() : null; + self.description = description; + self.queue = new jasmine.Queue(env); + self.parentSuite = parentSuite; + self.env = env; + self.before_ = []; + self.after_ = []; + self.children_ = []; + self.suites_ = []; + self.specs_ = []; +}; + +jasmine.Suite.prototype.getFullName = function() { + var fullName = this.description; + for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { + fullName = parentSuite.description + ' ' + fullName; + } + return fullName; +}; + +jasmine.Suite.prototype.finish = function(onComplete) { + this.env.reporter.reportSuiteResults(this); + this.finished = true; + if (typeof(onComplete) == 'function') { + onComplete(); + } +}; + +jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { + beforeEachFunction.typeName = 'beforeEach'; + this.before_.unshift(beforeEachFunction); +}; + +jasmine.Suite.prototype.afterEach = function(afterEachFunction) { + afterEachFunction.typeName = 'afterEach'; + this.after_.unshift(afterEachFunction); +}; + +jasmine.Suite.prototype.results = function() { + return this.queue.results(); +}; + +jasmine.Suite.prototype.add = function(suiteOrSpec) { + this.children_.push(suiteOrSpec); + if (suiteOrSpec instanceof jasmine.Suite) { + this.suites_.push(suiteOrSpec); + this.env.currentRunner().addSuite(suiteOrSpec); + } else { + this.specs_.push(suiteOrSpec); + } + this.queue.add(suiteOrSpec); +}; + +jasmine.Suite.prototype.specs = function() { + return this.specs_; +}; + +jasmine.Suite.prototype.suites = function() { + return this.suites_; +}; + +jasmine.Suite.prototype.children = function() { + return this.children_; +}; + +jasmine.Suite.prototype.execute = function(onComplete) { + var self = this; + this.queue.start(function () { + self.finish(onComplete); + }); +}; +jasmine.WaitsBlock = function(env, timeout, spec) { + this.timeout = timeout; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); + +jasmine.WaitsBlock.prototype.execute = function (onComplete) { + this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); + this.env.setTimeout(function () { + onComplete(); + }, this.timeout); +}; +/** + * A block which waits for some condition to become true, with timeout. + * + * @constructor + * @extends jasmine.Block + * @param {jasmine.Env} env The Jasmine environment. + * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. + * @param {Function} latchFunction A function which returns true when the desired condition has been met. + * @param {String} message The message to display if the desired condition hasn't been met within the given time period. + * @param {jasmine.Spec} spec The Jasmine spec. + */ +jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { + this.timeout = timeout || env.defaultTimeoutInterval; + this.latchFunction = latchFunction; + this.message = message; + this.totalTimeSpentWaitingForLatch = 0; + jasmine.Block.call(this, env, null, spec); +}; +jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); + +jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; + +jasmine.WaitsForBlock.prototype.execute = function(onComplete) { + this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); + var latchFunctionResult; + try { + latchFunctionResult = this.latchFunction.apply(this.spec); + } catch (e) { + this.spec.fail(e); + onComplete(); + return; + } + + if (latchFunctionResult) { + onComplete(); + } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { + var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); + this.spec.fail({ + name: 'timeout', + message: message + }); + + this.abort = true; + onComplete(); + } else { + this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; + var self = this; + this.env.setTimeout(function() { + self.execute(onComplete); + }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); + } +}; +// Mock setTimeout, clearTimeout +// Contributed by Pivotal Computer Systems, www.pivotalsf.com + +jasmine.FakeTimer = function() { + this.reset(); + + var self = this; + self.setTimeout = function(funcToCall, millis) { + self.timeoutsMade++; + self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); + return self.timeoutsMade; + }; + + self.setInterval = function(funcToCall, millis) { + self.timeoutsMade++; + self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); + return self.timeoutsMade; + }; + + self.clearTimeout = function(timeoutKey) { + self.scheduledFunctions[timeoutKey] = jasmine.undefined; + }; + + self.clearInterval = function(timeoutKey) { + self.scheduledFunctions[timeoutKey] = jasmine.undefined; + }; + +}; + +jasmine.FakeTimer.prototype.reset = function() { + this.timeoutsMade = 0; + this.scheduledFunctions = {}; + this.nowMillis = 0; +}; + +jasmine.FakeTimer.prototype.tick = function(millis) { + var oldMillis = this.nowMillis; + var newMillis = oldMillis + millis; + this.runFunctionsWithinRange(oldMillis, newMillis); + this.nowMillis = newMillis; +}; + +jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { + var scheduledFunc; + var funcsToRun = []; + for (var timeoutKey in this.scheduledFunctions) { + scheduledFunc = this.scheduledFunctions[timeoutKey]; + if (scheduledFunc != jasmine.undefined && + scheduledFunc.runAtMillis >= oldMillis && + scheduledFunc.runAtMillis <= nowMillis) { + funcsToRun.push(scheduledFunc); + this.scheduledFunctions[timeoutKey] = jasmine.undefined; + } + } + + if (funcsToRun.length > 0) { + funcsToRun.sort(function(a, b) { + return a.runAtMillis - b.runAtMillis; + }); + for (var i = 0; i < funcsToRun.length; ++i) { + try { + var funcToRun = funcsToRun[i]; + this.nowMillis = funcToRun.runAtMillis; + funcToRun.funcToCall(); + if (funcToRun.recurring) { + this.scheduleFunction(funcToRun.timeoutKey, + funcToRun.funcToCall, + funcToRun.millis, + true); + } + } catch(e) { + } + } + this.runFunctionsWithinRange(oldMillis, nowMillis); + } +}; + +jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { + this.scheduledFunctions[timeoutKey] = { + runAtMillis: this.nowMillis + millis, + funcToCall: funcToCall, + recurring: recurring, + timeoutKey: timeoutKey, + millis: millis + }; +}; + +/** + * @namespace + */ +jasmine.Clock = { + defaultFakeTimer: new jasmine.FakeTimer(), + + reset: function() { + jasmine.Clock.assertInstalled(); + jasmine.Clock.defaultFakeTimer.reset(); + }, + + tick: function(millis) { + jasmine.Clock.assertInstalled(); + jasmine.Clock.defaultFakeTimer.tick(millis); + }, + + runFunctionsWithinRange: function(oldMillis, nowMillis) { + jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); + }, + + scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { + jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); + }, + + useMock: function() { + if (!jasmine.Clock.isInstalled()) { + var spec = jasmine.getEnv().currentSpec; + spec.after(jasmine.Clock.uninstallMock); + + jasmine.Clock.installMock(); + } + }, + + installMock: function() { + jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; + }, + + uninstallMock: function() { + jasmine.Clock.assertInstalled(); + jasmine.Clock.installed = jasmine.Clock.real; + }, + + real: { + setTimeout: jasmine.getGlobal().setTimeout, + clearTimeout: jasmine.getGlobal().clearTimeout, + setInterval: jasmine.getGlobal().setInterval, + clearInterval: jasmine.getGlobal().clearInterval + }, + + assertInstalled: function() { + if (!jasmine.Clock.isInstalled()) { + throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); + } + }, + + isInstalled: function() { + return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; + }, + + installed: null +}; +jasmine.Clock.installed = jasmine.Clock.real; + +//else for IE support +jasmine.getGlobal().setTimeout = function(funcToCall, millis) { + if (jasmine.Clock.installed.setTimeout.apply) { + return jasmine.Clock.installed.setTimeout.apply(this, arguments); + } else { + return jasmine.Clock.installed.setTimeout(funcToCall, millis); + } +}; + +jasmine.getGlobal().setInterval = function(funcToCall, millis) { + if (jasmine.Clock.installed.setInterval.apply) { + return jasmine.Clock.installed.setInterval.apply(this, arguments); + } else { + return jasmine.Clock.installed.setInterval(funcToCall, millis); + } +}; + +jasmine.getGlobal().clearTimeout = function(timeoutKey) { + if (jasmine.Clock.installed.clearTimeout.apply) { + return jasmine.Clock.installed.clearTimeout.apply(this, arguments); + } else { + return jasmine.Clock.installed.clearTimeout(timeoutKey); + } +}; + +jasmine.getGlobal().clearInterval = function(timeoutKey) { + if (jasmine.Clock.installed.clearTimeout.apply) { + return jasmine.Clock.installed.clearInterval.apply(this, arguments); + } else { + return jasmine.Clock.installed.clearInterval(timeoutKey); + } +}; + + +jasmine.version_= { + "major": 1, + "minor": 0, + "build": "0.rc1", + "revision": 1282853377 +}; -- cgit v1.2.3 From cd1b836ed4577afc74e3ee7bc480ee329ab68e90 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Fri, 27 Jan 2012 02:13:07 +0100 Subject: Scripts and styleshets for geolocation map - Conditional Scripts and stylesheets for the geolocation map are now switched on/off with the geolocation map itself. --- mediagoblin/templates/mediagoblin/user_pages/media.html | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index a2ad117e..2229bbb2 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -23,16 +23,20 @@ {% block title %}{{ media.title }} — {{ super() }}{% endblock %} {% block mediagoblin_head %} - - - + + {% if app_config['geolocation_map_visible'] %} + + + + + {% endif %} {% endblock mediagoblin_head %} {% block mediagoblin_content %} -- cgit v1.2.3 From 9542a2ba076b7e00e79d7adb1a4e90a095427645 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 Jan 2012 01:31:56 +0100 Subject: JavaScript fixes - AGPL headers, etc - Added AGPL header to comment_show.js, show_password.js and geolocation-map.js - Removed console.log from geolocation-map.js --- mediagoblin/static/js/comment_show.js | 18 ++++++++++++++++++ mediagoblin/static/js/geolocation-map.js | 23 ++++++++++++++++++++--- mediagoblin/static/js/show_password.js | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js index 2212b9ad..71466a8d 100644 --- a/mediagoblin/static/js/comment_show.js +++ b/mediagoblin/static/js/comment_show.js @@ -1,3 +1,21 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function(){ $('#form_comment').hide(); $('#button_addcomment').click(function(){ diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js index 22cbe2f3..35083d4f 100644 --- a/mediagoblin/static/js/geolocation-map.js +++ b/mediagoblin/static/js/geolocation-map.js @@ -1,11 +1,28 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function () { var longitude = Number( $('#tile-map #gps-longitude').val()); var latitude = Number( $('#tile-map #gps-latitude').val()); - console.log(longitude, latitude); - + // Get a new map instance attached and element with id="tile-map" var map = new L.Map('tile-map'); var mqtileUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg'; @@ -21,7 +38,7 @@ $(document).ready(function () { attribution: mqtileAttrib, subdomains: '1234'}); - var location = new L.LatLng(latitude, longitude); // geographical point (longitude and latitude) + var location = new L.LatLng(latitude, longitude); map.setView(location, 13).addLayer(mqtile); var marker = new L.Marker(location); diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js index 519b29c1..513fe327 100644 --- a/mediagoblin/static/js/show_password.js +++ b/mediagoblin/static/js/show_password.js @@ -1,3 +1,21 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function(){ $("#password").after(''); $('#password_clear').hide(); -- cgit v1.2.3 From 3e907d5516d50fc4a75e7ccb4e687db924ec9ff6 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 22 Jan 2012 17:11:43 +0100 Subject: Let some code support "media without slug" The upcoming SQL database will allow having media without a slug again. This might especially be useful for API support, where the uploaded image (media) does not have *any* information to generate a slug from. This code change mostly allows the sql backend to have no slug in its model and improves some parts to properly handle that. It specifically does not have any web frontend support to edit/create MediaEntries with no slug. --- mediagoblin/db/mixin.py | 21 +++++++++------------ mediagoblin/db/sql/models.py | 2 +- .../templates/mediagoblin/user_pages/media.html | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index d587ccb4..254dbcff 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -63,6 +63,10 @@ class MediaEntryMixin(object): def main_mediafile(self): pass + @property + def slug_or_id(self): + return (self.slug or self._id) + def url_for_self(self, urlgen, **extra_args): """ Generate an appropriate url for ourselves @@ -71,18 +75,11 @@ class MediaEntryMixin(object): """ uploader = self.get_uploader - if self.get('slug'): - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=self.slug, - **extra_args) - else: - return urlgen( - 'mediagoblin.user_pages.media_home', - user=uploader.username, - media=unicode(self._id), - **extra_args) + return urlgen( + 'mediagoblin.user_pages.media_home', + user=uploader.username, + media=self.slug_or_id, + **extra_args) def get_fail_exception(self): """ diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 95147d50..6232fff8 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -72,7 +72,7 @@ class MediaEntry(Base, MediaEntryMixin): id = Column(Integer, primary_key=True) uploader = Column(Integer, ForeignKey('users.id'), nullable=False) title = Column(Unicode, nullable=False) - slug = Column(Unicode, nullable=False) + slug = Column(Unicode) created = Column(DateTime, nullable=False, default=datetime.datetime.now) description = Column(UnicodeText) # ?? description_html = Column(UnicodeText) # ?? diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index cbe26cbf..9df3dfbc 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -127,7 +127,7 @@ + media = media.slug_or_id) }}#comment"> {{ comment.created.strftime("%I:%M%p %Y-%m-%d") }}
    -- cgit v1.2.3 From da471f26f201e2e9912f6a51e05a299a8b139199 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 28 Jan 2012 11:13:03 -0600 Subject: We aren't using translitcodec anymore. Kill it! --- mediagoblin/tools/url.py | 1 - setup.py | 1 - 2 files changed, 2 deletions(-) diff --git a/mediagoblin/tools/url.py b/mediagoblin/tools/url.py index 78b5dd63..e2caed39 100644 --- a/mediagoblin/tools/url.py +++ b/mediagoblin/tools/url.py @@ -15,7 +15,6 @@ # along with this program. If not, see . import re -import translitcodec _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') diff --git a/setup.py b/setup.py index ca7d4ae2..4761f2b5 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,6 @@ setup( 'sphinx', 'PIL', 'Babel', - 'translitcodec', 'argparse', 'webtest', 'ConfigObj', -- cgit v1.2.3 From b4e877ae9712df7c095d6a9c068ee6f2c234a059 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 28 Jan 2012 11:31:26 -0600 Subject: We were using translitcodec and I didn't understand how it worked ;) My bad! --- mediagoblin/tools/url.py | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/mediagoblin/tools/url.py b/mediagoblin/tools/url.py index e2caed39..78b5dd63 100644 --- a/mediagoblin/tools/url.py +++ b/mediagoblin/tools/url.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import re +import translitcodec _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') diff --git a/setup.py b/setup.py index 4761f2b5..ca7d4ae2 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,7 @@ setup( 'sphinx', 'PIL', 'Babel', + 'translitcodec', 'argparse', 'webtest', 'ConfigObj', -- cgit v1.2.3 From d7bec8577ea1b4d83df097f586324445fed1ef50 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 24 Dec 2011 16:53:32 +0100 Subject: Add develover sql switch If you want to play with the current state of sql, you need a switch to turn it on. So here is the super secret developer switch. So you want to know where it is? Here it is: Create a file mediagoblin/db/sql_switch.py and put one line in it: "use_sql = True" (or False to disable again). Right, that's it. If you want to delete it, remember to delete the *.pyc too. Be careful not to "git add" it by accident! --- mediagoblin/db/open.py | 13 +++++++++++-- mediagoblin/db/util.py | 11 +++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py index 32827fcb..6cd17869 100644 --- a/mediagoblin/db/open.py +++ b/mediagoblin/db/open.py @@ -14,5 +14,14 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.mongo.open import \ - setup_connection_and_db_from_config, check_db_migrations_current +try: + from mediagoblin.db.sql_switch import use_sql +except ImportError: + use_sql = False + +if use_sql: + from mediagoblin.db.sql.open import \ + setup_connection_and_db_from_config, check_db_migrations_current +else: + from mediagoblin.db.mongo.open import \ + setup_connection_and_db_from_config, check_db_migrations_current diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 1df9494c..fff71d06 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -14,5 +14,12 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.db.mongo.util import (ObjectId, InvalidId, - DESCENDING) +try: + from mediagoblin.db.sql_switch import use_sql +except ImportError: + use_sql = False + +if use_sql: + from mediagoblin.db.sql.fake import ObjectId, InvalidId, DESCENDING +else: + from mediagoblin.db.mongo.util import ObjectId, InvalidId, DESCENDING -- cgit v1.2.3 From ebc0e382398fbc665e6b133bd3925c5352d3d51d Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 Jan 2012 18:53:36 +0100 Subject: Resized a test_exif test image. 1.9M is unnecessarily large. --- mediagoblin/tests/test_exif/has-gps.jpg | Bin 1933121 -> 141246 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mediagoblin/tests/test_exif/has-gps.jpg b/mediagoblin/tests/test_exif/has-gps.jpg index c7d2cc93..f6f39d86 100644 Binary files a/mediagoblin/tests/test_exif/has-gps.jpg and b/mediagoblin/tests/test_exif/has-gps.jpg differ -- cgit v1.2.3 From de91730336951f27cb83c3e60ac2d071bb3d4cef Mon Sep 17 00:00:00 2001 From: Elrond Date: Wed, 4 Jan 2012 22:00:44 +0100 Subject: Nearly complete support for Tags These changes allow all of the rest of the code to use tags in sql as they were used on mongo. It's not efficient at all, as changing tags usually means to remove all old tags and adding all new. The only problem here is: Old slugs for tags are not removed, because they're shared across all MediaTags and dropping orphans is not always easy. --- mediagoblin/db/sql/base.py | 16 ++++++++++++++++ mediagoblin/db/sql/models.py | 40 ++++++++++++++++++++++++++++++++++++---- mediagoblin/edit/views.py | 2 +- mediagoblin/submit/views.py | 2 +- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 1db53c56..f1affc83 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -77,3 +77,19 @@ class GMGTableBase(object): Base = declarative_base(cls=GMGTableBase) + + +class DictReadAttrProxy(object): + """ + Maps read accesses to obj['key'] to obj.key + and hides all the rest of the obj + """ + def __init__(self, proxied_obj): + self.proxied_obj = proxied_obj + + def __getitem__(self, key): + try: + return getattr(self.proxied_obj, key) + except AttributeError: + raise KeyError("%r is not an attribute on %r" + % (key, self.proxied_obj)) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 6232fff8..9abd8ec7 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -26,7 +26,7 @@ from sqlalchemy.sql.expression import desc from sqlalchemy.ext.associationproxy import association_proxy from mediagoblin.db.sql.extratypes import PathTupleWithSlashes -from mediagoblin.db.sql.base import Base +from mediagoblin.db.sql.base import Base, DictReadAttrProxy from mediagoblin.db.mixin import UserMixin, MediaEntryMixin @@ -101,6 +101,13 @@ class MediaEntry(Base, MediaEntryMixin): creator=lambda k, v: MediaFile(name=k, file_path=v) ) + tags_helper = relationship("MediaTag", + cascade="all, delete-orphan" + ) + tags = association_proxy("tags_helper", "dict_view", + creator=lambda v: MediaTag(name=v["name"], slug=v["slug"]) + ) + ## TODO # media_data # attachment_files @@ -153,22 +160,47 @@ class Tag(Base): id = Column(Integer, primary_key=True) slug = Column(Unicode, nullable=False, unique=True) + def __repr__(self): + return "" % (self.id, self.slug) + + @classmethod + def find_or_new(cls, slug): + t = cls.query.filter_by(slug=slug).first() + if t is not None: + return t + return cls(slug=slug) + class MediaTag(Base): __tablename__ = "media_tags" id = Column(Integer, primary_key=True) - tag = Column(Integer, ForeignKey('tags.id'), nullable=False) - name = Column(Unicode) media_entry = Column( - Integer, ForeignKey('media_entries.id'), + Integer, ForeignKey(MediaEntry.id), nullable=False) + tag = Column(Integer, ForeignKey('tags.id'), nullable=False) + name = Column(Unicode) # created = Column(DateTime, nullable=False, default=datetime.datetime.now) __table_args__ = ( UniqueConstraint('tag', 'media_entry'), {}) + tag_helper = relationship(Tag) + slug = association_proxy('tag_helper', 'slug', + creator=Tag.find_or_new + ) + + def __init__(self, name, slug): + Base.__init__(self) + self.name = name + self.tag_helper = Tag.find_or_new(slug) + + @property + def dict_view(self): + """A dict like view on this object""" + return DictReadAttrProxy(self) + class MediaComment(Base): __tablename__ = "media_comments" diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index cf7182e5..a637d699 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -69,7 +69,7 @@ def edit_media(request, media): else: media.title = unicode(request.POST['title']) media.description = unicode(request.POST.get('description')) - media['tags'] = convert_to_tag_list_of_dicts( + media.tags = convert_to_tag_list_of_dicts( request.POST.get('tags')) media.description_html = cleaned_markdown_conversion( diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index f70e4ba5..0efee803 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -74,7 +74,7 @@ def submit_start(request): entry.uploader = request.user._id # Process the user's folksonomy "tags" - entry['tags'] = convert_to_tag_list_of_dicts( + entry.tags = convert_to_tag_list_of_dicts( request.POST.get('tags')) # Generate a slug from the title -- cgit v1.2.3 From f4b206166e706ac6d89e60c3cc8db71a7ef680ff Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:22:21 -0600 Subject: Update update_translations script to consider several things conditionally Specifically, previously if there was nothing to git add, whole script would just die --- devtools/update_translations.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh index 1708e7e0..069b47af 100755 --- a/devtools/update_translations.sh +++ b/devtools/update_translations.sh @@ -27,8 +27,9 @@ git pull echo "==> pulling present translations" ./bin/tx pull -a -git add mediagoblin/i18n/ -git commit -m "Committing present MediaGoblin translations before pushing extracted messages" +if git add mediagoblin/i18n/; then + git commit -m "Committing present MediaGoblin translations before pushing extracted messages"; +fi echo "==> Extracting translations" ./bin/pybabel extract -F babel.ini -o mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po . @@ -44,5 +45,6 @@ echo "==> Compiling .mo files" ./bin/pybabel compile -D mediagoblin -d mediagoblin/i18n/ echo "==> Committing to git" -git add mediagoblin/i18n/ -git commit -m "Committing extracted and compiled translations" +if git add mediagoblin/i18n/; then + git commit -m "Committing extracted and compiled translations"; +fi -- cgit v1.2.3 From 8e5596fb1d7c038bac769ebe544c8c4e2f297a5a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:30:18 -0600 Subject: Hm, maybe this is better... that didn't fix the stop-in-the-middle issue. --- devtools/update_translations.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh index 069b47af..537aa95b 100755 --- a/devtools/update_translations.sh +++ b/devtools/update_translations.sh @@ -27,9 +27,10 @@ git pull echo "==> pulling present translations" ./bin/tx pull -a -if git add mediagoblin/i18n/; then - git commit -m "Committing present MediaGoblin translations before pushing extracted messages"; -fi + +git add mediagoblin/i18n/ +git commit -m "Committing present MediaGoblin translations before pushing extracted messages" \ + || true # Don't fail if nothing to commit echo "==> Extracting translations" ./bin/pybabel extract -F babel.ini -o mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po . @@ -45,6 +46,6 @@ echo "==> Compiling .mo files" ./bin/pybabel compile -D mediagoblin -d mediagoblin/i18n/ echo "==> Committing to git" -if git add mediagoblin/i18n/; then - git commit -m "Committing extracted and compiled translations"; -fi +git add mediagoblin/i18n/ + +git commit -m "Committing extracted and compiled translations" || true -- cgit v1.2.3 From f62b697eb2245e14d86f1c0b7295550687e23c94 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:31:47 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo | Bin 14396 -> 14278 bytes mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo | Bin 13397 -> 13279 bytes mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 13692 -> 13618 bytes mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 133 ++++---- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 105 +++--- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 13543 -> 13752 bytes mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 160 +++++----- mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo | Bin 13891 -> 14298 bytes mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po | 179 ++++++----- mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 12357 -> 13938 bytes mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 369 ++++++++++++--------- mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo | Bin 13161 -> 13043 bytes mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po | 106 +++--- mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo | Bin 13574 -> 13456 bytes mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo | Bin 13736 -> 13618 bytes mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 11670 -> 13516 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 371 +++++++++++++-------- mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo | Bin 12901 -> 12783 bytes mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo | Bin 13279 -> 13158 bytes mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po | 110 ++++--- mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 13685 -> 14058 bytes mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 176 +++++----- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 16681 -> 17134 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 147 +++++---- mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo | Bin 13900 -> 14214 bytes mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po | 177 +++++----- mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo | Bin 13350 -> 13232 bytes mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po | 108 ++++--- mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo | Bin 13259 -> 13141 bytes mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po | 106 +++--- mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo | Bin 13448 -> 13361 bytes mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po | 137 ++++---- mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 13409 -> 13291 bytes mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 106 +++--- mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo | Bin 11198 -> 13179 bytes mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po | 372 ++++++++++++++-------- 41 files changed, 1953 insertions(+), 1449 deletions(-) diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo index 1a7267e5..b23b0be4 100644 Binary files a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po index c53fc387..578be678 100644 --- a/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ar/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -94,91 +94,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "العنوان" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "وصف هذا العمل." -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "الوسوم" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "المسار" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "لا يمكن ترك المسار فارغًا" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "السيرة" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "الموقع الإلكتروني" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "يوجد ملف آخر بهذا المسار لدى هذى المستخدم." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "أنت تحرّر وسائط مستخدم آخر. كن حذرًا أثناء العملية." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "أنت تحرّر ملف مستخدم آخر. كن حذرًا أثناء العملية." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -190,15 +188,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "الملف" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "يجب أن تضع ملفًا." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "يا سلام! نُشرَت!" @@ -221,30 +219,30 @@ msgid "" msgstr "" "إن كنت متأكدًا من صحة العنوان فربما تكون الصفحة التي تريدها نُقلت أو حُذفت." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "شعار ميدياغوبلن" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "أضف وسائط" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "لِج" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -433,53 +431,53 @@ msgstr "" msgid "%(username)s's media" msgstr "وسائط %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -602,6 +600,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -632,6 +638,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "أنا متأكد من رغبتي بحذف هذا العمل" diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo index 45f2331f..6fdb7cbf 100644 Binary files a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po index a5d6732b..0c956b9b 100644 --- a/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ca/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -92,91 +92,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Títol" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Etiquetes" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Lloc web" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Esteu editant fitxers d'un altre usuari. Aneu amb compte." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Esteu editant el perfil d'un usuari. Aneu amb compte" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -188,15 +186,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Fitxer" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Heu d'escollir un fitxer." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Visca! S'ha enviat!" @@ -220,30 +218,30 @@ msgstr "" "Si esteu convençut que l'adreça és correcta, pot ser que la pàgina que " "cerqueu s'hagi canviat d'ubicació o s'hagi eliminat." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Logo de mediagoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Tots els fitxers" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entra" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -425,53 +423,53 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s's media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -596,6 +594,14 @@ msgstr "Icona RSS" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -626,6 +632,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 4f4bbfda..0a5af04c 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 1fb472f0..f71f139f 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -5,8 +5,8 @@ # Translators: # , 2011. # , 2011. -# Elrond , 2011. -# , 2011. +# Elrond , 2011, 2012. +# , 2011, 2012. # Jan-Christoph Borchardt , 2011. # Jan-Christoph Borchardt , 2011. # , 2011. @@ -17,8 +17,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" @@ -102,91 +102,91 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Beschreibung des Werkes" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Markierungen" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "Kommaseparierte Schlagwörter" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Kurztitel" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Bitte gib einen Kurztitel ein" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" +"Der Titelteil der Medienadresse. Normalerweise muss hier nichts geändert " +"werden." -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Biographie" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Webseite" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Altes Passwort" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "Neues Passwort" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Diesen Kurztitel hast du bereits vergeben." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Du bearbeitest die Medien eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Du bearbeitest das Profil eines Anderen. Bitte sei vorsichtig." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Das Profil wurde aktualisiert" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Falsches Passwort" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -198,15 +198,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Datei" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Du musst eine Datei angeben." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Yeeeaaah! Geschafft!" @@ -230,30 +230,30 @@ msgstr "" "Wenn du sicher bist, dass die Adresse stimmt, wurde die Seite eventuell " "verschoben oder gelöscht." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin-Logo" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Medien hinzufügen" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Bitte bestätige deine E-Mail-Adresse!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "Abmelden" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Anmelden" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -296,6 +296,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Registriere dich auf dieser Seite\n" +" oder\n" +" Installiere MediaGoblin auf deinem eigenen Server" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -447,53 +450,53 @@ msgstr "%(username)ss Medien" msgid "%(username)s's media" msgstr "%(username)ss Medien" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Bearbeiten" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Löschen" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s Kommentar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s Kommentare" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "bei" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -608,7 +611,7 @@ msgstr "Alle Medien von %(username)s anschauen" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "Hier erscheinen deine Medien. Sobald du etwas hochgeladen hast." +msgstr "Hier erscheinen deine Medien, sobald du etwas hochgeladen hast." #: mediagoblin/templates/mediagoblin/user_pages/user.html:163 #: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 @@ -623,13 +626,21 @@ msgstr "Feed-Symbol" msgid "Atom feed" msgstr "Atom-Feed" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Neuere" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Ältere →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -651,6 +662,10 @@ msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "oder" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 3584cd4f..9841beec 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -85,15 +85,16 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 -msgid "Bio" +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." +#: mediagoblin/edit/forms.py:50 +msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -183,15 +180,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "" @@ -213,30 +210,30 @@ msgid "" "has been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -415,53 +412,53 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown " "for formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -580,6 +577,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -610,6 +615,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index d0c5f2bf..63cf7739 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 6536f4d5..a98409ac 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: -# , 2011. +# , 2011, 2012. # Fernando Inocencio , 2011. # , 2011. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -76,7 +76,7 @@ msgstr "Resendi vian kontrol-mesaĝon." #: mediagoblin/auth/views.py:260 msgid "" "An email has been sent with instructions on how to change your password." -msgstr "" +msgstr "Senditas retletero kun instrukcio pri kiel ŝanĝi vian pasvorton." #: mediagoblin/auth/views.py:270 msgid "" @@ -88,99 +88,99 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." -msgstr "" +msgstr "Mi trovis neniun kun tiu salutnomo aŭ retpoŝtadreso." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Nun vi povas ensaluti per via nova pasvorto." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titolo" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Priskribo de ĉi tiu verko" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Etikedoj" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "Dividu la etikedojn per komoj." -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "La distingiga adresparto" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "La distingiga adresparto ne povas esti malplena" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" +"La dosiertitol-bazita parto de la dosieradreso. Ordinare ne necesas ĝin " +"ŝanĝi." + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Retejo" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "La malnova pasvorto" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." -msgstr "" +msgstr "Enigu vian malnovan pasvorton por pruvi, ke ĉi tiu konto estas via." -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "La nova pasvorto" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Ĉi tiu uzanto jam havas dosieron kun tiu distingiga adresparto." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Vi priredaktas dosieron de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Vi redaktas profilon de alia uzanto. Agu singardeme." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Profilŝanĝoj estis konservitaj" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Malĝusta pasvorto" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "Kontagordoj estis konservitaj" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" @@ -188,17 +188,17 @@ msgstr "" #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Mi pardonpetas, mi ne subtenas tiun dosiertipon :(" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Dosiero" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Vi devas provizi dosieron." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Hura! Alŝutitas!" @@ -222,30 +222,30 @@ msgstr "" "Se vi estas certa, ke la adreso estas ĝusta, eble la serĉata de vi paĝo " "estis movita aŭ forigita." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Emblemo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Aldoni dosieron" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Konfirmu viecon de la retpoŝtadreso!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "elsaluti" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Ensaluti" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -390,7 +390,7 @@ msgstr "Konservi ŝanĝojn" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "Ŝanĝado de kontagordoj de %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -414,6 +414,9 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Bedaŭrinde ĉi tiu filmo ne spekteblas, ĉar\n" +"» via TTT-legilo ne subtenas montradon\n" +"» de filmoj laŭ HTML5." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -421,14 +424,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Vi povas akiri modernan TTT-legilon,\n" +"» kapablan montri ĉi tiun filmon, ĉe \n" +"» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Aldono de via dosiero" #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Aldoni" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -440,53 +446,53 @@ msgstr "Dosieroj de %(username)s" msgid "%(username)s's media" msgstr "Dosieroj de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Aldonita je %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Ŝanĝi" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Forigi" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s komento" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s komentoj" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "Estas neniom da komentoj." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Aldoni sian." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Aldoni ĉi tiun komenton" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "je" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -588,12 +594,12 @@ msgstr "Ĉi tiu uzanto ne jam aldonis informojn pri si." #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Ŝanĝi kontagordojn" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" -msgstr "Rigardi ĉiujn dosierojn de %(username)s'" +msgstr "Rigardi ĉiujn dosierojn de %(username)s" #: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" @@ -615,6 +621,14 @@ msgstr "flusimbolo" msgid "Atom feed" msgstr "Atom-a informfluo" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -639,10 +653,14 @@ msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Vidi aliajn dosierojn kun la etikedo" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "aŭ" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo index b9f8eeed..93a849fb 100644 Binary files a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po index ab8c6b3f..3bb46098 100644 --- a/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/es/LC_MESSAGES/mediagoblin.po @@ -5,7 +5,7 @@ # Translators: # , 2011. # , 2011. -# , 2011. +# , 2011, 2012. # Javier Di Mauro , 2011. # , 2011. # , 2011. @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/mediagoblin/team/es/)\n" "MIME-Version: 1.0\n" @@ -85,6 +85,8 @@ msgstr "Se reenvió tu correo electrónico de verificación." msgid "" "An email has been sent with instructions on how to change your password." msgstr "" +"Un correo electrónico ha sido enviado con instrucciones sobre cómo cambiar " +"tu contraseña." #: mediagoblin/auth/views.py:270 msgid "" @@ -98,116 +100,122 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." msgstr "" +"No se pudo encontrar a alguien con ese nombre de usuario o correo " +"electrónico." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Ahora tu puedes entrar usando tu nueva contraseña." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Descripción de esta obra" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" +"Tu puedes usar\n" +" \n" +" Markdown Para el formato." -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "Separa las etiquetas por comas." -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Ficha" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "La ficha no puede estar vacía" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" +"El título de esta parte de la dirección de los contenidos. Por lo general no" +" es necesario cambiar esto." + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Sitio web" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Vieja contraseña" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" +"Escriba la anterior contraseña para demostrar la propiedad de la cuenta." -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "Nueva contraseña" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Una entrada con esa ficha ya existe para este usuario." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Estás editando el contenido de otro usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Estás editando un perfil de usuario. Proceder con precaución." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Los cambios de perfil fueron salvados" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Contraseña incorrecta" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "las configuraciones de cuenta fueron salvadas" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "No se pudo extraer ninguna extensión de archivo de \"{filename}\"" #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Lo sentidos, No soportamos ese tipo de archivo :(" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Archivo" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Debes proporcionar un archivo." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "¡Yujú! ¡Enviado!" @@ -231,30 +239,30 @@ msgstr "" "Si estás seguro que la dirección es correcta, puede ser que la pagina haya " "sido movida o borrada." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Logo de MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Añadir contenido" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "¡Verifica tu email!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "Cerrar sesión" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Conectarse" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -298,6 +306,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Crea una cuenta en este sitio\n" +" o\n" +" Instala Mediagoblin en tu propio servidor" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -305,11 +316,11 @@ msgstr "El contenido más reciente" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Coloca tu nueva contraseña " #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Coloca la contraseña" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -399,7 +410,7 @@ msgstr "Guardar cambios" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "Cambio de %(username)s's la configuración de la cuenta " #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -423,6 +434,9 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Lo sentidos, este video no va funcionar porque\n" +"» Tu explorador web no soporta HTML5\n" +"» video." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -430,14 +444,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Ti puedes conseguir un navegador web moderno que\n" +"» que puede reproducir este vídeo en \n" +"» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Añade tu contenido " #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Añadir " #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -449,56 +466,56 @@ msgstr "Contenidos de %(username)s" msgid "%(username)s's media" msgstr "Contenido de %(username)s's" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Agregado el %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Editar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Borrar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s comentarios de" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s comentarios de" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "No hay comentarios aún. " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Añadir un" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Añade un comentario " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "en" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " -msgstr "" +msgstr "

    ❖ Buscar contenido por %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -598,7 +615,7 @@ msgstr "Este usuario (todavia) no ha completado su perfil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Cambiar la configuración de la cuenta" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format @@ -625,13 +642,21 @@ msgstr "ícono feed" msgid "Atom feed" msgstr "Atom feed" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Más viejo" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Más viejo →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -640,19 +665,23 @@ msgstr "Ir a la página:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "Más nuevo" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "Más viejo" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Ver más contenido etiquetado con" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "o" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo index b805cca5..c29f7f08 100644 Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po index ba5c639d..3bffeef8 100644 --- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2011-12-29 17:39+0000\n" -"Last-Translator: ianux \n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -29,29 +29,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Le fichier envoyé ne correspond pas au type de média." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Nom d'utilisateur" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Mot de passe" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Les mots de passe doivent correspondre." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Confirmer le mot de passe" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "" -"Tapez-le à nouveau ici pour vous assurer qu'il n'y a pas de fautes " -"d'orthographe." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "Adresse e-mail" @@ -67,7 +53,7 @@ msgstr "Un utilisateur existe déjà avec ce nom, désolé." msgid "Sorry, a user with that email address already exists." msgstr "Désolé, il existe déjà un utilisateur ayant cette adresse e-mail." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -75,24 +61,29 @@ msgstr "" "Votre adresse e-mail a bien été vérifiée. Vous pouvez maintenant vous " "identifier, modifier votre profil, et soumettre des images !" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "La clé de vérification ou le nom d'utilisateur est incorrect." -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" "Vous devez être authentifié afin que nous sachions à qui envoyer l'e-mail !" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Votre adresse e-mail a déjà été vérifiée !" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "E-mail de vérification renvoyé." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -100,98 +91,129 @@ msgstr "" "Impossible d'envoyer un email de récupération de mot de passe : votre compte" " est inactif ou bien l'email de votre compte n'a pas été vérifiée." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "" + +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titre" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "Description of this work" +msgstr "Descriptif pour ce travail" + +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Tags" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Séparez les tags par des virgules." +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 +msgid "Separate tags by commas." +msgstr "" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Légende" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "La légende ne peut pas être laissée vide." -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:40 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "" -"Le nom de ce media dans l'URL. Vous n'avez normalement pas besoin de le " -"changer" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Site web" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Ancien mot de passe." -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "Nouveau mot de passe" +#: mediagoblin/edit/forms.py:65 +msgid "Enter your old password to prove you own this account." +msgstr "" + +#: mediagoblin/edit/forms.py:68 +msgid "New password" +msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Une entrée existe déjà pour cet utilisateur avec la même légende." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le média d'un autre utilisateur. Veuillez " "prendre garde." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "Vous vous apprêtez à modifier le profil d'un utilisateur. Veuillez prendre " "garde." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:180 +msgid "Profile changes saved" +msgstr "" + +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Mauvais mot de passe" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Profile mis à jour !" +#: mediagoblin/edit/views.py:222 +msgid "Account settings saved" +msgstr "" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "Impossible d'extraire une extension de fichier de \"{nomfichier}\"" +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "" + +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Fichier" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Descriptif pour ce travail" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Il vous faut fournir un fichier." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Youhou, c'est envoyé !" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Type de fichier invalide." +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Image de 404 gobelin angoissé" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Zut !" @@ -207,33 +229,30 @@ msgstr "" "Si vous êtes sûr que l'adresse est correcte, peut-être la page que vous " "recherchez a été déplacée ou supprimée." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Image de 404 gobelin angoissé" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "Soumettre un média" +#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "Ajouter des médias" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Vérifiez votre adresse e-mail !" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "déconnexion" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "S'identifier" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -245,7 +264,7 @@ msgstr "" msgid "Explore" msgstr "Explorer" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Bonjour, et bienvenu sur ce site MediaGoblin !" @@ -273,25 +292,21 @@ msgstr "Vous n'en avez pas ? C'est facile !" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Créez un compte sur ce site\n" -" ou\n" -" Déployez MediaGoblin sur votre propre serveur" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Tout derniers media" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "Entrez un nouveau mot de passe" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Soumettre" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -301,18 +316,6 @@ msgstr "Récupérer le mot de passe" msgid "Send instructions" msgstr "Envoyer les instructions" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "" -"Votre mot de passe a été changé. Essayez maintenant de vous identifier." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Verifiez votre boîte de réception. Nous vous avons envoyé un email avec une " -"URL vous permettant de changer votre mot de passe." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -352,11 +355,11 @@ msgstr "Créez-en un ici !" msgid "Forgot your password?" msgstr "Vous avez oublié votre mot de passe ?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Créer un compte !" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Créer" @@ -387,10 +390,16 @@ msgid "Cancel" msgstr "Annuler" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Enregistrer les modifications" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -402,13 +411,32 @@ msgstr "Modification du profil de %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "Médias taggés avec : %(tag_name)s " -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Original" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "Soumettez ce média" +msgid "Add your media" +msgstr "" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -420,31 +448,57 @@ msgstr "Medias de %(username)s" msgid "%(username)s's media" msgstr "Médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Par %(username)s le %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Poster un commentaire" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "à" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Poster le commentaire !" +msgid "Added on %(date)s." +msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Éditer" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Effacer" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#, python-format +msgid "%(comment_count)s comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 +#, python-format +msgid "%(comment_count)s comments" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 +msgid "No comments yet." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Add one" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 +msgid "" +"You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 +msgid "Add this comment" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 +msgid "at" +msgstr "à" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -534,20 +588,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Voici un endroit pour parler aux autres de vous-même." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Modifier le profil" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Cet utilisateur n'a pas (encore) rempli son profil." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Voir tous les médias de %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -555,11 +613,8 @@ msgstr "" "C'est là où vos médias apparaîssent, mais vous ne semblez pas avoir encore " "ajouté quoi que ce soit." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Ajouter des médias" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Il ne semble pas y avoir de média là, pour l'instant ..." @@ -571,29 +626,47 @@ msgstr "icone de flux" msgid "Atom feed" msgstr "flux Atom" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Nouveaux" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Anciens" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Aller à la page :" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Taggé avec" +msgid "View more media tagged with" +msgstr "" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "et" +msgid "or" +msgstr "" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Commentaire" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo index 94b378d2..5bf0f220 100644 Binary files a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po index 56f74573..017cd64d 100644 --- a/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ia/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -88,91 +88,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titulo" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 -msgid "Bio" +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." +#: mediagoblin/edit/forms.py:50 +msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -184,15 +182,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "" @@ -214,30 +212,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Initiar session" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -413,53 +411,53 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -580,6 +578,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -610,6 +616,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo index d5fb3eac..9b94ec7f 100644 Binary files a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po index 6a8b8b65..2b896572 100644 --- a/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/it/LC_MESSAGES/mediagoblin.po @@ -9,8 +9,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -94,93 +94,91 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titolo" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Descrizione di questo lavoro" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Tags" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Sito web" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Password vecchia" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" "Stai modificando documenti multimediale di un altro utente. Procedi con " "attenzione." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Stai modificando il profilo di un utente. Procedi con attenzione." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Password errata" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -192,15 +190,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Documento" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Devi specificare un documento." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Evviva! " @@ -224,30 +222,30 @@ msgstr "" "Se sei sicuro che l'indirizzo è corretto, forse la pagina che stai cercando " "è stata spostata o cancellata." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Aggiungi documenti multimediali" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Verifica la tua email!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "disconnettiti" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Accedi" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -443,53 +441,53 @@ msgstr "file di %(username)s" msgid "%(username)s's media" msgstr "Documenti multimediali di %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Modifica" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Elimina" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "a" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -617,6 +615,14 @@ msgstr "feed icon" msgid "Atom feed" msgstr "Atom feed" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -647,6 +653,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Sono sicuro di volerlo cancellare" diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo index 21aeed26..3b24dd2d 100644 Binary files a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po index 7ed8652b..35231f66 100644 --- a/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ja/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -88,91 +88,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "タイトル" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "タグ" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "スラグ" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "スラグは必要です。" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "自己紹介" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "URL" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "そのスラグを持つエントリは、このユーザーは既に存在します。" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "あなたは、他のユーザーのメディアを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "あなたは、他のユーザーのプロファイルを編集しています。ご注意ください。" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -184,15 +182,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "ファイル" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "ファイルを提供する必要があります。" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "投稿終了!" @@ -214,30 +212,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "ログイン" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -418,53 +416,53 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)sさんのコンテンツ" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -585,6 +583,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -615,6 +621,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index 4d03c586..455849b2 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index 7b63a859..c70bb19e 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2012-01-04 18:42+0000\n" -"Last-Translator: schendje \n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,27 +23,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "Verkeerd bestandsformaat voor mediatype opgegeven." -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "Gebruikersnaam" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "Wachtwoord" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "Wachtwoorden moeten overeenkomen." - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "Bevestig wachtwoord" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "Typ het hier nog een keer om spelfouten te voorkomen." - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "E-mail adres" @@ -59,7 +47,7 @@ msgstr "Sorry, er bestaat al een gebruiker met die naam." msgid "Sorry, a user with that email address already exists." msgstr "Sorry, een gebruiker met dat e-mailadres bestaat al." -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" @@ -67,25 +55,31 @@ msgstr "" "Uw e-mailadres is geverifieerd. U kunt nu inloggen, uw profiel bewerken, en " "afbeeldingen toevoegen!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "De verificatie sleutel of gebruikers-ID is onjuist" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" "Je moet ingelogd zijn, anders weten we niet waar we de e-mail naartoe moeten" " sturen!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "Je hebt je e-mailadres al geverifieerd!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "Verificatie e-mail opnieuw opgestuurd." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "" +"Een e-mail met instructies om je wachtwoord te veranderen is verstuurd." + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." @@ -93,97 +87,133 @@ msgstr "" "Email kon niet verstuurd worden omdat je gebruikersnaam inactief is of omdat" " je e-mailadres nog niet geverifieerd is." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "Kon niemand vinden met die gebruikersnaam of dat e-mailadres." + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "Je kunt nu inloggen met je nieuwe wachtwoord." + +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "Description of this work" +msgstr "Beschrijving van dit werk" + +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" +"Voor opmaak kun je Markdown " +"gebruiken." + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Etiket" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "Scheidt labels met komma's." +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 +msgid "Separate tags by commas." +msgstr "Hou labels gescheiden met komma's." -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Slug" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "De slug kan niet leeg zijn" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:40 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." +msgstr "" +"Het titelgedeelte van het adres van deze media. Normaal gesproken hoef je " +"deze niet te veranderen." + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -"Het titeldeel van het adres van deze media. Meestal hoef je dit niet aan te " -"passen." -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Website" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Oud wachtwoord" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" +#: mediagoblin/edit/forms.py:65 +msgid "Enter your old password to prove you own this account." +msgstr "Vul je oude wachtwoord in om te bewijzen dat dit jouw account is" + +#: mediagoblin/edit/forms.py:68 +msgid "New password" msgstr "Nieuw wachtwoord" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Er bestaat al een met die slug voor deze gebruiker." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" "U bent de media van een andere gebruiker aan het aanpassen. Ga voorzichtig " "te werk." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" "U bent een gebruikersprofiel aan het aanpassen. Ga voorzichtig te werk." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:180 +msgid "Profile changes saved" +msgstr "Profielaanpassingen opgeslagen" + +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Verkeerd wachtwoord" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "Profiel aangepast!" +#: mediagoblin/edit/views.py:222 +msgid "Account settings saved" +msgstr "Accountinstellingen opgeslagen" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "Kon geen bestandsextensie uit \"{filename}\" halen" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "Kon geen bestandsformaat voor \"{filename}\" vinden" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "Sorry, dat bestandstype wordt niet ondersteunt." -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Bestand" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "Beschrijving van dit werk" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "U moet een bestand aangeven." -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Mooizo! Toegevoegd!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "Ongeldig bestandstype" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Afbeelding van de 404 goblin onder stress" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "Oeps!" @@ -199,33 +229,30 @@ msgstr "" "Als je zeker weet dat het adres klopt is de pagina misschien verplaatst of " "verwijderd." -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Afbeelding van de 404 goblin onder stress" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" +#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" msgstr "Voeg media toe" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Verifieer je e-mailadres!" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "uitloggen" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Inloggen" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -238,7 +265,7 @@ msgstr "" msgid "Explore" msgstr "Verkennen" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "Hoi, welkom op deze MediaGoblin website!" @@ -266,25 +293,24 @@ msgstr "Heb je er nog geen? Het is heel eenvoudig!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"Creëer een account op deze website\n" +"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Creëer een account op deze website</a>\n" " of\n" -" Gebruik MediaGoblin op je eigen server" +" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">Gebruik MediaGoblin op je eigen server</a>" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "Nieuwste media" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" msgstr "Voer je nieuwe wachtwoord in" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "Voeg toe" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "Wachtwoord opslaan" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -294,17 +320,6 @@ msgstr "Wachtwoord herstellen" msgid "Send instructions" msgstr "Stuur instructies" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "Je wachtwoord is veranderd. Probeer om opnieuw in te loggen." - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "" -"Check je inbox. Er is een e-mail verstuurd waarmee je je wachtwoord kunt " -"veranderen." - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -342,11 +357,11 @@ msgstr "Maak er hier een!" msgid "Forgot your password?" msgstr "Wachtwoord vergeten?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "Maak een account aan!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "Creëer" @@ -374,10 +389,16 @@ msgid "Cancel" msgstr "Annuleren" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "Wijzigingen opslaan" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "%(username)ss accountinstellingen aanpassen" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -389,14 +410,37 @@ msgstr "Het profiel aanpassen van %(username)s" msgid "Media tagged with: %(tag_name)s" msgstr "Media met het label: %(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "Origineel" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" +"Sorry, deze video werkt niet omdat je webbrowser geen HTML5 video " +"ondersteunt." + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" +"Je kunt een moderne webbrowser die deze video af kan spelen krijgen op http://getfirefox.com!" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" +msgid "Add your media" msgstr "Voeg media toe" +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "Voeg toe" + #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" @@ -407,31 +451,59 @@ msgstr "Media van %(username)s" msgid "%(username)s's media" msgstr "Media van %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "Door %(username)s op %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "Plaats een bericht" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "op" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "Plaats bericht!" +msgid "Added on %(date)s." +msgstr "Toegevoegd op %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Pas aan" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Verwijderen" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#, python-format +msgid "%(comment_count)s comment" +msgstr "%(comment_count)s bericht" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 +#, python-format +msgid "%(comment_count)s comments" +msgstr "%(comment_count)s berichten" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 +msgid "No comments yet." +msgstr "Er zijn nog geen berichten." + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Add one" +msgstr "Voeg er een toe" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 +msgid "" +"You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 +msgid "Add this comment" +msgstr "Voeg dit bericht toe" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 +msgid "at" +msgstr "op" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "" +"

    ❖ Media aan het bekijken van %(username)s

    " + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -518,20 +590,24 @@ msgid "Here's a spot to tell others about yourself." msgstr "Hier is een plekje om anderen over jezelf te vertellen." #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "Profiel aanpassen." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "Deze gebruiker heeft zijn of haar profiel (nog) niet ingevuld." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "Accountinstellingen aanpassen" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "Bekijk alle media van %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." @@ -539,11 +615,8 @@ msgstr "" "Dit is waar je nieuwe media zal verschijnen, maar het lijkt erop dat je nog " "niets heb toegevoegd." -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "Voeg media toe" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "Het lijkt erop dat er nog geen media is." @@ -555,29 +628,47 @@ msgstr "feed icoon" msgid "Atom feed" msgstr "Atom feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "Nieuwer" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "← Nieuwer" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "Ouder" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "Ouder →" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "Ga naar pagina:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "nieuwer" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "ouder" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "Gelabeld met" +msgid "View more media tagged with" +msgstr "Bekijk meer media gelabeld met" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "en" +msgid "or" +msgstr "of" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "Commentaar" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo index 11b00041..01179e47 100644 Binary files a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po index dcc82f90..1cc0b878 100644 --- a/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nn_NO/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -91,91 +91,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Tittel" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Skildring av mediefila" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Merkelappar" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Nettnamn" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Nettnamnet kan ikkje vera tomt" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Presentasjon" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Heimeside" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Eit innlegg med denne adressetittelen finst allereie." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Trå varsamt, du endrar nokon andre sine mediefiler." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Trå varsamt, du endrar nokon andre sin profil." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -187,15 +185,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Fil" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Du må velja ei fil." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Johoo! Opplasta!" @@ -219,30 +217,30 @@ msgstr "" "Er du sikker på at adressa er korrekt, so er sida truleg flytta eller " "sletta." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Legg til mediefiler" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logg inn" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -432,53 +430,53 @@ msgstr "" msgid "%(username)s's media" msgstr "%(username)s sine mediefiler" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -601,6 +599,14 @@ msgstr " " msgid "Atom feed" msgstr "Atom-kjelde" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -631,6 +637,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Eg er sikker eg vil sletta dette" diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo index 5b7445f7..6d2e6fc6 100644 Binary files a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po index 11400a2f..14c54fb3 100644 --- a/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/pt_BR/LC_MESSAGES/mediagoblin.po @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" -"Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.net/projects/p/mediagoblin/team/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -93,91 +93,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Título" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Descrição desse trabalho" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Etiquetas" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Arquivo" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "O arquivo não pode estar vazio" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Biografia" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Website" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Senha antiga" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Uma entrada com esse arquivo já existe para esse usuário" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Você está editando a mídia de outro usuário. Tenha cuidado." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Você está editando um perfil de usuário. Tenha cuidado." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Senha errada" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -189,15 +187,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Arquivo" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Você deve fornecer um arquivo." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Eba! Enviado!" @@ -221,30 +219,30 @@ msgstr "" "Se você está certo de que o endereço está correto, talvez a página que " "esteja procurando tenha sido apagada ou mudou de endereço" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Adicionar mídia" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Verifique seu email!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "Sair" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Entrar" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -435,53 +433,53 @@ msgstr "" msgid "%(username)s's media" msgstr "Mídia de %(username)s " -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Editar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Apagar" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -609,6 +607,14 @@ msgstr "ícone feed" msgid "Atom feed" msgstr "Atom feed" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -639,6 +645,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Eu tenho certeza de que quero pagar isso" diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo index 5a711266..226474af 100644 Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po index 4981e988..9139e59d 100644 --- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po @@ -4,13 +4,13 @@ # # Translators: # , 2011. -# George Pop , 2011. +# George Pop , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -75,7 +75,7 @@ msgstr "E-mail-ul de verificare a fost retrimis." #: mediagoblin/auth/views.py:260 msgid "" "An email has been sent with instructions on how to change your password." -msgstr "" +msgstr "S-a trimis un e-mail cu instrucțiuni pentru schimbarea parolei." #: mediagoblin/auth/views.py:270 msgid "" @@ -88,117 +88,122 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." msgstr "" +"Nu s-a găsit nicio persoană cu acel nume de utilizator sau adresă de e-mail." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Acum te poți autentifica cu noua parolă." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titlu" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Descrierea acestui fișier" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" +"Poți folosi\n" +" \n" +" Markdown pentru formatare." -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Tag-uri" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "Desparte tag-urile prin virgulă." -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Identificator" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Identificatorul nu poate să lipsească" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" +"Partea corespunzătoare titlului din adresa acestui fișier media. De regulă " +"poate fi lăsată nemodificată." -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Biografie" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Sit Web" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Vechea parolă" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" +"Introdu vechea parolă pentru a demonstra că ești titularul acestui cont." -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "Noua parolă" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" "Există deja un entry cu același identificator pentru acest utilizator." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Editezi fișierul unui alt utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Editezi profilul unui utilizator. Se recomandă prudență." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Modificările profilului au fost salvate" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Parolă incorectă" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "Setările pentru acest cont au fost salvate" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "Nu s-a putut extrage o extensie de fișier din „{filename}”." #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Scuze, nu recunosc acest tip de fișier :(" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Fișier" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Trebuie să selectezi un fișier." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Ura! Trimis!" @@ -222,30 +227,30 @@ msgstr "" "Dacă ești sigur că adresa e corectă, poate că pagina pe care o cauți a fost " "mutată sau ștearsă." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "logo MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Trimite fișier" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Verifică adresa de e-mail!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "ieșire" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Autentificare" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -288,6 +293,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Creează un cont pe acest site\n" +" sau\n" +" Instalează MediaGoblin pe serverul tău" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -295,11 +303,11 @@ msgstr "Cele mai recente fișiere" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Stabilește noua parolă" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Stabilește parola" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -389,7 +397,7 @@ msgstr "Salvează modificările" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "Se modifică setările contului pentru userul %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -413,6 +421,8 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Ne pare rău, această înregistrare video nu funcționează deoarece \n" +"» browserul tău nu este compatibil cu funcția video din HTML5." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -420,14 +430,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Poți lua un browser modern cu care\n" +"» care poți vedea această înregistrare video de la \n" +"» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Adaugă fișierele tale media" #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Adaugă" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -439,56 +452,57 @@ msgstr "Fișierele lui %(username)s" msgid "%(username)s's media" msgstr "Fișierele media ale lui %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Adăugat la data %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Editare" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Șterge" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s comentariu" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s comentarii" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "Deocamdată nu există comentarii." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Trimite unul" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Trimite acest comentariu" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "la" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" +"

    ❖ Fișierele media ale lui %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -584,7 +598,7 @@ msgstr "Acest utilizator nu și-a completat (încă) profilul." #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Modifică setările contului" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format @@ -612,13 +626,21 @@ msgstr "icon feed" msgid "Atom feed" msgstr "feed Atom" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Mai noi" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Mai vechi →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -627,19 +649,23 @@ msgstr "Salt la pagina:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "mai noi" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "mai vechi" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Vezi și alte fișiere etichetate cu tag-ul" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "sau" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 3ddb0c8e..9c1f739c 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 38748a97..91329920 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -3,13 +3,13 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: -# , 2011. +# , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -95,92 +95,92 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Название" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Описание этого произведения" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Метки" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "(через запятую)" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Отличительная часть адреса" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Отличительная часть адреса необходима" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" +"Часть адреса этого файла, производная от его названия. Её обычно не " +"требуется изменять." -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Биография" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Сайт" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Старый пароль" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "Новый пароль" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" "У этого пользователя уже есть файл с такой отличительной частью адреса." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Вы редактируете файлы другого пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Вы редактируете профиль пользователя. Будьте осторожны." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Неправильный пароль" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -192,15 +192,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Файл" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Вы должны загрузить файл." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Ура! Файл загружен!" @@ -222,30 +222,30 @@ msgid "" " been moved or deleted." msgstr "Возможно, страница, которую вы ищете, была удалена или переехала." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Символ MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Добавить файлы" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Подтвердите ваш адрес электронной почты!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "завершение сеанса" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Войти" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -423,14 +423,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Вы можете скачать современный браузер,\n" +"» способный воспроизводить это видео, с \n" +"» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Добавление ваших файлов" #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Добавить" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -442,53 +445,53 @@ msgstr "Файлы %(username)s" msgid "%(username)s's media" msgstr "Файлы пользователя %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Добавлено %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Изменить" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Удалить" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s комментарий" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s комментариев" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "Комментариев пока нет." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Добавить свой" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Добавить этот комментарий" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "в" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -589,7 +592,7 @@ msgstr "Это пользователь не заполнил свой проф #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Изменить настройки учётной записи" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format @@ -615,13 +618,21 @@ msgstr "значок ленты" msgid "Atom feed" msgstr "лента в формате Atom" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Более новые" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Более старые →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -630,19 +641,23 @@ msgstr "Перейти к странице:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "более новые" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "более старые" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Найти другие файлы с меткой" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "или" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo index 2d3f505f..e79b6848 100644 Binary files a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po index 53ad3080..8cde8800 100644 --- a/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sk/LC_MESSAGES/mediagoblin.po @@ -3,13 +3,13 @@ # This file is distributed under the same license as the PROJECT project. # # Translators: -# , 2011. +# , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -75,7 +75,7 @@ msgstr "Opätovne zaslať overovaciu správu na e-mail." #: mediagoblin/auth/views.py:260 msgid "" "An email has been sent with instructions on how to change your password." -msgstr "" +msgstr "E-mailová správa s inštrukciami pre zmenu tvojho hesla bola odoslaná." #: mediagoblin/auth/views.py:270 msgid "" @@ -89,116 +89,119 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." msgstr "" +"Nebolo možné nájsť nikoho s týmto používateľským menom alebo e-mailovou " +"adresou." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Teraz sa môžeš prihlásiť so svojim novým heslom." -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Nadpis" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Charakteristika tohto diela" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" +"Môžeš využiť\n" +" \n" +" Markdown pri formátovaní." -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Značky" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." -msgstr "" +msgstr "Oddeľ jednotlivé štítky čiarkami." -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Unikátna časť adresy" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Unikátna časť adresy nesmie byť prázdna" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." +msgstr "Titulná časť adresy tohto výtvoru. Väčšinou nie je potrebná zmena." + +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Bio" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Webstránka" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "Staré heslo" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." -msgstr "" +msgstr "Potvrď, že vlastníš tento účet zadaním svojho starého hesla." -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" -msgstr "" +msgstr "Nové heslo" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Položku s rovnakou unikátnou časťou adresy už niekde máš." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Upravuješ médiá niekoho iného. Dbaj na to." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Upravuješ používateľský profil. Dbaj na to." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Úpravy profilu uložené" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "Nesprávne heslo" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "Nastavenia účtu uložené" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "Nebolo možné extrahovať žiadnu súborovú príponu z \"{filename}\"" #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Prepáč, nepodporujem tento súborový typ =(" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Súbor" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Musíš poskytnúť súbor." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Juchú! Úspešne vložené!" @@ -222,30 +225,30 @@ msgstr "" "Ak vieš s istotou, že adresa je správna, tak najskôr bola hľadaná stánka " "presunutá alebo zmazaná." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin logo" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Pridať výtvor" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "Over si e-mailovú adresu!" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "odhlásiť sa" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prihlásenie" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -288,6 +291,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Vytvoriť účet na tejto stránke\n" +" alebo\n" +" Založiť MediaGoblin na vlastnom serveri" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -295,11 +301,11 @@ msgstr "Najčerstvejšie výtvory" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Vlož svoje nové heslo" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Vlož heslo" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -390,7 +396,7 @@ msgstr "Uložiť zmeny" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "Mením nastavenia účtu používateľa %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -414,6 +420,9 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Prepáč, toto video nepôjde prehrať \n" +"» tvoj webový prehliadač nepodporuje HTML5 \n" +"» video." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -421,14 +430,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Môžeš získať moderný prehliadač, ktorý \n" +"» vie prehrať toto video na \n" +"» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Pridaj svoj výtvor" #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Pridať" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -440,56 +452,57 @@ msgstr "Výtvory, ktoré vlastní %(username)s" msgid "%(username)s's media" msgstr "Výtvory, ktoré vlastní %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Pridané v %(date)s." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "Upraviť" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "Odstrániť" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" -msgstr "" +msgstr "%(comment_count)s komentár" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" -msgstr "" +msgstr "%(comment_count)s komentáre" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "Zatiaľ žiadny komentár." -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Pridaj jeden" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Pridať tento komentár" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "o" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" +"

    ❖ Prezeranie výtvorov podľa %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -585,7 +598,7 @@ msgstr "Dotyčný používateľ ešte nevyplnil svoj profil (zatiaľ)." #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Zmeniť nastavenia účtu" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format @@ -612,13 +625,21 @@ msgstr "ikona čítačky" msgid "Atom feed" msgstr "Čítačka Atom" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Novšie" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Staršie →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -627,19 +648,23 @@ msgstr "Prejsť na stránku:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "novšie" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "staršie" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Zobraziť viac výtvorov označených ako" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" +msgstr "alebo" + +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." msgstr "" #: mediagoblin/user_pages/forms.py:30 diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo index 73bb4113..daa6b23b 100644 Binary files a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po index c5d3104c..35fb4841 100644 --- a/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sl/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -90,91 +90,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Naslov" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Oznake" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Oznaka" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Oznaka ne sme biti prazna" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Biografija" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Spletna stran" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Vnos s to oznako za tega uporabnika že obstaja." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Urejate vsebino drugega uporabnika. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Urejate uporabniški profil. Nadaljujte pazljivo." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -186,15 +184,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Datoteka" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Podati morate datoteko." -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Juhej! Poslano." @@ -218,30 +216,30 @@ msgstr "" "Če ste v točnost naslova prepričani, je bila iskana stran morda premaknjena " "ali pa izbrisana." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "Logotip MediaGoblin" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Dodaj vsebino" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Prijava" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -423,53 +421,53 @@ msgstr "" msgid "%(username)s's media" msgstr "Vsebina uporabnika %(username)s" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -594,6 +592,14 @@ msgstr "Ikona vira" msgid "Atom feed" msgstr "Ikona Atom" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -624,6 +630,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo index 2a99cb53..8191444c 100644 Binary files a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po index cdfdad05..e0f59766 100644 --- a/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sr/LC_MESSAGES/mediagoblin.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: Serbian (http://www.transifex.net/projects/p/mediagoblin/team/sr/)\n" "MIME-Version: 1.0\n" @@ -87,91 +87,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 -msgid "Bio" +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." +#: mediagoblin/edit/forms.py:50 +msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -183,15 +181,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "" @@ -213,30 +211,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -412,53 +410,53 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -579,6 +577,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -609,6 +615,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo index d647e373..095deaa2 100644 Binary files a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po index acace870..91791796 100644 --- a/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/sv/LC_MESSAGES/mediagoblin.po @@ -4,13 +4,13 @@ # # Translators: # , 2011. -# , 2011. +# , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: Swedish (http://www.transifex.net/projects/p/mediagoblin/team/sv/)\n" "MIME-Version: 1.0\n" @@ -46,7 +46,7 @@ msgstr "En användare med det användarnamnet finns redan." #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" +msgstr "Det finns redan en användare med den e-postadressen." #: mediagoblin/auth/views.py:180 msgid "" @@ -63,10 +63,11 @@ msgstr "Verifieringsnyckeln eller användar-IDt är fel." #: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "" +"Du måste vara inloggad för att vi ska kunna skicka meddelandet till dig." #: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" -msgstr "" +msgstr "Du har redan verifierat din e-postadress!" #: mediagoblin/auth/views.py:225 msgid "Resent your verification email." @@ -93,91 +94,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "Titel" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "Beskrivning av verket" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "Taggar" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "Sökvägsnamn" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "Sökvägsnamnet kan inte vara tomt" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "Presentation" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." -msgstr "" - -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "Hemsida" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" -msgstr "" +msgstr "Tidigare lösenord" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "Ett inlägg med det sökvägsnamnet existerar redan." -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "Var försiktig, du redigerar någon annans inlägg." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "Var försiktig, du redigerar en annan användares profil." -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" -msgstr "" +msgstr "Fel lösenord" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -189,15 +188,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "Fil" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "Du måste ange en fil" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "Tjohoo! Upladdat!" @@ -221,30 +220,30 @@ msgstr "" "Om du är säker på att adressen stämmer så kanske sidan du letar efter har " "flyttats eller tagits bort." -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin-logotyp" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "Lägg till media" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" -msgstr "" +msgstr "Verifiera din e-postadress" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" -msgstr "" +msgstr "Logga ut" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "Logga in" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -258,7 +257,7 @@ msgstr "Utforska" #: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" -msgstr "" +msgstr "Hej, välkommen till den här MediaGoblin-sidan!" #: mediagoblin/templates/mediagoblin/root.html:28 msgid "" @@ -274,7 +273,7 @@ msgstr "" #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" -msgstr "" +msgstr "Har du inte ett redan?" #: mediagoblin/templates/mediagoblin/root.html:32 #, python-format @@ -298,11 +297,11 @@ msgstr "" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" -msgstr "" +msgstr "Återställ lösenord" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:30 msgid "Send instructions" -msgstr "" +msgstr "Skicka instruktioner" #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format @@ -396,12 +395,12 @@ msgstr "Redigerar %(username)ss profil" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "" +msgstr "Media taggat med: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 #: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" -msgstr "" +msgstr "Original" #: mediagoblin/templates/mediagoblin/media_displays/video.html:33 msgid "" @@ -428,60 +427,60 @@ msgstr "" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format msgid "%(username)s's media" -msgstr "" +msgstr "%(username)ss media" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:37 #, python-format msgid "%(username)s's media" msgstr "%(username)ss media" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -610,6 +609,14 @@ msgstr "feed-ikon" msgid "Atom feed" msgstr "Atom-feed" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -640,6 +647,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "Jag är säker på att jag vill radera detta" diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo index 5480404c..9467a3f1 100644 Binary files a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po index 14e12315..24155bff 100644 --- a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-07 13:47-0600\n" -"PO-Revision-Date: 2012-01-07 19:44+0000\n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" "Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -88,91 +88,89 @@ msgstr "" msgid "You can now log in using your new password." msgstr "" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "శీర్షిక" -#: mediagoblin/edit/forms.py:27 mediagoblin/submit/forms.py:30 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 msgid "Description of this work" msgstr "" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 msgid "" "You can use\n" " \n" " Markdown for formatting." msgstr "" -#: mediagoblin/edit/forms.py:32 mediagoblin/submit/forms.py:35 +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "" -#: mediagoblin/edit/forms.py:34 mediagoblin/submit/forms.py:37 +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." msgstr "" -#: mediagoblin/edit/forms.py:37 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "" -#: mediagoblin/edit/forms.py:38 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "" -#: mediagoblin/edit/forms.py:39 +#: mediagoblin/edit/forms.py:40 msgid "" "The title part of this media's address. You usually don't need to change " "this." msgstr "" -#: mediagoblin/edit/forms.py:46 -msgid "Bio" +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" msgstr "" -#: mediagoblin/edit/forms.py:48 -msgid "" -"You can use\n" -" \n" -" Markdown for formatting." +#: mediagoblin/edit/forms.py:50 +msgid "Bio" msgstr "" -#: mediagoblin/edit/forms.py:53 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "" -#: mediagoblin/edit/forms.py:60 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "" -#: mediagoblin/edit/forms.py:62 +#: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" -#: mediagoblin/edit/forms.py:65 +#: mediagoblin/edit/forms.py:68 msgid "New password" msgstr "" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:174 +#: mediagoblin/edit/views.py:180 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:200 +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:216 +#: mediagoblin/edit/views.py:222 msgid "Account settings saved" msgstr "" @@ -184,15 +182,15 @@ msgstr "" msgid "Sorry, I don't support that file type :(" msgstr "" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "" -#: mediagoblin/submit/views.py:50 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:128 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "" @@ -214,30 +212,30 @@ msgid "" " been moved or deleted." msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:48 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:53 +#: mediagoblin/templates/mediagoblin/base.html:51 #: mediagoblin/templates/mediagoblin/user_pages/user.html:157 msgid "Add media" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:64 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:71 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:74 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "" -#: mediagoblin/templates/mediagoblin/base.html:86 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -413,53 +411,53 @@ msgstr "" msgid "%(username)s's media" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:60 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:69 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:73 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:79 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 #, python-format msgid "%(comment_count)s comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 #, python-format msgid "%(comment_count)s comments" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:83 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:100 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" -"Type your comment here. You can use Markdown for" " formatting." msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:104 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:126 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" msgstr "" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:141 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" @@ -580,6 +578,14 @@ msgstr "" msgid "Atom feed" msgstr "" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" + #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" msgstr "" @@ -610,6 +616,10 @@ msgstr "" msgid "or" msgstr "" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" + #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" msgstr "" diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo index a7820c49..e907562e 100644 Binary files a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po index 2864ef8a..03571c01 100644 --- a/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/zh_TW/LC_MESSAGES/mediagoblin.po @@ -1,5 +1,5 @@ # Translations template for PROJECT. -# Copyright (C) 2011 ORGANIZATION +# Copyright (C) 2012 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2011-12-04 10:24-0600\n" -"PO-Revision-Date: 2012-01-03 16:35+0000\n" -"Last-Translator: Harry Chen \n" +"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"PO-Revision-Date: 2012-01-29 19:29+0000\n" +"Last-Translator: cwebber \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,27 +24,15 @@ msgstr "" msgid "Invalid file given for media type." msgstr "指定錯誤的媒體類別!" -#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49 +#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:41 msgid "Username" msgstr "使用者名稱" -#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53 +#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:45 msgid "Password" msgstr "密碼" -#: mediagoblin/auth/forms.py:35 -msgid "Passwords must match." -msgstr "密碼必須一致" - -#: mediagoblin/auth/forms.py:37 -msgid "Confirm password" -msgstr "確認密碼" - -#: mediagoblin/auth/forms.py:39 -msgid "Type it again here to make sure there are no spelling mistakes." -msgstr "再輸入一次,確定你沒有打錯字。" - -#: mediagoblin/auth/forms.py:42 +#: mediagoblin/auth/forms.py:34 msgid "Email address" msgstr "電子郵件位置" @@ -60,120 +48,161 @@ msgstr "抱歉, 這個使用者名稱已經存在." msgid "Sorry, a user with that email address already exists." msgstr "抱歉,此電子郵件已被註冊了。" -#: mediagoblin/auth/views.py:179 +#: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" msgstr "你的電子郵件位址已被認證. 你現在就可以登入, 編輯你的個人檔案而且遞交照片!" -#: mediagoblin/auth/views.py:185 +#: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" msgstr "認證碼或是使用者帳號錯誤" -#: mediagoblin/auth/views.py:203 +#: mediagoblin/auth/views.py:204 msgid "You must be logged in so we know who to send the email to!" msgstr "你必須登入,我們才知道信要送給誰!" -#: mediagoblin/auth/views.py:211 +#: mediagoblin/auth/views.py:212 msgid "You've already verified your email address!" msgstr "你的電子郵件已經確認了!" -#: mediagoblin/auth/views.py:224 +#: mediagoblin/auth/views.py:225 msgid "Resent your verification email." msgstr "重送認證信." -#: mediagoblin/auth/views.py:265 +#: mediagoblin/auth/views.py:260 +msgid "" +"An email has been sent with instructions on how to change your password." +msgstr "修改密碼的指示已經由電子郵件寄送到你的信箱。" + +#: mediagoblin/auth/views.py:270 msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." msgstr "無法傳送密碼回復信件,因為你的使用者名稱已失效或是帳號尚未認證。" -#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27 +#: mediagoblin/auth/views.py:282 +msgid "Couldn't find someone with that username or email." +msgstr "找不到相關的使用者名稱或是電子郵件。" + +#: mediagoblin/auth/views.py:330 +msgid "You can now log in using your new password." +msgstr "你現在可以用新的密碼登入了!" + +#: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" msgstr "標題" -#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32 +#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:31 +msgid "Description of this work" +msgstr "這個作品的描述" + +#: mediagoblin/edit/forms.py:29 mediagoblin/edit/forms.py:52 +#: mediagoblin/submit/forms.py:32 +msgid "" +"You can use\n" +" \n" +" Markdown for formatting." +msgstr "" +"你可以用\n" +" \n" +" Markdown 來排版." + +#: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" msgstr "標籤" -#: mediagoblin/edit/forms.py:30 mediagoblin/submit/forms.py:34 -msgid "Seperate tags by commas." -msgstr "用逗點分開標籤。" +#: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 +msgid "Separate tags by commas." +msgstr "用逗號分隔標籤。" -#: mediagoblin/edit/forms.py:33 +#: mediagoblin/edit/forms.py:38 msgid "Slug" msgstr "自訂字串" -#: mediagoblin/edit/forms.py:34 +#: mediagoblin/edit/forms.py:39 msgid "The slug can't be empty" msgstr "自訂字串不能空白" -#: mediagoblin/edit/forms.py:35 +#: mediagoblin/edit/forms.py:40 msgid "" -"The title part of this media's URL. You usually don't need to change this." +"The title part of this media's address. You usually don't need to change " +"this." msgstr "此媒體網址的名稱。你通常不需要變動這個的。" -#: mediagoblin/edit/forms.py:42 +#: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 +msgid "License" +msgstr "" + +#: mediagoblin/edit/forms.py:50 msgid "Bio" msgstr "自我介紹" -#: mediagoblin/edit/forms.py:45 +#: mediagoblin/edit/forms.py:56 msgid "Website" msgstr "網站" -#: mediagoblin/edit/forms.py:49 +#: mediagoblin/edit/forms.py:63 msgid "Old password" msgstr "舊的密碼" -#: mediagoblin/edit/forms.py:52 -msgid "New Password" -msgstr "新的密碼" +#: mediagoblin/edit/forms.py:65 +msgid "Enter your old password to prove you own this account." +msgstr "輸入你的舊密碼來證明你擁有這個帳號。" -#: mediagoblin/edit/views.py:65 +#: mediagoblin/edit/forms.py:68 +msgid "New password" +msgstr "新密碼" + +#: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." msgstr "這個自訂字串已經被其他人用了" -#: mediagoblin/edit/views.py:86 +#: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." msgstr "你正在編輯他人的媒體檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:156 +#: mediagoblin/edit/views.py:162 msgid "You are editing a user's profile. Proceed with caution." msgstr "你正在編輯一位用戶的檔案. 請謹慎處理." -#: mediagoblin/edit/views.py:171 +#: mediagoblin/edit/views.py:180 +msgid "Profile changes saved" +msgstr "修改的檔案已存檔" + +#: mediagoblin/edit/views.py:206 msgid "Wrong password" msgstr "密碼錯誤" -#: mediagoblin/edit/views.py:192 -msgid "Profile edited!" -msgstr "個人資料已被編輯了!" +#: mediagoblin/edit/views.py:222 +msgid "Account settings saved" +msgstr "帳號設定已存檔" + +#: mediagoblin/media_types/__init__.py:77 +msgid "Could not extract any file extension from \"{filename}\"" +msgstr "無法從 \"{filename}\"分析出任何的附檔名" -#: mediagoblin/media_types/__init__.py:65 -msgid "Could not find any file extension in \"{filename}\"" -msgstr "找不到任何 \"{filename}\" 的附檔名。" +#: mediagoblin/media_types/__init__.py:88 +msgid "Sorry, I don't support that file type :(" +msgstr "抱歉,我不支援這樣的檔案格式 :(" -#: mediagoblin/submit/forms.py:25 +#: mediagoblin/submit/forms.py:26 msgid "File" msgstr "檔案" -#: mediagoblin/submit/forms.py:30 -msgid "Description of this work" -msgstr "這個作品的描述" - -#: mediagoblin/submit/views.py:49 +#: mediagoblin/submit/views.py:54 msgid "You must provide a file." msgstr "你必須提供一個檔案" -#: mediagoblin/submit/views.py:127 +#: mediagoblin/submit/views.py:158 msgid "Woohoo! Submitted!" msgstr "呼呼! 送出去嚕!" -#: mediagoblin/submit/views.py:133 -msgid "Invalid file type." -msgstr "不正確的檔案格式" +#: mediagoblin/templates/mediagoblin/404.html:22 +msgid "Image of 404 goblin stressing out" +msgstr "Image of 404 goblin stressing out" -#: mediagoblin/templates/mediagoblin/404.html:21 +#: mediagoblin/templates/mediagoblin/404.html:23 msgid "Oops!" msgstr "糟糕!" @@ -187,33 +216,30 @@ msgid "" " been moved or deleted." msgstr "如果你確定這個位址是正確的,或許你在找的網頁已經被移除或是刪除了。" -#: mediagoblin/templates/mediagoblin/404.html:32 -msgid "Image of 404 goblin stressing out" -msgstr "Image of 404 goblin stressing out" - -#: mediagoblin/templates/mediagoblin/base.html:49 +#: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" msgstr "MediaGoblin 標誌" -#: mediagoblin/templates/mediagoblin/base.html:54 -msgid "Submit media" -msgstr "遞交媒體" +#: mediagoblin/templates/mediagoblin/base.html:51 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:157 +msgid "Add media" +msgstr "新增媒體檔案" -#: mediagoblin/templates/mediagoblin/base.html:65 +#: mediagoblin/templates/mediagoblin/base.html:62 msgid "Verify your email!" msgstr "確認你的電子郵件" -#: mediagoblin/templates/mediagoblin/base.html:72 +#: mediagoblin/templates/mediagoblin/base.html:69 msgid "log out" msgstr "登出" -#: mediagoblin/templates/mediagoblin/base.html:75 +#: mediagoblin/templates/mediagoblin/base.html:72 #: mediagoblin/templates/mediagoblin/auth/login.html:27 #: mediagoblin/templates/mediagoblin/auth/login.html:45 msgid "Log in" msgstr "登入" -#: mediagoblin/templates/mediagoblin/base.html:91 +#: mediagoblin/templates/mediagoblin/base.html:84 msgid "" "Powered by MediaGoblin, a GNU project" @@ -225,7 +251,7 @@ msgstr "" msgid "Explore" msgstr "探索" -#: mediagoblin/templates/mediagoblin/root.html:27 +#: mediagoblin/templates/mediagoblin/root.html:26 msgid "Hi there, welcome to this MediaGoblin site!" msgstr "嘿!歡迎來到 媒體怪獸(MediaGoblin) 網站" @@ -251,25 +277,24 @@ msgstr "還沒有嗎?其實非常簡單!" #, python-format msgid "" "Create an account at this site\n" -" or\n" -" Set up MediaGoblin on your own server" +" or\n" +" Set up MediaGoblin on your own server" msgstr "" -"在這網站建立帳號\n" +"<a class=\"button_action_highlight\" href=\"%(register_url)s\">在這網站建立帳號</a>\n" " 或是\n" -" 建立一個自己的媒體怪獸(MedaiGoblin)" +" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">建立一個自己的媒體怪獸(MedaiGoblin)</a>" -#: mediagoblin/templates/mediagoblin/root.html:44 +#: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" msgstr "最新的媒體" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29 -msgid "Enter your new password" -msgstr "輸入你的新密碼" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 +msgid "Set your new password" +msgstr "設定你的新密碼" -#: mediagoblin/templates/mediagoblin/auth/change_fp.html:33 -#: mediagoblin/templates/mediagoblin/submit/start.html:30 -msgid "Submit" -msgstr "送出" +#: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 +msgid "Set password" +msgstr "設定新密碼" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -279,15 +304,6 @@ msgstr "找回密碼" msgid "Send instructions" msgstr "送出指示" -#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22 -msgid "Your password has been changed. Try to log in now." -msgstr "你的密碼已經改變了。現在就登入試試看。" - -#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22 -msgid "" -"Check your inbox. We sent an email with a URL for changing your password." -msgstr "檢查你的收件匣。我們已經傳送了電子郵件,你可利用郵件中的網址變更密碼。" - #: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19 #, python-format msgid "" @@ -325,11 +341,11 @@ msgstr "在這裡建立一個吧!" msgid "Forgot your password?" msgstr "忘了密碼嗎?" -#: mediagoblin/templates/mediagoblin/auth/register.html:27 +#: mediagoblin/templates/mediagoblin/auth/register.html:32 msgid "Create an account!" msgstr "建立一個帳號!" -#: mediagoblin/templates/mediagoblin/auth/register.html:31 +#: mediagoblin/templates/mediagoblin/auth/register.html:36 msgid "Create" msgstr "建立" @@ -360,10 +376,16 @@ msgid "Cancel" msgstr "取消" #: mediagoblin/templates/mediagoblin/edit/edit.html:37 +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:40 #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35 msgid "Save changes" msgstr "儲存變更" +#: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 +#, python-format +msgid "Changing %(username)s's account settings" +msgstr "正在改變 %(username)s的帳號設定" + #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format msgid "Editing %(username)s's profile" @@ -375,13 +397,38 @@ msgstr "編輯 %(username)s'的檔案中" msgid "Media tagged with: %(tag_name)s" msgstr "此媒體被標識為:%(tag_name)s" -#: mediagoblin/templates/mediagoblin/media_displays/video.html:19 +#: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 +#: mediagoblin/templates/mediagoblin/media_displays/video.html:46 msgid "Original" msgstr "原始的" +#: mediagoblin/templates/mediagoblin/media_displays/video.html:33 +msgid "" +"Sorry, this video will not work because \n" +"\t your web browser does not support HTML5 \n" +"\t video." +msgstr "" +"抱歉, 此影片無法使用,因為 \n" +"» 你的瀏覽器不支援 HTML5 \n" +"» 的影片." + +#: mediagoblin/templates/mediagoblin/media_displays/video.html:36 +msgid "" +"You can get a modern web browser that \n" +"\t can play this video at \n" +"\t http://getfirefox.com!" +msgstr "" +"你可以取得\n" +"» 播放這樣檔案的最新瀏覽器 \n" +"» http://getfirefox.com!" + #: mediagoblin/templates/mediagoblin/submit/start.html:26 -msgid "Submit yer media" -msgstr "遞交你的媒體檔案" +msgid "Add your media" +msgstr "加入你的媒體" + +#: mediagoblin/templates/mediagoblin/submit/start.html:30 +msgid "Add" +msgstr "增加" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -393,31 +440,57 @@ msgstr "%(username)s的媒體" msgid "%(username)s's media" msgstr "%(username)s的媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:57 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format -msgid "By %(username)s on %(date)s" -msgstr "由 %(username)s 於 %(date)s" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:67 -msgid "Post a comment" -msgstr "刊登評論" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 -msgid "at" -msgstr "在" +msgid "Added on %(date)s." +msgstr "%(date)s. 加入" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:102 -msgid "Post comment!" -msgstr "刊登評論!" - -#: mediagoblin/templates/mediagoblin/user_pages/media.html:124 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" msgstr "編輯" -#: mediagoblin/templates/mediagoblin/user_pages/media.html:130 +#: mediagoblin/templates/mediagoblin/user_pages/media.html:85 msgid "Delete" msgstr "刪除" +#: mediagoblin/templates/mediagoblin/user_pages/media.html:91 +#, python-format +msgid "%(comment_count)s comment" +msgstr "%(comment_count)s 評論" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:93 +#, python-format +msgid "%(comment_count)s comments" +msgstr "%(comment_count)s 評論" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:95 +msgid "No comments yet." +msgstr "尚未有評論" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:103 +msgid "Add one" +msgstr "新增一個" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:112 +msgid "" +"You can use Markdown for" +" formatting." +msgstr "" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:116 +msgid "Add this comment" +msgstr "增加此評論" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:138 +msgid "at" +msgstr "在" + +#: mediagoblin/templates/mediagoblin/user_pages/media.html:153 +#, python-format +msgid "

    ❖ Browsing media by %(username)s

    " +msgstr "

    ❖ 以%(username)s瀏覽媒體檔案

    " + #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format msgid "Really delete %(title)s?" @@ -498,30 +571,31 @@ msgid "Here's a spot to tell others about yourself." msgstr "這是一個地方,能讓你向他人介紹自己。" #: mediagoblin/templates/mediagoblin/user_pages/user.html:101 -#: mediagoblin/templates/mediagoblin/user_pages/user.html:119 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:118 msgid "Edit profile" msgstr "編輯個人檔案" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:107 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:106 msgid "This user hasn't filled in their profile (yet)." msgstr "這個使用者還沒(來得及)填寫個人檔案。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:133 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:125 +msgid "Change account settings" +msgstr "更改帳號設定" + +#: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format msgid "View all of %(username)s's media" msgstr "查看%(username)s的全部媒體檔案" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:146 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:151 msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." msgstr "這個地方是你的媒體檔案會出現的地方,但是你似乎還沒有加入任何東西。" -#: mediagoblin/templates/mediagoblin/user_pages/user.html:152 -msgid "Add media" -msgstr "新增媒體檔案" - -#: mediagoblin/templates/mediagoblin/user_pages/user.html:158 +#: mediagoblin/templates/mediagoblin/user_pages/user.html:163 +#: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 msgid "There doesn't seem to be any media here yet..." msgstr "似乎還沒有任何的媒體檔案..." @@ -533,29 +607,47 @@ msgstr "feed圖示" msgid "Atom feed" msgstr "Atom feed" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:40 -msgid "Newer" -msgstr "新一點" +#: mediagoblin/templates/mediagoblin/utils/license.html:21 +msgid "License:" +msgstr "" + +#: mediagoblin/templates/mediagoblin/utils/license.html:25 +msgid "All rights reserved" +msgstr "" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:46 -msgid "Older" -msgstr "舊一點" +#: mediagoblin/templates/mediagoblin/utils/pagination.html:39 +msgid "← Newer" +msgstr "← 更新" -#: mediagoblin/templates/mediagoblin/utils/pagination.html:50 +#: mediagoblin/templates/mediagoblin/utils/pagination.html:45 +msgid "Older →" +msgstr "更舊 →" + +#: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" msgstr "跳到頁數:" +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 +msgid "newer" +msgstr "更新" + +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 +#: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 +msgid "older" +msgstr "更舊" + #: mediagoblin/templates/mediagoblin/utils/tags.html:20 -msgid "Tagged with" -msgstr "被標籤為" +msgid "View more media tagged with" +msgstr "看更多被標籤的媒體" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 -msgid "and" -msgstr "且" +msgid "or" +msgstr "或是" -#: mediagoblin/user_pages/forms.py:24 -msgid "Comment" -msgstr "評論" +#: mediagoblin/tools/exif.py:68 +msgid "Could not read the image file." +msgstr "" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -- cgit v1.2.3 From 76d6323fff5f1678b8b06bfd2f0d3e237c4eb039 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:32:41 -0600 Subject: Adding a line reminding user to push up commits --- devtools/update_translations.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh index 537aa95b..527bd274 100755 --- a/devtools/update_translations.sh +++ b/devtools/update_translations.sh @@ -49,3 +49,5 @@ echo "==> Committing to git" git add mediagoblin/i18n/ git commit -m "Committing extracted and compiled translations" || true + +echo "... done. Now consider pushing up those commits!" -- cgit v1.2.3 From ef9c5bbda67b83bdf3a5c5355863aab63b162b74 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:47:36 -0600 Subject: Committing present MediaGoblin translations before pushing extracted messages --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index f71f139f..381005a8 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -18,8 +18,8 @@ msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" "POT-Creation-Date: 2012-01-29 13:31-0600\n" -"PO-Revision-Date: 2012-01-29 19:29+0000\n" -"Last-Translator: cwebber \n" +"PO-Revision-Date: 2012-01-29 19:44+0000\n" +"Last-Translator: Elrond \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -144,7 +144,7 @@ msgstr "" #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" -msgstr "" +msgstr "Lizenz" #: mediagoblin/edit/forms.py:50 msgid "Bio" -- cgit v1.2.3 From 8a9aa0758393336fb751c6f77a3d4feaa1903c06 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:47:51 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 13618 -> 13630 bytes mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index 0a5af04c..a63886d8 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 9841beec..eca38526 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-01-29 13:31-0600\n" +"POT-Creation-Date: 2012-01-29 13:47-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -- cgit v1.2.3 From 51fba99125c63a6a5e68480e7d4b1ea08f33a4db Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 28 Jan 2012 00:33:23 +0100 Subject: Some small SQL model improvements - Add default for User.email_verified - Add default for MediaEntry.state - Let PathTupleWithSlashes store [] as "NULL", but not handling the reverse properly yet! - Add _id alias field to MediaEntry and MediaComment --- mediagoblin/db/sql/extratypes.py | 6 ++++-- mediagoblin/db/sql/models.py | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py index 33c9edee..21c806ec 100644 --- a/mediagoblin/db/sql/extratypes.py +++ b/mediagoblin/db/sql/extratypes.py @@ -25,8 +25,10 @@ class PathTupleWithSlashes(TypeDecorator): def process_bind_param(self, value, dialect): if value is not None: - assert len(value), "Does not support empty lists" - value = '/'.join(value) + if len(value) == 0: + value = None + else: + value = '/'.join(value) return value def process_result_value(self, value, dialect): diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 9abd8ec7..7ec05876 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -50,7 +50,7 @@ class User(Base, UserMixin): email = Column(Unicode, nullable=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) pw_hash = Column(Unicode, nullable=False) - email_verified = Column(Boolean) + email_verified = Column(Boolean, default=False) status = Column(Unicode, default=u"needs_email_verification", nullable=False) verification_key = Column(Unicode) is_admin = Column(Boolean, default=False, nullable=False) @@ -77,7 +77,8 @@ class MediaEntry(Base, MediaEntryMixin): description = Column(UnicodeText) # ?? description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) - state = Column(Unicode, nullable=False) # or use sqlalchemy.types.Enum? + state = Column(Unicode, default=u'unprocessed', nullable=False) + # or use sqlalchemy.types.Enum? license = Column(Unicode) fail_error = Column(Unicode) @@ -113,6 +114,8 @@ class MediaEntry(Base, MediaEntryMixin): # attachment_files # fail_error + _id = SimpleFieldAlias("id") + def get_comments(self, ascending=False): order_col = MediaComment.created if not ascending: @@ -215,6 +218,8 @@ class MediaComment(Base): get_author = relationship(User) + _id = SimpleFieldAlias("id") + def show_table_init(): from sqlalchemy import create_engine -- cgit v1.2.3 From 70b44584ae4a81e53d39481781c63aec23b23884 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 29 Dec 2011 11:15:55 -0600 Subject: Big ol' start of the SQL migrations system. Things definitely don't work yet, but should be heading in the right direction. --- mediagoblin/db/sql/migrations.py | 17 +++++++ mediagoblin/db/sql/models.py | 21 +++++++++ mediagoblin/db/sql/util.py | 59 +++++++++++++++++++++++ mediagoblin/gmg_commands/dbupdate.py | 84 +++++++++++++++++++++++++++++++++ mediagoblin/media_types/image/models.py | 17 +++++++ mediagoblin/media_types/video/models.py | 16 +++++++ 6 files changed, 214 insertions(+) create mode 100644 mediagoblin/db/sql/migrations.py create mode 100644 mediagoblin/db/sql/util.py create mode 100644 mediagoblin/gmg_commands/dbupdate.py create mode 100644 mediagoblin/media_types/image/models.py create mode 100644 mediagoblin/media_types/video/models.py diff --git a/mediagoblin/db/sql/migrations.py b/mediagoblin/db/sql/migrations.py new file mode 100644 index 00000000..67a02c96 --- /dev/null +++ b/mediagoblin/db/sql/migrations.py @@ -0,0 +1,17 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +MIGRATIONS = [] diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 9abd8ec7..3573bc3f 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -216,6 +216,27 @@ class MediaComment(Base): get_author = relationship(User) +MODELS = [ + User, MediaEntry, Tag, MediaTag, MediaComment] + + +###################################################### +# Special, migrations-tracking table +# +# Not listed in MODELS because this is special and not +# really migrated, but used for migrations (for now) +###################################################### + +class MigrationData(Base): + __tablename__ = "migrations" + + id = Column(Integer, primary_key=True) + name = Column(Unicode, nullable=False, unique=True) + version = Column(Integer, nullable=False, default=0) + +###################################################### + + def show_table_init(): from sqlalchemy import create_engine engine = create_engine('sqlite:///:memory:', echo=True) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py new file mode 100644 index 00000000..a0cea111 --- /dev/null +++ b/mediagoblin/db/sql/util.py @@ -0,0 +1,59 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +class MigrationManager(object): + pass + + +class RegisterMigration(object): + """ + Tool for registering migrations + + Call like: + + @RegisterMigration(33) + def update_dwarves(database): + [...] + + This will register your migration with the default migration + registry. Alternately, to specify a very specific + migration_registry, you can pass in that as the second argument. + + Note, the number of your migration should NEVER be 0 or less than + 0. 0 is the default "no migrations" state! + """ + def __init__(self, migration_number, migration_registry): + assert migration_number > 0, "Migration number must be > 0!" + assert migration_number not in migration_registry, \ + "Duplicate migration numbers detected! That's not allowed!" + + self.migration_number = migration_number + self.migration_registry = migration_registry + + def __call__(self, migration): + self.migration_registry[self.migration_number] = migration + return migration + + +def assure_migrations_table_setup(db): + """ + Make sure the migrations table is set up in the database. + """ + from mediagoblin.db.sql.models import MigrationData + + if not MigrationData.__table__.exists(db): + MigrationData.metadata.create_all( + db, tables=[MigrationData.__table__]) diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py new file mode 100644 index 00000000..52819c6d --- /dev/null +++ b/mediagoblin/gmg_commands/dbupdate.py @@ -0,0 +1,84 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.db.sql.open import setup_connection_and_db_from_config +from mediagoblin.db.sql.util import ( + MigrationManager, assure_migrations_table_setup) +from mediagoblin.init import setup_global_and_app_config +from mediagoblin.tools.common import import_component + + +class DatabaseData(object): + def __init__(self, name, models, migrations): + self.name = name + self.models = models + self.migrations = migrations + + def make_migration_manager(self, db): + return MigrationManager( + self.name, self.models, self.migrations, db) + + +def gather_database_data(self, media_types): + """ + Gather all database data relevant to the extensions we have + installed so we can do migrations and table initialization. + + Returns a list of DatabaseData objects. + """ + managed_dbdata = [] + + # Add main first + from mediagoblin.db.sql.models import MODELS as MAIN_MODELS + from mediagoblin.db.sql.migrations import MIGRATIONS as MAIN_MIGRATIONS + + managed_dbdata.append( + DatabaseData( + '__main__', MAIN_MODELS, MAIN_MIGRATIONS)) + + # Then get all registered media managers (eventually, plugins) + for media_type in media_types: + models = import_component('%s.models:MODELS' % media_type) + migrations = import_component('%s.migrations:MIGRATIONS' % media_type) + managed_dbdata.append( + DatabaseData(media_type, models, migrations)) + + return managed_dbdata + + +def dbupdate(args): + """ + Initialize or migrate the database as specified by the config file. + + Will also initialize or migrate all extensions (media types, and + in the future, plugins) + """ + globa_config, app_config = setup_global_and_app_config(args.conf_file) + + # Gather information from all media managers / projects + dbdatas = gather_database_data(app_config['media_types']) + + # Set up the database + connection, db = setup_connection_and_db_from_config(app_config) + + # If migrations table not made, make it! + assure_migrations_table_setup(db) + + # Setup media managers for all dbdata, run init/migrate and print info + # For each component, create/migrate tables + for dbdata in dbdatas: + migration_manager = dbdata.make_migration_manager(db) + migration_manager.init_or_migrate() diff --git a/mediagoblin/media_types/image/models.py b/mediagoblin/media_types/image/models.py new file mode 100644 index 00000000..96b5cdf2 --- /dev/null +++ b/mediagoblin/media_types/image/models.py @@ -0,0 +1,17 @@ +from mediagoblin.db.sql.models import Base + +from sqlalchemy import ( + Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint) + + +class ImageData(Base): + __tablename__ = "image__data" + + id = Column(Integer, primary_key=True) + width = Column(Integer) + height = Column(Integer) + + +DATA_MODEL = ImageData +MODELS = [ImageData] diff --git a/mediagoblin/media_types/video/models.py b/mediagoblin/media_types/video/models.py new file mode 100644 index 00000000..c44f1919 --- /dev/null +++ b/mediagoblin/media_types/video/models.py @@ -0,0 +1,16 @@ +from mediagoblin.db.sql.models import Base + +from sqlalchemy import ( + Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint) + + +class VideoData(Base): + __tablename__ = "video__data" + + id = Column(Integer, primary_key=True) + integer + + +DATA_MODEL = VideoData +MODELS = [VideoData] -- cgit v1.2.3 From def13c549a99c36da06f80191fed3bb607ff0cce Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 29 Dec 2011 14:44:21 -0600 Subject: Beginnings of the SQL migration manager --- mediagoblin/db/sql/util.py | 101 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index a0cea111..ec3d6dcf 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -14,8 +14,107 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . + class MigrationManager(object): - pass + """ + Migration handling tool. + + Takes information about a database, lets you update the database + to the latest migrations, etc. + """ + + def __init__(self, name, models, migration_registry, database): + """ + Args: + - name: identifier of this section of the database + - database: database we're going to migrate + - migration_registry: where we should find all migrations to + run + """ + self.name = name + self.models = models + self.database = database + self.migration_registry = migration_registry + self._sorted_migrations = None + + # For convenience + from mediagoblin.db.sql.models import MigrationData + + self.migration_model = MigrationData + self.migration_table = MigrationData.__table__ + + @property + def sorted_migrations(self): + """ + Sort migrations if necessary and store in self._sorted_migrations + """ + if not self._sorted_migrations: + self._sorted_migrations = sorted( + self.migration_registry.items(), + # sort on the key... the migration number + key=lambda migration_tuple: migration_tuple[0]) + + return self._sorted_migrations + + def latest_migration(self): + """ + Return a migration number for the latest migration, or 0 if + there are no migrations. + """ + if self.sorted_migrations: + return self.sorted_migrations[-1][0] + else: + # If no migrations have been set, we start at 0. + return 0 + + def database_current_migration(self): + """ + Return the current migration in the database. + """ + # TODO + + def set_current_migration(self, migration_number): + """ + Set the migration in the database to migration_number + """ + # TODO + pass + + def migrations_to_run(self): + """ + Get a list of migrations to run still, if any. + + Note that calling this will set your migration version to the + latest version if it isn't installed to anything yet! + """ + ## TODO + # self._ensure_current_migration_record() + # + # db_current_migration = self.database_current_migration() + # + # return [ + # (migration_number, migration_func) + # for migration_number, migration_func in self.sorted_migrations + # if migration_number > db_current_migration] + pass + + def init_or_migrate(self): + # Find out what migration number, if any, this database data is at, + # and what the latest is. + + # Is this our first time? Is there even a table entry for + # this identifier? + # + # If so: + # - create all tables + # - create record in migrations registry + # - print / inform the user + # - return 'inited' + + # Run migrations, if appropriate. + + # If ran migrations, return 'migrated'. Otherwise, return None. + pass class RegisterMigration(object): -- cgit v1.2.3 From 705689b96faedc952f039b433287b0e2b852b11d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 31 Dec 2011 08:45:41 -0600 Subject: More work on migration manager, including adding a dry run function --- mediagoblin/db/sql/util.py | 82 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index ec3d6dcf..585c3b89 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -15,6 +15,16 @@ # along with this program. If not, see . +import sys + +def _simple_printer(string): + """ + Prints a string, but without an auto \n at the end. + """ + sys.stdout.write(string) + sys.stdout.flush() + + class MigrationManager(object): """ Migration handling tool. @@ -23,7 +33,8 @@ class MigrationManager(object): to the latest migrations, etc. """ - def __init__(self, name, models, migration_registry, database): + def __init__(self, name, models, migration_registry, database, + printer=_simple_printer): """ Args: - name: identifier of this section of the database @@ -36,6 +47,7 @@ class MigrationManager(object): self.database = database self.migration_registry = migration_registry self._sorted_migrations = None + self.printer = printer # For convenience from mediagoblin.db.sql.models import MigrationData @@ -98,23 +110,81 @@ class MigrationManager(object): # if migration_number > db_current_migration] pass - def init_or_migrate(self): + def init_tables(self): + ## TODO + pass + + def create_new_migration_record(self): + ## TODO + pass + + def dry_run(self): + """ + Print out a dry run of what we would have upgraded. + """ + if self.database_current_migration() is None: + self.printer( + u'~> Woulda initialized: %s\n' % self.name_for_printing()) + return u'inited' + + migrations_to_run = self.migrations_to_run() + if migrations_to_run: + self.printer( + u'~> Woulda updated %s:\n' % self.name_for_printing()) + + for migration_number, migration_func in migrations_to_run(): + self.printer( + u' + Would update %s, "%s"\n' % ( + migration_number, migration_func.func_name)) + + return u'migrated' + + def name_for_printing(self): + if self.name == u'__main__': + return u"main mediagoblin tables" + else: + # TODO: Use the friendlier media manager "human readable" name + return u'media type "%s"' % self.name + + def init_or_migrate(self, printer=_simple_printer): + """ + Initialize the database or migrate if appropriate. + + Returns information about whether or not we initialized + ('inited'), migrated ('migrated'), or did nothing (None) + """ # Find out what migration number, if any, this database data is at, # and what the latest is. + migration_number = self.database_current_migration() # Is this our first time? Is there even a table entry for # this identifier? - # # If so: # - create all tables # - create record in migrations registry # - print / inform the user # - return 'inited' + if migration_number is None: + self.printer(u"-> Initializing %s... " % self.name_for_printing()) - # Run migrations, if appropriate. + self.init_tables() + # auto-set at latest migration number + self.create_new_migration_record() + + self.printer(u"done.\n") + return u'inited' - # If ran migrations, return 'migrated'. Otherwise, return None. - pass + # Run migrations, if appropriate. + migrations_to_run = self.migrations_to_run() + if migrations_to_run: + self.printer( + u'~> Updating %s:\n' % self.name_for_printing()) + for migration_number, migration_func in migrations_to_run(): + self.printer( + u' + Running migration %s, "%s"\n' % ( + migration_number, migration_func.func_name)) + + return u'migrated' class RegisterMigration(object): -- cgit v1.2.3 From a315962f0db38ba89bdc38740709a6124e58557c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 Jan 2012 11:47:05 -0600 Subject: Finishing the init_or_migrate function --- mediagoblin/db/sql/util.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 585c3b89..296c8b78 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -181,11 +181,17 @@ class MigrationManager(object): u'~> Updating %s:\n' % self.name_for_printing()) for migration_number, migration_func in migrations_to_run(): self.printer( - u' + Running migration %s, "%s"\n' % ( + u' + Running migration %s, "%s"... ' % ( migration_number, migration_func.func_name)) + migration_func(self.database) + self.printer('done.') return u'migrated' + # Otherwise return None. Well it would do this anyway, but + # for clarity... ;) + return None + class RegisterMigration(object): """ -- cgit v1.2.3 From 4c86905789a4732af38c618ec0132d431f60b04d Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 Jan 2012 11:47:39 -0600 Subject: Removing printer argument now that we use self.printer --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 296c8b78..d4cbffea 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -146,7 +146,7 @@ class MigrationManager(object): # TODO: Use the friendlier media manager "human readable" name return u'media type "%s"' % self.name - def init_or_migrate(self, printer=_simple_printer): + def init_or_migrate(self): """ Initialize the database or migrate if appropriate. -- cgit v1.2.3 From 3635ccdf346ceea12358a410a39f6edb34255182 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 1 Jan 2012 16:02:14 -0600 Subject: More work on SQL MigrationManager Added methods: - migration_data - database_current_migration - migrations_to_run --- mediagoblin/db/sql/util.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index d4cbffea..db66776d 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -68,6 +68,17 @@ class MigrationManager(object): return self._sorted_migrations + @property + def migration_data(self): + """ + Get the migration row associated with this object, if any. + """ + query = self.database.query( + self.migration_model).filter_by(name=self.name)[0] + + if query.count(): + return query[0] + def latest_migration(self): """ Return a migration number for the latest migration, or 0 if @@ -83,32 +94,31 @@ class MigrationManager(object): """ Return the current migration in the database. """ - # TODO + return self.migration_data.version def set_current_migration(self, migration_number): """ Set the migration in the database to migration_number """ - # TODO - pass + self.migration_data = migration_number + self.database.commit() def migrations_to_run(self): """ Get a list of migrations to run still, if any. - Note that calling this will set your migration version to the - latest version if it isn't installed to anything yet! + Note that this will fail if there's no migration record for + this class! """ - ## TODO - # self._ensure_current_migration_record() - # - # db_current_migration = self.database_current_migration() - # - # return [ - # (migration_number, migration_func) - # for migration_number, migration_func in self.sorted_migrations - # if migration_number > db_current_migration] - pass + assert self.database_current_migration is None + + db_current_migration = self.database_current_migration() + + return [ + (migration_number, migration_func) + for migration_number, migration_func in self.sorted_migrations + if migration_number > db_current_migration] + def init_tables(self): ## TODO -- cgit v1.2.3 From 8bf3f63af14152099d653e426aa22c1c4e487943 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 08:55:25 -0600 Subject: Added init_tables method to MigrationManager --- mediagoblin/db/sql/util.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index db66776d..59e8eb8b 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -121,8 +121,16 @@ class MigrationManager(object): def init_tables(self): - ## TODO - pass + """ + Create all tables relative to this package + """ + # sanity check before we proceed, none of these should be created + for model in self.models: + assert not model.__table__.exists(self.database) + + self.migration_model.metadata.create_all( + self.database, + tables=[model.__table__ for model in self.models]) def create_new_migration_record(self): ## TODO @@ -163,6 +171,8 @@ class MigrationManager(object): Returns information about whether or not we initialized ('inited'), migrated ('migrated'), or did nothing (None) """ + assure_migrations_table_setup(self.database) + # Find out what migration number, if any, this database data is at, # and what the latest is. migration_number = self.database_current_migration() -- cgit v1.2.3 From b0ec21bff3fd01dc5e1d217560ca6479aadaae8b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 09:12:11 -0600 Subject: Add create_new_migration_record method to MigrationManager --- mediagoblin/db/sql/util.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 59e8eb8b..a42d992f 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -126,6 +126,7 @@ class MigrationManager(object): """ # sanity check before we proceed, none of these should be created for model in self.models: + # Maybe in the future just print out a "Yikes!" or something? assert not model.__table__.exists(self.database) self.migration_model.metadata.create_all( @@ -133,8 +134,12 @@ class MigrationManager(object): tables=[model.__table__ for model in self.models]) def create_new_migration_record(self): - ## TODO - pass + """ + Create a new migration record for this migration set + """ + self.migration_model( + name=self.name, + version=self.latest_migration()) def dry_run(self): """ -- cgit v1.2.3 From 09dcc34c95a361c76a1aeed59b41cb14f91c17c6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 13:36:19 -0600 Subject: Commit that new migration record ;) --- mediagoblin/db/sql/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index a42d992f..61ba1b45 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -140,6 +140,7 @@ class MigrationManager(object): self.migration_model( name=self.name, version=self.latest_migration()) + self.database.commit() def dry_run(self): """ -- cgit v1.2.3 From 23f4c6b2fd2440433bcb2443633d847ddad17238 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 13:38:08 -0600 Subject: We should probably add that object to the DB also :P --- mediagoblin/db/sql/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 61ba1b45..4938bcad 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -137,9 +137,10 @@ class MigrationManager(object): """ Create a new migration record for this migration set """ - self.migration_model( + migration_record = self.migration_model( name=self.name, version=self.latest_migration()) + self.database.add(migration_record) self.database.commit() def dry_run(self): -- cgit v1.2.3 From 851df6214ee0332eb45282702524934cdb9ebcf7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 13:59:36 -0600 Subject: Use .first() instead of [0]... thanks elrond :) --- mediagoblin/db/sql/util.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 4938bcad..dfc36a61 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -73,11 +73,8 @@ class MigrationManager(object): """ Get the migration row associated with this object, if any. """ - query = self.database.query( - self.migration_model).filter_by(name=self.name)[0] - - if query.count(): - return query[0] + return self.database.query( + self.migration_model).filter_by(name=self.name).first() def latest_migration(self): """ -- cgit v1.2.3 From cbf29f2d5897c90794e6a6f855a4371296e56794 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 14:04:16 -0600 Subject: assert was positive when it should be negative, fixed --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index dfc36a61..604f040c 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -107,7 +107,7 @@ class MigrationManager(object): Note that this will fail if there's no migration record for this class! """ - assert self.database_current_migration is None + assert self.database_current_migration is not None db_current_migration = self.database_current_migration() -- cgit v1.2.3 From bf81382896e98e5a7c3dcd426ee8c73fe9ef84a6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 14:40:32 -0600 Subject: Make name the primary key in migration records --- mediagoblin/db/sql/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 3573bc3f..ed733aff 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -230,8 +230,7 @@ MODELS = [ class MigrationData(Base): __tablename__ = "migrations" - id = Column(Integer, primary_key=True) - name = Column(Unicode, nullable=False, unique=True) + name = Column(Unicode, primary_key=True) version = Column(Integer, nullable=False, default=0) ###################################################### -- cgit v1.2.3 From dc5da0f891895c79f29be05df1e14035b080dcdc Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 14:56:05 -0600 Subject: Another MigrationManager fix. self.database -> self.database.engine (thanks again Elrond for the catch) --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 604f040c..0911884e 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -127,7 +127,7 @@ class MigrationManager(object): assert not model.__table__.exists(self.database) self.migration_model.metadata.create_all( - self.database, + self.database.engine, tables=[model.__table__ for model in self.models]) def create_new_migration_record(self): -- cgit v1.2.3 From 3f2c6f96c191eb89f1c6ec7c903219b445f410a0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 16:08:32 -0600 Subject: No need for self here (thanks again Elrond ;)) --- mediagoblin/gmg_commands/dbupdate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py index 52819c6d..1fc5121a 100644 --- a/mediagoblin/gmg_commands/dbupdate.py +++ b/mediagoblin/gmg_commands/dbupdate.py @@ -32,7 +32,7 @@ class DatabaseData(object): self.name, self.models, self.migrations, db) -def gather_database_data(self, media_types): +def gather_database_data(media_types): """ Gather all database data relevant to the extensions we have installed so we can do migrations and table initialization. -- cgit v1.2.3 From cfbbdcc5ad08f2c6a0614cae2256880d6cbff8f6 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 2 Jan 2012 16:14:55 -0600 Subject: Another db->db.engine because I'm bad at things ;) Thanks again Elrond. --- mediagoblin/db/sql/util.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 0911884e..65976538 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -50,10 +50,10 @@ class MigrationManager(object): self.printer = printer # For convenience - from mediagoblin.db.sql.models import MigrationData + from mediagoblin.db.sql.models import MigrationRecord - self.migration_model = MigrationData - self.migration_table = MigrationData.__table__ + self.migration_model = MigrationRecord + self.migration_table = MigrationRecord.__table__ @property def sorted_migrations(self): @@ -251,8 +251,8 @@ def assure_migrations_table_setup(db): """ Make sure the migrations table is set up in the database. """ - from mediagoblin.db.sql.models import MigrationData + from mediagoblin.db.sql.models import MigrationRecord - if not MigrationData.__table__.exists(db): - MigrationData.metadata.create_all( - db, tables=[MigrationData.__table__]) + if not MigrationRecord.__table__.exists(db.engine): + MigrationRecord.metadata.create_all( + db, tables=[MigrationRecord.__table__]) -- cgit v1.2.3 From 0f10058fd38f1b97068320fe62eb2494803a263a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 Jan 2012 11:35:26 -0600 Subject: A theoretical set of models to migrate about with, plus one migration ;) --- mediagoblin/tests/test_sql_migrations.py | 177 +++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 mediagoblin/tests/test_sql_migrations.py diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py new file mode 100644 index 00000000..32950d38 --- /dev/null +++ b/mediagoblin/tests/test_sql_migrations.py @@ -0,0 +1,177 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import copy + +from sqlalchemy import ( + Table, Column, MetaData, + Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint, PickleType) +from sqlalchemy.ext.declarative import declarative_base +from migrate import changeset + +from mediagoblin.db.sql.base import GMGTableBase + + +# This one will get filled with local migrations +FULL_MIGRATIONS = {} + + +####################################################### +# Migration set 1: Define initial models, no migrations +####################################################### + +Base1 = declarative_base(cls=GMGTableBase) + +class Creature1(Base1): + __tablename__ = "creature" + + id = Column(Integer, primary_key=True) + name = Column(Unicode, unique=True, nullable=False, index=True) + num_legs = Column(Integer, nullable=False) + is_demon = Column(Boolean) + +class Level1(Base1): + __tablename__ = "level" + + id = Column(Integer, primary_key=True) + name = Column(Unicode, unique=True, nullable=False, index=True) + description = Column(UnicodeText) + exits = Column(PickleType) + +SET1_MODELS = [Creature1, Level1] + +SET1_MIGRATIONS = [] + +####################################################### +# Migration set 2: A few migrations and new model +####################################################### + +Base2 = declarative_base(cls=GMGTableBase) + +class Creature2(Base2): + __tablename__ = "creature" + + id = Column(Integer, primary_key=True) + name = Column(Unicode, unique=True, nullable=False, index=True) + num_legs = Column(Integer, nullable=False) + +class CreaturePower2(Base2): + __tablename__ = "creature_power" + + id = Column(Integer, primary_key=True) + creature = Column( + Integer, ForeignKey('creature.id'), nullable=False) + name = Column(Unicode) + description = Column(Unicode) + +class Level2(Base2): + __tablename__ = "level" + + id = Column(Integer, primary_key=True) + name = Column(Unicode) + description = Column(UnicodeText) + +class LevelExit2(Base2): + __tablename__ = "level_exit" + + id = Column(Integer, primary_key=True) + name = Column(Unicode) + from_level = Column( + Integer, ForeignKey('level.id'), nullable=False) + to_level = Column( + Integer, ForeignKey('level.id'), nullable=False) + +SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2] + + +@RegisterMigration(1, FULL_MIGRATIONS) +def creature_remove_is_demon(db_conn): + creature_table = Table( + 'creature', MetaData(), + autoload=True, autoload_with=db_conn.engine) + db_conn.execute( + creature_table.drop_column('is_demon')) + + +@RegisterMigration(2, FULL_MIGRATIONS) +def creature_powers_new_table(db_conn): + pass + +@RegisterMigration(3, FULL_MIGRATIONS) +def level_exits_new_table(db_conn): + pass + + +# A hack! At this point we freeze-fame and get just a partial list of +# migrations + +PARTIAL_MIGRATIONS = copy.copy(FULL_MIGRATIONS) + +####################################################### +# Migration set 3: Final migrations +####################################################### + +Base3 = declarative_base(cls=GMGTableBase) + +class Creature3(Base3): + __tablename__ = "creature" + + id = Column(Integer, primary_key=True) + name = Column(Unicode, unique=True, nullable=False, index=True) + num_limbs= Column(Integer, nullable=False) + +class CreaturePower3(Base3): + __tablename__ = "creature_power" + + id = Column(Integer, primary_key=True) + creature = Column( + Integer, ForeignKey('creature.id'), nullable=False, index=True) + name = Column(Unicode) + description = Column(Unicode) + +class Level3(Base3): + __tablename__ = "level" + + id = Column(Integer, primary_key=True) + name = Column(Unicode) + description = Column(UnicodeText) + +class LevelExit3(Base3): + __tablename__ = "level_exit" + + id = Column(Integer, primary_key=True) + name = Column(Unicode) + from_level = Column( + Integer, ForeignKey('level.id'), nullable=False, index=True) + to_level = Column( + Integer, ForeignKey('level.id'), nullable=False, index=True) + + +SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] + + +@RegisterMigration(4, FULL_MIGRATIONS) +def creature_num_legs_to_num_limbs(db_conn): + pass + +@RegisterMigration(5, FULL_MIGRATIONS) +def level_exit_index_from_and_to_level(db_conn): + pass + +@RegisterMigration(6, FULL_MIGRATIONS) +def creature_power_index_creature(db_conn): + pass -- cgit v1.2.3 From 129c36be6f29977ca18ae719c1d3a5c2aad25d89 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 Jan 2012 11:36:00 -0600 Subject: Might as well call it "set2 migrations" --- mediagoblin/tests/test_sql_migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 32950d38..8682e69d 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -119,7 +119,7 @@ def level_exits_new_table(db_conn): # A hack! At this point we freeze-fame and get just a partial list of # migrations -PARTIAL_MIGRATIONS = copy.copy(FULL_MIGRATIONS) +SET2_MIGRATIONS = copy.copy(FULL_MIGRATIONS) ####################################################### # Migration set 3: Final migrations -- cgit v1.2.3 From 89694d6d69c855f1dbaaa725867ab070cc7b2490 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 Jan 2012 14:55:07 -0600 Subject: More test migration work. Closing to working migrations for set 2... Also, this file is written in 2012, correct that ;) --- mediagoblin/tests/test_sql_migrations.py | 67 +++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 8682e69d..0f1f02bd 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2012, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -18,9 +18,10 @@ import copy from sqlalchemy import ( Table, Column, MetaData, - Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, - UniqueConstraint, PickleType) + Integer, Float, Unicode, UnicodeText, DateTime, Boolean, + ForeignKey, UniqueConstraint, PickleType) from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.sql import select, insert from migrate import changeset from mediagoblin.db.sql.base import GMGTableBase @@ -77,6 +78,7 @@ class CreaturePower2(Base2): Integer, ForeignKey('creature.id'), nullable=False) name = Column(Unicode) description = Column(Unicode) + hitpower = Column(Integer, nullable=False) class Level2(Base2): __tablename__ = "level" @@ -109,11 +111,61 @@ def creature_remove_is_demon(db_conn): @RegisterMigration(2, FULL_MIGRATIONS) def creature_powers_new_table(db_conn): - pass + metadata = MetaData() + creature_powers = Table( + 'creature_power', metadata, + Column('id', Integer, primary_key=True), + Column('creature', + Integer, ForeignKey('creature.id'), nullable=False), + Column('name', Unicode), + Column('description', Unicode), + Column('hitpower', Integer, nullable=False)) + metadata.create_all(db_conn.engine) + @RegisterMigration(3, FULL_MIGRATIONS) def level_exits_new_table(db_conn): - pass + # First, create the table + # ----------------------- + metadata = MetaData() + level_exits = Table( + 'level_exit', metadata, + Column('id', Integer, primary_key=True), + Column('name', Unicode), + Column('from_level', + Integer, ForeignKey('level.id'), nullable=False), + Column('to_level', + Integer, ForeignKey('level.id'), nullable=False)) + metadata.create_all(db_conn.engine) + + # And now, convert all the old exit pickles to new level exits + # ------------------------------------------------------------ + + # Minimal representation of level table. + # Not auto-introspecting here because of pickle table. I'm not + # sure sqlalchemy can auto-introspect pickle columns. + levels = Table( + 'level', metadata, + Column('id', Integer, primary_key=True), + Column('exits', PickleType)) + + # query over and insert + result = db_conn.execute( + select([levels], levels.c.exits!=None)) + + for level in result: + this_exit = level['exits'] + + # Insert the level exit + db_conn.execute( + level_exits.insert().values( + name=this_exit['name'], + from_level=this_exit['from_level'], + to_level=this_exit['to_level'])) + + # Finally, drop the old level exits pickle table + # ---------------------------------------------- + # A hack! At this point we freeze-fame and get just a partial list of @@ -142,6 +194,7 @@ class CreaturePower3(Base3): Integer, ForeignKey('creature.id'), nullable=False, index=True) name = Column(Unicode) description = Column(Unicode) + hitpower = Column(Float, nullable=False) class Level3(Base3): __tablename__ = "level" @@ -175,3 +228,7 @@ def level_exit_index_from_and_to_level(db_conn): @RegisterMigration(6, FULL_MIGRATIONS) def creature_power_index_creature(db_conn): pass + +@RegisterMigration(7, FULL_MIGRATIONS) +def creature_power_hitpower_to_float(db_conn): + pass -- cgit v1.2.3 From 473e06053c45de534d1e9e5d94f48cf0188856af Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 Jan 2012 15:43:59 -0600 Subject: binding migration metadata to engine, and level_exits_new_table should now work --- mediagoblin/tests/test_sql_migrations.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 0f1f02bd..ba9e967a 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -102,16 +102,16 @@ SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2] @RegisterMigration(1, FULL_MIGRATIONS) def creature_remove_is_demon(db_conn): + metadata = MetaData(bind=db_conn.engine) creature_table = Table( - 'creature', MetaData(), + 'creature', metadata, autoload=True, autoload_with=db_conn.engine) - db_conn.execute( - creature_table.drop_column('is_demon')) + creature_table.drop_column('is_demon') @RegisterMigration(2, FULL_MIGRATIONS) def creature_powers_new_table(db_conn): - metadata = MetaData() + metadata = MetaData(bind=db_conn.engine) creature_powers = Table( 'creature_power', metadata, Column('id', Integer, primary_key=True), @@ -127,7 +127,7 @@ def creature_powers_new_table(db_conn): def level_exits_new_table(db_conn): # First, create the table # ----------------------- - metadata = MetaData() + metadata = MetaData(bind=db_conn.engine) level_exits = Table( 'level_exit', metadata, Column('id', Integer, primary_key=True), @@ -165,7 +165,7 @@ def level_exits_new_table(db_conn): # Finally, drop the old level exits pickle table # ---------------------------------------------- - + levels.drop_column('exits') # A hack! At this point we freeze-fame and get just a partial list of -- cgit v1.2.3 From 248b5061ec5671e5dd371c2ea1573e5b10219656 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 15 Jan 2012 16:43:14 -0600 Subject: All theoretical migrations written! --- mediagoblin/tests/test_sql_migrations.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index ba9e967a..d5b9b30e 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -17,7 +17,7 @@ import copy from sqlalchemy import ( - Table, Column, MetaData, + Table, Column, MetaData, Index Integer, Float, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint, PickleType) from sqlalchemy.ext.declarative import declarative_base @@ -219,16 +219,36 @@ SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] @RegisterMigration(4, FULL_MIGRATIONS) def creature_num_legs_to_num_limbs(db_conn): - pass + metadata = MetaData(bind=db_conn.engine) + creature_table = Table( + 'creature', metadata, + autoload=True, autoload_with=db_conn.engine) + creature_table.c.num_legs.alter(name="num_limbs") + @RegisterMigration(5, FULL_MIGRATIONS) def level_exit_index_from_and_to_level(db_conn): - pass + metadata = MetaData(bind=db_conn.engine) + level_exit = Table( + 'level_exit', metadata, + autoload=True, autoload_with=db_conn.engine) + Index('ix_from_level', level_exit.c.from_level).create(engine) + Index('ix_to_exit', level_exit.c.to_exit).create(engine) + @RegisterMigration(6, FULL_MIGRATIONS) def creature_power_index_creature(db_conn): - pass + metadata = MetaData(bind=db_conn.engine) + creature_power = Table( + 'creature_power', metadata, + autoload=True, autoload_with=db_conn.engine) + Index('ix_creature', creature_power.c.creature).create(engine) + @RegisterMigration(7, FULL_MIGRATIONS) def creature_power_hitpower_to_float(db_conn): - pass + metadata = MetaData(bind=db_conn.engine) + creature_power = Table( + 'creature_power', metadata, + autoload=True, autoload_with=db_conn.engine) + creature_power.c.hitpower.alter(type=Float) -- cgit v1.2.3 From 64d280647c1b6c1166b1e096914a590710eb0f4e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 Jan 2012 14:39:24 -0600 Subject: Insert migration1 objects. Also, Level1 id from Integer->Unicode --- mediagoblin/tests/test_sql_migrations.py | 50 +++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index d5b9b30e..50bdbd9d 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -20,6 +20,7 @@ from sqlalchemy import ( Table, Column, MetaData, Index Integer, Float, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint, PickleType) +from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import select, insert from migrate import changeset @@ -48,7 +49,7 @@ class Creature1(Base1): class Level1(Base1): __tablename__ = "level" - id = Column(Integer, primary_key=True) + id = Column(Unicode, primary_key=True) name = Column(Unicode, unique=True, nullable=False, index=True) description = Column(UnicodeText) exits = Column(PickleType) @@ -83,7 +84,7 @@ class CreaturePower2(Base2): class Level2(Base2): __tablename__ = "level" - id = Column(Integer, primary_key=True) + id = Column(Unicode, primary_key=True) name = Column(Unicode) description = Column(UnicodeText) @@ -93,9 +94,9 @@ class LevelExit2(Base2): id = Column(Integer, primary_key=True) name = Column(Unicode) from_level = Column( - Integer, ForeignKey('level.id'), nullable=False) + Unicode, ForeignKey('level.id'), nullable=False) to_level = Column( - Integer, ForeignKey('level.id'), nullable=False) + Unicode, ForeignKey('level.id'), nullable=False) SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2] @@ -199,7 +200,7 @@ class CreaturePower3(Base3): class Level3(Base3): __tablename__ = "level" - id = Column(Integer, primary_key=True) + id = Column(Unicode, primary_key=True) name = Column(Unicode) description = Column(UnicodeText) @@ -209,9 +210,9 @@ class LevelExit3(Base3): id = Column(Integer, primary_key=True) name = Column(Unicode) from_level = Column( - Integer, ForeignKey('level.id'), nullable=False, index=True) + Unicode, ForeignKey('level.id'), nullable=False, index=True) to_level = Column( - Integer, ForeignKey('level.id'), nullable=False, index=True) + Unicode, ForeignKey('level.id'), nullable=False, index=True) SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] @@ -252,3 +253,38 @@ def creature_power_hitpower_to_float(db_conn): 'creature_power', metadata, autoload=True, autoload_with=db_conn.engine) creature_power.c.hitpower.alter(type=Float) + + +def _insert_migration1_objects(session): + # Insert creatures + session.add_all( + [Creature1(name='centipede', + num_legs=100, + is_demon=False), + Creature1(name='wolf', + num_legs=4, + is_demon=False), + # don't ask me what a wizardsnake is. + Creature1(name='wizardsnake', + num_legs=0, + is_demon=True)]) + + session.add_all( + [Level1(id='necroplex', + name='The Necroplex', + description='A complex full of pure deathzone.', + exits={ + 'deathwell': 'evilstorm', + 'portal': 'central_park'}), + Level1(id='evilstorm', + name='Evil Storm', + description='A storm full of pure evil.', + exits={}), # you can't escape the evilstorm + Level1(id='central_park' + name='Central Park, NY, NY', + description="New York's friendly Central Park.", + exits={ + 'portal': 'necroplex'})]) + + session.commit() + -- cgit v1.2.3 From d74a9483ded26c575686b751e47c1e2a6f395fef Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 Jan 2012 16:22:25 -0600 Subject: Theoretical full set of migration2 objects to insert for testing --- mediagoblin/tests/test_sql_migrations.py | 77 +++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 50bdbd9d..4d58cfbf 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -20,7 +20,7 @@ from sqlalchemy import ( Table, Column, MetaData, Index Integer, Float, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint, PickleType) -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import select, insert from migrate import changeset @@ -70,6 +70,7 @@ class Creature2(Base2): id = Column(Integer, primary_key=True) name = Column(Unicode, unique=True, nullable=False, index=True) num_legs = Column(Integer, nullable=False) + magical_powers = relationship("CreaturePower2") class CreaturePower2(Base2): __tablename__ = "creature_power" @@ -196,6 +197,7 @@ class CreaturePower3(Base3): name = Column(Unicode) description = Column(Unicode) hitpower = Column(Float, nullable=False) + magical_powers = relationship("CreaturePower3") class Level3(Base3): __tablename__ = "level" @@ -269,6 +271,7 @@ def _insert_migration1_objects(session): num_legs=0, is_demon=True)]) + # Insert levels session.add_all( [Level1(id='necroplex', name='The Necroplex', @@ -288,3 +291,75 @@ def _insert_migration1_objects(session): session.commit() + +def _insert_migration2_objects(session): + # Insert creatures + session.add_all( + [Creature2( + name='centipede', + num_legs=100), + Creature2( + name='wolf', + num_legs=4, + magical_powers = [ + CreaturePower2( + name="ice breath", + description="A blast of icy breath!", + hitpower=20), + CreaturePower2( + name="death stare", + description="A frightening stare, for sure!", + hitpower=45)]), + Creature2( + name='wizardsnake', + num_legs=0, + magical_powers=[ + CreaturePower2( + name='death_rattle', + description='A rattle... of DEATH!', + hitpower=1000), + CreaturePower2( + name='sneaky_stare', + description="The sneakiest stare you've ever seen!" + hitpower=300), + CreaturePower2( + name='slithery_smoke', + description="A blast of slithery, slithery smoke.", + hitpower=10), + CreaturePower2( + name='treacherous_tremors', + description="The ground shakes beneath footed animals!", + hitpower=0)])]) + + # Insert levels + session.add_all( + [Level2(id='necroplex', + name='The Necroplex', + description='A complex full of pure deathzone.'), + Level2(id='evilstorm', + name='Evil Storm', + description='A storm full of pure evil.', + exits=[]), # you can't escape the evilstorm + Level2(id='central_park' + name='Central Park, NY, NY', + description="New York's friendly Central Park.")]) + + # necroplex exits + session.add_all( + [LevelExit2(name='deathwell', + from_level='necroplex', + to_level='evilstorm'), + LevelExit2(name='portal', + from_level='necroplex', + to_level='central_park')]) + + # there are no evilstorm exits because there is no exit from the + # evilstorm + + # central park exits + session.add_all( + [LevelExit2(name='portal', + from_level='central_park', + to_level='necroplex')] + + session.commit() -- cgit v1.2.3 From 356654deb878d667806c347e47500a2dd0dadb09 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 Jan 2012 16:40:51 -0600 Subject: Docstrings for stage 2 migrations --- mediagoblin/tests/test_sql_migrations.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 4d58cfbf..ccaf60ba 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -104,6 +104,10 @@ SET2_MODELS = [Creature2, CreaturePower2, Level2, LevelExit2] @RegisterMigration(1, FULL_MIGRATIONS) def creature_remove_is_demon(db_conn): + """ + Remove the is_demon field from the creature model. We don't need + it! + """ metadata = MetaData(bind=db_conn.engine) creature_table = Table( 'creature', metadata, @@ -113,6 +117,11 @@ def creature_remove_is_demon(db_conn): @RegisterMigration(2, FULL_MIGRATIONS) def creature_powers_new_table(db_conn): + """ + Add a new table for creature powers. Nothing needs to go in it + yet though as there wasn't anything that previously held this + information + """ metadata = MetaData(bind=db_conn.engine) creature_powers = Table( 'creature_power', metadata, @@ -127,6 +136,10 @@ def creature_powers_new_table(db_conn): @RegisterMigration(3, FULL_MIGRATIONS) def level_exits_new_table(db_conn): + """ + Make a new table for level exits and move the previously pickled + stuff over to here (then drop the old unneeded table) + """ # First, create the table # ----------------------- metadata = MetaData(bind=db_conn.engine) @@ -258,6 +271,9 @@ def creature_power_hitpower_to_float(db_conn): def _insert_migration1_objects(session): + """ + Test objects to insert for the first set of things + """ # Insert creatures session.add_all( [Creature1(name='centipede', @@ -293,6 +309,9 @@ def _insert_migration1_objects(session): def _insert_migration2_objects(session): + """ + Test objects to insert for the second set of things + """ # Insert creatures session.add_all( [Creature2( -- cgit v1.2.3 From d6cdf64b4f498fabfcf8262c3f444b1d4c2147df Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 16 Jan 2012 16:59:14 -0600 Subject: Wrote some (semi-silly) descriptions of each migration --- mediagoblin/tests/test_sql_migrations.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index ccaf60ba..4117ce0c 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -235,6 +235,11 @@ SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] @RegisterMigration(4, FULL_MIGRATIONS) def creature_num_legs_to_num_limbs(db_conn): + """ + Turns out we're tracking all sorts of limbs, not "legs" + specifically. Humans would be 4 here, for instance. So we + renamed the column. + """ metadata = MetaData(bind=db_conn.engine) creature_table = Table( 'creature', metadata, @@ -244,6 +249,9 @@ def creature_num_legs_to_num_limbs(db_conn): @RegisterMigration(5, FULL_MIGRATIONS) def level_exit_index_from_and_to_level(db_conn): + """ + Index the from and to levels of the level exit table. + """ metadata = MetaData(bind=db_conn.engine) level_exit = Table( 'level_exit', metadata, @@ -254,6 +262,9 @@ def level_exit_index_from_and_to_level(db_conn): @RegisterMigration(6, FULL_MIGRATIONS) def creature_power_index_creature(db_conn): + """ + Index our foreign key relationship to the creatures + """ metadata = MetaData(bind=db_conn.engine) creature_power = Table( 'creature_power', metadata, @@ -263,6 +274,13 @@ def creature_power_index_creature(db_conn): @RegisterMigration(7, FULL_MIGRATIONS) def creature_power_hitpower_to_float(db_conn): + """ + Convert hitpower column on creature power table from integer to + float. + + Turns out we want super precise values of how much hitpower there + really is. + """ metadata = MetaData(bind=db_conn.engine) creature_power = Table( 'creature_power', metadata, -- cgit v1.2.3 From 780fdd7bd6c88b55ee7058d8156a0d233d997236 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 Jan 2012 21:30:47 -0600 Subject: import changeset into sql models --- mediagoblin/db/sql/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index ed733aff..41b8b490 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -29,6 +29,13 @@ from mediagoblin.db.sql.extratypes import PathTupleWithSlashes from mediagoblin.db.sql.base import Base, DictReadAttrProxy from mediagoblin.db.mixin import UserMixin, MediaEntryMixin +# It's actually kind of annoying how sqlalchemy-migrate does this, if +# I understand it right, but whatever. Anyway, don't remove this :P +# +# We could do migration calls more manually instead of relying on +# this import-based meddling... +from migrate import changeset + class SimpleFieldAlias(object): """An alias for any field""" -- cgit v1.2.3 From dc3db4681f0e3c99914dac99945a399a045f895f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 19 Jan 2012 21:32:37 -0600 Subject: Insert migration objects round 3 --- mediagoblin/tests/test_sql_migrations.py | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 4117ce0c..96324d77 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -400,3 +400,90 @@ def _insert_migration2_objects(session): to_level='necroplex')] session.commit() + + +def _insert_migration3_objects(session): + """ + Test objects to insert for the third set of things + """ + # Insert creatures + session.add_all( + [Creature3( + name='centipede', + num_limbs=100), + Creature3( + name='wolf', + num_limbs=4, + magical_powers = [ + CreaturePower3( + name="ice breath", + description="A blast of icy breath!", + hitpower=20.0), + CreaturePower3( + name="death stare", + description="A frightening stare, for sure!", + hitpower=45.0)]), + Creature3( + name='wizardsnake', + num_limbs=0, + magical_powers=[ + CreaturePower3( + name='death_rattle', + description='A rattle... of DEATH!', + hitpower=1000.0), + CreaturePower3( + name='sneaky_stare', + description="The sneakiest stare you've ever seen!" + hitpower=300.0), + CreaturePower3( + name='slithery_smoke', + description="A blast of slithery, slithery smoke.", + hitpower=10.0), + CreaturePower3( + name='treacherous_tremors', + description="The ground shakes beneath footed animals!", + hitpower=0.0)])], + # annnnnd one more to test a floating point hitpower + Creature3( + name='deity', + numb_limbs=30, + magical_powers[ + CreaturePower3( + name='smite', + description='Smitten by holy wrath!', + hitpower=9999.9)) + + # Insert levels + session.add_all( + [Level3(id='necroplex', + name='The Necroplex', + description='A complex full of pure deathzone.'), + Level3(id='evilstorm', + name='Evil Storm', + description='A storm full of pure evil.', + exits=[]), # you can't escape the evilstorm + Level3(id='central_park' + name='Central Park, NY, NY', + description="New York's friendly Central Park.")]) + + # necroplex exits + session.add_all( + [LevelExit3(name='deathwell', + from_level='necroplex', + to_level='evilstorm'), + LevelExit3(name='portal', + from_level='necroplex', + to_level='central_park')]) + + # there are no evilstorm exits because there is no exit from the + # evilstorm + + # central park exits + session.add_all( + [LevelExit3(name='portal', + from_level='central_park', + to_level='necroplex')] + + session.commit() + + -- cgit v1.2.3 From 09e2c48701f8a3fb00da68a61935e75c46a3ec3b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 21 Jan 2012 16:14:32 -0600 Subject: Wrote up some scaffolding for the actual tests --- mediagoblin/tests/test_sql_migrations.py | 56 ++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 96324d77..d94888e9 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -397,7 +397,7 @@ def _insert_migration2_objects(session): session.add_all( [LevelExit2(name='portal', from_level='central_park', - to_level='necroplex')] + to_level='necroplex')]) session.commit() @@ -451,7 +451,7 @@ def _insert_migration3_objects(session): CreaturePower3( name='smite', description='Smitten by holy wrath!', - hitpower=9999.9)) + hitpower=9999.9)))) # Insert levels session.add_all( @@ -482,8 +482,58 @@ def _insert_migration3_objects(session): session.add_all( [LevelExit3(name='portal', from_level='central_park', - to_level='necroplex')] + to_level='necroplex')]) session.commit() +def create_test_engine(): + from sqlalchemy import create_engine + engine = create_engine('sqlite:///:memory:', echo=False) + return engine + + +def test_set1_to_set3(): + # Create / connect to database + # Create tables by migrating on empty initial set + + # Install the initial set + # Check version in database + # Sanity check a few things in the database + + # Migrate + # Make sure version matches expected + # Check all things in database match expected + pass + + +def test_set2_to_set3(): + # Create / connect to database + # Create tables by migrating on empty initial set + + # Install the initial set + # Check version in database + # Sanity check a few things in the database + + # Migrate + # Make sure version matches expected + # Check all things in database match expected + pass + + +def test_set1_to_set2_to_set3(): + # Create / connect to database + # Create tables by migrating on empty initial set + + # Install the initial set + # Check version in database + # Sanity check a few things in the database + + # Migrate + # Make sure version matches expected + # Check all things in database match expected + + # Migrate again + # Make sure version matches expected again + # Check all things in database match expected again + pass -- cgit v1.2.3 From 40f0996ab9160fe586e3d8f3fd22412ce6a34d27 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Fri, 27 Jan 2012 18:19:34 -0600 Subject: A ton more work on the SQL migration unit tests... --- mediagoblin/tests/test_sql_migrations.py | 90 ++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index d94888e9..4e0a89d9 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -51,7 +51,7 @@ class Level1(Base1): id = Column(Unicode, primary_key=True) name = Column(Unicode, unique=True, nullable=False, index=True) - description = Column(UnicodeText) + description = Column(Unicode) exits = Column(PickleType) SET1_MODELS = [Creature1, Level1] @@ -87,7 +87,7 @@ class Level2(Base2): id = Column(Unicode, primary_key=True) name = Column(Unicode) - description = Column(UnicodeText) + description = Column(Unicode) class LevelExit2(Base2): __tablename__ = "level_exit" @@ -217,7 +217,7 @@ class Level3(Base3): id = Column(Unicode, primary_key=True) name = Column(Unicode) - description = Column(UnicodeText) + description = Column(Unicode) class LevelExit3(Base3): __tablename__ = "level_exit" @@ -487,21 +487,101 @@ def _insert_migration3_objects(session): session.commit() +def CollectingPrinter(object): + def __init__(self): + self.collection = [] + + def __call__(self, string): + self.collection.append(string) + + @property + def combined_string(self): + return u''.join(self.collection) + + def create_test_engine(): from sqlalchemy import create_engine engine = create_engine('sqlite:///:memory:', echo=False) - return engine + sqlalchemy.orm import sessionmaker + Session = sessionmaker(bind=engine) + return engine, Session + + +def assert_col_type(column, class): + assert isinstance(column.type, class) def test_set1_to_set3(): # Create / connect to database + engine, Session = create_test_engine() # Create tables by migrating on empty initial set + printer = CollectingPrinter + migration_manager = MigrationManager( + '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), + printer) + # Check latest migration and database current migration + assert migration_manager.latest_migration == 0 + assert migration_manager.database_current_migration == None + + result = migration_manager.init_or_migrate() + # Make sure output was "inited" + assert result == u'inited' + # Check output + assert printer.combined_string == "-> Initializing __main__... done.\n" + # Check version in database + assert migration_manager.latest_migration == 0 + assert migration_manager.database_current_migration == 0 # Install the initial set + _insert_migration1_objects(Session()) + # Try to "re-migrate" with same manager settings... nothing should happen + migration_manager = MigrationManager( + '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), + printer) + assert migration_manager.init_or_migrate() == None + # Check version in database - # Sanity check a few things in the database + assert migration_manager.latest_migration == 0 + assert migration_manager.database_current_migration == 0 + + # Sanity check a few things in the database... + metadata = MetaData(bind=db_conn.engine) + + # Check the structure of the creature table + creature_table = Table( + 'creature', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(creature_table.c.keys()) == set( + ['id', 'name', 'num_legs', 'is_demon']) + assert_col_type(creature_table.c.id, Integer) + assert_col_type(creature_table.c.name, Unicode) + assert creature_table.c.name.nullable is False + assert creature_table.c.name.index is True + assert creature_table.c.name.unique is True + assert_col_type(creature_table.c.num_legs, Integer) + assert creature_table.c.num_legs.nullable is False + assert_col_type(creature_table.c.is_demon, Boolean) + + # Check the structure of the level table + level_table = Table( + 'level', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(level_table.c.keys()) == set( + ['id', 'name', 'description', 'exits']) + assert_col_type(level_table.c.id, Integer) + assert_col_type(level_table.c.name, Unicode) + assert level_table.c.name.nullable is False + assert level_table.c.name.index is True + assert level_table.c.name.unique is True + assert_col_type(level_table.c.description, Unicode) + # Skipping exits... Not sure if we can detect pickletype, not a + # big deal regardless. + + # Now check to see if stuff seems to be in there. # Migrate + # Make sure result was "migrated" + # Check output to user # Make sure version matches expected # Check all things in database match expected pass -- cgit v1.2.3 From 94eff10deb62f6f52c270d0926e0fa74e44001a7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 08:58:34 -0600 Subject: unicode stuff and more bits on the actual migration method --- mediagoblin/tests/test_sql_migrations.py | 303 ++++++++++++++++++++++--------- 1 file changed, 214 insertions(+), 89 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 4e0a89d9..57a83ec5 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -50,7 +50,7 @@ class Level1(Base1): __tablename__ = "level" id = Column(Unicode, primary_key=True) - name = Column(Unicode, unique=True, nullable=False, index=True) + name = Column(Unicode)x description = Column(Unicode) exits = Column(PickleType) @@ -244,7 +244,7 @@ def creature_num_legs_to_num_limbs(db_conn): creature_table = Table( 'creature', metadata, autoload=True, autoload_with=db_conn.engine) - creature_table.c.num_legs.alter(name="num_limbs") + creature_table.c.num_legs.alter(name=u"num_limbs") @RegisterMigration(5, FULL_MIGRATIONS) @@ -294,32 +294,32 @@ def _insert_migration1_objects(session): """ # Insert creatures session.add_all( - [Creature1(name='centipede', + [Creature1(name=u'centipede', num_legs=100, is_demon=False), - Creature1(name='wolf', + Creature1(name=u'wolf', num_legs=4, is_demon=False), # don't ask me what a wizardsnake is. - Creature1(name='wizardsnake', + Creature1(name=u'wizardsnake', num_legs=0, is_demon=True)]) # Insert levels session.add_all( - [Level1(id='necroplex', - name='The Necroplex', - description='A complex full of pure deathzone.', + [Level1(id=u'necroplex', + name=u'The Necroplex', + description=u'A complex full of pure deathzone.', exits={ 'deathwell': 'evilstorm', 'portal': 'central_park'}), - Level1(id='evilstorm', - name='Evil Storm', - description='A storm full of pure evil.', + Level1(id=u'evilstorm', + name=u'Evil Storm', + description=u'A storm full of pure evil.', exits={}), # you can't escape the evilstorm - Level1(id='central_park' - name='Central Park, NY, NY', - description="New York's friendly Central Park.", + Level1(id=u'central_park' + name=u'Central Park, NY, NY', + description=u"New York's friendly Central Park.", exits={ 'portal': 'necroplex'})]) @@ -333,71 +333,71 @@ def _insert_migration2_objects(session): # Insert creatures session.add_all( [Creature2( - name='centipede', + name=u'centipede', num_legs=100), Creature2( - name='wolf', + name=u'wolf', num_legs=4, magical_powers = [ CreaturePower2( - name="ice breath", - description="A blast of icy breath!", + name=u"ice breath", + description=u"A blast of icy breath!", hitpower=20), CreaturePower2( - name="death stare", - description="A frightening stare, for sure!", + name=u"death stare", + description=u"A frightening stare, for sure!", hitpower=45)]), Creature2( - name='wizardsnake', + name=u'wizardsnake', num_legs=0, magical_powers=[ CreaturePower2( - name='death_rattle', - description='A rattle... of DEATH!', + name=u'death_rattle', + description=u'A rattle... of DEATH!', hitpower=1000), CreaturePower2( - name='sneaky_stare', - description="The sneakiest stare you've ever seen!" + name=u'sneaky_stare', + description=u"The sneakiest stare you've ever seen!" hitpower=300), CreaturePower2( - name='slithery_smoke', - description="A blast of slithery, slithery smoke.", + name=u'slithery_smoke', + description=u"A blast of slithery, slithery smoke.", hitpower=10), CreaturePower2( - name='treacherous_tremors', - description="The ground shakes beneath footed animals!", + name=u'treacherous_tremors', + description=u"The ground shakes beneath footed animals!", hitpower=0)])]) # Insert levels session.add_all( - [Level2(id='necroplex', - name='The Necroplex', - description='A complex full of pure deathzone.'), - Level2(id='evilstorm', - name='Evil Storm', - description='A storm full of pure evil.', + [Level2(id=u'necroplex', + name=u'The Necroplex', + description=u'A complex full of pure deathzone.'), + Level2(id=u'evilstorm', + name=u'Evil Storm', + description=u'A storm full of pure evil.', exits=[]), # you can't escape the evilstorm - Level2(id='central_park' - name='Central Park, NY, NY', - description="New York's friendly Central Park.")]) + Level2(id=u'central_park' + name=u'Central Park, NY, NY', + description=u"New York's friendly Central Park.")]) # necroplex exits session.add_all( - [LevelExit2(name='deathwell', - from_level='necroplex', - to_level='evilstorm'), - LevelExit2(name='portal', - from_level='necroplex', - to_level='central_park')]) + [LevelExit2(name=u'deathwell', + from_level=u'necroplex', + to_level=u'evilstorm'), + LevelExit2(name=u'portal', + from_level=u'necroplex', + to_level=u'central_park')]) # there are no evilstorm exits because there is no exit from the # evilstorm # central park exits session.add_all( - [LevelExit2(name='portal', - from_level='central_park', - to_level='necroplex')]) + [LevelExit2(name=u'portal', + from_level=u'central_park', + to_level=u'necroplex')]) session.commit() @@ -409,80 +409,80 @@ def _insert_migration3_objects(session): # Insert creatures session.add_all( [Creature3( - name='centipede', + name=u'centipede', num_limbs=100), Creature3( - name='wolf', + name=u'wolf', num_limbs=4, magical_powers = [ CreaturePower3( - name="ice breath", - description="A blast of icy breath!", + name=u"ice breath", + description=u"A blast of icy breath!", hitpower=20.0), CreaturePower3( - name="death stare", - description="A frightening stare, for sure!", + name=u"death stare", + description=u"A frightening stare, for sure!", hitpower=45.0)]), Creature3( - name='wizardsnake', + name=u'wizardsnake', num_limbs=0, magical_powers=[ CreaturePower3( - name='death_rattle', - description='A rattle... of DEATH!', + name=u'death_rattle', + description=u'A rattle... of DEATH!', hitpower=1000.0), CreaturePower3( - name='sneaky_stare', - description="The sneakiest stare you've ever seen!" + name=u'sneaky_stare', + description=u"The sneakiest stare you've ever seen!" hitpower=300.0), CreaturePower3( - name='slithery_smoke', - description="A blast of slithery, slithery smoke.", + name=u'slithery_smoke', + description=u"A blast of slithery, slithery smoke.", hitpower=10.0), CreaturePower3( - name='treacherous_tremors', - description="The ground shakes beneath footed animals!", + name=u'treacherous_tremors', + description=u"The ground shakes beneath footed animals!", hitpower=0.0)])], # annnnnd one more to test a floating point hitpower Creature3( - name='deity', + name=u'deity', numb_limbs=30, magical_powers[ CreaturePower3( - name='smite', - description='Smitten by holy wrath!', + name=u'smite', + description=u'Smitten by holy wrath!', hitpower=9999.9)))) # Insert levels session.add_all( - [Level3(id='necroplex', - name='The Necroplex', - description='A complex full of pure deathzone.'), - Level3(id='evilstorm', - name='Evil Storm', - description='A storm full of pure evil.', + [Level3(id=u'necroplex', + name=u'The Necroplex', + description=u'A complex full of pure deathzone.'), + Level3(id=u'evilstorm', + name=u'Evil Storm', + description=u'A storm full of pure evil.', exits=[]), # you can't escape the evilstorm - Level3(id='central_park' - name='Central Park, NY, NY', - description="New York's friendly Central Park.")]) + Level3(id=u'central_park' + name=u'Central Park, NY, NY', + description=u"New York's friendly Central Park.")]) # necroplex exits session.add_all( - [LevelExit3(name='deathwell', - from_level='necroplex', - to_level='evilstorm'), - LevelExit3(name='portal', - from_level='necroplex', - to_level='central_park')]) + [LevelExit3(name=u'deathwell', + from_level=u'necroplex', + to_level=u'evilstorm'), + LevelExit3(name=u'portal', + from_level=u'necroplex', + to_level=u'central_park')]) # there are no evilstorm exits because there is no exit from the # evilstorm # central park exits session.add_all( - [LevelExit3(name='portal', - from_level='central_park', - to_level='necroplex')]) + [LevelExit3(name=u'portal', + from_level=u'central_park', + to_level=u'necroplex')]) session.commit() @@ -513,27 +513,38 @@ def assert_col_type(column, class): def test_set1_to_set3(): # Create / connect to database + # ---------------------------- + engine, Session = create_test_engine() + # Create tables by migrating on empty initial set + # ----------------------------------------------- + printer = CollectingPrinter migration_manager = MigrationManager( '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), printer) + # Check latest migration and database current migration assert migration_manager.latest_migration == 0 assert migration_manager.database_current_migration == None result = migration_manager.init_or_migrate() + # Make sure output was "inited" assert result == u'inited' # Check output - assert printer.combined_string == "-> Initializing __main__... done.\n" + assert printer.combined_string == ( + "-> Initializing main mediagoblin tables... done.\n") # Check version in database assert migration_manager.latest_migration == 0 assert migration_manager.database_current_migration == 0 # Install the initial set + # ----------------------- + _insert_migration1_objects(Session()) + # Try to "re-migrate" with same manager settings... nothing should happen migration_manager = MigrationManager( '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), @@ -568,22 +579,136 @@ def test_set1_to_set3(): autoload=True, autoload_with=db_conn.engine) assert set(level_table.c.keys()) == set( ['id', 'name', 'description', 'exits']) - assert_col_type(level_table.c.id, Integer) + assert_col_type(level_table.c.id, Unicode) + assert level_table.c.id.primary_key is True assert_col_type(level_table.c.name, Unicode) - assert level_table.c.name.nullable is False - assert level_table.c.name.index is True - assert level_table.c.name.unique is True assert_col_type(level_table.c.description, Unicode) # Skipping exits... Not sure if we can detect pickletype, not a # big deal regardless. # Now check to see if stuff seems to be in there. + creature = session.query(Creature1).filter_by( + name=u'centipede').one() + assert creature.num_legs == 100 + assert creature.is_demon == False + + creature = session.query(Creature1).filter_by( + name=u'wolf').one() + assert creature.num_legs == 4 + assert creature.is_demon == False + + creature = session.query(Creature1).filter_by( + name=u'wizardsnake').one() + assert creature.num_legs == 0 + assert creature.is_demon == True + + level = session.query(Level1).filter_by( + id=u'necroplex') + assert level.name == u'The Necroplex' + assert level.description == u'A complex of pure deathzone.' + assert level.exits == { + 'deathwell': 'evilstorm', + 'portal': 'central_park'} + + level = session.query(Level1).filter_by( + id=u'evilstorm') + assert level.name == u'Evil Storm' + assert level.description == u'A storm full of pure evil.' + assert level.exits == {} # You still can't escape the evilstorm! + + level = session.query(Level1).filter_by( + id=u'central_park') + assert level.name == u'Central Park, NY, NY' + assert level.description == u"New York's friendly Central Park." + assert level.exits == { + 'portal': 'necroplex'} + + # Create new migration manager, but make sure the db migration + # isn't said to be updated yet + printer = CollectingPrinter + migration_manager = MigrationManager( + '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), + printer) + + assert migration_manager.latest_migration == 3 + assert migration_manager.database_current_migration == 0 # Migrate + result = migration_manager.init_or_migrate() + # Make sure result was "migrated" - # Check output to user + assert result == u'migrated' + + # TODO: Check output to user + assert printer.combined_string == """\ +-> Updating main mediagoblin tables... + + Running migration 1, "creature_remove_is_demon"... done. + + Running migration 2, "creature_powers_new_table"... done. + + Running migration 3, "level_exits_new_table"... done.""" + # Make sure version matches expected + migration_manager = MigrationManager( + '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), + printer) + assert migration_manager.latest_migration == 3 + assert migration_manager.database_current_migration == 3 + # Check all things in database match expected + + # Check the creature table + creature_table = Table( + 'creature', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(creature_table.c.keys()) == set( + ['id', 'name', 'num_legs']) + assert_col_type(creature_table.c.id, Integer) + assert_col_type(creature_table.c.name, Unicode) + assert creature_table.c.name.nullable is False + assert creature_table.c.name.index is True + assert creature_table.c.name.unique is True + assert_col_type(creature_table.c.num_legs, Integer) + assert creature_table.c.num_legs.nullable is False + + # Check the CreaturePower table + creature_power_table = Table( + 'creature_power', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(creature_power_table.c.keys()) == set( + ['id', 'creature', 'name', 'description', 'hitpower']) + assert_col_type(creature_power_table.c.id, Integer) + assert_col_type(creature_power_table.c.creature, Integer) + assert creature_power_table.c.creature.nullable is False + assert_col_type(creature_power_table.c.name, Unicode) + assert_col_type(creature_power_table.c.description, Unicode) + assert_col_type(creature_power_table.c.hitpower, Integer) + assert creature_power_table.c.hitpower.nullable is False + + # Check the structure of the level table + level_table = Table( + 'level', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(level_table.c.keys()) == set( + ['id', 'name', 'description']) + assert_col_type(level_table.c.id, Unicode) + assert level_table.c.id.primary_key is True + assert_col_type(level_table.c.name, Unicode) + assert_col_type(level_table.c.description, Unicode) + + # Check the structure of the level_exits table + level_exit_table = Table( + 'level_exit', metadata, + autoload=True, autoload_with=db_conn.engine) + assert set(level_exit_table.c.keys()) == set( + ['id', 'name', 'from_level', 'to_level']) + assert_col_type(level_exit_table.c.id, Integer) + assert_col_type(level_exit_table.c.name, Unicode) + assert_col_type(level_exit_table.c.from_level, Unicode) + assert level_exit_table.c.from_level.nullable is False + assert_col_type(level_exit_table.c.to_level, Unicode) + assert level_exit_table.c.to_level.nullable is False + + # Now check to see if stuff seems to be in there. + pass -- cgit v1.2.3 From 690b51faa7aa8723bb08639f21b60dacd5696fcd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 13:14:56 -0600 Subject: Closer to the end of this migration test... --- mediagoblin/tests/test_sql_migrations.py | 72 +++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 57a83ec5..33580432 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -660,7 +660,7 @@ def test_set1_to_set3(): 'creature', metadata, autoload=True, autoload_with=db_conn.engine) assert set(creature_table.c.keys()) == set( - ['id', 'name', 'num_legs']) + ['id', 'name', 'num_limbs']) assert_col_type(creature_table.c.id, Integer) assert_col_type(creature_table.c.name, Unicode) assert creature_table.c.name.nullable is False @@ -680,7 +680,7 @@ def test_set1_to_set3(): assert creature_power_table.c.creature.nullable is False assert_col_type(creature_power_table.c.name, Unicode) assert_col_type(creature_power_table.c.description, Unicode) - assert_col_type(creature_power_table.c.hitpower, Integer) + assert_col_type(creature_power_table.c.hitpower, Float) assert creature_power_table.c.hitpower.nullable is False # Check the structure of the level table @@ -704,10 +704,26 @@ def test_set1_to_set3(): assert_col_type(level_exit_table.c.name, Unicode) assert_col_type(level_exit_table.c.from_level, Unicode) assert level_exit_table.c.from_level.nullable is False + assert level_exit_table.c.from_level.indexed is True assert_col_type(level_exit_table.c.to_level, Unicode) assert level_exit_table.c.to_level.nullable is False + assert level_exit_table.c.to_level.indexed is True # Now check to see if stuff seems to be in there. + creature = session.query(Creature1).filter_by( + name=u'centipede').one() + assert creature.num_legs == 100.0 + assert creature.creature_powers == [] + + creature = session.query(Creature1).filter_by( + name=u'wolf').one() + assert creature.num_legs == 4.0 + assert creature.creature_powers == [] + + creature = session.query(Creature1).filter_by( + name=u'wizardsnake').one() + assert creature.num_legs == 0.0 + assert creature.creature_powers == [] pass @@ -741,4 +757,56 @@ def test_set1_to_set2_to_set3(): # Migrate again # Make sure version matches expected again # Check all things in database match expected again + + ##### Set2 + # creature_table = Table( + # 'creature', metadata, + # autoload=True, autoload_with=db_conn.engine) + # assert set(creature_table.c.keys()) == set( + # ['id', 'name', 'num_legs']) + # assert_col_type(creature_table.c.id, Integer) + # assert_col_type(creature_table.c.name, Unicode) + # assert creature_table.c.name.nullable is False + # assert creature_table.c.name.index is True + # assert creature_table.c.name.unique is True + # assert_col_type(creature_table.c.num_legs, Integer) + # assert creature_table.c.num_legs.nullable is False + + # # Check the CreaturePower table + # creature_power_table = Table( + # 'creature_power', metadata, + # autoload=True, autoload_with=db_conn.engine) + # assert set(creature_power_table.c.keys()) == set( + # ['id', 'creature', 'name', 'description', 'hitpower']) + # assert_col_type(creature_power_table.c.id, Integer) + # assert_col_type(creature_power_table.c.creature, Integer) + # assert creature_power_table.c.creature.nullable is False + # assert_col_type(creature_power_table.c.name, Unicode) + # assert_col_type(creature_power_table.c.description, Unicode) + # assert_col_type(creature_power_table.c.hitpower, Integer) + # assert creature_power_table.c.hitpower.nullable is False + + # # Check the structure of the level table + # level_table = Table( + # 'level', metadata, + # autoload=True, autoload_with=db_conn.engine) + # assert set(level_table.c.keys()) == set( + # ['id', 'name', 'description']) + # assert_col_type(level_table.c.id, Unicode) + # assert level_table.c.id.primary_key is True + # assert_col_type(level_table.c.name, Unicode) + # assert_col_type(level_table.c.description, Unicode) + + # # Check the structure of the level_exits table + # level_exit_table = Table( + # 'level_exit', metadata, + # autoload=True, autoload_with=db_conn.engine) + # assert set(level_exit_table.c.keys()) == set( + # ['id', 'name', 'from_level', 'to_level']) + # assert_col_type(level_exit_table.c.id, Integer) + # assert_col_type(level_exit_table.c.name, Unicode) + # assert_col_type(level_exit_table.c.from_level, Unicode) + # assert level_exit_table.c.from_level.nullable is False + # assert_col_type(level_exit_table.c.to_level, Unicode) + pass -- cgit v1.2.3 From 5de0f4daf5cb38606485e84253706b97f78e97ee Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 14:57:42 -0600 Subject: More stuff even yet per sql migration stuff! And still not ready! --- mediagoblin/tests/test_sql_migrations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 33580432..4975945c 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -17,7 +17,7 @@ import copy from sqlalchemy import ( - Table, Column, MetaData, Index + Table, Column, MetaData, Index, Integer, Float, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, UniqueConstraint, PickleType) from sqlalchemy.orm import sessionmaker, relationship @@ -712,17 +712,17 @@ def test_set1_to_set3(): # Now check to see if stuff seems to be in there. creature = session.query(Creature1).filter_by( name=u'centipede').one() - assert creature.num_legs == 100.0 + assert creature.num_limbs == 100.0 assert creature.creature_powers == [] creature = session.query(Creature1).filter_by( name=u'wolf').one() - assert creature.num_legs == 4.0 + assert creature.num_limbs == 4.0 assert creature.creature_powers == [] creature = session.query(Creature1).filter_by( name=u'wizardsnake').one() - assert creature.num_legs == 0.0 + assert creature.num_limbs == 0.0 assert creature.creature_powers == [] pass -- cgit v1.2.3 From caed154af020eb0fadefa955d0a15b836433e3a4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 15:27:45 -0600 Subject: Fixing some obvious errors caught by pyflakes --- mediagoblin/tests/test_sql_migrations.py | 46 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 4975945c..92e99ab1 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -23,6 +23,7 @@ from sqlalchemy import ( from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import select, insert +from sqlalchemy.sql.util import MigrationManager from migrate import changeset from mediagoblin.db.sql.base import GMGTableBase @@ -50,7 +51,7 @@ class Level1(Base1): __tablename__ = "level" id = Column(Unicode, primary_key=True) - name = Column(Unicode)x + name = Column(Unicode) description = Column(Unicode) exits = Column(PickleType) @@ -231,6 +232,7 @@ class LevelExit3(Base3): SET3_MODELS = [Creature3, CreaturePower3, Level3, LevelExit3] +SET3_MIGRATIONS = FULL_MIGRATIONS @RegisterMigration(4, FULL_MIGRATIONS) @@ -256,8 +258,8 @@ def level_exit_index_from_and_to_level(db_conn): level_exit = Table( 'level_exit', metadata, autoload=True, autoload_with=db_conn.engine) - Index('ix_from_level', level_exit.c.from_level).create(engine) - Index('ix_to_exit', level_exit.c.to_exit).create(engine) + Index('ix_from_level', level_exit.c.from_level).create(db_conn.engine) + Index('ix_to_exit', level_exit.c.to_exit).create(db_conn.engine) @RegisterMigration(6, FULL_MIGRATIONS) @@ -269,7 +271,7 @@ def creature_power_index_creature(db_conn): creature_power = Table( 'creature_power', metadata, autoload=True, autoload_with=db_conn.engine) - Index('ix_creature', creature_power.c.creature).create(engine) + Index('ix_creature', creature_power.c.creature).create(db_conn.engine) @RegisterMigration(7, FULL_MIGRATIONS) @@ -317,7 +319,7 @@ def _insert_migration1_objects(session): name=u'Evil Storm', description=u'A storm full of pure evil.', exits={}), # you can't escape the evilstorm - Level1(id=u'central_park' + Level1(id=u'central_park', name=u'Central Park, NY, NY', description=u"New York's friendly Central Park.", exits={ @@ -357,7 +359,7 @@ def _insert_migration2_objects(session): hitpower=1000), CreaturePower2( name=u'sneaky_stare', - description=u"The sneakiest stare you've ever seen!" + description=u"The sneakiest stare you've ever seen!", hitpower=300), CreaturePower2( name=u'slithery_smoke', @@ -377,7 +379,7 @@ def _insert_migration2_objects(session): name=u'Evil Storm', description=u'A storm full of pure evil.', exits=[]), # you can't escape the evilstorm - Level2(id=u'central_park' + Level2(id=u'central_park', name=u'Central Park, NY, NY', description=u"New York's friendly Central Park.")]) @@ -433,7 +435,7 @@ def _insert_migration3_objects(session): hitpower=1000.0), CreaturePower3( name=u'sneaky_stare', - description=u"The sneakiest stare you've ever seen!" + description=u"The sneakiest stare you've ever seen!", hitpower=300.0), CreaturePower3( name=u'slithery_smoke', @@ -447,11 +449,11 @@ def _insert_migration3_objects(session): Creature3( name=u'deity', numb_limbs=30, - magical_powers[ + magical_powers=[ CreaturePower3( name=u'smite', description=u'Smitten by holy wrath!', - hitpower=9999.9)))) + hitpower=9999.9)])) # Insert levels session.add_all( @@ -462,7 +464,7 @@ def _insert_migration3_objects(session): name=u'Evil Storm', description=u'A storm full of pure evil.', exits=[]), # you can't escape the evilstorm - Level3(id=u'central_park' + Level3(id=u'central_park', name=u'Central Park, NY, NY', description=u"New York's friendly Central Park.")]) @@ -502,13 +504,12 @@ def CollectingPrinter(object): def create_test_engine(): from sqlalchemy import create_engine engine = create_engine('sqlite:///:memory:', echo=False) - sqlalchemy.orm import sessionmaker Session = sessionmaker(bind=engine) return engine, Session -def assert_col_type(column, class): - assert isinstance(column.type, class) +def assert_col_type(column, this_class): + assert isinstance(column.type, this_class) def test_set1_to_set3(): @@ -556,12 +557,12 @@ def test_set1_to_set3(): assert migration_manager.database_current_migration == 0 # Sanity check a few things in the database... - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=engine) # Check the structure of the creature table creature_table = Table( 'creature', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(creature_table.c.keys()) == set( ['id', 'name', 'num_legs', 'is_demon']) assert_col_type(creature_table.c.id, Integer) @@ -576,7 +577,7 @@ def test_set1_to_set3(): # Check the structure of the level table level_table = Table( 'level', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(level_table.c.keys()) == set( ['id', 'name', 'description', 'exits']) assert_col_type(level_table.c.id, Unicode) @@ -587,6 +588,8 @@ def test_set1_to_set3(): # big deal regardless. # Now check to see if stuff seems to be in there. + session = Session() + creature = session.query(Creature1).filter_by( name=u'centipede').one() assert creature.num_legs == 100 @@ -658,7 +661,7 @@ def test_set1_to_set3(): # Check the creature table creature_table = Table( 'creature', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(creature_table.c.keys()) == set( ['id', 'name', 'num_limbs']) assert_col_type(creature_table.c.id, Integer) @@ -672,7 +675,7 @@ def test_set1_to_set3(): # Check the CreaturePower table creature_power_table = Table( 'creature_power', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(creature_power_table.c.keys()) == set( ['id', 'creature', 'name', 'description', 'hitpower']) assert_col_type(creature_power_table.c.id, Integer) @@ -686,7 +689,7 @@ def test_set1_to_set3(): # Check the structure of the level table level_table = Table( 'level', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(level_table.c.keys()) == set( ['id', 'name', 'description']) assert_col_type(level_table.c.id, Unicode) @@ -697,7 +700,7 @@ def test_set1_to_set3(): # Check the structure of the level_exits table level_exit_table = Table( 'level_exit', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=engine) assert set(level_exit_table.c.keys()) == set( ['id', 'name', 'from_level', 'to_level']) assert_col_type(level_exit_table.c.id, Integer) @@ -710,6 +713,7 @@ def test_set1_to_set3(): assert level_exit_table.c.to_level.indexed is True # Now check to see if stuff seems to be in there. + session = Session() creature = session.query(Creature1).filter_by( name=u'centipede').one() assert creature.num_limbs == 100.0 -- cgit v1.2.3 From e8e52b3a0b353849cbdbfa70bb44270ec8211e17 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:07:16 -0600 Subject: test_set1_to_set3() now has appropriate amount of code, even if it doesn't run :) --- mediagoblin/tests/test_sql_migrations.py | 45 ++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 92e99ab1..1f97b6ce 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -23,10 +23,10 @@ from sqlalchemy import ( from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import select, insert -from sqlalchemy.sql.util import MigrationManager from migrate import changeset from mediagoblin.db.sql.base import GMGTableBase +from mediagoblin.db.sql.util import MigrationManager, RegisterMigration # This one will get filled with local migrations @@ -512,6 +512,13 @@ def assert_col_type(column, this_class): assert isinstance(column.type, this_class) +def _get_level3_exits(session, level): + return dict( + [(level_exit.name, level_exit.to_level) + for level_exit in + session.query(LevelExit3).filter_by(from_level=level.id)]) + + def test_set1_to_set3(): # Create / connect to database # ---------------------------- @@ -606,7 +613,7 @@ def test_set1_to_set3(): assert creature.is_demon == True level = session.query(Level1).filter_by( - id=u'necroplex') + id=u'necroplex').one() assert level.name == u'The Necroplex' assert level.description == u'A complex of pure deathzone.' assert level.exits == { @@ -614,13 +621,13 @@ def test_set1_to_set3(): 'portal': 'central_park'} level = session.query(Level1).filter_by( - id=u'evilstorm') + id=u'evilstorm').one() assert level.name == u'Evil Storm' assert level.description == u'A storm full of pure evil.' assert level.exits == {} # You still can't escape the evilstorm! level = session.query(Level1).filter_by( - id=u'central_park') + id=u'central_park').one() assert level.name == u'Central Park, NY, NY' assert level.description == u"New York's friendly Central Park." assert level.exits == { @@ -714,22 +721,44 @@ def test_set1_to_set3(): # Now check to see if stuff seems to be in there. session = Session() - creature = session.query(Creature1).filter_by( + creature = session.query(Creature3).filter_by( name=u'centipede').one() assert creature.num_limbs == 100.0 assert creature.creature_powers == [] - creature = session.query(Creature1).filter_by( + creature = session.query(Creature3).filter_by( name=u'wolf').one() assert creature.num_limbs == 4.0 assert creature.creature_powers == [] - creature = session.query(Creature1).filter_by( + creature = session.query(Creature3).filter_by( name=u'wizardsnake').one() assert creature.num_limbs == 0.0 assert creature.creature_powers == [] - pass + level = session.query(Level3).filter_by( + id=u'necroplex').one() + assert level.name == u'The Necroplex' + assert level.description == u'A complex of pure deathzone.' + level_exits = _get_level3_exits(session, level) + assert level_exits == { + u'deathwell': u'evilstorm', + u'portal': u'central_park'} + + level = session.query(Level3).filter_by( + id=u'evilstorm').one() + assert level.name == u'Evil Storm' + assert level.description == u'A storm full of pure evil.' + level_exits = _get_level3_exits(session, level) + assert level_exits == {} # You still can't escape the evilstorm! + + level = session.query(Level3).filter_by( + id=u'central_park').one() + assert level.name == u'Central Park, NY, NY' + assert level.description == u"New York's friendly Central Park." + level_exits = _get_level3_exits(session, level) + assert level_exits == { + 'portal': 'necroplex'} def test_set2_to_set3(): -- cgit v1.2.3 From 9a185731903e750c041061139cc3738859b6acf7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:32:10 -0600 Subject: Import MigrationData, not MigrationRecord --- mediagoblin/db/sql/util.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 65976538..e81cf845 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -50,10 +50,10 @@ class MigrationManager(object): self.printer = printer # For convenience - from mediagoblin.db.sql.models import MigrationRecord + from mediagoblin.db.sql.models import MigrationData - self.migration_model = MigrationRecord - self.migration_table = MigrationRecord.__table__ + self.migration_model = MigrationData + self.migration_table = MigrationData.__table__ @property def sorted_migrations(self): -- cgit v1.2.3 From 47616ece50b34ea15c7449345f3528947822adc5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:36:33 -0600 Subject: Make latest_migration a property --- mediagoblin/db/sql/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index e81cf845..33d2c59b 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -76,6 +76,7 @@ class MigrationManager(object): return self.database.query( self.migration_model).filter_by(name=self.name).first() + @property def latest_migration(self): """ Return a migration number for the latest migration, or 0 if -- cgit v1.2.3 From a5e03db6c2d16581251802bcf1eeae1a7c1f2d9f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:39:08 -0600 Subject: Migration records are dicts, not lists. Fix SET1_MIGATIONS! --- mediagoblin/tests/test_sql_migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 1f97b6ce..cae29549 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -57,7 +57,7 @@ class Level1(Base1): SET1_MODELS = [Creature1, Level1] -SET1_MIGRATIONS = [] +SET1_MIGRATIONS = {} ####################################################### # Migration set 2: A few migrations and new model -- cgit v1.2.3 From e8ba2223fa2bf79e8998dfbb54794b6a1cb93e63 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:40:46 -0600 Subject: Also switch database_current_migration to a property --- mediagoblin/db/sql/util.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 33d2c59b..d9ce7d2b 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -88,6 +88,7 @@ class MigrationManager(object): # If no migrations have been set, we start at 0. return 0 + @property def database_current_migration(self): """ Return the current migration in the database. @@ -110,7 +111,7 @@ class MigrationManager(object): """ assert self.database_current_migration is not None - db_current_migration = self.database_current_migration() + db_current_migration = self.database_current_migration return [ (migration_number, migration_func) @@ -145,7 +146,7 @@ class MigrationManager(object): """ Print out a dry run of what we would have upgraded. """ - if self.database_current_migration() is None: + if self.database_current_migration is None: self.printer( u'~> Woulda initialized: %s\n' % self.name_for_printing()) return u'inited' @@ -180,7 +181,7 @@ class MigrationManager(object): # Find out what migration number, if any, this database data is at, # and what the latest is. - migration_number = self.database_current_migration() + migration_number = self.database_current_migration # Is this our first time? Is there even a table entry for # this identifier? -- cgit v1.2.3 From 0f3526c601b7848a54808ec0baef832d3baaa8b7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:48:44 -0600 Subject: magical_powers relationship set on wrong table, fixed --- mediagoblin/tests/test_sql_migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index cae29549..7a49a4a5 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -201,6 +201,7 @@ class Creature3(Base3): id = Column(Integer, primary_key=True) name = Column(Unicode, unique=True, nullable=False, index=True) num_limbs= Column(Integer, nullable=False) + magical_powers = relationship("CreaturePower3") class CreaturePower3(Base3): __tablename__ = "creature_power" @@ -211,7 +212,6 @@ class CreaturePower3(Base3): name = Column(Unicode) description = Column(Unicode) hitpower = Column(Float, nullable=False) - magical_powers = relationship("CreaturePower3") class Level3(Base3): __tablename__ = "level" -- cgit v1.2.3 From f3791a9490f7dca7eaadc8229e31fe7285823d12 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 16:58:58 -0600 Subject: A few basic fixes to sql/util.py - MigrationRecord to MigrationData, again - If the table doesn't exist, return None for database_current_migration - database.engine -> database.bind --- mediagoblin/db/sql/util.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index d9ce7d2b..604ea19c 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -93,6 +93,10 @@ class MigrationManager(object): """ Return the current migration in the database. """ + # If the table doesn't even exist, return None. + if not self.migration_table.exists(self.database.bind): + return None + return self.migration_data.version def set_current_migration(self, migration_number): @@ -129,7 +133,7 @@ class MigrationManager(object): assert not model.__table__.exists(self.database) self.migration_model.metadata.create_all( - self.database.engine, + self.database.bind, tables=[model.__table__ for model in self.models]) def create_new_migration_record(self): @@ -253,8 +257,8 @@ def assure_migrations_table_setup(db): """ Make sure the migrations table is set up in the database. """ - from mediagoblin.db.sql.models import MigrationRecord + from mediagoblin.db.sql.models import MigrationData - if not MigrationRecord.__table__.exists(db.engine): - MigrationRecord.metadata.create_all( - db, tables=[MigrationRecord.__table__]) + if not MigrationData.__table__.exists(db.bind): + MigrationData.metadata.create_all( + db, tables=[MigrationData.__table__]) -- cgit v1.2.3 From 16d4dce9e94644ba783d7ca8d4f87e75420ce3d9 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:00:39 -0600 Subject: another db -> db.bind fix. --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 604ea19c..87234019 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -261,4 +261,4 @@ def assure_migrations_table_setup(db): if not MigrationData.__table__.exists(db.bind): MigrationData.metadata.create_all( - db, tables=[MigrationData.__table__]) + db.bind, tables=[MigrationData.__table__]) -- cgit v1.2.3 From 396f39c3e9e5346b4b2e86f6bcce9cdb0c6ee683 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:05:16 -0600 Subject: Fix database_current_version for when self.migration_data is None. --- mediagoblin/db/sql/util.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 87234019..cb8fbf0d 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -97,6 +97,10 @@ class MigrationManager(object): if not self.migration_table.exists(self.database.bind): return None + # Also return None if self.migration_data is None. + if self.migration_data is None: + return None + return self.migration_data.version def set_current_migration(self, migration_number): -- cgit v1.2.3 From ef8591fdd09a4910a590b145d781cdd1e1eff0f4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:06:19 -0600 Subject: Yet *another* self.database -> self.database.bind fix! --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index cb8fbf0d..52c57543 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -134,7 +134,7 @@ class MigrationManager(object): # sanity check before we proceed, none of these should be created for model in self.models: # Maybe in the future just print out a "Yikes!" or something? - assert not model.__table__.exists(self.database) + assert not model.__table__.exists(self.database.bind) self.migration_model.metadata.create_all( self.database.bind, -- cgit v1.2.3 From f98be6a65ba10f230547a51ff202b577a76c1556 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:07:47 -0600 Subject: For clarity, self.database -> self.session. Actually, I'm not even sure *that* is ideal! But better than what we had... --- mediagoblin/db/sql/util.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 52c57543..9487d391 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -33,18 +33,18 @@ class MigrationManager(object): to the latest migrations, etc. """ - def __init__(self, name, models, migration_registry, database, + def __init__(self, name, models, migration_registry, session, printer=_simple_printer): """ Args: - name: identifier of this section of the database - - database: database we're going to migrate + - session: session we're going to migrate - migration_registry: where we should find all migrations to run """ self.name = name self.models = models - self.database = database + self.session = session self.migration_registry = migration_registry self._sorted_migrations = None self.printer = printer @@ -73,7 +73,7 @@ class MigrationManager(object): """ Get the migration row associated with this object, if any. """ - return self.database.query( + return self.session.query( self.migration_model).filter_by(name=self.name).first() @property @@ -94,7 +94,7 @@ class MigrationManager(object): Return the current migration in the database. """ # If the table doesn't even exist, return None. - if not self.migration_table.exists(self.database.bind): + if not self.migration_table.exists(self.session.bind): return None # Also return None if self.migration_data is None. @@ -108,7 +108,7 @@ class MigrationManager(object): Set the migration in the database to migration_number """ self.migration_data = migration_number - self.database.commit() + self.session.commit() def migrations_to_run(self): """ @@ -134,10 +134,10 @@ class MigrationManager(object): # sanity check before we proceed, none of these should be created for model in self.models: # Maybe in the future just print out a "Yikes!" or something? - assert not model.__table__.exists(self.database.bind) + assert not model.__table__.exists(self.session.bind) self.migration_model.metadata.create_all( - self.database.bind, + self.session.bind, tables=[model.__table__ for model in self.models]) def create_new_migration_record(self): @@ -147,8 +147,8 @@ class MigrationManager(object): migration_record = self.migration_model( name=self.name, version=self.latest_migration()) - self.database.add(migration_record) - self.database.commit() + self.session.add(migration_record) + self.session.commit() def dry_run(self): """ @@ -185,7 +185,7 @@ class MigrationManager(object): Returns information about whether or not we initialized ('inited'), migrated ('migrated'), or did nothing (None) """ - assure_migrations_table_setup(self.database) + assure_migrations_table_setup(self.session) # Find out what migration number, if any, this database data is at, # and what the latest is. @@ -217,7 +217,7 @@ class MigrationManager(object): self.printer( u' + Running migration %s, "%s"... ' % ( migration_number, migration_func.func_name)) - migration_func(self.database) + migration_func(self.session) self.printer('done.') return u'migrated' -- cgit v1.2.3 From 9303d47df0ec4779e692529a2791aa2b98e3bc70 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:08:38 -0600 Subject: self.latest_migration now a property, so we shouldn't __call__ it! --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 9487d391..a7f5fedf 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -146,7 +146,7 @@ class MigrationManager(object): """ migration_record = self.migration_model( name=self.name, - version=self.latest_migration()) + version=self.latest_migration) self.session.add(migration_record) self.session.commit() -- cgit v1.2.3 From 245e6d83a618f524be0c71d071374ddc6da291f0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:10:18 -0600 Subject: CollectingPrinter is a class, not a function! --- mediagoblin/tests/test_sql_migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 7a49a4a5..7dfc4b26 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -489,7 +489,7 @@ def _insert_migration3_objects(session): session.commit() -def CollectingPrinter(object): +class CollectingPrinter(object): def __init__(self): self.collection = [] -- cgit v1.2.3 From ecb4cc89900b897b26fe5f6a1f4c1d94b4a50b6a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:11:41 -0600 Subject: printer = CollectingPrinter -> printer = CollectingPrinter() --- mediagoblin/tests/test_sql_migrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 7dfc4b26..d9d30237 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -528,7 +528,7 @@ def test_set1_to_set3(): # Create tables by migrating on empty initial set # ----------------------------------------------- - printer = CollectingPrinter + printer = CollectingPrinter() migration_manager = MigrationManager( '__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), printer) @@ -635,7 +635,7 @@ def test_set1_to_set3(): # Create new migration manager, but make sure the db migration # isn't said to be updated yet - printer = CollectingPrinter + printer = CollectingPrinter() migration_manager = MigrationManager( '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), printer) -- cgit v1.2.3 From c7fa585bffd1f2cf55455c810ce5c30c8b16d690 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:21:44 -0600 Subject: assert column type from Unicode -> VARCHAR. SQLAlchemy reflection only so smart ;) --- mediagoblin/tests/test_sql_migrations.py | 58 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index d9d30237..71ea321a 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -19,7 +19,7 @@ import copy from sqlalchemy import ( Table, Column, MetaData, Index, Integer, Float, Unicode, UnicodeText, DateTime, Boolean, - ForeignKey, UniqueConstraint, PickleType) + ForeignKey, UniqueConstraint, PickleType, VARCHAR) from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import select, insert @@ -573,10 +573,10 @@ def test_set1_to_set3(): assert set(creature_table.c.keys()) == set( ['id', 'name', 'num_legs', 'is_demon']) assert_col_type(creature_table.c.id, Integer) - assert_col_type(creature_table.c.name, Unicode) + assert_col_type(creature_table.c.name, VARCHAR) assert creature_table.c.name.nullable is False - assert creature_table.c.name.index is True - assert creature_table.c.name.unique is True + #assert creature_table.c.name.index is True + #assert creature_table.c.name.unique is True assert_col_type(creature_table.c.num_legs, Integer) assert creature_table.c.num_legs.nullable is False assert_col_type(creature_table.c.is_demon, Boolean) @@ -587,10 +587,10 @@ def test_set1_to_set3(): autoload=True, autoload_with=engine) assert set(level_table.c.keys()) == set( ['id', 'name', 'description', 'exits']) - assert_col_type(level_table.c.id, Unicode) + assert_col_type(level_table.c.id, VARCHAR) assert level_table.c.id.primary_key is True - assert_col_type(level_table.c.name, Unicode) - assert_col_type(level_table.c.description, Unicode) + assert_col_type(level_table.c.name, VARCHAR) + assert_col_type(level_table.c.description, VARCHAR) # Skipping exits... Not sure if we can detect pickletype, not a # big deal regardless. @@ -672,10 +672,10 @@ def test_set1_to_set3(): assert set(creature_table.c.keys()) == set( ['id', 'name', 'num_limbs']) assert_col_type(creature_table.c.id, Integer) - assert_col_type(creature_table.c.name, Unicode) + assert_col_type(creature_table.c.name, VARCHAR) assert creature_table.c.name.nullable is False - assert creature_table.c.name.index is True - assert creature_table.c.name.unique is True + #assert creature_table.c.name.index is True + #assert creature_table.c.name.unique is True assert_col_type(creature_table.c.num_legs, Integer) assert creature_table.c.num_legs.nullable is False @@ -688,8 +688,8 @@ def test_set1_to_set3(): assert_col_type(creature_power_table.c.id, Integer) assert_col_type(creature_power_table.c.creature, Integer) assert creature_power_table.c.creature.nullable is False - assert_col_type(creature_power_table.c.name, Unicode) - assert_col_type(creature_power_table.c.description, Unicode) + assert_col_type(creature_power_table.c.name, VARCHAR) + assert_col_type(creature_power_table.c.description, VARCHAR) assert_col_type(creature_power_table.c.hitpower, Float) assert creature_power_table.c.hitpower.nullable is False @@ -699,10 +699,10 @@ def test_set1_to_set3(): autoload=True, autoload_with=engine) assert set(level_table.c.keys()) == set( ['id', 'name', 'description']) - assert_col_type(level_table.c.id, Unicode) + assert_col_type(level_table.c.id, VARCHAR) assert level_table.c.id.primary_key is True - assert_col_type(level_table.c.name, Unicode) - assert_col_type(level_table.c.description, Unicode) + assert_col_type(level_table.c.name, VARCHAR) + assert_col_type(level_table.c.description, VARCHAR) # Check the structure of the level_exits table level_exit_table = Table( @@ -711,13 +711,13 @@ def test_set1_to_set3(): assert set(level_exit_table.c.keys()) == set( ['id', 'name', 'from_level', 'to_level']) assert_col_type(level_exit_table.c.id, Integer) - assert_col_type(level_exit_table.c.name, Unicode) - assert_col_type(level_exit_table.c.from_level, Unicode) + assert_col_type(level_exit_table.c.name, VARCHAR) + assert_col_type(level_exit_table.c.from_level, VARCHAR) assert level_exit_table.c.from_level.nullable is False - assert level_exit_table.c.from_level.indexed is True - assert_col_type(level_exit_table.c.to_level, Unicode) + #assert level_exit_table.c.from_level.index is True + assert_col_type(level_exit_table.c.to_level, VARCHAR) assert level_exit_table.c.to_level.nullable is False - assert level_exit_table.c.to_level.indexed is True + #assert level_exit_table.c.to_level.index is True # Now check to see if stuff seems to be in there. session = Session() @@ -798,7 +798,7 @@ def test_set1_to_set2_to_set3(): # assert set(creature_table.c.keys()) == set( # ['id', 'name', 'num_legs']) # assert_col_type(creature_table.c.id, Integer) - # assert_col_type(creature_table.c.name, Unicode) + # assert_col_type(creature_table.c.name, VARCHAR) # assert creature_table.c.name.nullable is False # assert creature_table.c.name.index is True # assert creature_table.c.name.unique is True @@ -814,8 +814,8 @@ def test_set1_to_set2_to_set3(): # assert_col_type(creature_power_table.c.id, Integer) # assert_col_type(creature_power_table.c.creature, Integer) # assert creature_power_table.c.creature.nullable is False - # assert_col_type(creature_power_table.c.name, Unicode) - # assert_col_type(creature_power_table.c.description, Unicode) + # assert_col_type(creature_power_table.c.name, VARCHAR) + # assert_col_type(creature_power_table.c.description, VARCHAR) # assert_col_type(creature_power_table.c.hitpower, Integer) # assert creature_power_table.c.hitpower.nullable is False @@ -825,10 +825,10 @@ def test_set1_to_set2_to_set3(): # autoload=True, autoload_with=db_conn.engine) # assert set(level_table.c.keys()) == set( # ['id', 'name', 'description']) - # assert_col_type(level_table.c.id, Unicode) + # assert_col_type(level_table.c.id, VARCHAR) # assert level_table.c.id.primary_key is True - # assert_col_type(level_table.c.name, Unicode) - # assert_col_type(level_table.c.description, Unicode) + # assert_col_type(level_table.c.name, VARCHAR) + # assert_col_type(level_table.c.description, VARCHAR) # # Check the structure of the level_exits table # level_exit_table = Table( @@ -837,9 +837,9 @@ def test_set1_to_set2_to_set3(): # assert set(level_exit_table.c.keys()) == set( # ['id', 'name', 'from_level', 'to_level']) # assert_col_type(level_exit_table.c.id, Integer) - # assert_col_type(level_exit_table.c.name, Unicode) - # assert_col_type(level_exit_table.c.from_level, Unicode) + # assert_col_type(level_exit_table.c.name, VARCHAR) + # assert_col_type(level_exit_table.c.from_level, VARCHAR) # assert level_exit_table.c.from_level.nullable is False - # assert_col_type(level_exit_table.c.to_level, Unicode) + # assert_col_type(level_exit_table.c.to_level, VARCHAR) pass -- cgit v1.2.3 From 505c0db119c9a33a2ee823b4da3859054cce48fd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:22:29 -0600 Subject: Fixed the descriptions for the necroplex! --- mediagoblin/tests/test_sql_migrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 71ea321a..8bb82efd 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -615,7 +615,7 @@ def test_set1_to_set3(): level = session.query(Level1).filter_by( id=u'necroplex').one() assert level.name == u'The Necroplex' - assert level.description == u'A complex of pure deathzone.' + assert level.description == u'A complex full of pure deathzone.' assert level.exits == { 'deathwell': 'evilstorm', 'portal': 'central_park'} @@ -739,7 +739,7 @@ def test_set1_to_set3(): level = session.query(Level3).filter_by( id=u'necroplex').one() assert level.name == u'The Necroplex' - assert level.description == u'A complex of pure deathzone.' + assert level.description == u'A complex full of pure deathzone.' level_exits = _get_level3_exits(session, level) assert level_exits == { u'deathwell': u'evilstorm', -- cgit v1.2.3 From be1077ac44ac4a6ad659e202b93363af2d033f96 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:23:27 -0600 Subject: Migration manager's current migration should be 3, not 7, after running all migrations! --- mediagoblin/tests/test_sql_migrations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 8bb82efd..92925e64 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -640,7 +640,7 @@ def test_set1_to_set3(): '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), printer) - assert migration_manager.latest_migration == 3 + assert migration_manager.latest_migration == 7 assert migration_manager.database_current_migration == 0 # Migrate @@ -660,8 +660,8 @@ def test_set1_to_set3(): migration_manager = MigrationManager( '__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), printer) - assert migration_manager.latest_migration == 3 - assert migration_manager.database_current_migration == 3 + assert migration_manager.latest_migration == 7 + assert migration_manager.database_current_migration == 7 # Check all things in database match expected -- cgit v1.2.3 From bff7098a6c8efa699f7344ee0f5d4e1326f996c2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:26:23 -0600 Subject: migrations_to_run here a list, so no reason to call it --- mediagoblin/db/sql/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index a7f5fedf..17c8bf8a 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -213,7 +213,7 @@ class MigrationManager(object): if migrations_to_run: self.printer( u'~> Updating %s:\n' % self.name_for_printing()) - for migration_number, migration_func in migrations_to_run(): + for migration_number, migration_func in migrations_to_run: self.printer( u' + Running migration %s, "%s"... ' % ( migration_number, migration_func.func_name)) -- cgit v1.2.3 From e920b96859b37e5404415bd0573f57b81f7d14d0 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 17:28:25 -0600 Subject: db_conn.engine -> db_conn.bind --- mediagoblin/tests/test_sql_migrations.py | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 92925e64..f91d449c 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -109,10 +109,10 @@ def creature_remove_is_demon(db_conn): Remove the is_demon field from the creature model. We don't need it! """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) creature_table = Table( 'creature', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=db_conn.bind) creature_table.drop_column('is_demon') @@ -123,7 +123,7 @@ def creature_powers_new_table(db_conn): yet though as there wasn't anything that previously held this information """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) creature_powers = Table( 'creature_power', metadata, Column('id', Integer, primary_key=True), @@ -132,7 +132,7 @@ def creature_powers_new_table(db_conn): Column('name', Unicode), Column('description', Unicode), Column('hitpower', Integer, nullable=False)) - metadata.create_all(db_conn.engine) + metadata.create_all(db_conn.bind) @RegisterMigration(3, FULL_MIGRATIONS) @@ -143,7 +143,7 @@ def level_exits_new_table(db_conn): """ # First, create the table # ----------------------- - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) level_exits = Table( 'level_exit', metadata, Column('id', Integer, primary_key=True), @@ -152,7 +152,7 @@ def level_exits_new_table(db_conn): Integer, ForeignKey('level.id'), nullable=False), Column('to_level', Integer, ForeignKey('level.id'), nullable=False)) - metadata.create_all(db_conn.engine) + metadata.create_all(db_conn.bind) # And now, convert all the old exit pickles to new level exits # ------------------------------------------------------------ @@ -242,10 +242,10 @@ def creature_num_legs_to_num_limbs(db_conn): specifically. Humans would be 4 here, for instance. So we renamed the column. """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) creature_table = Table( 'creature', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=db_conn.bind) creature_table.c.num_legs.alter(name=u"num_limbs") @@ -254,12 +254,12 @@ def level_exit_index_from_and_to_level(db_conn): """ Index the from and to levels of the level exit table. """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) level_exit = Table( 'level_exit', metadata, - autoload=True, autoload_with=db_conn.engine) - Index('ix_from_level', level_exit.c.from_level).create(db_conn.engine) - Index('ix_to_exit', level_exit.c.to_exit).create(db_conn.engine) + autoload=True, autoload_with=db_conn.bind) + Index('ix_from_level', level_exit.c.from_level).create(db_conn.bind) + Index('ix_to_exit', level_exit.c.to_exit).create(db_conn.bind) @RegisterMigration(6, FULL_MIGRATIONS) @@ -267,11 +267,11 @@ def creature_power_index_creature(db_conn): """ Index our foreign key relationship to the creatures """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) creature_power = Table( 'creature_power', metadata, - autoload=True, autoload_with=db_conn.engine) - Index('ix_creature', creature_power.c.creature).create(db_conn.engine) + autoload=True, autoload_with=db_conn.bind) + Index('ix_creature', creature_power.c.creature).create(db_conn.bind) @RegisterMigration(7, FULL_MIGRATIONS) @@ -283,10 +283,10 @@ def creature_power_hitpower_to_float(db_conn): Turns out we want super precise values of how much hitpower there really is. """ - metadata = MetaData(bind=db_conn.engine) + metadata = MetaData(bind=db_conn.bind) creature_power = Table( 'creature_power', metadata, - autoload=True, autoload_with=db_conn.engine) + autoload=True, autoload_with=db_conn.bind) creature_power.c.hitpower.alter(type=Float) @@ -794,7 +794,7 @@ def test_set1_to_set2_to_set3(): ##### Set2 # creature_table = Table( # 'creature', metadata, - # autoload=True, autoload_with=db_conn.engine) + # autoload=True, autoload_with=db_conn.bind) # assert set(creature_table.c.keys()) == set( # ['id', 'name', 'num_legs']) # assert_col_type(creature_table.c.id, Integer) @@ -808,7 +808,7 @@ def test_set1_to_set2_to_set3(): # # Check the CreaturePower table # creature_power_table = Table( # 'creature_power', metadata, - # autoload=True, autoload_with=db_conn.engine) + # autoload=True, autoload_with=db_conn.bind) # assert set(creature_power_table.c.keys()) == set( # ['id', 'creature', 'name', 'description', 'hitpower']) # assert_col_type(creature_power_table.c.id, Integer) @@ -822,7 +822,7 @@ def test_set1_to_set2_to_set3(): # # Check the structure of the level table # level_table = Table( # 'level', metadata, - # autoload=True, autoload_with=db_conn.engine) + # autoload=True, autoload_with=db_conn.bind) # assert set(level_table.c.keys()) == set( # ['id', 'name', 'description']) # assert_col_type(level_table.c.id, VARCHAR) @@ -833,7 +833,7 @@ def test_set1_to_set2_to_set3(): # # Check the structure of the level_exits table # level_exit_table = Table( # 'level_exit', metadata, - # autoload=True, autoload_with=db_conn.engine) + # autoload=True, autoload_with=db_conn.bind) # assert set(level_exit_table.c.keys()) == set( # ['id', 'name', 'from_level', 'to_level']) # assert_col_type(level_exit_table.c.id, Integer) -- cgit v1.2.3 From adf54363735172badc5984817cc9debd9c39ea0e Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 21:45:05 -0600 Subject: Update the string outputs to match our tests: newlines, ...->:, etc. --- mediagoblin/db/sql/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 17c8bf8a..731593f6 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -212,13 +212,13 @@ class MigrationManager(object): migrations_to_run = self.migrations_to_run() if migrations_to_run: self.printer( - u'~> Updating %s:\n' % self.name_for_printing()) + u'-> Updating %s:\n' % self.name_for_printing()) for migration_number, migration_func in migrations_to_run: self.printer( u' + Running migration %s, "%s"... ' % ( migration_number, migration_func.func_name)) migration_func(self.session) - self.printer('done.') + self.printer('done.\n') return u'migrated' -- cgit v1.2.3 From 78d17b8055ca19b3af52f97337ccf3c6b8e610b7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 22:19:03 -0600 Subject: Excepting that migration 1 doesn't work(!), sqlalchemy migration branch working The reason migration 1 doesn't work, and is commented out, is because of sqlalchemy-migrate not handling certain constraints while dropping binary sqlite columns right. See also: http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242 --- mediagoblin/db/sql/util.py | 7 +- mediagoblin/tests/test_sql_migrations.py | 108 ++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 38 deletions(-) diff --git a/mediagoblin/db/sql/util.py b/mediagoblin/db/sql/util.py index 731593f6..08602414 100644 --- a/mediagoblin/db/sql/util.py +++ b/mediagoblin/db/sql/util.py @@ -103,11 +103,12 @@ class MigrationManager(object): return self.migration_data.version - def set_current_migration(self, migration_number): + def set_current_migration(self, migration_number=None): """ Set the migration in the database to migration_number + (or, the latest available) """ - self.migration_data = migration_number + self.migration_data.version = migration_number or self.latest_migration self.session.commit() def migrations_to_run(self): @@ -206,6 +207,7 @@ class MigrationManager(object): self.create_new_migration_record() self.printer(u"done.\n") + self.set_current_migration() return u'inited' # Run migrations, if appropriate. @@ -220,6 +222,7 @@ class MigrationManager(object): migration_func(self.session) self.printer('done.\n') + self.set_current_migration() return u'migrated' # Otherwise return None. Well it would do this anyway, but diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index f91d449c..e1af2586 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -109,12 +109,13 @@ def creature_remove_is_demon(db_conn): Remove the is_demon field from the creature model. We don't need it! """ - metadata = MetaData(bind=db_conn.bind) - creature_table = Table( - 'creature', metadata, - autoload=True, autoload_with=db_conn.bind) - creature_table.drop_column('is_demon') - + # metadata = MetaData(bind=db_conn.bind) + # creature_table = Table( + # 'creature', metadata, + # autoload=True, autoload_with=db_conn.bind) + # creature_table.drop_column('is_demon') + pass + @RegisterMigration(2, FULL_MIGRATIONS) def creature_powers_new_table(db_conn): @@ -124,6 +125,13 @@ def creature_powers_new_table(db_conn): information """ metadata = MetaData(bind=db_conn.bind) + + # We have to access the creature table so sqlalchemy can make the + # foreign key relationship + creature_table = Table( + 'creature', metadata, + autoload=True, autoload_with=db_conn.bind) + creature_powers = Table( 'creature_power', metadata, Column('id', Integer, primary_key=True), @@ -144,40 +152,43 @@ def level_exits_new_table(db_conn): # First, create the table # ----------------------- metadata = MetaData(bind=db_conn.bind) + + # Minimal representation of level table. + # Not auto-introspecting here because of pickle table. I'm not + # sure sqlalchemy can auto-introspect pickle columns. + levels = Table( + 'level', metadata, + Column('id', Unicode, primary_key=True), + Column('name', Unicode), + Column('description', Unicode), + Column('exits', PickleType)) + level_exits = Table( 'level_exit', metadata, Column('id', Integer, primary_key=True), Column('name', Unicode), Column('from_level', - Integer, ForeignKey('level.id'), nullable=False), + Unicode, ForeignKey('level.id'), nullable=False), Column('to_level', - Integer, ForeignKey('level.id'), nullable=False)) + Unicode, ForeignKey('level.id'), nullable=False)) metadata.create_all(db_conn.bind) # And now, convert all the old exit pickles to new level exits # ------------------------------------------------------------ - # Minimal representation of level table. - # Not auto-introspecting here because of pickle table. I'm not - # sure sqlalchemy can auto-introspect pickle columns. - levels = Table( - 'level', metadata, - Column('id', Integer, primary_key=True), - Column('exits', PickleType)) - # query over and insert result = db_conn.execute( select([levels], levels.c.exits!=None)) for level in result: - this_exit = level['exits'] - - # Insert the level exit - db_conn.execute( - level_exits.insert().values( - name=this_exit['name'], - from_level=this_exit['from_level'], - to_level=this_exit['to_level'])) + + for exit_name, to_level in level['exits'].iteritems(): + # Insert the level exit + db_conn.execute( + level_exits.insert().values( + name=exit_name, + from_level=level.id, + to_level=to_level)) # Finally, drop the old level exits pickle table # ---------------------------------------------- @@ -258,8 +269,10 @@ def level_exit_index_from_and_to_level(db_conn): level_exit = Table( 'level_exit', metadata, autoload=True, autoload_with=db_conn.bind) - Index('ix_from_level', level_exit.c.from_level).create(db_conn.bind) - Index('ix_to_exit', level_exit.c.to_exit).create(db_conn.bind) + Index('ix_level_exit_from_level', + level_exit.c.from_level).create(db_conn.bind) + Index('ix_level_exit_to_level', + level_exit.c.to_level).create(db_conn.bind) @RegisterMigration(6, FULL_MIGRATIONS) @@ -271,7 +284,8 @@ def creature_power_index_creature(db_conn): creature_power = Table( 'creature_power', metadata, autoload=True, autoload_with=db_conn.bind) - Index('ix_creature', creature_power.c.creature).create(db_conn.bind) + Index('ix_creature_power_creature', + creature_power.c.creature).create(db_conn.bind) @RegisterMigration(7, FULL_MIGRATIONS) @@ -284,9 +298,23 @@ def creature_power_hitpower_to_float(db_conn): really is. """ metadata = MetaData(bind=db_conn.bind) + + # We have to access the creature table so sqlalchemy can make the + # foreign key relationship + creature_table = Table( + 'creature', metadata, + autoload=True, autoload_with=db_conn.bind) + creature_power = Table( 'creature_power', metadata, - autoload=True, autoload_with=db_conn.bind) + Column('id', Integer, primary_key=True), + Column('creature', Integer, + ForeignKey('creature.id'), nullable=False, + index=True), + Column('name', Unicode), + Column('description', Unicode), + Column('hitpower', Integer, nullable=False)) + creature_power.c.hitpower.alter(type=Float) @@ -651,10 +679,15 @@ def test_set1_to_set3(): # TODO: Check output to user assert printer.combined_string == """\ --> Updating main mediagoblin tables... +-> Updating main mediagoblin tables: + Running migration 1, "creature_remove_is_demon"... done. + Running migration 2, "creature_powers_new_table"... done. - + Running migration 3, "level_exits_new_table"... done.""" + + Running migration 3, "level_exits_new_table"... done. + + Running migration 4, "creature_num_legs_to_num_limbs"... done. + + Running migration 5, "level_exit_index_from_and_to_level"... done. + + Running migration 6, "creature_power_index_creature"... done. + + Running migration 7, "creature_power_hitpower_to_float"... done. +""" # Make sure version matches expected migration_manager = MigrationManager( @@ -666,18 +699,21 @@ def test_set1_to_set3(): # Check all things in database match expected # Check the creature table + metadata = MetaData(bind=engine) creature_table = Table( 'creature', metadata, autoload=True, autoload_with=engine) + # assert set(creature_table.c.keys()) == set( + # ['id', 'name', 'num_limbs']) assert set(creature_table.c.keys()) == set( - ['id', 'name', 'num_limbs']) + [u'id', 'name', u'num_limbs', u'is_demon']) assert_col_type(creature_table.c.id, Integer) assert_col_type(creature_table.c.name, VARCHAR) assert creature_table.c.name.nullable is False #assert creature_table.c.name.index is True #assert creature_table.c.name.unique is True - assert_col_type(creature_table.c.num_legs, Integer) - assert creature_table.c.num_legs.nullable is False + assert_col_type(creature_table.c.num_limbs, Integer) + assert creature_table.c.num_limbs.nullable is False # Check the CreaturePower table creature_power_table = Table( @@ -724,17 +760,17 @@ def test_set1_to_set3(): creature = session.query(Creature3).filter_by( name=u'centipede').one() assert creature.num_limbs == 100.0 - assert creature.creature_powers == [] + assert creature.magical_powers == [] creature = session.query(Creature3).filter_by( name=u'wolf').one() assert creature.num_limbs == 4.0 - assert creature.creature_powers == [] + assert creature.magical_powers == [] creature = session.query(Creature3).filter_by( name=u'wizardsnake').one() assert creature.num_limbs == 0.0 - assert creature.creature_powers == [] + assert creature.magical_powers == [] level = session.query(Level3).filter_by( id=u'necroplex').one() -- cgit v1.2.3 From 7f3ec607a34e727324397c2bf240f771b12a0455 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 29 Jan 2012 22:19:53 -0600 Subject: Explained why migration #1 commented out. --- mediagoblin/tests/test_sql_migrations.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index e1af2586..1b7fb903 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -109,6 +109,9 @@ def creature_remove_is_demon(db_conn): Remove the is_demon field from the creature model. We don't need it! """ + # :( Commented out 'cuz of: + # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=143&thanks=143&ts=1327882242 + # metadata = MetaData(bind=db_conn.bind) # creature_table = Table( # 'creature', metadata, -- cgit v1.2.3 From 95ff15d66e89d4aacc9a452410efa0b8e9c602dd Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 2 Feb 2012 09:29:25 -0600 Subject: Updating deployment guide so that it can handle the current virtualenv site-packages changes Now it should try using --system-site-packages and if that fails (older version) it tries it without the argument. --- docs/source/deploying.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index 4aded2e6..a8ee6ff1 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -118,7 +118,7 @@ Clone the MediaGoblin repository:: And setup the in-package virtualenv:: cd mediagoblin - virtualenv . && ./bin/python setup.py develop + (virtualenv --system-site-packages . || virtualenv .) && ./bin/python setup.py develop .. note:: -- cgit v1.2.3 From cf29e8a824e0ef4612f1144f079c80c1d20b89e5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 2 Feb 2012 09:44:13 -0600 Subject: It's 2012 all up in here --- mediagoblin/__init__.py | 2 +- mediagoblin/_version.py | 2 +- mediagoblin/app.py | 2 +- mediagoblin/auth/__init__.py | 2 +- mediagoblin/auth/forms.py | 2 +- mediagoblin/auth/lib.py | 2 +- mediagoblin/auth/routing.py | 2 +- mediagoblin/auth/views.py | 2 +- mediagoblin/db/__init__.py | 2 +- mediagoblin/db/mongo/__init__.py | 2 +- mediagoblin/db/mongo/indexes.py | 2 +- mediagoblin/db/mongo/migrations.py | 2 +- mediagoblin/db/mongo/models.py | 2 +- mediagoblin/db/mongo/open.py | 2 +- mediagoblin/db/mongo/util.py | 2 +- mediagoblin/db/open.py | 2 +- mediagoblin/db/sql/__init__.py | 2 +- mediagoblin/db/util.py | 2 +- mediagoblin/decorators.py | 2 +- mediagoblin/edit/__init__.py | 2 +- mediagoblin/edit/forms.py | 2 +- mediagoblin/edit/lib.py | 2 +- mediagoblin/edit/routing.py | 2 +- mediagoblin/edit/views.py | 2 +- mediagoblin/errormiddleware.py | 2 +- mediagoblin/gmg_commands/__init__.py | 2 +- mediagoblin/gmg_commands/import_export.py | 2 +- mediagoblin/gmg_commands/migrate.py | 2 +- mediagoblin/gmg_commands/shell.py | 2 +- mediagoblin/gmg_commands/users.py | 2 +- mediagoblin/gmg_commands/util.py | 2 +- mediagoblin/gmg_commands/wipealldata.py | 2 +- mediagoblin/init/__init__.py | 2 +- mediagoblin/init/celery/__init__.py | 2 +- mediagoblin/init/celery/from_celery.py | 2 +- mediagoblin/init/celery/from_tests.py | 2 +- mediagoblin/init/config.py | 2 +- mediagoblin/listings/__init__.py | 2 +- mediagoblin/listings/routing.py | 2 +- mediagoblin/listings/views.py | 2 +- mediagoblin/meddleware/__init__.py | 2 +- mediagoblin/meddleware/csrf.py | 2 +- mediagoblin/meddleware/noop.py | 2 +- mediagoblin/media_types/__init__.py | 2 +- mediagoblin/media_types/ascii/__init__.py | 2 +- mediagoblin/media_types/ascii/asciitoimage.py | 2 +- mediagoblin/media_types/ascii/processing.py | 2 +- mediagoblin/media_types/image/__init__.py | 2 +- mediagoblin/media_types/image/processing.py | 2 +- mediagoblin/media_types/video/__init__.py | 2 +- mediagoblin/media_types/video/processing.py | 2 +- mediagoblin/media_types/video/transcoders.py | 2 +- mediagoblin/messages.py | 2 +- mediagoblin/mg_globals.py | 2 +- mediagoblin/processing.py | 2 +- mediagoblin/routing.py | 2 +- mediagoblin/static/js/comment_show.js | 2 +- mediagoblin/static/js/geolocation-map.js | 2 +- mediagoblin/static/js/show_password.js | 2 +- mediagoblin/staticdirect.py | 2 +- mediagoblin/storage/__init__.py | 2 +- mediagoblin/storage/cloudfiles.py | 2 +- mediagoblin/storage/filestorage.py | 2 +- mediagoblin/storage/mountstorage.py | 2 +- mediagoblin/submit/__init__.py | 2 +- mediagoblin/submit/forms.py | 2 +- mediagoblin/submit/routing.py | 2 +- mediagoblin/submit/security.py | 2 +- mediagoblin/submit/views.py | 2 +- mediagoblin/templates/mediagoblin/404.html | 2 +- mediagoblin/templates/mediagoblin/auth/login.html | 2 +- mediagoblin/templates/mediagoblin/auth/register.html | 2 +- mediagoblin/templates/mediagoblin/auth/verification_email.txt | 2 +- mediagoblin/templates/mediagoblin/base.html | 2 +- mediagoblin/templates/mediagoblin/edit/attachments.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit_account.html | 2 +- mediagoblin/templates/mediagoblin/edit/edit_profile.html | 2 +- mediagoblin/templates/mediagoblin/listings/tag.html | 2 +- mediagoblin/templates/mediagoblin/media_displays/ascii.html | 2 +- mediagoblin/templates/mediagoblin/media_displays/image.html | 2 +- mediagoblin/templates/mediagoblin/media_displays/video.html | 2 +- mediagoblin/templates/mediagoblin/root.html | 2 +- mediagoblin/templates/mediagoblin/submit/start.html | 2 +- mediagoblin/templates/mediagoblin/test_submit.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/gallery.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/processing_panel.html | 2 +- mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +- mediagoblin/templates/mediagoblin/utils/exif.html | 2 +- mediagoblin/templates/mediagoblin/utils/feed_link.html | 2 +- mediagoblin/templates/mediagoblin/utils/geolocation_map.html | 2 +- mediagoblin/templates/mediagoblin/utils/license.html | 2 +- mediagoblin/templates/mediagoblin/utils/messages.html | 2 +- mediagoblin/templates/mediagoblin/utils/object_gallery.html | 2 +- mediagoblin/templates/mediagoblin/utils/pagination.html | 2 +- mediagoblin/templates/mediagoblin/utils/prev_next.html | 2 +- mediagoblin/templates/mediagoblin/utils/profile.html | 2 +- mediagoblin/templates/mediagoblin/utils/tags.html | 2 +- mediagoblin/templates/mediagoblin/utils/wtforms.html | 2 +- mediagoblin/templates/mediagoblin/webfinger/host-meta.xml | 2 +- mediagoblin/templates/mediagoblin/webfinger/xrd.xml | 2 +- mediagoblin/tests/__init__.py | 2 +- mediagoblin/tests/fake_celery_module.py | 2 +- mediagoblin/tests/test_auth.py | 2 +- mediagoblin/tests/test_celery_setup.py | 2 +- mediagoblin/tests/test_config.py | 2 +- mediagoblin/tests/test_csrf_middleware.py | 2 +- mediagoblin/tests/test_edit.py | 2 +- mediagoblin/tests/test_exif.py | 2 +- mediagoblin/tests/test_globals.py | 2 +- mediagoblin/tests/test_messages.py | 2 +- mediagoblin/tests/test_migrations.py | 2 +- mediagoblin/tests/test_misc.py | 2 +- mediagoblin/tests/test_storage.py | 2 +- mediagoblin/tests/test_submission.py | 2 +- mediagoblin/tests/test_tags.py | 2 +- mediagoblin/tests/test_tests.py | 2 +- mediagoblin/tests/test_util.py | 2 +- mediagoblin/tests/test_workbench.py | 2 +- mediagoblin/tests/tools.py | 2 +- mediagoblin/tools/exif.py | 2 +- mediagoblin/tools/files.py | 2 +- mediagoblin/tools/licenses.py | 2 +- mediagoblin/tools/mail.py | 2 +- mediagoblin/tools/pagination.py | 2 +- mediagoblin/tools/request.py | 2 +- mediagoblin/tools/response.py | 2 +- mediagoblin/tools/template.py | 2 +- mediagoblin/tools/testing.py | 2 +- mediagoblin/tools/text.py | 2 +- mediagoblin/tools/translate.py | 2 +- mediagoblin/user_pages/__init__.py | 2 +- mediagoblin/user_pages/forms.py | 2 +- mediagoblin/user_pages/routing.py | 2 +- mediagoblin/user_pages/views.py | 2 +- mediagoblin/views.py | 2 +- mediagoblin/webfinger/__init__.py | 2 +- mediagoblin/webfinger/routing.py | 2 +- mediagoblin/webfinger/views.py | 2 +- mediagoblin/workbench.py | 2 +- 142 files changed, 142 insertions(+), 142 deletions(-) diff --git a/mediagoblin/__init__.py b/mediagoblin/__init__.py index f9c7ccfb..88dedd28 100644 --- a/mediagoblin/__init__.py +++ b/mediagoblin/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index 5e69f21a..fc1a0f6e 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 96b2c8ab..06627675 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/auth/__init__.py +++ b/mediagoblin/auth/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py index 5a707c7b..1b3e214c 100644 --- a/mediagoblin/auth/forms.py +++ b/mediagoblin/auth/forms.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/auth/lib.py b/mediagoblin/auth/lib.py index c0af3b5b..1136a252 100644 --- a/mediagoblin/auth/lib.py +++ b/mediagoblin/auth/lib.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index ea9388c5..15d8fc3c 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index c04a49a7..9af89c2a 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py index 27e8a90f..d149f62a 100644 --- a/mediagoblin/db/__init__.py +++ b/mediagoblin/db/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/__init__.py b/mediagoblin/db/mongo/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/db/mongo/__init__.py +++ b/mediagoblin/db/mongo/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/indexes.py b/mediagoblin/db/mongo/indexes.py index 1dd73f2b..a63c24ae 100644 --- a/mediagoblin/db/mongo/indexes.py +++ b/mediagoblin/db/mongo/indexes.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py index 168fa530..261e21a5 100644 --- a/mediagoblin/db/mongo/migrations.py +++ b/mediagoblin/db/mongo/migrations.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 56ed7dcf..541086bc 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/open.py b/mediagoblin/db/mongo/open.py index 48c909d9..bedc497b 100644 --- a/mediagoblin/db/mongo/open.py +++ b/mediagoblin/db/mongo/open.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/mongo/util.py b/mediagoblin/db/mongo/util.py index e2065693..4daf616a 100644 --- a/mediagoblin/db/mongo/util.py +++ b/mediagoblin/db/mongo/util.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/open.py b/mediagoblin/db/open.py index 6cd17869..0163469f 100644 --- a/mediagoblin/db/open.py +++ b/mediagoblin/db/open.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/__init__.py b/mediagoblin/db/sql/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/db/sql/__init__.py +++ b/mediagoblin/db/sql/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index fff71d06..1fc949a6 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 4cf14a70..83602c70 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/edit/__init__.py b/mediagoblin/edit/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/edit/__init__.py +++ b/mediagoblin/edit/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 3e3612fe..46ee02e2 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/edit/lib.py b/mediagoblin/edit/lib.py index a199cbf7..b4715134 100644 --- a/mediagoblin/edit/lib.py +++ b/mediagoblin/edit/lib.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py index 5216f7ca..5bcafeac 100644 --- a/mediagoblin/edit/routing.py +++ b/mediagoblin/edit/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a637d699..a7245517 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/errormiddleware.py b/mediagoblin/errormiddleware.py index ccfe4d03..c6789f32 100644 --- a/mediagoblin/errormiddleware.py +++ b/mediagoblin/errormiddleware.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 04187ff2..db944b3c 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/import_export.py b/mediagoblin/gmg_commands/import_export.py index 7f699429..20cc8fe4 100644 --- a/mediagoblin/gmg_commands/import_export.py +++ b/mediagoblin/gmg_commands/import_export.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/migrate.py b/mediagoblin/gmg_commands/migrate.py index 0a8ee7dc..cacf5d19 100644 --- a/mediagoblin/gmg_commands/migrate.py +++ b/mediagoblin/gmg_commands/migrate.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/shell.py b/mediagoblin/gmg_commands/shell.py index 910560a0..fe15e9f7 100644 --- a/mediagoblin/gmg_commands/shell.py +++ b/mediagoblin/gmg_commands/shell.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py index 4bfe30a5..70e591c9 100644 --- a/mediagoblin/gmg_commands/users.py +++ b/mediagoblin/gmg_commands/users.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/util.py b/mediagoblin/gmg_commands/util.py index 3e26c53f..6a6853d5 100644 --- a/mediagoblin/gmg_commands/util.py +++ b/mediagoblin/gmg_commands/util.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/gmg_commands/wipealldata.py b/mediagoblin/gmg_commands/wipealldata.py index cddbab38..3081bbc0 100644 --- a/mediagoblin/gmg_commands/wipealldata.py +++ b/mediagoblin/gmg_commands/wipealldata.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index 23c1c26d..7ac59db1 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index 1eb21d7a..fb958909 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/init/celery/from_celery.py b/mediagoblin/init/celery/from_celery.py index 05669b67..5a44efe3 100644 --- a/mediagoblin/init/celery/from_celery.py +++ b/mediagoblin/init/celery/from_celery.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/init/celery/from_tests.py b/mediagoblin/init/celery/from_tests.py index 059d829f..3149e1ba 100644 --- a/mediagoblin/init/celery/from_tests.py +++ b/mediagoblin/init/celery/from_tests.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/init/config.py b/mediagoblin/init/config.py index ae232e91..ac4ab9bf 100644 --- a/mediagoblin/init/config.py +++ b/mediagoblin/init/config.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/listings/__init__.py b/mediagoblin/listings/__init__.py index 0c53acf5..3f873e0c 100644 --- a/mediagoblin/listings/__init__.py +++ b/mediagoblin/listings/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/listings/routing.py b/mediagoblin/listings/routing.py index 234f2595..d228a727 100644 --- a/mediagoblin/listings/routing.py +++ b/mediagoblin/listings/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index ca8e8229..48320cb2 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/meddleware/__init__.py b/mediagoblin/meddleware/__init__.py index 7ba70d87..a9c712d7 100644 --- a/mediagoblin/meddleware/__init__.py +++ b/mediagoblin/meddleware/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/meddleware/csrf.py b/mediagoblin/meddleware/csrf.py index a4e4e5c6..ea8372bf 100644 --- a/mediagoblin/meddleware/csrf.py +++ b/mediagoblin/meddleware/csrf.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/meddleware/noop.py b/mediagoblin/meddleware/noop.py index f5376494..98477706 100644 --- a/mediagoblin/meddleware/noop.py +++ b/mediagoblin/meddleware/noop.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index e7eb1dde..5128826b 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py index 21b31d0e..e54427b1 100644 --- a/mediagoblin/media_types/ascii/__init__.py +++ b/mediagoblin/media_types/ascii/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py index 39c75a19..da1a3bcc 100644 --- a/mediagoblin/media_types/ascii/asciitoimage.py +++ b/mediagoblin/media_types/ascii/asciitoimage.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index a74690c1..ec530df6 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py index 3b63d8eb..98e0c32a 100644 --- a/mediagoblin/media_types/image/__init__.py +++ b/mediagoblin/media_types/image/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 78f64be0..769de89b 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py index a970ab01..ed542f16 100644 --- a/mediagoblin/media_types/video/__init__.py +++ b/mediagoblin/media_types/video/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 49a50647..9dc23c55 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 7071b887..6137c3bf 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/messages.py b/mediagoblin/messages.py index 054d46c0..80d8ece7 100644 --- a/mediagoblin/messages.py +++ b/mediagoblin/messages.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/mg_globals.py b/mediagoblin/mg_globals.py index 2d304111..3bd2070d 100644 --- a/mediagoblin/mg_globals.py +++ b/mediagoblin/mg_globals.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index cbac8030..4f1bf61b 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index bd727db5..2ca18cc7 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js index 71466a8d..c5ccee66 100644 --- a/mediagoblin/static/js/comment_show.js +++ b/mediagoblin/static/js/comment_show.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js index 35083d4f..a2c62045 100644 --- a/mediagoblin/static/js/geolocation-map.js +++ b/mediagoblin/static/js/geolocation-map.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js index 513fe327..e42d44ea 100644 --- a/mediagoblin/static/js/show_password.js +++ b/mediagoblin/static/js/show_password.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/staticdirect.py b/mediagoblin/staticdirect.py index 2bddb160..7477de68 100644 --- a/mediagoblin/staticdirect.py +++ b/mediagoblin/staticdirect.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py index 0840614b..e7ea1aa5 100644 --- a/mediagoblin/storage/__init__.py +++ b/mediagoblin/storage/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py index 51b73579..46843274 100644 --- a/mediagoblin/storage/cloudfiles.py +++ b/mediagoblin/storage/cloudfiles.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/storage/filestorage.py b/mediagoblin/storage/filestorage.py index a904865f..00d6335e 100644 --- a/mediagoblin/storage/filestorage.py +++ b/mediagoblin/storage/filestorage.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/storage/mountstorage.py b/mediagoblin/storage/mountstorage.py index 7239931f..3fdf4ef0 100644 --- a/mediagoblin/storage/mountstorage.py +++ b/mediagoblin/storage/mountstorage.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/submit/__init__.py b/mediagoblin/submit/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/submit/__init__.py +++ b/mediagoblin/submit/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 1ff59c18..7d9e8fcf 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/submit/routing.py b/mediagoblin/submit/routing.py index 03e01f45..8ce23cd9 100644 --- a/mediagoblin/submit/routing.py +++ b/mediagoblin/submit/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/submit/security.py b/mediagoblin/submit/security.py index 6708baf7..5dbc0db4 100644 --- a/mediagoblin/submit/security.py +++ b/mediagoblin/submit/security.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 0efee803..cdd097ec 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/404.html b/mediagoblin/templates/mediagoblin/404.html index 392c14f5..5e58d191 100644 --- a/mediagoblin/templates/mediagoblin/404.html +++ b/mediagoblin/templates/mediagoblin/404.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 993790eb..39f07d33 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html index afcfcda9..39c9efff 100644 --- a/mediagoblin/templates/mediagoblin/auth/register.html +++ b/mediagoblin/templates/mediagoblin/auth/register.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/auth/verification_email.txt b/mediagoblin/templates/mediagoblin/auth/verification_email.txt index c54ca353..969ef96a 100644 --- a/mediagoblin/templates/mediagoblin/auth/verification_email.txt +++ b/mediagoblin/templates/mediagoblin/auth/verification_email.txt @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 5335ebe3..f3ebc3fa 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html index bd972b2a..580127fb 100644 --- a/mediagoblin/templates/mediagoblin/edit/attachments.html +++ b/mediagoblin/templates/mediagoblin/edit/attachments.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index fc6b1605..0c4d5bb1 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/edit/edit_account.html b/mediagoblin/templates/mediagoblin/edit/edit_account.html index e8a968e6..1d80debc 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_account.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_account.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index 97c03e37..90862a4f 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/listings/tag.html b/mediagoblin/templates/mediagoblin/listings/tag.html index a7cbe241..4d502201 100644 --- a/mediagoblin/templates/mediagoblin/listings/tag.html +++ b/mediagoblin/templates/mediagoblin/listings/tag.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/media_displays/ascii.html b/mediagoblin/templates/mediagoblin/media_displays/ascii.html index 6b40bf08..6330595b 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/ascii.html +++ b/mediagoblin/templates/mediagoblin/media_displays/ascii.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/media_displays/image.html b/mediagoblin/templates/mediagoblin/media_displays/image.html index 94420e89..7dfecb11 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/image.html +++ b/mediagoblin/templates/mediagoblin/media_displays/image.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index 6b5e7a0e..ec4338fa 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 3f834572..bb12fe4f 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index afae2f1f..31163384 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/test_submit.html b/mediagoblin/templates/mediagoblin/test_submit.html index 38be8efc..0771a0c7 100644 --- a/mediagoblin/templates/mediagoblin/test_submit.html +++ b/mediagoblin/templates/mediagoblin/test_submit.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html index b0bfacf8..e234914f 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html +++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index dec443cd..d2503a4e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index dcb148e0..e64845e7 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html index a14b0123..65549860 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html +++ b/mediagoblin/templates/mediagoblin/user_pages/processing_panel.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index d3b4021d..c74535d7 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html index 9962dd65..0dd187f2 100644 --- a/mediagoblin/templates/mediagoblin/utils/exif.html +++ b/mediagoblin/templates/mediagoblin/utils/exif.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/feed_link.html b/mediagoblin/templates/mediagoblin/utils/feed_link.html index 3afcc844..6a41cef5 100644 --- a/mediagoblin/templates/mediagoblin/utils/feed_link.html +++ b/mediagoblin/templates/mediagoblin/utils/feed_link.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html index ce1edc39..c1909ae5 100644 --- a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html +++ b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 5a268e39..2438ed4e 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/messages.html b/mediagoblin/templates/mediagoblin/utils/messages.html index 9d4dc58a..cb45f59a 100644 --- a/mediagoblin/templates/mediagoblin/utils/messages.html +++ b/mediagoblin/templates/mediagoblin/utils/messages.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 5f628dc7..81506a84 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index caa79fcc..2ac990ae 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 66766555..d0cf3f8c 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/profile.html b/mediagoblin/templates/mediagoblin/utils/profile.html index 9a134e5f..945bd0bb 100644 --- a/mediagoblin/templates/mediagoblin/utils/profile.html +++ b/mediagoblin/templates/mediagoblin/utils/profile.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 1f587411..6408102d 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html index 44b27bb8..a85a3d96 100644 --- a/mediagoblin/templates/mediagoblin/utils/wtforms.html +++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html @@ -1,6 +1,6 @@ {# # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml index 95a1a176..0f5fa7a3 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/host-meta.xml @@ -1,5 +1,5 @@ {# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml index 1fe34577..bb2c5905 100644 --- a/mediagoblin/templates/mediagoblin/webfinger/xrd.xml +++ b/mediagoblin/templates/mediagoblin/webfinger/xrd.xml @@ -1,5 +1,5 @@ {# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py index eac3dff4..15a5add0 100644 --- a/mediagoblin/tests/__init__.py +++ b/mediagoblin/tests/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/fake_celery_module.py b/mediagoblin/tests/fake_celery_module.py index ba347c69..621845ba 100644 --- a/mediagoblin/tests/fake_celery_module.py +++ b/mediagoblin/tests/fake_celery_module.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 411b4539..3a33c66c 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index 19a9b899..c9c77821 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_config.py b/mediagoblin/tests/test_config.py index 0764e12d..c596f6a6 100644 --- a/mediagoblin/tests/test_config.py +++ b/mediagoblin/tests/test_config.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py index c8fca23a..f49dc94e 100644 --- a/mediagoblin/tests/test_csrf_middleware.py +++ b/mediagoblin/tests/test_csrf_middleware.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index 55f34b42..398a5d25 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py index 9f2219c0..bfafe129 100644 --- a/mediagoblin/tests/test_exif.py +++ b/mediagoblin/tests/test_exif.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_globals.py b/mediagoblin/tests/test_globals.py index 84f1c74a..98f6a436 100644 --- a/mediagoblin/tests/test_globals.py +++ b/mediagoblin/tests/test_globals.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_messages.py b/mediagoblin/tests/test_messages.py index 2635f4d7..d3b84828 100644 --- a/mediagoblin/tests/test_messages.py +++ b/mediagoblin/tests/test_messages.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_migrations.py b/mediagoblin/tests/test_migrations.py index 8e573f5a..f6e6c1a8 100644 --- a/mediagoblin/tests/test_migrations.py +++ b/mediagoblin/tests/test_migrations.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_misc.py b/mediagoblin/tests/test_misc.py index 09623355..94ae5a51 100644 --- a/mediagoblin/tests/test_misc.py +++ b/mediagoblin/tests/test_misc.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py index eab4d032..6fc2e57c 100644 --- a/mediagoblin/tests/test_storage.py +++ b/mediagoblin/tests/test_storage.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index b3c11249..e31a7783 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -1,6 +1,6 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py index 583c1a55..79f925aa 100644 --- a/mediagoblin/tests/test_tags.py +++ b/mediagoblin/tests/test_tags.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_tests.py b/mediagoblin/tests/test_tests.py index 25bb52b3..20832ac7 100644 --- a/mediagoblin/tests/test_tests.py +++ b/mediagoblin/tests/test_tests.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py index 48fa8669..452090e1 100644 --- a/mediagoblin/tests/test_util.py +++ b/mediagoblin/tests/test_util.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_workbench.py b/mediagoblin/tests/test_workbench.py index 977d64b9..b5243a9b 100644 --- a/mediagoblin/tests/test_workbench.py +++ b/mediagoblin/tests/test_workbench.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 49a3d33e..7cf355b0 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/exif.py b/mediagoblin/tools/exif.py index 3c1aebe5..de6dd128 100644 --- a/mediagoblin/tools/exif.py +++ b/mediagoblin/tools/exif.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/files.py b/mediagoblin/tools/files.py index 10f1d994..b2f316b2 100644 --- a/mediagoblin/tools/files.py +++ b/mediagoblin/tools/files.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/licenses.py b/mediagoblin/tools/licenses.py index 0ff6453b..48cb442b 100644 --- a/mediagoblin/tools/licenses.py +++ b/mediagoblin/tools/licenses.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/mail.py b/mediagoblin/tools/mail.py index 9e00be7d..655d5b99 100644 --- a/mediagoblin/tools/mail.py +++ b/mediagoblin/tools/mail.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/pagination.py b/mediagoblin/tools/pagination.py index 5ebc3c5a..ff7d4cad 100644 --- a/mediagoblin/tools/pagination.py +++ b/mediagoblin/tools/pagination.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/request.py b/mediagoblin/tools/request.py index 7e193125..a45f716a 100644 --- a/mediagoblin/tools/request.py +++ b/mediagoblin/tools/request.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py index c905097c..a54c32fb 100644 --- a/mediagoblin/tools/response.py +++ b/mediagoblin/tools/response.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index 54a40de6..72c87a99 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/testing.py b/mediagoblin/tools/testing.py index 39435ca5..7f2bcbfb 100644 --- a/mediagoblin/tools/testing.py +++ b/mediagoblin/tools/testing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/text.py b/mediagoblin/tools/text.py index d576224d..82de8a48 100644 --- a/mediagoblin/tools/text.py +++ b/mediagoblin/tools/text.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/translate.py b/mediagoblin/tools/translate.py index b99c4aa4..33ee889a 100644 --- a/mediagoblin/tools/translate.py +++ b/mediagoblin/tools/translate.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/user_pages/__init__.py b/mediagoblin/user_pages/__init__.py index ba347c69..621845ba 100644 --- a/mediagoblin/user_pages/__init__.py +++ b/mediagoblin/user_pages/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index e04fd559..acfbadab 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 3586d9cd..f9780edc 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 29360e23..ba499731 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -1,5 +1,5 @@ # MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 1e1db6c3..9d34750b 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/webfinger/__init__.py b/mediagoblin/webfinger/__init__.py index ec7ec884..126e6ea2 100644 --- a/mediagoblin/webfinger/__init__.py +++ b/mediagoblin/webfinger/__init__.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/webfinger/routing.py b/mediagoblin/webfinger/routing.py index effb2bf2..7e84a00a 100644 --- a/mediagoblin/webfinger/routing.py +++ b/mediagoblin/webfinger/routing.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/webfinger/views.py b/mediagoblin/webfinger/views.py index 22086396..97fc3ef7 100644 --- a/mediagoblin/webfinger/views.py +++ b/mediagoblin/webfinger/views.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/workbench.py b/mediagoblin/workbench.py index 9578494c..2331b551 100644 --- a/mediagoblin/workbench.py +++ b/mediagoblin/workbench.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by -- cgit v1.2.3 From 3f1dc64ed15a8f1f9141338561028efc6758bdf2 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 2 Feb 2012 19:54:47 +0100 Subject: Added extensions 'asc' and 'nfo' to ASCII media type --- mediagoblin/media_types/ascii/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py index e54427b1..1c8ca562 100644 --- a/mediagoblin/media_types/ascii/__init__.py +++ b/mediagoblin/media_types/ascii/__init__.py @@ -24,4 +24,4 @@ MEDIA_MANAGER = { "display_template": "mediagoblin/media_displays/ascii.html", "default_thumb": "images/media_thumbs/ascii.jpg", "accepted_extensions": [ - "txt"]} + "txt", "asc", "nfo"]} -- cgit v1.2.3 From 010d28b4f0a39103949692209106a1b47fceeaf2 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 2 Feb 2012 21:28:21 +0100 Subject: ASCII art support - Fixes - Improved(?) character set detection, chardet will not win over UTF-8 unless it is >= 90% sure. - Changed the unicode.txt to ascii-portable.txt, since there is no unicode in the file. - etc. --- mediagoblin/media_types/ascii/asciitoimage.py | 26 ++++++-------------------- mediagoblin/media_types/ascii/processing.py | 22 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py index da1a3bcc..186d8066 100644 --- a/mediagoblin/media_types/ascii/asciitoimage.py +++ b/mediagoblin/media_types/ascii/asciitoimage.py @@ -65,7 +65,8 @@ class AsciiToImage(object): self._if = ImageFont.truetype( self._font, - self._font_size) + self._font_size, + encoding='unic') # ,-,-^-'-^'^-^'^-'^-. # ( I am a wall socket )Oo, ___ @@ -91,6 +92,9 @@ class AsciiToImage(object): - Character set detection and decoding, http://pypi.python.org/pypi/chardet ''' + # Convert the input from str to unicode + text = text.decode('utf-8') + # TODO: Account for alternative line endings lines = text.split('\n') @@ -123,7 +127,7 @@ class AsciiToImage(object): px_pos = self._px_pos(char_pos) - _log.debug('Writing character "{0}" at {1} (px pos {2}'.format( + _log.debug('Writing character "{0}" at {1} (px pos {2})'.format( char, char_pos, px_pos)) @@ -152,21 +156,3 @@ class AsciiToImage(object): px_pos[index] = char_pos[index] * self._if_dims[index] return px_pos - - -if __name__ == "__main__": - import urllib - txt = urllib.urlopen('file:///home/joar/Dropbox/ascii/install-all-the-dependencies.txt') - - _log.setLevel(logging.DEBUG) - logging.basicConfig() - - converter = AsciiToImage() - - converter.convert(txt.read(), '/tmp/test.png') - - ''' - im, x, y, duration = renderImage(h, 10) - print "Rendered image in %.5f seconds" % duration - im.save('tldr.png', "PNG") - ''' diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index ec530df6..96dfce80 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -17,10 +17,12 @@ import asciitoimage import chardet import os import Image +import logging from mediagoblin import mg_globals as mgg from mediagoblin.processing import create_pub_filepath, THUMB_SIZE +_log = logging.getLogger(__name__) def process_ascii(entry): ''' @@ -42,6 +44,17 @@ def process_ascii(entry): with queued_file: queued_file_charset = chardet.detect(queued_file.read()) + # Only select a non-utf-8 charset if chardet is *really* sure + # Tested with "Feli\x0109an superjaron", which was detecte + if queued_file_charset['confidence'] < 0.9: + interpreted_charset = 'utf-8' + else: + interpreted_charset = queued_file_charset['encoding'] + + _log.info('Charset detected: {0}\nWill interpret as: {1}'.format( + queued_file_charset, + interpreted_charset)) + queued_file.seek(0) # Rewind the queued file thumb_filepath = create_pub_filepath( @@ -73,13 +86,16 @@ def process_ascii(entry): queued_file.seek(0) # Rewind *again* - unicode_filepath = create_pub_filepath(entry, 'unicode.txt') + unicode_filepath = create_pub_filepath(entry, 'ascii-portable.txt') with mgg.public_store.get_file(unicode_filepath, 'wb') \ as unicode_file: + # Decode the original file from its detected charset (or UTF8) + # Encode the unicode instance to ASCII and replace any non-ASCII + # with an HTML entity (&# unicode_file.write( - unicode(queued_file.read().decode( - queued_file_charset['encoding'])).encode( + unicode(queued_file.read().decode( + interpreted_charset)).encode( 'ascii', 'xmlcharrefreplace')) -- cgit v1.2.3 From 64da09e86a755e49832e3c324582c65d352632d4 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 4 Feb 2012 20:51:05 +0100 Subject: ASCII media support - Fixes - Added debug logging in - mediagoblin.processing - mediagoblin.media_types.ascii.processing - mediagoblin.media_types.ascii.asciitoimage --- mediagoblin/media_types/ascii/asciitoimage.py | 11 ++++++----- mediagoblin/media_types/ascii/processing.py | 1 + mediagoblin/processing.py | 12 +++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py index 186d8066..e1c4fb44 100644 --- a/mediagoblin/media_types/ascii/asciitoimage.py +++ b/mediagoblin/media_types/ascii/asciitoimage.py @@ -59,15 +59,15 @@ class AsciiToImage(object): if kw.get('font_size'): self._font_size = kw.get('font_size') - _log.info('Setting font to {0}, size {1}'.format( - self._font, - self._font_size)) - self._if = ImageFont.truetype( self._font, self._font_size, encoding='unic') + _log.info('Font set to {0}, size {1}'.format( + self._font, + self._font_size)) + # ,-,-^-'-^'^-^'^-'^-. # ( I am a wall socket )Oo, ___ # `-.,.-.,.-.-.,.-.--' ' ` @@ -92,6 +92,7 @@ class AsciiToImage(object): - Character set detection and decoding, http://pypi.python.org/pypi/chardet ''' + _log.debug('Drawing image') # Convert the input from str to unicode text = text.decode('utf-8') @@ -128,7 +129,7 @@ class AsciiToImage(object): px_pos = self._px_pos(char_pos) _log.debug('Writing character "{0}" at {1} (px pos {2})'.format( - char, + char.encode('ascii', 'replace'), char_pos, px_pos)) diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index 96dfce80..837b9830 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -72,6 +72,7 @@ def process_ascii(entry): thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) thumb.save(thumb_file) + _log.debug('Copying local file to public storage') mgg.public_store.copy_local_to_storage( tmp_thumb_filename, thumb_filepath) diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index 4f1bf61b..9e57380d 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import logging + from celery.task import Task from mediagoblin.db.util import ObjectId @@ -23,6 +25,7 @@ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from mediagoblin.media_types import get_media_manager +_log = logging.getLogger(__name__) THUMB_SIZE = 180, 180 MEDIUM_SIZE = 640, 640 @@ -57,12 +60,19 @@ class ProcessMedia(Task): try: #__import__(entry.media_type) manager = get_media_manager(entry.media_type) + _log.debug('Processing {0}'.format(entry)) manager['processor'](entry) except BaseProcessingFail, exc: mark_entry_failed(entry._id, exc) return except ImportError, exc: - mark_entry_failed(entry[u'_id'], exc) + _log.error( + 'Entry {0} failed to process due to an import error: {1}'\ + .format( + entry.title, + exc)) + + mark_entry_failed(entry._id, exc) entry.state = u'processed' entry.save() -- cgit v1.2.3 From ccca39f1d8a397f20d56406540785931ef7c419f Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 4 Feb 2012 20:54:14 +0100 Subject: Fix EXIF based image rotation test The test checks for a pixel value after rotation (good idea!). But the value seems to be a bit different on some platforms, so use a list of seen values. Not the perfect solution, but it works. --- mediagoblin/tests/test_exif.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py index bfafe129..ed95045c 100644 --- a/mediagoblin/tests/test_exif.py +++ b/mediagoblin/tests/test_exif.py @@ -21,6 +21,11 @@ import Image from mediagoblin.tools.exif import exif_fix_image_orientation, \ extract_exif, clean_exif, get_gps_data, get_useful + +def assert_in(a, b): + assert a in b, "%r not in %r" % (a, b) + + GOOD_JPG = pkg_resources.resource_filename( 'mediagoblin.tests', os.path.join( @@ -42,6 +47,7 @@ GPS_JPG = pkg_resources.resource_filename( 'test_exif', 'has-gps.jpg')) + def test_exif_extraction(): ''' Test EXIF extraction from a good image @@ -130,6 +136,7 @@ def test_exif_extraction(): 32, 32, 32], 'field_length': 44}} + def test_exif_image_orientation(): ''' Test image reorientation based on EXIF data @@ -144,7 +151,10 @@ def test_exif_image_orientation(): assert image.size == (428, 640) # If this pixel looks right, the rest of the image probably will too. - assert image.getdata()[10000] == (41, 28, 11) + assert_in(image.getdata()[10000], + ((41, 28, 11), (43, 27, 11)) + ) + def test_exif_no_exif(): ''' @@ -160,6 +170,7 @@ def test_exif_no_exif(): assert gps == {} assert useful == {} + def test_exif_bad_image(): ''' Test EXIF extraction from a faithful, but bad image @@ -174,6 +185,7 @@ def test_exif_bad_image(): assert gps == {} assert useful == {} + def test_exif_gps_data(): ''' Test extractiion of GPS data @@ -186,4 +198,3 @@ def test_exif_gps_data(): 'direction': 25.674046740467404, 'altitude': 37.64365671641791, 'longitude': 18.016166666666667} - -- cgit v1.2.3 From 1eb0bd71c54e9552116c02b40667ef2b05f805ff Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 5 Feb 2012 16:21:14 -0600 Subject: Committing present MediaGoblin translations before pushing extracted messages --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 73 ++++++++++++++++---------- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 41 +++++++++------ mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po | 19 ++++--- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 52 +++++++++++------- 4 files changed, 114 insertions(+), 71 deletions(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po index 381005a8..e435971a 100644 --- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ # Elrond , 2011, 2012. # , 2011, 2012. # Jan-Christoph Borchardt , 2011. -# Jan-Christoph Borchardt , 2011. +# Jan-Christoph Borchardt , 2011, 2012. # , 2011. # , 2011. # Rafael Maguiña , 2011. @@ -16,10 +16,10 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" -"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-29 13:31-0600\n" -"PO-Revision-Date: 2012-01-29 19:44+0000\n" -"Last-Translator: Elrond \n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2012-01-29 13:47-0600\n" +"PO-Revision-Date: 2012-02-05 20:23+0000\n" +"Last-Translator: Jan-Christoph Borchardt \n" "Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -84,6 +84,8 @@ msgstr "Bestätigungs-E-Mail wurde erneut versandt." msgid "" "An email has been sent with instructions on how to change your password." msgstr "" +"Es wurde eine Email mit Anweisungen für die Änderung des Passwortes an dich " +"gesendet." #: mediagoblin/auth/views.py:270 msgid "" @@ -96,11 +98,11 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." -msgstr "" +msgstr "Es konnte niemand mit diesem Nutzernamen oder Email gefunden werden." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Du kannst dich jetzt mit deinem neuen Passwort anmelden." #: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" @@ -117,10 +119,13 @@ msgid "" " \n" " Markdown for formatting." msgstr "" +"Für Formatierung kannst du\n" +" \n" +" Markdown benutzen." #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" -msgstr "Markierungen" +msgstr "Schlagworte" #: mediagoblin/edit/forms.py:35 mediagoblin/submit/forms.py:38 msgid "Separate tags by commas." @@ -161,6 +166,7 @@ msgstr "Altes Passwort" #: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" +"Gib dein altes Passwort ein, um zu bestätigen dass du dieses Konto besitzt." #: mediagoblin/edit/forms.py:68 msgid "New password" @@ -188,15 +194,15 @@ msgstr "Falsches Passwort" #: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "Kontoeinstellungen gespeichert" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "Es konnten keine Dateierweiterungen von »{filename}« gelesen werden." #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Entschuldigung, dieser Dateityp wird nicht unterstützt." #: mediagoblin/submit/forms.py:26 msgid "File" @@ -306,11 +312,11 @@ msgstr "Neuste Medien" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Dein neues Passwort" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Passwort setzen" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -400,7 +406,7 @@ msgstr "Änderungen speichern" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "%(username)s's Kontoeinstellungen werden geändert" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -411,7 +417,7 @@ msgstr "%(username)ss Profil bearbeiten" #: mediagoblin/templates/mediagoblin/listings/tag.html:35 #, python-format msgid "Media tagged with: %(tag_name)s" -msgstr "Medien markiert mit: %(tag_name)s" +msgstr "Medien mit Schlagwort: %(tag_name)s" #: mediagoblin/templates/mediagoblin/media_displays/ascii.html:34 #: mediagoblin/templates/mediagoblin/media_displays/video.html:46 @@ -424,6 +430,9 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Entschuldige, dieses Video wird nicht funktionieren weil \n" +"» dein Webbrowser kein HTML5 \n" +"» Video unterstützt." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -431,14 +440,17 @@ msgid "" "\t can play this video at \n" "\t http://getfirefox.com!" msgstr "" +"Hol dir einen modernen Webbrowser, der \n" +"» dieses Video abspielen kann, \n" +"» Firefox!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" -msgstr "" +msgstr "Deine Medien" #: mediagoblin/templates/mediagoblin/submit/start.html:30 msgid "Add" -msgstr "" +msgstr "Hinzufügen" #: mediagoblin/templates/mediagoblin/user_pages/gallery.html:30 #, python-format @@ -453,7 +465,7 @@ msgstr "%(username)ss Medien" #: mediagoblin/templates/mediagoblin/user_pages/media.html:72 #, python-format msgid "Added on %(date)s." -msgstr "" +msgstr "Hinzugefügt am %(date)s." #: mediagoblin/templates/mediagoblin/user_pages/media.html:81 msgid "Edit" @@ -475,11 +487,11 @@ msgstr "%(comment_count)s Kommentare" #: mediagoblin/templates/mediagoblin/user_pages/media.html:95 msgid "No comments yet." -msgstr "" +msgstr "Bisher keine Kommentare." #: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "" +msgstr "Kommentiere etwas" #: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" @@ -487,10 +499,13 @@ msgid "" "href=\"http://daringfireball.net/projects/markdown/basics\">Markdown for" " formatting." msgstr "" +"Für Formatierung kannst du Markdown " +"benutzen." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" -msgstr "" +msgstr "Kommentar absenden" #: mediagoblin/templates/mediagoblin/user_pages/media.html:138 msgid "at" @@ -499,7 +514,7 @@ msgstr "bei" #: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " -msgstr "" +msgstr "

    ❖ Medien von %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -600,7 +615,7 @@ msgstr "Dieser Benutzer hat (noch) keine Daten in seinem Profil." #: mediagoblin/templates/mediagoblin/user_pages/user.html:125 msgid "Change account settings" -msgstr "" +msgstr "Kontoeinstellungen ändern" #: mediagoblin/templates/mediagoblin/user_pages/user.html:138 #, python-format @@ -628,11 +643,11 @@ msgstr "Atom-Feed" #: mediagoblin/templates/mediagoblin/utils/license.html:21 msgid "License:" -msgstr "" +msgstr "Lizenz:" #: mediagoblin/templates/mediagoblin/utils/license.html:25 msgid "All rights reserved" -msgstr "" +msgstr "Alle Rechte vorbehalten" #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" @@ -649,16 +664,16 @@ msgstr "Zu Seite:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "neuer" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "älter" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" -msgstr "" +msgstr "Mehr Medien anschauen mit dem Schlagwort" #: mediagoblin/templates/mediagoblin/utils/tags.html:25 msgid "or" @@ -666,7 +681,7 @@ msgstr "oder" #: mediagoblin/tools/exif.py:68 msgid "Could not read the image file." -msgstr "" +msgstr "Die Bilddatei konnte nicht gelesen werden." #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index a98409ac..49626556 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -9,10 +9,10 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" -"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-29 13:31-0600\n" -"PO-Revision-Date: 2012-01-29 19:29+0000\n" -"Last-Translator: cwebber \n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2012-01-29 13:47-0600\n" +"PO-Revision-Date: 2012-02-05 21:07+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -109,6 +109,9 @@ msgid "" " \n" " Markdown for formatting." msgstr "" +"Vi povas uzi por markado la lingvon\n" +" «\n" +" Markdown»." #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" @@ -136,7 +139,7 @@ msgstr "" #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" -msgstr "" +msgstr "Permesilo" #: mediagoblin/edit/forms.py:50 msgid "Bio" @@ -184,7 +187,7 @@ msgstr "Kontagordoj estis konservitaj" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "Ne eblis eltrovi finaĵon de la dosiernomo «{filename}»" #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" @@ -289,6 +292,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"Kreu konton en ĉi tiu retejo\n" +" aŭ\n" +" ekfunkciigu MediaGoblin’on en via propra servilo" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -296,11 +302,11 @@ msgstr "Laste aldonitaj dosieroj" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Enigu vian novan pasvorton" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Difini pasvorton" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -475,7 +481,7 @@ msgstr "Estas neniom da komentoj." #: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "Aldoni sian." +msgstr "Komenti" #: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" @@ -483,6 +489,8 @@ msgid "" "href=\"http://daringfireball.net/projects/markdown/basics\">Markdown for" " formatting." msgstr "" +"Vi povas uzi por markado la lingvon «<a " +"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a>»." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" @@ -496,6 +504,7 @@ msgstr "je" #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" +"

    ❖ Foliumado de dosieraro de %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -623,19 +632,19 @@ msgstr "Atom-a informfluo" #: mediagoblin/templates/mediagoblin/utils/license.html:21 msgid "License:" -msgstr "" +msgstr "Permesilo:" #: mediagoblin/templates/mediagoblin/utils/license.html:25 msgid "All rights reserved" -msgstr "" +msgstr "Ĉiuj rajtoj estas rezervitaj" #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" -msgstr "" +msgstr "← Pli novaj" #: mediagoblin/templates/mediagoblin/utils/pagination.html:45 msgid "Older →" -msgstr "" +msgstr "Malpli novaj →" #: mediagoblin/templates/mediagoblin/utils/pagination.html:48 msgid "Go to page:" @@ -644,12 +653,12 @@ msgstr "Iri al paĝo:" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:27 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:32 msgid "newer" -msgstr "" +msgstr "pli nova" #: mediagoblin/templates/mediagoblin/utils/prev_next.html:38 #: mediagoblin/templates/mediagoblin/utils/prev_next.html:43 msgid "older" -msgstr "" +msgstr "malpli nova" #: mediagoblin/templates/mediagoblin/utils/tags.html:20 msgid "View more media tagged with" @@ -661,7 +670,7 @@ msgstr "aŭ" #: mediagoblin/tools/exif.py:68 msgid "Could not read the image file." -msgstr "" +msgstr "Malsukcesis lego de la bildodosiero" #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po index c70bb19e..c40671e6 100644 --- a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.po @@ -7,10 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" -"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-29 13:31-0600\n" -"PO-Revision-Date: 2012-01-29 19:29+0000\n" -"Last-Translator: cwebber \n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2012-01-29 13:47-0600\n" +"PO-Revision-Date: 2012-02-05 20:14+0000\n" +"Last-Translator: schendje \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -140,7 +140,7 @@ msgstr "" #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" -msgstr "" +msgstr "Licentie" #: mediagoblin/edit/forms.py:50 msgid "Bio" @@ -488,6 +488,9 @@ msgid "" "href=\"http://daringfireball.net/projects/markdown/basics\">Markdown for" " formatting." msgstr "" +"Voor opmaak kun je <a " +"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a>" +" gebruiken." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" @@ -630,11 +633,11 @@ msgstr "Atom feed" #: mediagoblin/templates/mediagoblin/utils/license.html:21 msgid "License:" -msgstr "" +msgstr "Licentie:" #: mediagoblin/templates/mediagoblin/utils/license.html:25 msgid "All rights reserved" -msgstr "" +msgstr "Alle rechten voorbehouden" #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" @@ -668,7 +671,7 @@ msgstr "of" #: mediagoblin/tools/exif.py:68 msgid "Could not read the image file." -msgstr "" +msgstr "Kon het afbeeldingsbestand niet lezen." #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index 91329920..d895f3bf 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -7,10 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" -"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" -"POT-Creation-Date: 2012-01-29 13:31-0600\n" -"PO-Revision-Date: 2012-01-29 19:29+0000\n" -"Last-Translator: cwebber \n" +"Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" +"POT-Creation-Date: 2012-01-29 13:47-0600\n" +"PO-Revision-Date: 2012-02-05 21:04+0000\n" +"Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -76,7 +76,7 @@ msgstr "Переслать сообщение с подтверждением а #: mediagoblin/auth/views.py:260 msgid "" "An email has been sent with instructions on how to change your password." -msgstr "" +msgstr "Вам отправлено электронное письмо с инструкциями по смене пароля." #: mediagoblin/auth/views.py:270 msgid "" @@ -90,10 +90,11 @@ msgstr "" #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." msgstr "" +"Не найдено никого с таким именем пользователя или адресом электронной почты." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." -msgstr "" +msgstr "Теперь вы можете войти, используя ваш новый пароль." #: mediagoblin/edit/forms.py:25 mediagoblin/submit/forms.py:28 msgid "Title" @@ -110,6 +111,9 @@ msgid "" " \n" " Markdown for formatting." msgstr "" +"Для разметки можете использовать язык\n" +" \n" +" Markdown." #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" @@ -137,7 +141,7 @@ msgstr "" #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" -msgstr "" +msgstr "Лицензия" #: mediagoblin/edit/forms.py:50 msgid "Bio" @@ -154,6 +158,8 @@ msgstr "Старый пароль" #: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." msgstr "" +"Введите свой старый пароль в качестве доказательства, что это ваша учётная " +"запись." #: mediagoblin/edit/forms.py:68 msgid "New password" @@ -174,7 +180,7 @@ msgstr "Вы редактируете профиль пользователя. #: mediagoblin/edit/views.py:180 msgid "Profile changes saved" -msgstr "" +msgstr "Изменения профиля сохранены" #: mediagoblin/edit/views.py:206 msgid "Wrong password" @@ -182,15 +188,15 @@ msgstr "Неправильный пароль" #: mediagoblin/edit/views.py:222 msgid "Account settings saved" -msgstr "" +msgstr "Настройки учётной записи записаны" #: mediagoblin/media_types/__init__.py:77 msgid "Could not extract any file extension from \"{filename}\"" -msgstr "" +msgstr "Не удалось найти расширение в имени файла «{filename}»" #: mediagoblin/media_types/__init__.py:88 msgid "Sorry, I don't support that file type :(" -msgstr "" +msgstr "Увы, я не поддерживаю этот тип файлов :(" #: mediagoblin/submit/forms.py:26 msgid "File" @@ -289,6 +295,9 @@ msgid "" " or\n" " Set up MediaGoblin on your own server" msgstr "" +"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Создайте учётную запись на этом сайте</a>\n" +" или\n" +" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">установите MediaGoblin на собственный сервер</a>" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -296,11 +305,11 @@ msgstr "Самые новые файлы" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:32 msgid "Set your new password" -msgstr "" +msgstr "Введите свой новый пароль" #: mediagoblin/templates/mediagoblin/auth/change_fp.html:35 msgid "Set password" -msgstr "" +msgstr "Установить пароль" #: mediagoblin/templates/mediagoblin/auth/forgot_password.html:27 msgid "Recover password" @@ -392,7 +401,7 @@ msgstr "Сохранить изменения" #: mediagoblin/templates/mediagoblin/edit/edit_account.html:34 #, python-format msgid "Changing %(username)s's account settings" -msgstr "" +msgstr "Настройка учётной записи %(username)s" #: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29 #, python-format @@ -416,6 +425,9 @@ msgid "" "\t your web browser does not support HTML5 \n" "\t video." msgstr "" +"Сожалеем, этот ролик не проиграется, ⏎\n" +"» потому что ваш браузер не поддерживает ⏎\n" +"» видео в соответствии со стандартом HTML5." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" @@ -474,7 +486,7 @@ msgstr "Комментариев пока нет." #: mediagoblin/templates/mediagoblin/user_pages/media.html:103 msgid "Add one" -msgstr "Добавить свой" +msgstr "Комментировать" #: mediagoblin/templates/mediagoblin/user_pages/media.html:112 msgid "" @@ -482,6 +494,8 @@ msgid "" "href=\"http://daringfireball.net/projects/markdown/basics\">Markdown for" " formatting." msgstr "" +"Для разметки можете использовать язык Markdown." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" @@ -495,6 +509,8 @@ msgstr "в" #, python-format msgid "

    ❖ Browsing media by %(username)s

    " msgstr "" +"

    ❖ Просмотр файлов пользователя %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -620,11 +636,11 @@ msgstr "лента в формате Atom" #: mediagoblin/templates/mediagoblin/utils/license.html:21 msgid "License:" -msgstr "" +msgstr "Лицензия:" #: mediagoblin/templates/mediagoblin/utils/license.html:25 msgid "All rights reserved" -msgstr "" +msgstr "Все права сохранены" #: mediagoblin/templates/mediagoblin/utils/pagination.html:39 msgid "← Newer" @@ -658,7 +674,7 @@ msgstr "или" #: mediagoblin/tools/exif.py:68 msgid "Could not read the image file." -msgstr "" +msgstr "Не удалось прочитать файл с изображением." #: mediagoblin/user_pages/forms.py:30 msgid "I am sure I want to delete this" -- cgit v1.2.3 From 56d1ebdf2968bd5888296bee43d9640ec4b1c5e5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 5 Feb 2012 16:23:18 -0600 Subject: Committing present MediaGoblin translations before pushing extracted messages --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index eca38526..23225ed8 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-01-29 13:47-0600\n" +"POT-Creation-Date: 2012-02-05 16:21-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.6\n" -#: mediagoblin/processing.py:143 +#: mediagoblin/processing.py:153 msgid "Invalid file given for media type." msgstr "" -- cgit v1.2.3 From 110b4acc3d1e10931b3464f37d5f3bec08d64ede Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 5 Feb 2012 16:23:29 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 13630 -> 14018 bytes mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 2 +- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 13752 -> 13840 bytes mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo | Bin 13516 -> 13526 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 17134 -> 18051 bytes 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo index a63886d8..e3ba1606 100644 Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 23225ed8..57dd7eb0 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-02-05 16:21-0600\n" +"POT-Creation-Date: 2012-02-05 16:23-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 63cf7739..25ab5836 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo index 455849b2..0baae15d 100644 Binary files a/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/nl/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index 9c1f739c..dd7735fd 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ -- cgit v1.2.3 From 473a4431c2632891e152913c7b4eed6fe7ba8bb3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 7 Feb 2012 21:25:41 -0600 Subject: Added CC0 header to all MediaGoblin docs in docs/source/ --- docs/source/about.rst | 13 +++++++++++++ docs/source/codebase.rst | 13 +++++++++++++ docs/source/configuration.rst | 13 +++++++++++++ docs/source/deploying.rst | 13 +++++++++++++ docs/source/foreword.rst | 13 +++++++++++++ docs/source/help.rst | 13 +++++++++++++ docs/source/index.rst | 13 +++++++++++++ docs/source/media-types.rst | 13 +++++++++++++ docs/source/production-deployments.rst | 13 +++++++++++++ docs/source/theming.rst | 13 +++++++++++++ 10 files changed, 130 insertions(+) diff --git a/docs/source/about.rst b/docs/source/about.rst index 1a2df809..7a6aa510 100644 --- a/docs/source/about.rst +++ b/docs/source/about.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + ======================= About GNU MediaGoblin ======================= diff --git a/docs/source/codebase.rst b/docs/source/codebase.rst index 28d73802..2518e48f 100644 --- a/docs/source/codebase.rst +++ b/docs/source/codebase.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + .. _codebase-chapter: ======================== diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index 1e22ad2d..6596cef4 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + .. _configuration-chapter: ======================== diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst index a8ee6ff1..ce39dc4e 100644 --- a/docs/source/deploying.rst +++ b/docs/source/deploying.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + ===================== Deploying MediaGoblin ===================== diff --git a/docs/source/foreword.rst b/docs/source/foreword.rst index aa27647f..be0c84b8 100644 --- a/docs/source/foreword.rst +++ b/docs/source/foreword.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + ======== Foreword ======== diff --git a/docs/source/help.rst b/docs/source/help.rst index 34d4f37e..4b584ac1 100644 --- a/docs/source/help.rst +++ b/docs/source/help.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + ================================== How to Get Help with MediaGoblin ================================== diff --git a/docs/source/index.rst b/docs/source/index.rst index f9c9285d..444ed688 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + .. GNU MediaGoblin documentation master file, created by sphinx-quickstart on Thu Apr 7 20:10:27 2011. You can adapt this file completely to your liking, but it should at least diff --git a/docs/source/media-types.rst b/docs/source/media-types.rst index 76478143..86409b55 100644 --- a/docs/source/media-types.rst +++ b/docs/source/media-types.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + .. _media-types-chapter: ==================== diff --git a/docs/source/production-deployments.rst b/docs/source/production-deployments.rst index ef0bcad6..1e6631db 100644 --- a/docs/source/production-deployments.rst +++ b/docs/source/production-deployments.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + ========================================= Considerations for Production Deployments ========================================= diff --git a/docs/source/theming.rst b/docs/source/theming.rst index 2f4fcb4c..7584b688 100644 --- a/docs/source/theming.rst +++ b/docs/source/theming.rst @@ -1,3 +1,16 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + . + .. _theming-chapter: ===================== -- cgit v1.2.3 From c2dfe1dd4090ef40eeb615d09c4607e6d5853994 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 8 Feb 2012 09:29:24 -0600 Subject: Fully qualify the import of asciitoimage --- mediagoblin/media_types/ascii/processing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index 837b9830..7ece866e 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -13,7 +13,6 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import asciitoimage import chardet import os import Image @@ -21,6 +20,7 @@ import logging from mediagoblin import mg_globals as mgg from mediagoblin.processing import create_pub_filepath, THUMB_SIZE +from mediagoblin.media_types.ascii import asciitoimage _log = logging.getLogger(__name__) -- cgit v1.2.3 From 7f4ebeed7677a229f539bd2eaa78f9783dfc1477 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 8 Feb 2012 10:46:33 -0500 Subject: Fix copyright statements; add LICENSE for EXIF.py --- extlib/exif/LICENSE | 1 + mediagoblin/db/mixin.py | 2 +- mediagoblin/db/sql/base.py | 2 +- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/extratypes.py | 2 +- mediagoblin/db/sql/fake.py | 2 +- mediagoblin/db/sql/models.py | 2 +- mediagoblin/db/sql/open.py | 2 +- mediagoblin/tests/test_cache.py | 2 +- mediagoblin/tests/test_submission.py | 1 - mediagoblin/tools/common.py | 2 +- mediagoblin/tools/url.py | 2 +- mediagoblin/user_pages/views.py | 2 +- runtests.sh | 2 +- setup.py | 2 +- 15 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 extlib/exif/LICENSE diff --git a/extlib/exif/LICENSE b/extlib/exif/LICENSE new file mode 100644 index 00000000..3bd77141 --- /dev/null +++ b/extlib/exif/LICENSE @@ -0,0 +1 @@ +See top of EXIF.py for license and copyright. diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 254dbcff..beaff9b0 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index f1affc83..6ed24a03 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 260328c6..f6575be9 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py index 21c806ec..3a594728 100644 --- a/mediagoblin/db/sql/extratypes.py +++ b/mediagoblin/db/sql/extratypes.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/fake.py b/mediagoblin/db/sql/fake.py index 482b85da..0fd0cc41 100644 --- a/mediagoblin/db/sql/fake.py +++ b/mediagoblin/db/sql/fake.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 7ec05876..36f94b25 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/db/sql/open.py b/mediagoblin/db/sql/open.py index 3c06c676..1bfc5538 100644 --- a/mediagoblin/db/sql/open.py +++ b/mediagoblin/db/sql/open.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011,2012 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_cache.py b/mediagoblin/tests/test_cache.py index cbffeb84..48fa1386 100644 --- a/mediagoblin/tests/test_cache.py +++ b/mediagoblin/tests/test_cache.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index e31a7783..217926a4 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -1,4 +1,3 @@ - # GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # diff --git a/mediagoblin/tools/common.py b/mediagoblin/tools/common.py index 12d8309e..0b29087c 100644 --- a/mediagoblin/tools/common.py +++ b/mediagoblin/tools/common.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/tools/url.py b/mediagoblin/tools/url.py index 78b5dd63..7477173a 100644 --- a/mediagoblin/tools/url.py +++ b/mediagoblin/tools/url.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index ba499731..82791278 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -1,4 +1,4 @@ -# MediaGoblin -- federated, autonomous media hosting +# GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify diff --git a/runtests.sh b/runtests.sh index 4265326c..94e77da2 100755 --- a/runtests.sh +++ b/runtests.sh @@ -1,7 +1,7 @@ #!/bin/sh # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/setup.py b/setup.py index ca7d4ae2..9dd8964a 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by -- cgit v1.2.3 From 0c8e20cf13db50f2e51ade41e204ae5e0501e4e5 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Wed, 8 Feb 2012 11:07:19 -0500 Subject: Minor rewording Tried to address confusion I had when I read the document and tweaked some formatting. --- docs/source/configuration.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst index 6596cef4..a3dafa4c 100644 --- a/docs/source/configuration.rst +++ b/docs/source/configuration.rst @@ -20,6 +20,7 @@ Configuring MediaGoblin So! You've got MediaGoblin up and running, but you need to adjust some configuration parameters. Well you've come to the right place! + MediaGoblin's config files ========================== @@ -84,16 +85,20 @@ Common changes Enabling email notifications ---------------------------- -You'll almost certainly want to enable sending emails. By default, +You'll almost certainly want to enable sending email. By default, MediaGoblin doesn't really do this... for the sake of developer -convenience, it runs in "email debug mode". Change this:: +convenience, it runs in "email debug mode". + +To make MediaGoblin send email, you need a mailer daemon. + +Change this in your ``mediagoblin.ini`` file:: email_debug_mode = false -You can (and should) change the "from" email address by setting -``email_sender_address``. +You should also change the "from" email address by setting +``email_sender_address``. For example:: -Note that you need a mailer daemon running for this to work. + email_sender_address = "foo@example.com" If you have more custom SMTP settings, you also have the following options at your disposal, which are all optional, and do exactly what @@ -104,17 +109,19 @@ they sound like. - email_smtp_user - email_smtp_pass + All other configuration changes ------------------------------- To be perfectly honest, there are quite a few options and we haven't had -time to document them all +time to document them all. So here's a cop-out section saying that if you get into trouble, hop onto IRC and we'll help you out:: #mediagoblin on irc.freenode.net + Celery ====== -- cgit v1.2.3 From 973f37e9c39a8784f21f97a256890509eefb6f31 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 9 Feb 2012 09:10:08 -0600 Subject: Updating codebase.rst to reflect the modern mediagoblin world - adding/removing libraries listed as appropriate - buildout->virtualenv references - Updating directory structure description to reflect current reality --- docs/source/codebase.rst | 53 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/docs/source/codebase.rst b/docs/source/codebase.rst index 2518e48f..e784c9e5 100644 --- a/docs/source/codebase.rst +++ b/docs/source/codebase.rst @@ -48,8 +48,10 @@ Software Stack * `Nose `_: for unit tests - * `buildout `_: for getting dependencies, - building a runtime environment, ... + * `virtualenv `_: for setting up an + isolated environment to keep mediagoblin and related packages + (potentially not required if MediaGoblin is packaged for your + distro) * Data storage @@ -67,21 +69,47 @@ Software Stack * `Routes `_: for URL routing - * `Beaker `_: for handling sessions + * `Beaker `_: for handling sessions and + caching * `Jinja2 `_: the templating engine - * `MongoKit `_: the lightweight - ORM for MongoDB we're using which will make it easier to define - structures and all that - * `WTForms `_: for handling, validation, and abstraction from HTML forms * `Celery `_: for task queuing (resizing images, encoding video, ...) - * `RabbitMQ `_: for sending tasks to celery + * `MongoKit `_: the lightweight + ORM for MongoDB we're using which will make it easier to define + structures and all that (will be swapped out soon...) + + * `SQLAlchemy `_: SQL ORM and database + interaction library for Python. We'll be moving to this in the + upcoming move to SQL. + + * `Babel `_: Used to extract and compile + translations. + + * `Markdown (for python) `_: + implementation of `Markdown `_ + text-to-html tool to make it easy for people to write richtext + comments, descriptions, and etc. + + * `lxml `_: nice xml and html processing for + python. + +* Media processing libraries + + * `Python Imaging Library `_: + used to resize and otherwise convert images for display. + + * `GStreamer `_: (Optional, for + video hosting sites only) Used to transcode video, and in the + future, probably audio too. + + * `chardet `_: (Optional, for + ascii art hosting sites only) Used to make ascii art thumbnails. * Front end @@ -92,7 +120,8 @@ Software Stack What's where ============ -After you've run buildout, you're faced with the following directory +After you've run checked out mediagoblin and followed the virtualenv +instantiation instructions, you're faced with the following directory tree:: mediagoblin/ @@ -102,12 +131,14 @@ tree:: | |- auth/ | \- submit/ |- docs/ # documentation + |- devtools/ # some scripts for developer convenience | - | # the below directories are generated by buildout. + | # the below directories are installed into your virtualenv checkout | |- bin/ # scripts |- develop-eggs/ - |- eggs/ + |- lib/ # python libraries installed into your virtualenv + |- include/ |- mediagoblin.egg-info/ |- parts/ |- user_dev/ # sessions, etc -- cgit v1.2.3 From efd69313d0a1ab01d96795d4dd098d6c30844e50 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 9 Feb 2012 09:15:23 -0600 Subject: Added info on how to enable ascii art --- docs/source/media-types.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/source/media-types.rst b/docs/source/media-types.rst index 86409b55..ec068422 100644 --- a/docs/source/media-types.rst +++ b/docs/source/media-types.rst @@ -45,3 +45,22 @@ Note that you almost certainly want to separate Celery from the normal paste process or your users will probably find that their connections time out as the video transcodes. To set that up, check out the ":doc:`production-deployments`" section of this manual. + + +Ascii art +========= + +To enable ascii art support, first install the +`chardet `_ +library, which is necessary for creating thumbnails of ascii art:: + + ./bin/easy_install chardet + + +Next, modify (and possibly copy over from ``mediagoblin.ini``) your +``mediagoblin_local.ini``. Uncomment or add to the media_types line +'mediagoblin.media_types.ascii' like so:: + + media_types = mediagoblin.media_types.image, mediagoblin.media_types.ascii + +Now any .txt file you uploaded will be processed as ascii art! -- cgit v1.2.3 From df900eed1718d9bb83c3289f00fdb539fa9b5063 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 9 Feb 2012 10:20:42 -0500 Subject: Update copyright headers for shell scripts --- devtools/maketarball.sh | 2 +- devtools/update_translations.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devtools/maketarball.sh b/devtools/maketarball.sh index 5f17e578..5a25faea 100755 --- a/devtools/maketarball.sh +++ b/devtools/maketarball.sh @@ -1,7 +1,7 @@ #!/bin/bash # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 GNU MediaGoblin Contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by diff --git a/devtools/update_translations.sh b/devtools/update_translations.sh index 527bd274..7fcb3d49 100755 --- a/devtools/update_translations.sh +++ b/devtools/update_translations.sh @@ -1,7 +1,7 @@ #!/bin/bash # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 GNU MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by -- cgit v1.2.3 From 1da5052ff7b415efa6e523ed21a6a0a98c391432 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 9 Feb 2012 10:23:03 -0500 Subject: Removing youcanhelp stuff This was never used. It doesn't support Texinfo files. It was only half completed. Best to remove it. --- devtools/maketarball.sh | 2 -- docs/source/conf.py | 2 +- docs/source/mgext/__init__.py | 0 docs/source/mgext/youcanhelp.py | 44 ----------------------------------------- 4 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 docs/source/mgext/__init__.py delete mode 100644 docs/source/mgext/youcanhelp.py diff --git a/devtools/maketarball.sh b/devtools/maketarball.sh index 5a25faea..7d88c6fd 100755 --- a/devtools/maketarball.sh +++ b/devtools/maketarball.sh @@ -154,13 +154,11 @@ then mv docs/build/texinfo/ docs/texinfo/ rm -rf docs/build/ - rm -rf docs/source/mgext/*.pyc else # this is the old directory structure pre-0.0.4 mv docs/_build/html/ docs/html/ rm -rf docs/_build/ - rm -rf docs/mgext/*.pyc fi popd diff --git a/docs/source/conf.py b/docs/source/conf.py index 3014e592..16fd22a9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ sys.path.insert(0, os.path.abspath('.')) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ["mgext.youcanhelp"] +extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['source/_templates'] diff --git a/docs/source/mgext/__init__.py b/docs/source/mgext/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/source/mgext/youcanhelp.py b/docs/source/mgext/youcanhelp.py deleted file mode 100644 index a99d0e4d..00000000 --- a/docs/source/mgext/youcanhelp.py +++ /dev/null @@ -1,44 +0,0 @@ -from docutils import nodes - -from sphinx.util.compat import Directive, make_admonition - -class youcanhelp_node(nodes.Admonition, nodes.Element): - pass - -class YouCanHelp(Directive): - has_content = True - required_arguments = 0 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = {} - - def run(self): - ad = make_admonition( - youcanhelp_node, - self.name, - ["You Can Help!"], - self.options, - self.content, - self.lineno, - self.content_offset, - self.block_text, - self.state, - self.state_machine) - ad[0].line = self.lineno - return ad - -def visit_youcanhelp_node(self, node): - self.visit_admonition(node) - -def depart_youcanhelp_node(self, node): - self.depart_admonition(node) - -def setup(app): - app.add_node( - youcanhelp_node, - html=(visit_youcanhelp_node, depart_youcanhelp_node), - latex=(visit_youcanhelp_node, depart_youcanhelp_node), - text=(visit_youcanhelp_node, depart_youcanhelp_node) - ) - - app.add_directive('youcanhelp', YouCanHelp) -- cgit v1.2.3 From 39edc73cb076db5c1c7ed5256763e082590fb755 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 9 Feb 2012 09:30:26 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index 57dd7eb0..b5832fe4 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-02-05 16:23-0600\n" +"POT-Creation-Date: 2012-02-09 09:30-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -- cgit v1.2.3 From 58301e093c7b99dc66b1e9255e34ef2e90e48d4d Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 9 Feb 2012 10:44:36 -0500 Subject: Update version numbers --- docs/source/conf.py | 6 +++--- mediagoblin/_version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 16fd22a9..6b5dd93b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -41,16 +41,16 @@ master_doc = 'index' # General information about the project. project = u'GNU MediaGoblin' -copyright = u'2011, Free Software Foundation, Inc and contributors' +copyright = u'2011, 2012 GNU MediaGoblin contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.3.0' +version = '0.2.1' # The full version, including alpha/beta/rc tags. -release = '0.3.0-dev' +release = '0.2.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index fc1a0f6e..f0358495 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -23,4 +23,4 @@ # see http://www.python.org/dev/peps/pep-0386/ -__version__ = "0.3.0.dev" +__version__ = "0.2.1" -- cgit v1.2.3 From 934d0b67a00f764fa2bc6ce44f31864f3804a44e Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 9 Feb 2012 10:49:50 -0500 Subject: Update version to 0.3.0-dev --- docs/source/conf.py | 4 ++-- mediagoblin/_version.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6b5dd93b..8aedf596 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, 2012 GNU MediaGoblin contributors' # built documents. # # The short X.Y version. -version = '0.2.1' +version = '0.3.0' # The full version, including alpha/beta/rc tags. -release = '0.2.1' +release = '0.3.0-dev" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py index f0358495..381d1270 100644 --- a/mediagoblin/_version.py +++ b/mediagoblin/_version.py @@ -23,4 +23,4 @@ # see http://www.python.org/dev/peps/pep-0386/ -__version__ = "0.2.1" +__version__ = "0.3.0-dev" -- cgit v1.2.3 From 6e03e586718ad06da38e3f82a043e35643bb9764 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Thu, 9 Feb 2012 11:00:30 -0500 Subject: Fix docs version --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8aedf596..aafcf128 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -50,7 +50,7 @@ copyright = u'2011, 2012 GNU MediaGoblin contributors' # The short X.Y version. version = '0.3.0' # The full version, including alpha/beta/rc tags. -release = '0.3.0-dev" +release = '0.3.0-dev' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -- cgit v1.2.3 From 937c7ea5d90db6678ae08a3524cce872d21d24ad Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 9 Feb 2012 21:46:57 +0100 Subject: Fix for ticket #386 --- mediagoblin/static/css/base.css | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index efd7b561..73b07384 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -79,6 +79,22 @@ a.highlight { color: #fff; } +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +ul { + list-style: disc inside; +} + +ol { + list-style: decimal inside; +} + label { font-weight: normal; } -- cgit v1.2.3 From eea6d276bc03bbbea7bba325f3cb6ebf6663b451 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 11 Feb 2012 00:38:21 +0100 Subject: sql db design suggestions by Svavar Kjarrval Many thanks go to Svavar Kjarrval who has taken a deeper look at our current sql db design and made a bunch of suggestions. The suggestions are currently put as TODO items in the docstrings. This way we can keep track of them directly where we need it. --- mediagoblin/db/sql/models.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 36f94b25..9d06f79c 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -14,6 +14,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +""" +TODO: indexes on foreignkeys, where useful. +""" + import datetime @@ -43,6 +47,10 @@ class SimpleFieldAlias(object): class User(Base, UserMixin): + """ + TODO: We should consider moving some rarely used fields + into some sort of "shadow" table. + """ __tablename__ = "users" id = Column(Integer, primary_key=True) @@ -67,6 +75,9 @@ class User(Base, UserMixin): class MediaEntry(Base, MediaEntryMixin): + """ + TODO: Consider fetching the media_files using join + """ __tablename__ = "media_entries" id = Column(Integer, primary_key=True) @@ -145,6 +156,10 @@ class MediaEntry(Base, MediaEntryMixin): class MediaFile(Base): + """ + TODO: Highly consider moving "name" into a new table. + TODO: Consider preloading said table in software + """ __tablename__ = "mediafiles" media_entry = Column( @@ -221,12 +236,20 @@ class MediaComment(Base): _id = SimpleFieldAlias("id") -def show_table_init(): +def show_table_init(engine_uri): + if engine_uri is None: + engine_uri = 'sqlite:///:memory:' from sqlalchemy import create_engine - engine = create_engine('sqlite:///:memory:', echo=True) + engine = create_engine(engine_uri, echo=True) Base.metadata.create_all(engine) if __name__ == '__main__': - show_table_init() + from sys import argv + print repr(argv) + if len(argv) == 2: + uri = argv[1] + else: + uri = None + show_table_init(uri) -- cgit v1.2.3 From fb1dc4f56b5e6e4338aaf578874e42b9336a8476 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 11 Feb 2012 23:04:02 +0100 Subject: Layout overhaul time! --- mediagoblin/static/css/base.css | 25 +++++++++--- .../templates/mediagoblin/user_pages/media.html | 16 ++++---- .../templates/mediagoblin/utils/prev_next.html | 46 +++++++++++----------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 73b07384..04ab1840 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -109,7 +109,7 @@ input, textarea { .container { margin: auto; width: 96%; - max-width: 940px; + max-width: 820px; } header { @@ -150,12 +150,18 @@ footer { clear: both; } +/* TEMP removal -> permanent removal should also be done in html! .media_pane { width: 640px; margin-left: 0px; margin-right: 10px; float: left; } +*/ + +img.media_image { + width: 100%; +} .media_sidebar { width: 280px; @@ -382,6 +388,11 @@ h2.media_title { margin-bottom: 0px; } +p.context { + display: inline-block; + padding-top: 4px; +} + p.media_specs { font-size: 0.9em; border-top: 1px solid #222; @@ -406,19 +417,21 @@ img.media_icon { /* navigation */ +.navigation { + float: right; +} + .navigation_button { width: 135px; - display: block; - float: left; + display: inline-block; text-align: center; background-color: #1d1d1d; border: 1px solid; border-color: #2c2c2c #232323 #1a1a1a; border-radius: 4px; text-decoration: none; - padding: 12px 0 16px; - font-size: 1.4em; - margin: 0 0 20px + padding: 4px 0 8px; + margin: 0 0 6px } .navigation_left { diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index d2503a4e..01dba596 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -41,6 +41,13 @@ {% block mediagoblin_content %}
    + {% trans user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader.username), + username=media.get_uploader.username -%} +

    ❖ Browsing media by {{ username }}

    + {%- endtrans %} + {% include "mediagoblin/utils/prev_next.html" %}
    {% block mediagoblin_media %} {% set display_media = request.app.public_store.file_url( @@ -148,15 +155,6 @@ {{ render_pagination(request, pagination, media.url_for_self(request.urlgen)) }} {% endif %} -
    -
    - {% trans user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader.username), - username=media.get_uploader.username -%} -

    ❖ Browsing media by {{ username }}

    - {%- endtrans %} - {% include "mediagoblin/utils/prev_next.html" %} {% if media.attachment_files|count %}

    Attachments

      diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index d0cf3f8c..f1175ce4 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -21,26 +21,28 @@ {% set next_entry_url = media.url_to_next(request.urlgen) %} {% if prev_entry_url or next_entry_url %} - {# There are no previous entries for the very first media entry #} - {% if prev_entry_url %} - - ← {% trans %}newer{% endtrans %} - - {% else %} - {# This is the first entry. display greyed-out 'previous' image #} - - {% endif %} - {# Likewise, this could be the very last media entry #} - {% if next_entry_url %} - - {% trans %}older{% endtrans %} → - - {% else %} - {# This is the last entry. display greyed-out 'next' image #} - - {% endif %} + {% endif %} -- cgit v1.2.3 From b21c9434273484dce04e53d91dc916ecca61bf0a Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 16:18:58 +0100 Subject: Restore sidebar --- mediagoblin/static/css/base.css | 6 +-- .../templates/mediagoblin/user_pages/media.html | 54 +++++++++++----------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 04ab1840..2f36ed48 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -150,21 +150,19 @@ footer { clear: both; } -/* TEMP removal -> permanent removal should also be done in html! .media_pane { - width: 640px; + width: 560px; margin-left: 0px; margin-right: 10px; float: left; } -*/ img.media_image { width: 100%; } .media_sidebar { - width: 280px; + width: 240px; margin-left: 10px; margin-right: 0px; float: left; diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 01dba596..f1a1a5c5 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -40,35 +40,35 @@ {% endblock mediagoblin_head %} {% block mediagoblin_content %} -
      - {% trans user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader.username), - username=media.get_uploader.username -%} -

      ❖ Browsing media by {{ username }}

      - {%- endtrans %} - {% include "mediagoblin/utils/prev_next.html" %} -
      - {% block mediagoblin_media %} - {% set display_media = request.app.public_store.file_url( - media.get_display_media(media.media_files)) %} - {# if there's a medium file size, that means the medium size - # isn't the original... so link to the original! - #} - {% if media.media_files.has_key('medium') %} - - Image for {{ media.title }} - - {% else %} + {% trans user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader.username), + username=media.get_uploader.username -%} +

      ❖ Browsing media by {{ username }}

      + {%- endtrans %} + {% include "mediagoblin/utils/prev_next.html" %} +
      + {% block mediagoblin_media %} + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media.media_files.has_key('medium') %} + Image for {{ media.title }} - {% endif %} - {% endblock %} -
      + + {% else %} + Image for {{ media.title }} + {% endif %} + {% endblock %} +
      +

      {{ media.title }}

      @@ -155,6 +155,8 @@ {{ render_pagination(request, pagination, media.url_for_self(request.urlgen)) }} {% endif %} +
      +
      {% if media.attachment_files|count %}

      Attachments

        -- cgit v1.2.3 From 1fccaf4a81fbbe8c064b91d23a42ad04930caa4e Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 16:28:42 +0100 Subject: Consistencify sidebar bits (same headers and such) --- mediagoblin/templates/mediagoblin/utils/exif.html | 2 +- mediagoblin/templates/mediagoblin/utils/geolocation_map.html | 2 +- mediagoblin/templates/mediagoblin/utils/license.html | 2 +- mediagoblin/templates/mediagoblin/utils/tags.html | 9 +++++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html index 0dd187f2..bd2e3307 100644 --- a/mediagoblin/templates/mediagoblin/utils/exif.html +++ b/mediagoblin/templates/mediagoblin/utils/exif.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('exif') and app_config['exif_visible'] and media.media_data.exif.has_key('useful') %} -

        EXIF

        +

        EXIF

        {% for key, tag in media.media_data.exif.useful.items() %} diff --git a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html index c1909ae5..118d0e62 100644 --- a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html +++ b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('gps') and app_config['geolocation_map_visible'] and media.media_data.gps %} -

        Map

        +

        Location

        {% set gps = media.media_data.gps %}
        diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 2438ed4e..ab157508 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,8 +17,8 @@ #} {% block license_content -%} +

        {% trans %}License{% endtrans %}

        - {% trans %}License:{% endtrans %} {% if media.license %} {{ media.get_license_data().abbreviation }} {% else %} diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 6408102d..bcf3b5fd 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,16 +17,17 @@ #} {% block tags_content -%} -

        {% trans %}View more media tagged with{% endtrans %} +

        Tagged with

        +

        {% for tag in media.tags %} {% if loop.last %} {# the 'and' should only appear if there is more than one tag #} {% if media.tags|length > 1 %} - {% trans %}or{% endtrans %} + · {% endif %} {{ tag['name'] }}. + tag=tag['slug']) }}">{{ tag['name'] }} {% elif loop.revindex == 2 %} {{ tag['name'] }}, + tag=tag['slug']) }}">{{ tag['name'] }} · {% endif %} {% endfor %}

        -- cgit v1.2.3 From c6498b26be26a03fd80f15a5a80f04fcb5a7c5a7 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 16:30:21 +0100 Subject: Move Attachments from sidebar to default pane --- .../templates/mediagoblin/user_pages/media.html | 46 +++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index f1a1a5c5..1a2038bd 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -74,7 +74,29 @@ {% autoescape False %}

        {{ media.description_html }}

        - {% endautoescape %} + {% endautoescape %} + {% if media.attachment_files|count %} +

        Attachments

        + + {% endif %} + {% if app_config['allow_attachments'] + and request.user + and (media.uploader == request.user._id + or request.user.is_admin) %} +

        + Add attachment +

        + {% endif %}

        {% trans date=media.created.strftime("%Y-%m-%d") -%} Added on {{ date }}. @@ -157,28 +179,6 @@ {% endif %}

        - {% if media.attachment_files|count %} -

        Attachments

        - - {% endif %} - {% if app_config['allow_attachments'] - and request.user - and (media.uploader == request.user._id - or request.user.is_admin) %} -

        - Add attachment -

        - {% endif %} {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} -- cgit v1.2.3 From a1161b84a6bec7025ee446933ca0477b80cbca42 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 18:12:23 +0100 Subject: Fix sidebar margins --- mediagoblin/static/css/base.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 2f36ed48..25a2dc4f 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -163,8 +163,7 @@ img.media_image { .media_sidebar { width: 240px; - margin-left: 10px; - margin-right: 0px; + margin: 20px 0 0 10px; float: left; } -- cgit v1.2.3 From 630dd7941d1b558e8714857ffae14044636d10e4 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 18:23:18 +0100 Subject: Style sidedata h3; revert sidebar margin change --- mediagoblin/static/css/base.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 25a2dc4f..9ddeb404 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -163,7 +163,7 @@ img.media_image { .media_sidebar { width: 240px; - margin: 20px 0 0 10px; + margin-left: 10px; float: left; } @@ -273,6 +273,15 @@ textarea#comment_content { height: 0; } +h3.sidedata { + border: none; + background-color: #212121; + border-radius: 4px 4px 0 0; + padding: 3px 8px; + margin: 20px 0 5px 0; + font-size: 1em; +} + /* forms */ .form_box,.form_box_xl { -- cgit v1.2.3 From 28439be4e3d35c56f278b454ce7da75763e7ea35 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 18:25:52 +0100 Subject: Move "Added on" date to sidebar --- mediagoblin/templates/mediagoblin/user_pages/media.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 1a2038bd..4a376f87 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -98,9 +98,6 @@

        {% endif %}

        - {% trans date=media.created.strftime("%Y-%m-%d") -%} - Added on {{ date }}. - {%- endtrans %} {% if request.user and (media.uploader == request.user._id or request.user.is_admin) %} @@ -179,6 +176,11 @@ {% endif %}

        + {% trans date=media.created.strftime("%Y-%m-%d") -%} +

        Added on

        +

        {{ date }}

        + {%- endtrans %} + {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} -- cgit v1.2.3 From be09ed51c8118203c1e69be66d7d947f9fbf5e7b Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 18:39:55 +0100 Subject: Corrections for mobile layout --- mediagoblin/static/css/base.css | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 9ddeb404..0447d8e5 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -522,21 +522,27 @@ table.media_panel th { } /* Media queries and other responsivisivity */ -@media screen and (max-width: 680px) { + +@media screen and (max-width: 820px) { .media_pane { width: 100%; margin: 0px; } + + .media_sidebar { + width: 100%; + margin: 0px; + } + img.media_image { width: 100%; } -} -@media screen and (max-width: 960px) { .profile_sidebar { width: 100%; margin: 0px; } + .profile_showcase { width: 100%; margin: 0px; -- cgit v1.2.3 From 4944e3c374839d48f5de973db3a037de26df908e Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 19:33:05 +0100 Subject: Make media thumbnail gallery a list instead of a table --- mediagoblin/static/css/base.css | 1 + .../mediagoblin/utils/object_gallery.html | 36 +++++++++------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 0447d8e5..165fdcf7 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -381,6 +381,7 @@ textarea#comment_content { margin: 0px 4px 10px 4px; text-align: center; font-size: 0.875em; + list-style: none; } .media_thumbnail a { diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 81506a84..6b5988fb 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -19,29 +19,23 @@ {% from "mediagoblin/utils/pagination.html" import render_pagination %} {% macro media_grid(request, media_entries, col_number=5) %} -
        + - {% for entry in row %} - {% set entry_url = entry.url_for_self(request.urlgen) %} - - {% endfor %} - + {% for entry in row %} + {% set entry_url = entry.url_for_self(request.urlgen) %} +
      • + + + + {% if entry.title %} +
        + {{ entry.title }} + {% endif %} +
      • + {% endfor %} {% endfor %} - +
      {%- endmacro %} {# -- cgit v1.2.3 From b0ed64aa126b50863ebc4c9986e876e09ad313a5 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 20:47:25 +0100 Subject: Fix comment input field width/padding; change some text; remove weird #form_comment duplicate rules; move Edit/Delete buttons next to title --- mediagoblin/static/css/base.css | 17 +++++------ .../templates/mediagoblin/user_pages/media.html | 35 ++++++++-------------- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 165fdcf7..674568f5 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -255,15 +255,6 @@ text-align: center; float: right; } -textarea#comment_content { - resize: vertical; - width: 634px; - height: 90px; - border: none; - background-color: #f1f1f1; - padding: 3px; -} - .clear { clear: both; display: block; @@ -364,13 +355,18 @@ textarea#description, textarea#bio { } textarea#comment_content { - width: 634px; + resize: vertical; + width: 100%; height: 90px; border: none; background-color: #f1f1f1; padding: 3px; } +#form_comment .form_field_input { + padding-right: 6px; +} + /* media galleries */ .media_thumbnail { @@ -393,6 +389,7 @@ textarea#comment_content { h2.media_title { margin-bottom: 0px; + display: inline-block; } p.context { diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 4a376f87..3e711e92 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -72,6 +72,18 @@

      {{ media.title }}

      + {% if request.user and + (media.uploader == request.user._id or + request.user.is_admin) %} + {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Edit{% endtrans %} + {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Delete{% endtrans %} + {% endif %} {% autoescape False %}

      {{ media.description_html }}

      {% endautoescape %} @@ -97,36 +109,15 @@ media=media._id) }}">Add attachment

      {% endif %} -

      - {% if request.user and - (media.uploader == request.user._id or - request.user.is_admin) %} - {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Edit{% endtrans %} - {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Delete{% endtrans %} - {% endif %} -

      {% if comments %}

      - {% if comments.count()==1 %} - {% trans comment_count=comments.count() -%}{{ comment_count }} comment{%- endtrans %} - {% elif comments.count()>1 %} - {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %} - {% else %} - {% trans %}No comments yet.{% endtrans %} - {% endif %}

      -- cgit v1.2.3 From f2ca3ad6ac945f92c24e50204f4a1122f21437e8 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 21:00:20 +0100 Subject: Add navigation button styles for mobile --- mediagoblin/static/css/base.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 674568f5..f0ee888d 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -545,4 +545,16 @@ table.media_panel th { width: 100%; margin: 0px; } + + .navigation { + float: none; + } + + .navigation_button { + width: 49%; + } + + .navigation_left { + margin-right: 0; + } } -- cgit v1.2.3 From 92e8ca790b1faca9bbcb260b8dcc8c05bdabc8ea Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 12 Feb 2012 21:02:02 +0100 Subject: Wait, scratch that. This commit uses a better way. --- mediagoblin/static/css/base.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index f0ee888d..9c429404 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -552,9 +552,11 @@ table.media_panel th { .navigation_button { width: 49%; + float: right; } .navigation_left { margin-right: 0; + float: left; } } -- cgit v1.2.3 From e4c3077437042f5466c3f75c85c0d174c272a85a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 12 Feb 2012 20:36:46 -0600 Subject: Our javascript is actually AGPLv3+, not LGPL*. Correcting. --- COPYING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COPYING b/COPYING index f8d93cf6..23e8db70 100644 --- a/COPYING +++ b/COPYING @@ -30,7 +30,7 @@ If not, see . JavaScript files located in the ``mediagoblin/`` directory tree are free software: you can redistribute and/or modify them under the -terms of the GNU Lesser General Public License as published by the +terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -- cgit v1.2.3 From 53280164e2ebb5856a6f25d14f27439855f99dbb Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 13 Feb 2012 23:11:49 +0100 Subject: 47: Only lowercase host part of email According to most documentation it seems that the local part of an email adress is/can be case sensitive. While the host part is not. So we lowercase only the host part of the given adress. See: http://issues.mediagoblin.org/ticket/47 --- mediagoblin/auth/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 9af89c2a..e18469b9 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -60,7 +60,9 @@ def register(request): if request.method == 'POST' and register_form.validate(): # TODO: Make sure the user doesn't exist already username = unicode(request.POST['username'].lower()) - email = unicode(request.POST['email'].lower()) + em_user, em_dom = unicode(request.POST['email']).split("@", 1) + em_dom = em_dom.lower() + email = em_user + "@" + em_dom users_with_username = request.db.User.find( {'username': username}).count() users_with_email = request.db.User.find( -- cgit v1.2.3 From 38816c66078fe679dc4b51b545d15d331712bcb4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 13 Feb 2012 21:31:11 -0600 Subject: Revert "Layout overhaul time!" This reverts a whole bunch of commits, fb1dc4f5 thru 92e8ca79, where an experimental new layout was played with. Unfortunately, this layout broke the look and feel of master, even though it was going in the right direction for mobile stuff. Jef said he'll do things in a branch! --- mediagoblin/static/css/base.css | 81 ++++-------- .../templates/mediagoblin/user_pages/media.html | 141 +++++++++++---------- mediagoblin/templates/mediagoblin/utils/exif.html | 2 +- .../mediagoblin/utils/geolocation_map.html | 2 +- .../templates/mediagoblin/utils/license.html | 2 +- .../mediagoblin/utils/object_gallery.html | 36 +++--- .../templates/mediagoblin/utils/prev_next.html | 46 ++++--- mediagoblin/templates/mediagoblin/utils/tags.html | 9 +- 8 files changed, 146 insertions(+), 173 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 9c429404..73b07384 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -109,7 +109,7 @@ input, textarea { .container { margin: auto; width: 96%; - max-width: 820px; + max-width: 940px; } header { @@ -151,19 +151,16 @@ footer { } .media_pane { - width: 560px; + width: 640px; margin-left: 0px; margin-right: 10px; float: left; } -img.media_image { - width: 100%; -} - .media_sidebar { - width: 240px; + width: 280px; margin-left: 10px; + margin-right: 0px; float: left; } @@ -255,6 +252,15 @@ text-align: center; float: right; } +textarea#comment_content { + resize: vertical; + width: 634px; + height: 90px; + border: none; + background-color: #f1f1f1; + padding: 3px; +} + .clear { clear: both; display: block; @@ -264,15 +270,6 @@ text-align: center; height: 0; } -h3.sidedata { - border: none; - background-color: #212121; - border-radius: 4px 4px 0 0; - padding: 3px 8px; - margin: 20px 0 5px 0; - font-size: 1em; -} - /* forms */ .form_box,.form_box_xl { @@ -355,18 +352,13 @@ textarea#description, textarea#bio { } textarea#comment_content { - resize: vertical; - width: 100%; + width: 634px; height: 90px; border: none; background-color: #f1f1f1; padding: 3px; } -#form_comment .form_field_input { - padding-right: 6px; -} - /* media galleries */ .media_thumbnail { @@ -377,7 +369,6 @@ textarea#comment_content { margin: 0px 4px 10px 4px; text-align: center; font-size: 0.875em; - list-style: none; } .media_thumbnail a { @@ -389,12 +380,6 @@ textarea#comment_content { h2.media_title { margin-bottom: 0px; - display: inline-block; -} - -p.context { - display: inline-block; - padding-top: 4px; } p.media_specs { @@ -421,21 +406,19 @@ img.media_icon { /* navigation */ -.navigation { - float: right; -} - .navigation_button { width: 135px; - display: inline-block; + display: block; + float: left; text-align: center; background-color: #1d1d1d; border: 1px solid; border-color: #2c2c2c #232323 #1a1a1a; border-radius: 4px; text-decoration: none; - padding: 4px 0 8px; - margin: 0 0 6px + padding: 12px 0 16px; + font-size: 1.4em; + margin: 0 0 20px } .navigation_left { @@ -520,43 +503,23 @@ table.media_panel th { } /* Media queries and other responsivisivity */ - -@media screen and (max-width: 820px) { +@media screen and (max-width: 680px) { .media_pane { width: 100%; margin: 0px; } - - .media_sidebar { - width: 100%; - margin: 0px; - } - img.media_image { width: 100%; } +} +@media screen and (max-width: 960px) { .profile_sidebar { width: 100%; margin: 0px; } - .profile_showcase { width: 100%; margin: 0px; } - - .navigation { - float: none; - } - - .navigation_button { - width: 49%; - float: right; - } - - .navigation_left { - margin-right: 0; - float: left; - } } diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 3e711e92..d2503a4e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -40,84 +40,67 @@ {% endblock mediagoblin_head %} {% block mediagoblin_content %} - {% trans user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader.username), - username=media.get_uploader.username -%} -

      ❖ Browsing media by {{ username }}

      - {%- endtrans %} - {% include "mediagoblin/utils/prev_next.html" %} -
      - {% block mediagoblin_media %} - {% set display_media = request.app.public_store.file_url( - media.get_display_media(media.media_files)) %} - {# if there's a medium file size, that means the medium size - # isn't the original... so link to the original! - #} - {% if media.media_files.has_key('medium') %} - +
      + -
      + {% endif %} + {% endblock %} +

      {{ media.title }}

      - {% if request.user and - (media.uploader == request.user._id or - request.user.is_admin) %} - {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Edit{% endtrans %} - {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Delete{% endtrans %} - {% endif %} {% autoescape False %}

      {{ media.description_html }}

      - {% endautoescape %} - {% if media.attachment_files|count %} -

      Attachments

      - - {% endif %} - {% if app_config['allow_attachments'] - and request.user - and (media.uploader == request.user._id - or request.user.is_admin) %} -

      - Add attachment -

      - {% endif %} + {% endautoescape %} +

      + {% trans date=media.created.strftime("%Y-%m-%d") -%} + Added on {{ date }}. + {%- endtrans %} + {% if request.user and + (media.uploader == request.user._id or + request.user.is_admin) %} + {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Edit{% endtrans %} + {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Delete{% endtrans %} + {% endif %} +

      {% if comments %}

      + {% if comments.count()==1 %} + {% trans comment_count=comments.count() -%}{{ comment_count }} comment{%- endtrans %} + {% elif comments.count()>1 %} + {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %} + {% else %} + {% trans %}No comments yet.{% endtrans %} + {% endif %}

      @@ -167,11 +150,35 @@ {% endif %}
      - {% trans date=media.created.strftime("%Y-%m-%d") -%} -

      Added on

      -

      {{ date }}

      - {%- endtrans %} - + {% trans user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader.username), + username=media.get_uploader.username -%} +

      ❖ Browsing media by {{ username }}

      + {%- endtrans %} + {% include "mediagoblin/utils/prev_next.html" %} + {% if media.attachment_files|count %} +

      Attachments

      + + {% endif %} + {% if app_config['allow_attachments'] + and request.user + and (media.uploader == request.user._id + or request.user.is_admin) %} +

      + Add attachment +

      + {% endif %} {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html index bd2e3307..0dd187f2 100644 --- a/mediagoblin/templates/mediagoblin/utils/exif.html +++ b/mediagoblin/templates/mediagoblin/utils/exif.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('exif') and app_config['exif_visible'] and media.media_data.exif.has_key('useful') %} -

      EXIF

      +

      EXIF

      {% for key, tag in media.media_data.exif.useful.items() %} diff --git a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html index 118d0e62..c1909ae5 100644 --- a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html +++ b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('gps') and app_config['geolocation_map_visible'] and media.media_data.gps %} -

      Location

      +

      Map

      {% set gps = media.media_data.gps %}
      diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index ab157508..2438ed4e 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,8 +17,8 @@ #} {% block license_content -%} -

      {% trans %}License{% endtrans %}

      + {% trans %}License:{% endtrans %} {% if media.license %} {{ media.get_license_data().abbreviation }} {% else %} diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 6b5988fb..81506a84 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -19,23 +19,29 @@ {% from "mediagoblin/utils/pagination.html" import render_pagination %} {% macro media_grid(request, media_entries, col_number=5) %} -

      {% for row in gridify_cursor(media_entries, col_number) %} - {% for entry in row %} - {% set entry_url = entry.url_for_self(request.urlgen) %} -
    • - - - - {% if entry.title %} -
      - {{ entry.title }} - {% endif %} -
    • - {% endfor %} + + {% for entry in row %} + {% set entry_url = entry.url_for_self(request.urlgen) %} + + {% endfor %} + {% endfor %} - + {%- endmacro %} {# diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index f1175ce4..d0cf3f8c 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -21,28 +21,26 @@ {% set next_entry_url = media.url_to_next(request.urlgen) %} {% if prev_entry_url or next_entry_url %} - + {# There are no previous entries for the very first media entry #} + {% if prev_entry_url %} + + ← {% trans %}newer{% endtrans %} + + {% else %} + {# This is the first entry. display greyed-out 'previous' image #} + + {% endif %} + {# Likewise, this could be the very last media entry #} + {% if next_entry_url %} + + {% trans %}older{% endtrans %} → + + {% else %} + {# This is the last entry. display greyed-out 'next' image #} + + {% endif %} {% endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index bcf3b5fd..6408102d 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,17 +17,16 @@ #} {% block tags_content -%} -

      Tagged with

      -

      +

      {% trans %}View more media tagged with{% endtrans %} {% for tag in media.tags %} {% if loop.last %} {# the 'and' should only appear if there is more than one tag #} {% if media.tags|length > 1 %} - · + {% trans %}or{% endtrans %} {% endif %} {{ tag['name'] }} + tag=tag['slug']) }}">{{ tag['name'] }}. {% elif loop.revindex == 2 %} {{ tag['name'] }} · + tag=tag['slug']) }}">{{ tag['name'] }}, {% endif %} {% endfor %}

      -- cgit v1.2.3 From 00996b92559fe963bf7b824de0eb1baca1d23db2 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 14 Feb 2012 16:34:03 +0100 Subject: Remove form background images; replace them with regular border styles --- mediagoblin/static/css/base.css | 7 +++---- mediagoblin/static/images/background_edit.png | Bin 221 -> 0 bytes mediagoblin/static/images/background_lines.png | Bin 158 -> 0 bytes 3 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 mediagoblin/static/images/background_edit.png delete mode 100644 mediagoblin/static/images/background_lines.png diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 9c429404..a2ba97e3 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -277,8 +277,7 @@ h3.sidedata { .form_box,.form_box_xl { background-color: #222; - background-image: url("../images/background_lines.png"); - background-repeat: repeat-x; + border-top: 6px solid #D49086; padding: 3% 5%; display: block; float: none; @@ -293,7 +292,7 @@ h3.sidedata { } .edit_box { - background-image: url("../images/background_edit.png"); + border-top: 6px dashed #D49086 } .form_field_input input, .form_field_input textarea { @@ -370,10 +369,10 @@ textarea#comment_content { /* media galleries */ .media_thumbnail { + display: inline-block; padding: 0px; width: 180px; overflow: hidden; - float: left; margin: 0px 4px 10px 4px; text-align: center; font-size: 0.875em; diff --git a/mediagoblin/static/images/background_edit.png b/mediagoblin/static/images/background_edit.png deleted file mode 100644 index 4071fd53..00000000 Binary files a/mediagoblin/static/images/background_edit.png and /dev/null differ diff --git a/mediagoblin/static/images/background_lines.png b/mediagoblin/static/images/background_lines.png deleted file mode 100644 index e1b07afe..00000000 Binary files a/mediagoblin/static/images/background_lines.png and /dev/null differ -- cgit v1.2.3 From 85778e79a87fd60f552e5c0be4735cffa79aa030 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 14 Feb 2012 16:38:51 +0100 Subject: Add clear div to correct floating divs --- mediagoblin/templates/mediagoblin/user_pages/media.html | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 3e711e92..b8172eaa 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -182,4 +182,5 @@ {% include "mediagoblin/utils/exif.html" %}
      +
      {% endblock %} -- cgit v1.2.3 From 23f87661f0997b4c10f80116f4beebd41d38aada Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 14 Feb 2012 16:42:54 +0100 Subject: Center small images by default --- mediagoblin/static/css/base.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index a2ba97e3..1b0b2f3e 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -158,7 +158,9 @@ footer { } img.media_image { - width: 100%; + margin-left: auto; + margin-right: auto; + display: block; } .media_sidebar { @@ -533,6 +535,7 @@ table.media_panel th { img.media_image { width: 100%; + display: inline; } .profile_sidebar { -- cgit v1.2.3 From 643278243c3e68efdee579e9b92dd8ab7355391f Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 14 Feb 2012 16:59:31 +0100 Subject: Add left and right arrow keys navigation (add new JS file, link it from media.html; add new navigation_right class to right button) --- mediagoblin/static/js/keyboard_navigation.js | 29 ++++++++++++++++++++++ .../templates/mediagoblin/user_pages/media.html | 2 ++ .../templates/mediagoblin/utils/prev_next.html | 4 +-- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 mediagoblin/static/js/keyboard_navigation.js diff --git a/mediagoblin/static/js/keyboard_navigation.js b/mediagoblin/static/js/keyboard_navigation.js new file mode 100644 index 00000000..83d339ff --- /dev/null +++ b/mediagoblin/static/js/keyboard_navigation.js @@ -0,0 +1,29 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).keydown(function(event){ + switch(event.which){ + case 37: + window.location = $('.navigation_left').attr('href'); + break; + case 39: + window.location = $('.navigation_right').attr('href'); + break; + } +}); + diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index d2503a4e..0b9bb808 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -27,6 +27,8 @@ href="{{ request.staticdirect('/extlib/leaflet/leaflet.ie.css') }}" /> + {% if app_config['geolocation_map_visible'] %} + {% trans %}older{% endtrans %} → {% else %} {# This is the last entry. display greyed-out 'next' image #} - {% endif %} -- cgit v1.2.3 From 5a34a80d0a9d8a930d2a8c49f48d3fe08b60a237 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 14 Feb 2012 23:26:07 +0100 Subject: Audio media handler, media sniffing, video fixes * Added audio processing code * Added audio display template * Added audio configuration setting * Changed video docstring --- mediagoblin/config_spec.ini | 7 +- mediagoblin/media_types/__init__.py | 8 ++ mediagoblin/media_types/audio/__init__.py | 25 ++++ mediagoblin/media_types/audio/processing.py | 75 +++++++++++ mediagoblin/media_types/audio/transcoder.py | 18 +++ mediagoblin/media_types/audio/transcoders.py | 150 +++++++++++++++++++++ mediagoblin/media_types/video/processing.py | 13 +- mediagoblin/media_types/video/transcoders.py | 7 +- .../mediagoblin/media_displays/audio.html | 47 +++++++ 9 files changed, 334 insertions(+), 16 deletions(-) create mode 100644 mediagoblin/media_types/audio/__init__.py create mode 100644 mediagoblin/media_types/audio/processing.py create mode 100644 mediagoblin/media_types/audio/transcoder.py create mode 100644 mediagoblin/media_types/audio/transcoders.py create mode 100644 mediagoblin/templates/mediagoblin/media_displays/audio.html diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 2d410899..452d9745 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -65,11 +65,14 @@ base_url = string(default="/mgoblin_media/") storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/queue") - -# Should we keep the original file? [media_type:mediagoblin.media_types.video] +# Should we keep the original file? keep_original = boolean(default=False) +[media_type:mediagoblin.media_types.audio] +# vorbisenc qualiy +quality = float(default=0.3) + [beaker.cache] type = string(default="file") diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 5128826b..c53ef1ab 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -28,6 +28,14 @@ class InvalidFileType(Exception): pass +def sniff_media(media): + ''' + Iterate through the enabled media types and find those suited + for a certain file. + ''' + pass + + def get_media_types(): """ Generator, yields the available media types diff --git a/mediagoblin/media_types/audio/__init__.py b/mediagoblin/media_types/audio/__init__.py new file mode 100644 index 00000000..9b33f9e3 --- /dev/null +++ b/mediagoblin/media_types/audio/__init__.py @@ -0,0 +1,25 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.media_types.audio.processing import process_audio, \ + sniff_handler + +MEDIA_MANAGER = { + 'human_readable': 'Audio', + 'processor': process_audio, + 'sniff_handler': sniff_handler, + 'display_template': 'mediagoblin/media_displays/audio.html', + 'accepted_extensions': ['mp3', 'flac', 'ogg', 'wav', 'm4a']} diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py new file mode 100644 index 00000000..beb12391 --- /dev/null +++ b/mediagoblin/media_types/audio/processing.py @@ -0,0 +1,75 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import logging +import tempfile +import os + +from mediagoblin import mg_globals as mgg +from mediagoblin.processing import create_pub_filepath + +from mediagoblin.media_types.audio.transcoders import AudioTranscoder + +_log = logging.getLogger() + +def sniff_handler(media): + return True + +def process_audio(entry): + audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio'] + + workbench = mgg.workbench_manager.create_workbench() + + queued_filepath = entry.queued_media_file + queued_filename = workbench.localized_file( + mgg.queue_store, queued_filepath, + 'source') + + ogg_filepath = create_pub_filepath( + entry, + '{original}.webm'.format( + original=os.path.splitext( + queued_filepath[-1])[0])) + + ogg_tmp = tempfile.NamedTemporaryFile() + + with ogg_tmp: + transcoder = AudioTranscoder() + + transcoder.transcode( + queued_filename, + ogg_tmp.name, + quality=audio_config['quality']) + + data = transcoder.discover(ogg_tmp.name) + + _log.debug('Saving medium...') + mgg.public_store.get_file(ogg_filepath, 'wb').write( + ogg_tmp.read()) + + entry.media_files['ogg'] = ogg_filepath + + entry.media_data['audio'] = { + u'length': int(data.audiolength)} + + thumbnail_tmp = tempfile.NamedTemporaryFile() + + with thumbnail_tmp: + entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] + + mgg.queue_store.delete_file(queued_filepath) + + entry.save() diff --git a/mediagoblin/media_types/audio/transcoder.py b/mediagoblin/media_types/audio/transcoder.py new file mode 100644 index 00000000..e1000faa --- /dev/null +++ b/mediagoblin/media_types/audio/transcoder.py @@ -0,0 +1,18 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +class AudioTranscoder(object): + diff --git a/mediagoblin/media_types/audio/transcoders.py b/mediagoblin/media_types/audio/transcoders.py new file mode 100644 index 00000000..e59214b0 --- /dev/null +++ b/mediagoblin/media_types/audio/transcoders.py @@ -0,0 +1,150 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import pdb +import logging + +from mediagoblin.processing import BadMediaFail + + +_log = logging.getLogger(__name__) + +CPU_COUNT = 2 # Just assuming for now + +# IMPORT MULTIPROCESSING +try: + import multiprocessing + try: + CPU_COUNT = multiprocessing.cpu_count() + except NotImplementedError: + _log.warning('multiprocessing.cpu_count not implemented!\n' + 'Assuming 2 CPU cores') +except ImportError: + _log.warning('Could not import multiprocessing, assuming 2 CPU cores') + +# IMPORT GOBJECT +try: + import gobject + gobject.threads_init() +except ImportError: + raise Exception('gobject could not be found') + +# IMPORT PYGST +try: + import pygst + + # We won't settle for less. For now, this is an arbitrary limit + # as we have not tested with > 0.10 + pygst.require('0.10') + + import gst + + import gst.extend.discoverer +except ImportError: + raise Exception('gst/pygst >= 0.10 could not be imported') + +class AudioTranscoder(object): + def __init__(self): + _log.info('Initializing {0}'.format(self.__class__.__name__)) + + # Instantiate MainLoop + self._loop = gobject.MainLoop() + + def discover(self, src): + _log.info('Discovering {0}'.format(src)) + self._discovery_path = src + + self._discoverer = gst.extend.discoverer.Discoverer( + self._discovery_path) + self._discoverer.connect('discovered', self.__on_discovered) + self._discoverer.discover() + + self._loop.run() # Run MainLoop + + # Once MainLoop has returned, return discovery data + return self._discovery_data + + def __on_discovered(self, data, is_media): + if not is_media: + self.halt() + _log.error('Could not discover {0}'.format(self._src_path)) + raise BadMediaFail() + + _log.debug('Discovered: {0}'.format(data.__dict__)) + + self._discovery_data = data + + # Gracefully shut down MainLoop + self.halt() + + def transcode(self, src, dst, **kw): + self._discovery_data = kw.get('data', self.discover(src)) + + self.__on_progress = kw.get('progress_callback') + + quality = kw.get('quality', 0.3) + + # Set up pipeline + self.pipeline = gst.parse_launch( + 'filesrc location="{src}" ! ' + 'decodebin2 ! queue ! audiorate tolerance={tolerance} ! ' + 'audioconvert ! audio/x-raw-float,channels=2 ! ' + 'vorbisenc quality={quality} ! webmmux ! ' + 'progressreport silent=true ! ' + 'filesink location="{dst}"'.format( + src=src, + tolerance=80000000, + quality=quality, + dst=dst)) + + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.connect('message', self.__on_bus_message) + + self.pipeline.set_state(gst.STATE_PLAYING) + + self._loop.run() + + def __on_bus_message(self, bus, message): + _log.debug(message) + + if (message.type == gst.MESSAGE_ELEMENT + and message.structure.get_name() == 'progress'): + data = dict(message.structure) + + if self.__on_progress: + self.__on_progress(data) + + _log.info('{0}% done...'.format( + data.get('percent'))) + elif message.type == gst.MESSAGE_EOS: + _log.info('Done') + self.halt() + + def halt(self): + _log.info('Quitting MainLoop gracefully...') + gobject.idle_add(self._loop.quit) + +if __name__ == '__main__': + import sys + logging.basicConfig() + _log.setLevel(logging.INFO) + + transcoder = AudioTranscoder() + data = transcoder.discover(sys.argv[1]) + res = transcoder.transcode(*sys.argv[1:3]) + + pdb.set_trace() diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 9dc23c55..089d96fb 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -31,15 +31,8 @@ _log.setLevel(logging.DEBUG) def process_video(entry): """ - Code to process a video - - Much of this code is derived from the arista-transcoder script in - the arista PyPI package and changed to match the needs of - MediaGoblin - - This function sets up the arista video encoder in some kind of new thread - and attaches callbacks to that child process, hopefully, the - entry-complete callback will be called when the video is done. + Process a video entry, transcode the queued media files (originals) and + create a thumbnail for the entry. """ video_config = mgg.global_config['media_type:mediagoblin.media_types.video'] @@ -54,7 +47,7 @@ def process_video(entry): entry, '{original}-640p.webm'.format( original=os.path.splitext( - queued_filepath[-1])[0] # Select the + queued_filepath[-1])[0] # Select the file name without .ext )) thumbnail_filepath = create_pub_filepath( diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 6137c3bf..903bd810 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -38,17 +38,16 @@ try: pass except ImportError: _log.warning('Could not import multiprocessing, defaulting to 2 CPU cores') - pass try: import gtk -except: +except ImportError: raise Exception('Could not find pygtk') try: import gobject gobject.threads_init() -except: +except ImportError: raise Exception('gobject could not be found') try: @@ -56,7 +55,7 @@ try: pygst.require('0.10') import gst from gst.extend import discoverer -except: +except ImportError: raise Exception('gst/pygst 0.10 could not be found') diff --git a/mediagoblin/templates/mediagoblin/media_displays/audio.html b/mediagoblin/templates/mediagoblin/media_displays/audio.html new file mode 100644 index 00000000..802a85c1 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/media_displays/audio.html @@ -0,0 +1,47 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% extends 'mediagoblin/user_pages/media.html' %} + +{% block mediagoblin_media %} +
      + +
      + {% if 'original' in media.media_files %} +

      + + {%- trans -%} + Original + {%- endtrans -%} + +

      + {% endif %} +{% endblock %} -- cgit v1.2.3 From ec4261a449c11b015190bc90dd9ae828261065cd Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 15 Feb 2012 01:15:29 +0100 Subject: Changed media processing delegation to a 'sniffing' method - Added sniff handlers to all media plugins All of them except audio returning False for ANYTHING at the moment. --- mediagoblin/media_types/__init__.py | 15 ++++++++++++++- mediagoblin/media_types/ascii/__init__.py | 4 +++- mediagoblin/media_types/ascii/processing.py | 3 +++ mediagoblin/media_types/audio/processing.py | 11 +++++++++-- mediagoblin/media_types/audio/transcoders.py | 12 +++++++++--- mediagoblin/media_types/image/__init__.py | 4 +++- mediagoblin/media_types/image/processing.py | 3 +++ mediagoblin/media_types/video/__init__.py | 4 +++- mediagoblin/media_types/video/processing.py | 2 ++ mediagoblin/submit/views.py | 9 ++++++--- 10 files changed, 55 insertions(+), 12 deletions(-) diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index c53ef1ab..19d822a3 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -16,10 +16,13 @@ import os import sys +import logging +import tempfile from mediagoblin import mg_globals from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ +_log = logging.getLogger(__name__) class FileTypeNotSupported(Exception): pass @@ -33,7 +36,17 @@ def sniff_media(media): Iterate through the enabled media types and find those suited for a certain file. ''' - pass + media_file = tempfile.NamedTemporaryFile() + media_file.write(media.file.read()) + media.file.seek(0) + for media_type, manager in get_media_managers(): + _log.info('Sniffing {0}'.format(media_type)) + if manager['sniff_handler'](media_file, media=media): + return media_type, manager + + raise FileTypeNotSupported( + # TODO: Provide information on which file types are supported + _(u'Sorry, I don\'t support that file type :(')) def get_media_types(): diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py index 1c8ca562..856d1d7b 100644 --- a/mediagoblin/media_types/ascii/__init__.py +++ b/mediagoblin/media_types/ascii/__init__.py @@ -14,13 +14,15 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.media_types.ascii.processing import process_ascii +from mediagoblin.media_types.ascii.processing import process_ascii, \ + sniff_handler MEDIA_MANAGER = { "human_readable": "ASCII", "processor": process_ascii, # alternately a string, # 'mediagoblin.media_types.image.processing'? + "sniff_handler": sniff_handler, "display_template": "mediagoblin/media_displays/ascii.html", "default_thumb": "images/media_thumbs/ascii.jpg", "accepted_extensions": [ diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index 7ece866e..f698b97a 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -24,6 +24,9 @@ from mediagoblin.media_types.ascii import asciitoimage _log = logging.getLogger(__name__) +def sniff_handler(media_file, **kw): + return False + def process_ascii(entry): ''' Code to process a txt file diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py index beb12391..7aa7ace8 100644 --- a/mediagoblin/media_types/audio/processing.py +++ b/mediagoblin/media_types/audio/processing.py @@ -25,8 +25,15 @@ from mediagoblin.media_types.audio.transcoders import AudioTranscoder _log = logging.getLogger() -def sniff_handler(media): - return True +def sniff_handler(media_file, **kw): + transcoder = AudioTranscoder() + try: + data = transcoder.discover(media_file.name) + + if data.is_audio == True and data.is_video == False: + return True + except: + return False def process_audio(entry): audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio'] diff --git a/mediagoblin/media_types/audio/transcoders.py b/mediagoblin/media_types/audio/transcoders.py index e59214b0..c5634964 100644 --- a/mediagoblin/media_types/audio/transcoders.py +++ b/mediagoblin/media_types/audio/transcoders.py @@ -62,8 +62,10 @@ class AudioTranscoder(object): # Instantiate MainLoop self._loop = gobject.MainLoop() + self._failed = None def discover(self, src): + self._src_path = src _log.info('Discovering {0}'.format(src)) self._discovery_path = src @@ -74,14 +76,17 @@ class AudioTranscoder(object): self._loop.run() # Run MainLoop + if self._failed: + raise self._failed + # Once MainLoop has returned, return discovery data - return self._discovery_data + return getattr(self, '_discovery_data', False) def __on_discovered(self, data, is_media): if not is_media: - self.halt() + self._failed = BadMediaFail() _log.error('Could not discover {0}'.format(self._src_path)) - raise BadMediaFail() + self.halt() _log.debug('Discovered: {0}'.format(data.__dict__)) @@ -91,6 +96,7 @@ class AudioTranscoder(object): self.halt() def transcode(self, src, dst, **kw): + _log.info('Transcoding {0} into {1}'.format(src, dst)) self._discovery_data = kw.get('data', self.discover(src)) self.__on_progress = kw.get('progress_callback') diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py index 98e0c32a..d4720fab 100644 --- a/mediagoblin/media_types/image/__init__.py +++ b/mediagoblin/media_types/image/__init__.py @@ -14,13 +14,15 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.media_types.image.processing import process_image +from mediagoblin.media_types.image.processing import process_image, \ + sniff_handler MEDIA_MANAGER = { "human_readable": "Image", "processor": process_image, # alternately a string, # 'mediagoblin.media_types.image.processing'? + "sniff_handler": sniff_handler, "display_template": "mediagoblin/media_displays/image.html", "default_thumb": "images/media_thumbs/image.jpg", "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"]} diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 769de89b..d301a69f 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -23,6 +23,9 @@ from mediagoblin.processing import BadMediaFail, \ from mediagoblin.tools.exif import exif_fix_image_orientation, \ extract_exif, clean_exif, get_gps_data, get_useful +def sniff_handler(media_file, **kw): + return False + def process_image(entry): """ Code to process an image diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py index ed542f16..5351abe6 100644 --- a/mediagoblin/media_types/video/__init__.py +++ b/mediagoblin/media_types/video/__init__.py @@ -14,13 +14,15 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin.media_types.video.processing import process_video +from mediagoblin.media_types.video.processing import process_video, \ + sniff_handler MEDIA_MANAGER = { "human_readable": "Video", "processor": process_video, # alternately a string, # 'mediagoblin.media_types.image.processing'? + "sniff_handler": sniff_handler, "display_template": "mediagoblin/media_displays/video.html", "default_thumb": "images/media_thumbs/video.jpg", "accepted_extensions": [ diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 089d96fb..1890ef0c 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -28,6 +28,8 @@ logging.basicConfig() _log = logging.getLogger(__name__) _log.setLevel(logging.DEBUG) +def sniff_handler(media_file, **kw): + return False def process_video(entry): """ diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index cdd097ec..4fafe1e3 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -35,7 +35,7 @@ from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.processing import mark_entry_failed, ProcessMedia from mediagoblin.messages import add_message, SUCCESS -from mediagoblin.media_types import get_media_type_and_manager, \ +from mediagoblin.media_types import sniff_media, \ InvalidFileType, FileTypeNotSupported @@ -55,7 +55,11 @@ def submit_start(request): else: try: filename = request.POST['file'].filename - media_type, media_manager = get_media_type_and_manager(filename) + + # Sniff the submitted media to determine which + # media plugin should handle processing + media_type, media_manager = sniff_media( + request.POST['file']) # create entry and save in database entry = request.db.MediaEntry() @@ -164,7 +168,6 @@ def submit_start(request): This section is intended to catch exceptions raised in mediagobling.media_types ''' - if isinstance(e, InvalidFileType) or \ isinstance(e, FileTypeNotSupported): submit_form.file.errors.append( -- cgit v1.2.3 From b6a686913ffd8969f9504b1292fd321c573cedd5 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 15 Feb 2012 17:15:42 +0100 Subject: Removed cancel_link class; slight changes to button_form style --- mediagoblin/static/css/base.css | 27 +++++----------------- .../user_pages/media_confirm_delete.html | 4 ++-- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 1b0b2f3e..60e3c5b5 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -204,20 +204,14 @@ img.media_image { color: #283F35; } -.button_form, .cancel_link { +.button_form { height: 32px; min-width: 99px; - background-color: #86d4b1; - background-image: -webkit-gradient(linear, left top, left bottom, from(#86d4b1), to(#62caa2)); - background-image: -webkit-linear-gradient(top, #86d4b1, #62caa2); - background-image: -moz-linear-gradient(top, #86d4b1, #62caa2); - background-image: -ms-linear-gradient(top, #86d4b1, #62caa2); - background-image: -o-linear-gradient(top, #86d4b1, #62caa2); - background-image: linear-gradient(top, #86d4b1, #62caa2); - box-shadow: 0px 0px 4px #000; + background-color: #86D4B1; + border: 1px solid; + border-color: #A2DEC3 #6CAA8E #5C9179; + color: #283F35; border-radius: 3px; - border: none; - color: #272727; margin: 10px 0px 10px 15px; text-align: center; padding-left: 11px; @@ -225,16 +219,7 @@ img.media_image { text-decoration: none; font-family: 'Lato', sans-serif; font-weight: bold; -} - -.cancel_link { - background-color: #aaa; - background-image: -webkit-gradient(linear, left top, left bottom, from(##D2D2D2), to(#aaa)); - background-image: -webkit-linear-gradient(top, #D2D2D2, #aaa); - background-image: -moz-linear-gradient(top, #D2D2D2, #aaa); - background-image: -ms-linear-gradient(top, #D2D2D2, #aaa); - background-image: -o-linear-gradient(top, #D2D2D2, #aaa); - background-image: linear-gradient(top, #D2D2D2, #aaa); + cursor: pointer; } .pagination { diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html index e64845e7..a3459206 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html @@ -46,8 +46,8 @@
      {# TODO: This isn't a button really... might do unexpected things :) #} - {% trans %}Cancel{% endtrans %} - + {% trans %}Cancel{% endtrans %} + {{ csrf_token }}
      -- cgit v1.2.3 From f4cbe074facc549f70024a6caec336568e97a9c1 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 15 Feb 2012 17:30:32 +0100 Subject: Simplify and fix button styles; add larger button styles for mobile --- mediagoblin/static/css/base.css | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 60e3c5b5..31a8510a 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -183,7 +183,7 @@ img.media_image { /* common website elements */ -.button_action, .button_action_highlight { +.button_action, .button_action_highlight, .button_form { display: inline-block; color: #c3c3c3; background-color: #363636; @@ -198,28 +198,17 @@ img.media_image { cursor: pointer; } -.button_action_highlight { +.button_action_highlight, .button_form { background-color: #86D4B1; border-color: #A2DEC3 #6CAA8E #5C9179; color: #283F35; } .button_form { - height: 32px; min-width: 99px; - background-color: #86D4B1; - border: 1px solid; - border-color: #A2DEC3 #6CAA8E #5C9179; - color: #283F35; - border-radius: 3px; margin: 10px 0px 10px 15px; text-align: center; - padding-left: 11px; - padding-right: 11px; - text-decoration: none; font-family: 'Lato', sans-serif; - font-weight: bold; - cursor: pointer; } .pagination { @@ -546,4 +535,8 @@ table.media_panel th { margin-right: 0; float: left; } + + .button_action, .button_action_highlight, .button_form { + padding: 9px 14px; + } } -- cgit v1.2.3 From 5cbf73aacafe35d8e285777e06b362314cf221b2 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 15 Feb 2012 18:44:38 +0100 Subject: Change button style in edit.html --- mediagoblin/templates/mediagoblin/edit/edit.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/templates/mediagoblin/edit/edit.html b/mediagoblin/templates/mediagoblin/edit/edit.html index 0c4d5bb1..3f7cbe0e 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit.html +++ b/mediagoblin/templates/mediagoblin/edit/edit.html @@ -33,7 +33,7 @@
      {{ wtforms_util.render_divs(form) }} -- cgit v1.2.3 From 3d44c01ad67c186d886a328aa310118b5dc97c39 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Wed, 15 Feb 2012 18:47:34 +0100 Subject: Enlarge navigation buttons when mobile --- mediagoblin/static/css/base.css | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 31a8510a..d7628bf4 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -529,6 +529,7 @@ table.media_panel th { .navigation_button { width: 49%; float: right; + padding: 10px 0 14px; } .navigation_left { -- cgit v1.2.3 From 92f129b5c707bdeaceb0cdf9807342b52db33b45 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 16 Feb 2012 18:43:15 +0100 Subject: Added sniffing logic for image media type For now, it's a re-implementation of the old file-extension checking logic, as I have not found a GStreamer-like "discoverer" in PIL. --- mediagoblin/media_types/image/processing.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index d301a69f..364a5afa 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -16,6 +16,7 @@ import Image import os +import logging from mediagoblin import mg_globals as mgg from mediagoblin.processing import BadMediaFail, \ @@ -23,7 +24,30 @@ from mediagoblin.processing import BadMediaFail, \ from mediagoblin.tools.exif import exif_fix_image_orientation, \ extract_exif, clean_exif, get_gps_data, get_useful +_log = logging.getLogger(__name__) + +SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg'] + def sniff_handler(media_file, **kw): + if not kw.get('media') == None: # That's a double negative! + name, ext = os.path.splitext(kw['media'].filename) + clean_ext = ext[1:].lower() # Strip the . from ext and make lowercase + + _log.debug('name: {0}\next: {1}\nlower_ext: {2}'.format( + name, + ext, + clean_ext)) + + if clean_ext in SUPPORTED_FILETYPES: + _log.info('Found file extension in supported filetypes') + return True + else: + _log.debug('Media present, extension not found in {1}'.format( + SUPPORTED_FILETYPES)) + else: + _log.warning('Need additional information (keyword argument \'media\')' + ' to be able to handle sniffing') + return False def process_image(entry): -- cgit v1.2.3 From 9f46a79ddebcc3b2a8bc1dd1ef4f67575bfb53c6 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 16 Feb 2012 18:59:55 +0100 Subject: Removed old audio.transcoder file (the real one is audio.transcoders) --- mediagoblin/media_types/audio/transcoder.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 mediagoblin/media_types/audio/transcoder.py diff --git a/mediagoblin/media_types/audio/transcoder.py b/mediagoblin/media_types/audio/transcoder.py deleted file mode 100644 index e1000faa..00000000 --- a/mediagoblin/media_types/audio/transcoder.py +++ /dev/null @@ -1,18 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -class AudioTranscoder(object): - -- cgit v1.2.3 From e61ab0998b77eaf18268001fd2d70917c3cd3e37 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 4 Feb 2012 20:55:55 +0100 Subject: Drop pre-rendered html: User.bio_html After a bit of discussion, we decided to drop the pre-rendered html from the database and render it on the fly. In another step, we will use some proper caching method to cache this stuff. This commit affects the User.bio_html part. --- mediagoblin/db/mixin.py | 5 +++++ mediagoblin/db/mongo/migrations.py | 11 +++++++++++ mediagoblin/db/mongo/models.py | 2 -- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/models.py | 1 - mediagoblin/edit/views.py | 2 -- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index beaff9b0..2ff08722 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -29,6 +29,7 @@ real objects. from mediagoblin.auth import lib as auth_lib from mediagoblin.tools import common, licenses +from mediagoblin.tools.text import cleaned_markdown_conversion class UserMixin(object): @@ -39,6 +40,10 @@ class UserMixin(object): return auth_lib.bcrypt_check_password( password, self.pw_hash) + @property + def bio_html(self): + return cleaned_markdown_conversion(self.bio) + class MediaEntryMixin(object): def get_display_media(self, media_map, diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py index 261e21a5..74a810c1 100644 --- a/mediagoblin/db/mongo/migrations.py +++ b/mediagoblin/db/mongo/migrations.py @@ -115,3 +115,14 @@ def mediaentry_add_license(database): Add the 'license' field for entries that don't have it. """ add_table_field(database, 'media_entries', 'license', None) + + +@RegisterMigration(9) +def user_remove_bio_html(database): + """ + Drop bio_html again and calculate things on the fly (and cache) + """ + database['users'].update( + {'bio_html': {'$exists': True}}, + {'$unset': {'bio_html': 1}}, + multi=True) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 541086bc..c1282f4a 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -59,7 +59,6 @@ class User(Document, UserMixin): - is_admin: Whether or not this user is an administrator or not. - url: this user's personal webpage/website, if appropriate. - bio: biography of this user (plaintext, in markdown) - - bio_html: biography of the user converted to proper HTML. """ __collection__ = 'users' use_dot_notation = True @@ -76,7 +75,6 @@ class User(Document, UserMixin): 'is_admin': bool, 'url': unicode, 'bio': unicode, # May contain markdown - 'bio_html': unicode, # May contain plaintext, or HTML 'fp_verification_key': unicode, # forgotten password verification key 'fp_token_expire': datetime.datetime, } diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index f6575be9..a098927f 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -56,7 +56,7 @@ def convert_users(mk_db): copy_attrs(entry, new_entry, ('username', 'email', 'created', 'pw_hash', 'email_verified', 'status', 'verification_key', 'is_admin', 'url', - 'bio', 'bio_html', + 'bio', 'fp_verification_key', 'fp_token_expire',)) # new_entry.fp_verification_expire = entry.fp_token_expire diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 9d06f79c..3cf4ff40 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -64,7 +64,6 @@ class User(Base, UserMixin): is_admin = Column(Boolean, default=False, nullable=False) url = Column(Unicode) bio = Column(UnicodeText) # ?? - bio_html = Column(UnicodeText) # ?? fp_verification_key = Column(Unicode) fp_token_expire = Column(DateTime) diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a7245517..47761f23 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -171,8 +171,6 @@ def edit_profile(request): user.url = unicode(request.POST['url']) user.bio = unicode(request.POST['bio']) - user.bio_html = cleaned_markdown_conversion(user.bio) - user.save() messages.add_message(request, -- cgit v1.2.3 From 1e72e075f8d542f4aa1ad0262f4fd1a5645cc731 Mon Sep 17 00:00:00 2001 From: Elrond Date: Mon, 13 Feb 2012 13:42:59 +0100 Subject: Drop pre-rendered html: MediaEntry.description_html After a bit of discussion, we decided to drop the pre-rendered html from the database and render it on the fly. In another step, we will use some proper caching method to cache this stuff. This commit affects the MediaEntry.description_html part. --- mediagoblin/db/mixin.py | 8 ++++++++ mediagoblin/db/mongo/migrations.py | 20 ++++++++++++++------ mediagoblin/db/mongo/models.py | 4 ---- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/models.py | 1 - mediagoblin/edit/views.py | 5 +---- mediagoblin/listings/views.py | 2 +- mediagoblin/submit/views.py | 4 +--- mediagoblin/user_pages/views.py | 2 +- 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 2ff08722..4e3800ab 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -46,6 +46,14 @@ class UserMixin(object): class MediaEntryMixin(object): + @property + def description_html(self): + """ + Rendered version of the description, run through + Markdown and cleaned with our cleaning tool. + """ + return cleaned_markdown_conversion(self.description) + def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): """ diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py index 74a810c1..57da7dd8 100644 --- a/mediagoblin/db/mongo/migrations.py +++ b/mediagoblin/db/mongo/migrations.py @@ -29,6 +29,16 @@ def add_table_field(db, table_name, field_name, default_value): multi=True) +def drop_table_field(db, table_name, field_name): + """ + Drop an old field from a table/collection + """ + db[table_name].update( + {field_name: {'$exists': True}}, + {'$unset': {field_name: 1}}, + multi=True) + + # Please see mediagoblin/tests/test_migrations.py for some examples of # basic migrations. @@ -118,11 +128,9 @@ def mediaentry_add_license(database): @RegisterMigration(9) -def user_remove_bio_html(database): +def remove_calculated_html(database): """ - Drop bio_html again and calculate things on the fly (and cache) + Drop bio_html, description_html again and calculate things on the fly (and cache) """ - database['users'].update( - {'bio_html': {'$exists': True}}, - {'$unset': {'bio_html': 1}}, - multi=True) + drop_table_field(database, 'users', 'bio_html') + drop_table_field(database, 'media_entries', 'description_html') diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index c1282f4a..db38d502 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -110,9 +110,6 @@ class MediaEntry(Document, MediaEntryMixin): up with MarkDown for slight fanciness (links, boldness, italics, paragraphs...) - - description_html: Rendered version of the description, run through - Markdown and cleaned with our cleaning tool. - - media_type: What type of media is this? Currently we only support 'image' ;) @@ -177,7 +174,6 @@ class MediaEntry(Document, MediaEntryMixin): 'slug': unicode, 'created': datetime.datetime, 'description': unicode, # May contain markdown/up - 'description_html': unicode, # May contain plaintext, or HTML 'media_type': unicode, 'media_data': dict, # extra data relevant to this media_type 'plugin_data': dict, # plugins can dump stuff here. diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index a098927f..9d276866 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -77,7 +77,7 @@ def convert_media_entries(mk_db): new_entry = MediaEntry() copy_attrs(entry, new_entry, ('title', 'slug', 'created', - 'description', 'description_html', + 'description', 'media_type', 'state', 'license', 'fail_error', 'queued_task_id',)) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 3cf4ff40..72591f4e 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -85,7 +85,6 @@ class MediaEntry(Base, MediaEntryMixin): slug = Column(Unicode) created = Column(DateTime, nullable=False, default=datetime.datetime.now) description = Column(UnicodeText) # ?? - description_html = Column(UnicodeText) # ?? media_type = Column(Unicode, nullable=False) state = Column(Unicode, default=u'unprocessed', nullable=False) # or use sqlalchemy.types.Enum? diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 47761f23..3df36e8e 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -34,7 +34,7 @@ from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.text import ( clean_html, convert_to_tag_list_of_dicts, - media_tags_as_string, cleaned_markdown_conversion) + media_tags_as_string) from mediagoblin.tools.licenses import SUPPORTED_LICENSES @@ -72,9 +72,6 @@ def edit_media(request, media): media.tags = convert_to_tag_list_of_dicts( request.POST.get('tags')) - media.description_html = cleaned_markdown_conversion( - media.description) - media.license = unicode(request.POST.get('license', '')) or None media.slug = unicode(request.POST['slug']) diff --git a/mediagoblin/listings/views.py b/mediagoblin/listings/views.py index 48320cb2..ba23fc46 100644 --- a/mediagoblin/listings/views.py +++ b/mediagoblin/listings/views.py @@ -91,7 +91,7 @@ def tag_atom_feed(request): 'type': 'text/html'}]) for entry in cursor: feed.add(entry.get('title'), - entry.get('description_html'), + entry.description_html, id=entry.url_for_self(request.urlgen,qualified=True), content_type='html', author={'name': entry.get_uploader.username, diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index cdd097ec..845400ca 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -28,7 +28,7 @@ _log = logging.getLogger(__name__) from werkzeug.utils import secure_filename from mediagoblin.db.util import ObjectId -from mediagoblin.tools.text import cleaned_markdown_conversion, convert_to_tag_list_of_dicts +from mediagoblin.tools.text import convert_to_tag_list_of_dicts from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.response import render_to_response, redirect from mediagoblin.decorators import require_active_login @@ -66,8 +66,6 @@ def submit_start(request): or unicode(splitext(filename)[0])) entry.description = unicode(request.POST.get('description')) - entry.description_html = cleaned_markdown_conversion( - entry.description) entry.license = unicode(request.POST.get('license', "")) or None diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 82791278..46435d81 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -250,7 +250,7 @@ def atom_feed(request): for entry in cursor: feed.add(entry.get('title'), - entry.get('description_html'), + entry.description_html, id=entry.url_for_self(request.urlgen,qualified=True), content_type='html', author={ -- cgit v1.2.3 From feba5c5287a7cb4c0ed8f5124ad60a8a291770ad Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 18 Feb 2012 11:32:28 +0100 Subject: Drop pre-rendered html: MediaComment.content_html After a bit of discussion, we decided to drop the pre-rendered html from the database and render it on the fly. In another step, we will use some proper caching method to cache this stuff. This commit affects the MediaComment.content_html part. --- mediagoblin/db/mixin.py | 10 ++++++++++ mediagoblin/db/mongo/migrations.py | 7 ++++++- mediagoblin/db/mongo/models.py | 8 +++----- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/models.py | 5 ++--- mediagoblin/user_pages/views.py | 2 -- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 4e3800ab..758f7e72 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -104,3 +104,13 @@ class MediaEntryMixin(object): def get_license_data(self): """Return license dict for requested license""" return licenses.SUPPORTED_LICENSES[self.license or ""] + + +class MediaCommentMixin(object): + @property + def content_html(self): + """ + the actual html-rendered version of the comment displayed. + Run through Markdown and the HTML cleaner. + """ + return cleaned_markdown_conversion(self.content) diff --git a/mediagoblin/db/mongo/migrations.py b/mediagoblin/db/mongo/migrations.py index 57da7dd8..59035f3b 100644 --- a/mediagoblin/db/mongo/migrations.py +++ b/mediagoblin/db/mongo/migrations.py @@ -130,7 +130,12 @@ def mediaentry_add_license(database): @RegisterMigration(9) def remove_calculated_html(database): """ - Drop bio_html, description_html again and calculate things on the fly (and cache) + Drop pre-rendered html again and calculate things + on the fly (and cache): + - User.bio_html + - MediaEntry.description_html + - MediaComment.content_html """ drop_table_field(database, 'users', 'bio_html') drop_table_field(database, 'media_entries', 'description_html') + drop_table_field(database, 'media_comments', 'content_html') diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index db38d502..57af137d 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -23,7 +23,7 @@ from mediagoblin.db.mongo import migrations from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId from mediagoblin.tools.pagination import Pagination from mediagoblin.tools import url -from mediagoblin.db.mixin import UserMixin, MediaEntryMixin +from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin ################### # Custom validators @@ -251,7 +251,7 @@ class MediaEntry(Document, MediaEntryMixin): return self.db.User.find_one({'_id': self.uploader}) -class MediaComment(Document): +class MediaComment(Document, MediaCommentMixin): """ A comment on a MediaEntry. @@ -260,8 +260,6 @@ class MediaComment(Document): - author: user who posted this comment - created: when the comment was created - content: plaintext (but markdown'able) version of the comment's content. - - content_html: the actual html-rendered version of the comment displayed. - Run through Markdown and the HTML cleaner. """ __collection__ = 'media_comments' @@ -272,7 +270,7 @@ class MediaComment(Document): 'author': ObjectId, 'created': datetime.datetime, 'content': unicode, - 'content_html': unicode} + } required_fields = [ 'media_entry', 'author', 'created', 'content'] diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 9d276866..a46d62ea 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -133,7 +133,7 @@ def convert_media_comments(mk_db): new_entry = MediaComment() copy_attrs(entry, new_entry, ('created', - 'content', 'content_html',)) + 'content',)) copy_reference_attr(entry, new_entry, "media_entry") copy_reference_attr(entry, new_entry, "author") diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 72591f4e..18e1dfd7 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -31,7 +31,7 @@ from sqlalchemy.ext.associationproxy import association_proxy from mediagoblin.db.sql.extratypes import PathTupleWithSlashes from mediagoblin.db.sql.base import Base, DictReadAttrProxy -from mediagoblin.db.mixin import UserMixin, MediaEntryMixin +from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin class SimpleFieldAlias(object): @@ -218,7 +218,7 @@ class MediaTag(Base): return DictReadAttrProxy(self) -class MediaComment(Base): +class MediaComment(Base, MediaCommentMixin): __tablename__ = "media_comments" id = Column(Integer, primary_key=True) @@ -227,7 +227,6 @@ class MediaComment(Base): author = Column(Integer, ForeignKey('users.id'), nullable=False) created = Column(DateTime, nullable=False, default=datetime.datetime.now) content = Column(UnicodeText, nullable=False) - content_html = Column(UnicodeText) get_author = relationship(User) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 46435d81..05d07b1b 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -18,7 +18,6 @@ from webob import exc from mediagoblin import messages, mg_globals from mediagoblin.db.util import DESCENDING, ObjectId -from mediagoblin.tools.text import cleaned_markdown_conversion from mediagoblin.tools.response import render_to_response, render_404, redirect from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.pagination import Pagination @@ -146,7 +145,6 @@ def media_post_comment(request, media): comment['media_entry'] = media._id comment['author'] = request.user._id comment['content'] = unicode(request.POST['comment_content']) - comment['content_html'] = cleaned_markdown_conversion(comment['content']) if not comment['content'].strip(): messages.add_message( -- cgit v1.2.3 From 6c2e57304c302acfc005686515ce91d91727dd8d Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sat, 18 Feb 2012 14:46:12 +0100 Subject: Responsive thumbnail gallery time --- mediagoblin/static/css/base.css | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index d7628bf4..dc0f3b85 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -349,7 +349,7 @@ textarea#comment_content { padding: 0px; width: 180px; overflow: hidden; - margin: 0px 4px 10px 4px; + margin: 0px 5px 10px 5px; text-align: center; font-size: 0.875em; list-style: none; @@ -512,6 +512,10 @@ table.media_panel th { display: inline; } + .media_thumbnail { + width: 21%; + } + .profile_sidebar { width: 100%; margin: 0px; @@ -541,3 +545,15 @@ table.media_panel th { padding: 9px 14px; } } + +@media screen and (max-width: 570px) { + .media_thumbnail { + width: 29%; + } +} + +@media screen and (max-width: 380px) { + .media_thumbnail { + width: 46%; + } +} -- cgit v1.2.3 From cf27accc9e9f2d8eb0b697cb4cea801a388e7993 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 12 Feb 2012 23:49:01 +0100 Subject: SQL: fail_metadata as JSON encoded field fail_metadata used to be a dict in mongo. So a json encoded field should be okay too. We could use a pickled field instead, which would be more flexible. --- mediagoblin/db/sql/convert.py | 2 +- mediagoblin/db/sql/extratypes.py | 28 +++++++++++++++++++++++++++- mediagoblin/db/sql/models.py | 4 ++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index a46d62ea..14a0b911 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -79,7 +79,7 @@ def convert_media_entries(mk_db): ('title', 'slug', 'created', 'description', 'media_type', 'state', 'license', - 'fail_error', + 'fail_error', 'fail_metadata', 'queued_task_id',)) copy_reference_attr(entry, new_entry, "uploader") diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py index 3a594728..8e078f14 100644 --- a/mediagoblin/db/sql/extratypes.py +++ b/mediagoblin/db/sql/extratypes.py @@ -15,7 +15,8 @@ # along with this program. If not, see . -from sqlalchemy.types import TypeDecorator, Unicode +from sqlalchemy.types import TypeDecorator, Unicode, VARCHAR +import json class PathTupleWithSlashes(TypeDecorator): @@ -35,3 +36,28 @@ class PathTupleWithSlashes(TypeDecorator): if value is not None: value = tuple(value.split('/')) return value + + +# The following class and only this one class is in very +# large parts based on example code from sqlalchemy. +# +# The original copyright notice and license follows: +# Copyright (C) 2005-2011 the SQLAlchemy authors and contributors +# +# This module is part of SQLAlchemy and is released under +# the MIT License: http://www.opensource.org/licenses/mit-license.php +# +class JSONEncoded(TypeDecorator): + "Represents an immutable structure as a json-encoded string." + + impl = VARCHAR + + def process_bind_param(self, value, dialect): + if value is not None: + value = json.dumps(value) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = json.loads(value) + return value diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 18e1dfd7..a34ff3bc 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -29,7 +29,7 @@ from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.sql.expression import desc from sqlalchemy.ext.associationproxy import association_proxy -from mediagoblin.db.sql.extratypes import PathTupleWithSlashes +from mediagoblin.db.sql.extratypes import PathTupleWithSlashes, JSONEncoded from mediagoblin.db.sql.base import Base, DictReadAttrProxy from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin @@ -91,7 +91,7 @@ class MediaEntry(Base, MediaEntryMixin): license = Column(Unicode) fail_error = Column(Unicode) - fail_metadata = Column(UnicodeText) + fail_metadata = Column(JSONEncoded) queued_media_file = Column(PathTupleWithSlashes) -- cgit v1.2.3 From 6456cefa0ded3d442a7bdd7e84e2ffae248ce065 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 18 Feb 2012 19:22:00 +0100 Subject: Fix MediaTag __init__ to handle no args Let the init code also handle createing a fresh clean instance without any attrs set. --- mediagoblin/db/sql/models.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index a34ff3bc..53360f8d 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -207,10 +207,12 @@ class MediaTag(Base): creator=Tag.find_or_new ) - def __init__(self, name, slug): + def __init__(self, name=None, slug=None): Base.__init__(self) - self.name = name - self.tag_helper = Tag.find_or_new(slug) + if name is not None: + self.name = name + if slug is not None: + self.tag_helper = Tag.find_or_new(slug) @property def dict_view(self): -- cgit v1.2.3 From a45631e3f3791071571da3a59bf6d3ecad42033f Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 18 Feb 2012 11:00:13 +0100 Subject: Start having useful defaults for SQL Mostly this means: Havintg a config_spec.ini that has a local (relative to mediagoblin.ini) sqlite db with the name "mediagoblin.db". Also: - Add to .gitignore - Add a notice to mediagoblin.ini about the db --- .gitignore | 1 + mediagoblin.ini | 4 ++++ mediagoblin/config_spec.ini | 1 + mediagoblin/db/sql/convert.py | 3 +-- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b46ec38a..e3a83822 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ /user_dev/ /paste_local.ini /mediagoblin_local.ini +/mediagoblin.db /server-log.txt # Tests diff --git a/mediagoblin.ini b/mediagoblin.ini index dbde6e51..223f0f4a 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -5,6 +5,10 @@ direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" +## Uncomment and change to your DB's appropiate setting. +## Default is a local sqlite db "mediagoblin.db". +# sql_engine = postgresql:///gmg + # set to false to enable sending notices email_debug_mode = true diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 2d410899..2b4ba2f9 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -9,6 +9,7 @@ media_types = string_list(default=list("mediagoblin.media_types.image")) db_host = string() db_name = string(default="mediagoblin") db_port = integer() +sql_engine = string(default="sqlite:///%(here)s/mediagoblin.db") # Where temporary files used in processing and etc are kept workbench_path = string(default="%(here)s/user_dev/media/workbench") diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 14a0b911..36d6fc7f 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -148,8 +148,7 @@ def convert_media_comments(mk_db): def main(): global_config, app_config = setup_global_and_app_config("mediagoblin.ini") - sql_conn, sql_db = sql_connect({'sql_engine': 'sqlite:///mediagoblin.db'}) - + sql_conn, sql_db = sql_connect(app_config) mk_conn, mk_db = mongo_connect(app_config) Base.metadata.create_all(sql_db.engine) -- cgit v1.2.3 From 3ea1cf36fcfec9a381f2c425e626c4107e7dca43 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 18 Feb 2012 23:19:09 -0600 Subject: Updates so that dbupdate command works - Various fixes to dbupdate itself - Switching db/sql/migrations.py to use a dict instead of a list - Registering the function --- mediagoblin/db/sql/migrations.py | 2 +- mediagoblin/gmg_commands/__init__.py | 4 ++++ mediagoblin/gmg_commands/dbupdate.py | 17 ++++++++++----- mediagoblin/media_types/ascii/migrations.py | 17 +++++++++++++++ mediagoblin/media_types/ascii/models.py | 34 +++++++++++++++++++++++++++++ mediagoblin/media_types/image/migrations.py | 17 +++++++++++++++ mediagoblin/media_types/image/models.py | 4 +++- mediagoblin/media_types/video/migrations.py | 17 +++++++++++++++ mediagoblin/media_types/video/models.py | 22 +++++++++++++++++-- 9 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 mediagoblin/media_types/ascii/migrations.py create mode 100644 mediagoblin/media_types/ascii/models.py create mode 100644 mediagoblin/media_types/image/migrations.py create mode 100644 mediagoblin/media_types/video/migrations.py diff --git a/mediagoblin/db/sql/migrations.py b/mediagoblin/db/sql/migrations.py index 67a02c96..98d0d0aa 100644 --- a/mediagoblin/db/sql/migrations.py +++ b/mediagoblin/db/sql/migrations.py @@ -14,4 +14,4 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -MIGRATIONS = [] +MIGRATIONS = {} diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index db944b3c..d804376b 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -53,6 +53,10 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.import_export:import_export_parse_setup', 'func': 'mediagoblin.gmg_commands.import_export:env_import', 'help': 'Exports the data for this MediaGoblin instance'}, + 'dbupdate': { + 'setup': 'mediagoblin.gmg_commands.dbupdate:dbupdate_parse_setup', + 'func': 'mediagoblin.gmg_commands.dbupdate:dbupdate', + 'help': 'Set up or update the SQL database'}, } diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py index 1fc5121a..27698170 100644 --- a/mediagoblin/gmg_commands/dbupdate.py +++ b/mediagoblin/gmg_commands/dbupdate.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from sqlalchemy.orm import sessionmaker + from mediagoblin.db.sql.open import setup_connection_and_db_from_config from mediagoblin.db.sql.util import ( MigrationManager, assure_migrations_table_setup) @@ -21,15 +23,19 @@ from mediagoblin.init import setup_global_and_app_config from mediagoblin.tools.common import import_component +def dbupdate_parse_setup(subparser): + pass + + class DatabaseData(object): def __init__(self, name, models, migrations): self.name = name self.models = models self.migrations = migrations - def make_migration_manager(self, db): + def make_migration_manager(self, session): return MigrationManager( - self.name, self.models, self.migrations, db) + self.name, self.models, self.migrations, session) def gather_database_data(media_types): @@ -74,11 +80,10 @@ def dbupdate(args): # Set up the database connection, db = setup_connection_and_db_from_config(app_config) - # If migrations table not made, make it! - assure_migrations_table_setup(db) + Session = sessionmaker(bind=db.engine) # Setup media managers for all dbdata, run init/migrate and print info # For each component, create/migrate tables for dbdata in dbdatas: - migration_manager = dbdata.make_migration_manager(db) + migration_manager = dbdata.make_migration_manager(Session()) migration_manager.init_or_migrate() diff --git a/mediagoblin/media_types/ascii/migrations.py b/mediagoblin/media_types/ascii/migrations.py new file mode 100644 index 00000000..f54c23ea --- /dev/null +++ b/mediagoblin/media_types/ascii/migrations.py @@ -0,0 +1,17 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +MIGRATIONS = {} diff --git a/mediagoblin/media_types/ascii/models.py b/mediagoblin/media_types/ascii/models.py new file mode 100644 index 00000000..324794b9 --- /dev/null +++ b/mediagoblin/media_types/ascii/models.py @@ -0,0 +1,34 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +from mediagoblin.db.sql.models import Base + +from sqlalchemy import ( + Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey, + UniqueConstraint) + + +class AsciiData(Base): + __tablename__ = "ascii_data" + + id = Column(Integer, primary_key=True) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), nullable=False) + + +DATA_MODEL = AsciiData +MODELS = [AsciiData] diff --git a/mediagoblin/media_types/image/migrations.py b/mediagoblin/media_types/image/migrations.py new file mode 100644 index 00000000..f54c23ea --- /dev/null +++ b/mediagoblin/media_types/image/migrations.py @@ -0,0 +1,17 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +MIGRATIONS = {} diff --git a/mediagoblin/media_types/image/models.py b/mediagoblin/media_types/image/models.py index 96b5cdf2..296eca0a 100644 --- a/mediagoblin/media_types/image/models.py +++ b/mediagoblin/media_types/image/models.py @@ -6,11 +6,13 @@ from sqlalchemy import ( class ImageData(Base): - __tablename__ = "image__data" + __tablename__ = "image_data" id = Column(Integer, primary_key=True) width = Column(Integer) height = Column(Integer) + media_entry = Column( + Integer, ForeignKey('media_entries.id'), nullable=False) DATA_MODEL = ImageData diff --git a/mediagoblin/media_types/video/migrations.py b/mediagoblin/media_types/video/migrations.py new file mode 100644 index 00000000..f54c23ea --- /dev/null +++ b/mediagoblin/media_types/video/migrations.py @@ -0,0 +1,17 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +MIGRATIONS = {} diff --git a/mediagoblin/media_types/video/models.py b/mediagoblin/media_types/video/models.py index c44f1919..741c329b 100644 --- a/mediagoblin/media_types/video/models.py +++ b/mediagoblin/media_types/video/models.py @@ -1,3 +1,20 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + from mediagoblin.db.sql.models import Base from sqlalchemy import ( @@ -6,10 +23,11 @@ from sqlalchemy import ( class VideoData(Base): - __tablename__ = "video__data" + __tablename__ = "video_data" id = Column(Integer, primary_key=True) - integer + media_entry = Column( + Integer, ForeignKey('media_entries.id'), nullable=False) DATA_MODEL = VideoData -- cgit v1.2.3 From d2506eebb45e13616e51230b39f68db9ae91a0c2 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 18 Feb 2012 23:19:41 -0600 Subject: Commenting out the migrations that don't exist yet --- mediagoblin/tests/test_sql_migrations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 1b7fb903..507a7725 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -800,7 +800,7 @@ def test_set1_to_set3(): 'portal': 'necroplex'} -def test_set2_to_set3(): +#def test_set2_to_set3(): # Create / connect to database # Create tables by migrating on empty initial set @@ -811,10 +811,10 @@ def test_set2_to_set3(): # Migrate # Make sure version matches expected # Check all things in database match expected - pass + # pass -def test_set1_to_set2_to_set3(): +#def test_set1_to_set2_to_set3(): # Create / connect to database # Create tables by migrating on empty initial set @@ -881,4 +881,4 @@ def test_set1_to_set2_to_set3(): # assert level_exit_table.c.from_level.nullable is False # assert_col_type(level_exit_table.c.to_level, VARCHAR) - pass + # pass -- cgit v1.2.3 From 99812bbc4a76735824708b341ea283f09a1b423c Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 19 Feb 2012 15:30:38 -0600 Subject: We now require sqlalchemy and sqlalchemy-migrate --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 9dd8964a..1c7caf96 100644 --- a/setup.py +++ b/setup.py @@ -62,6 +62,8 @@ setup( 'webtest', 'ConfigObj', 'Markdown', + 'sqlalchemy', + 'sqlalchemy-migrate', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', -- cgit v1.2.3 From ee9a0e3c78a621b09a04914e53906d36a635899f Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 21 Feb 2012 18:09:38 +0100 Subject: Forgot to add these layout changes. Everything should work now. --- mediagoblin/static/css/base.css | 80 ++++++++---- .../templates/mediagoblin/user_pages/media.html | 140 ++++++++++----------- mediagoblin/templates/mediagoblin/utils/exif.html | 2 +- .../mediagoblin/utils/geolocation_map.html | 2 +- .../templates/mediagoblin/utils/license.html | 2 +- .../mediagoblin/utils/object_gallery.html | 36 +++--- .../templates/mediagoblin/utils/prev_next.html | 46 +++---- mediagoblin/templates/mediagoblin/utils/tags.html | 9 +- 8 files changed, 168 insertions(+), 149 deletions(-) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index cb321c85..0889baed 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -109,7 +109,7 @@ input, textarea { .container { margin: auto; width: 96%; - max-width: 940px; + max-width: 820px; } header { @@ -151,22 +151,19 @@ footer { } .media_pane { - width: 640px; + width: 560px; margin-left: 0px; margin-right: 10px; float: left; } img.media_image { - margin-left: auto; - margin-right: auto; - display: block; + width: 100%; } .media_sidebar { - width: 280px; + width: 240px; margin-left: 10px; - margin-right: 0px; float: left; } @@ -232,15 +229,6 @@ text-align: center; float: right; } -textarea#comment_content { - resize: vertical; - width: 634px; - height: 90px; - border: none; - background-color: #f1f1f1; - padding: 3px; -} - .clear { clear: both; display: block; @@ -250,6 +238,15 @@ textarea#comment_content { height: 0; } +h3.sidedata { + border: none; + background-color: #212121; + border-radius: 4px 4px 0 0; + padding: 3px 8px; + margin: 20px 0 5px 0; + font-size: 1em; +} + /* forms */ .form_box,.form_box_xl { @@ -331,13 +328,18 @@ textarea#description, textarea#bio { } textarea#comment_content { - width: 634px; + resize: vertical; + width: 100%; height: 90px; border: none; background-color: #f1f1f1; padding: 3px; } +#form_comment .form_field_input { + padding-right: 6px; +} + /* media galleries */ .media_thumbnail { @@ -348,6 +350,7 @@ textarea#comment_content { margin: 0px 5px 10px 5px; text-align: center; font-size: 0.875em; + list-style: none; } .media_thumbnail a { @@ -359,6 +362,12 @@ textarea#comment_content { h2.media_title { margin-bottom: 0px; + display: inline-block; +} + +p.context { + display: inline-block; + padding-top: 4px; } p.media_specs { @@ -385,19 +394,21 @@ img.media_icon { /* navigation */ +.navigation { + float: right; +} + .navigation_button { width: 135px; - display: block; - float: left; + display: inline-block; text-align: center; background-color: #1d1d1d; border: 1px solid; border-color: #2c2c2c #232323 #1a1a1a; border-radius: 4px; text-decoration: none; - padding: 12px 0 16px; - font-size: 1.4em; - margin: 0 0 20px + padding: 4px 0 8px; + margin: 0 0 6px; } .navigation_left { @@ -482,11 +493,17 @@ table.media_panel th { } /* Media queries and other responsivisivity */ -@media screen and (max-width: 680px) { +@media screen and (max-width: 820px) { .media_pane { width: 100%; margin: 0px; } + + .media_sidebar { + width: 100%; + margin: 0px; + } + img.media_image { width: 100%; display: inline; @@ -495,17 +512,30 @@ table.media_panel th { .media_thumbnail { width: 21%; } -} -@media screen and (max-width: 960px) { .profile_sidebar { width: 100%; margin: 0px; } + .profile_showcase { width: 100%; margin: 0px; } + + .navigation { + float: none; + } + + .navigation_button { + width: 49%; + float: right; + } + + .navigation_left { + margin-right: 0; + float: left; + } .navigation { float: none; diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index fb79e4dc..0100ad9e 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -40,67 +40,84 @@ {% endblock mediagoblin_head %} {% block mediagoblin_content %} -
      -
      - {% block mediagoblin_media %} - {% set display_media = request.app.public_store.file_url( - media.get_display_media(media.media_files)) %} - {# if there's a medium file size, that means the medium size - # isn't the original... so link to the original! - #} - {% if media.media_files.has_key('medium') %} - - Image for {{ media.title }} - - {% else %} + {% trans user_url=request.urlgen( + 'mediagoblin.user_pages.user_home', + user=media.get_uploader.username), + username=media.get_uploader.username -%} +

      ❖ Browsing media by {{ username }}

      + {%- endtrans %} + {% include "mediagoblin/utils/prev_next.html" %} +
      + {% block mediagoblin_media %} + {% set display_media = request.app.public_store.file_url( + media.get_display_media(media.media_files)) %} + {# if there's a medium file size, that means the medium size + # isn't the original... so link to the original! + #} + {% if media.media_files.has_key('medium') %} + Image for {{ media.title }} - {% endif %} - {% endblock %} -
      + + {% else %} + Image for {{ media.title }} + {% endif %} + {% endblock %} +
      +

      {{ media.title }}

      + {% if request.user and + (media.uploader == request.user._id or + request.user.is_admin) %} + {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Edit{% endtrans %} + {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', + user= media.get_uploader.username, + media= media._id) %} + {% trans %}Delete{% endtrans %} + {% endif %} {% autoescape False %}

      {{ media.description_html }}

      - {% endautoescape %} -

      - {% trans date=media.created.strftime("%Y-%m-%d") -%} - Added on {{ date }}. - {%- endtrans %} - {% if request.user and - (media.uploader == request.user._id or - request.user.is_admin) %} - {% set edit_url = request.urlgen('mediagoblin.edit.edit_media', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Edit{% endtrans %} - {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', - user= media.get_uploader.username, - media= media._id) %} - {% trans %}Delete{% endtrans %} - {% endif %} -

      + {% endautoescape %} + {% if media.attachment_files|count %} +

      Attachments

      + + {% endif %} + {% if app_config['allow_attachments'] + and request.user + and (media.uploader == request.user._id + or request.user.is_admin) %} +

      + Add attachment +

      + {% endif %} {% if comments %}

      - {% if comments.count()==1 %} - {% trans comment_count=comments.count() -%}{{ comment_count }} comment{%- endtrans %} - {% elif comments.count()>1 %} - {% trans comment_count=comments.count() -%}{{ comment_count }} comments{%- endtrans %} - {% else %} - {% trans %}No comments yet.{% endtrans %} - {% endif %}

      @@ -150,35 +167,10 @@ {% endif %}
      - {% trans user_url=request.urlgen( - 'mediagoblin.user_pages.user_home', - user=media.get_uploader.username), - username=media.get_uploader.username -%} -

      ❖ Browsing media by {{ username }}

      - {%- endtrans %} - {% include "mediagoblin/utils/prev_next.html" %} - {% if media.attachment_files|count %} -

      Attachments

      - - {% endif %} - {% if app_config['allow_attachments'] - and request.user - and (media.uploader == request.user._id - or request.user.is_admin) %} -

      - Add attachment -

      - {% endif %} + {% trans date=media.created.strftime("%Y-%m-%d") -%} +

      Added on

      +

      {{ date }}

      + {%- endtrans %} {% if media.tags %} {% include "mediagoblin/utils/tags.html" %} {% endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/exif.html b/mediagoblin/templates/mediagoblin/utils/exif.html index 0dd187f2..bd2e3307 100644 --- a/mediagoblin/templates/mediagoblin/utils/exif.html +++ b/mediagoblin/templates/mediagoblin/utils/exif.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('exif') and app_config['exif_visible'] and media.media_data.exif.has_key('useful') %} -

      EXIF

      +

      EXIF

      {% for key, tag in media.media_data.exif.useful.items() %} diff --git a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html index c1909ae5..118d0e62 100644 --- a/mediagoblin/templates/mediagoblin/utils/geolocation_map.html +++ b/mediagoblin/templates/mediagoblin/utils/geolocation_map.html @@ -20,7 +20,7 @@ {% if media.media_data.has_key('gps') and app_config['geolocation_map_visible'] and media.media_data.gps %} -

      Map

      +

      Location

      {% set gps = media.media_data.gps %}
      diff --git a/mediagoblin/templates/mediagoblin/utils/license.html b/mediagoblin/templates/mediagoblin/utils/license.html index 2438ed4e..ab157508 100644 --- a/mediagoblin/templates/mediagoblin/utils/license.html +++ b/mediagoblin/templates/mediagoblin/utils/license.html @@ -17,8 +17,8 @@ #} {% block license_content -%} +

      {% trans %}License{% endtrans %}

      - {% trans %}License:{% endtrans %} {% if media.license %} {{ media.get_license_data().abbreviation }} {% else %} diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 81506a84..6b5988fb 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -19,29 +19,23 @@ {% from "mediagoblin/utils/pagination.html" import render_pagination %} {% macro media_grid(request, media_entries, col_number=5) %} -

      + - {% for entry in row %} - {% set entry_url = entry.url_for_self(request.urlgen) %} - - {% endfor %} - + {% for entry in row %} + {% set entry_url = entry.url_for_self(request.urlgen) %} +
    • + + + + {% if entry.title %} +
      + {{ entry.title }} + {% endif %} +
    • + {% endfor %} {% endfor %} - +
    {%- endmacro %} {# diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index d0cf3f8c..f1175ce4 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -21,26 +21,28 @@ {% set next_entry_url = media.url_to_next(request.urlgen) %} {% if prev_entry_url or next_entry_url %} - {# There are no previous entries for the very first media entry #} - {% if prev_entry_url %} - - ← {% trans %}newer{% endtrans %} - - {% else %} - {# This is the first entry. display greyed-out 'previous' image #} - - {% endif %} - {# Likewise, this could be the very last media entry #} - {% if next_entry_url %} - - {% trans %}older{% endtrans %} → - - {% else %} - {# This is the last entry. display greyed-out 'next' image #} - - {% endif %} + {% endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html index 6408102d..bcf3b5fd 100644 --- a/mediagoblin/templates/mediagoblin/utils/tags.html +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -17,16 +17,17 @@ #} {% block tags_content -%} -

    {% trans %}View more media tagged with{% endtrans %} +

    Tagged with

    +

    {% for tag in media.tags %} {% if loop.last %} {# the 'and' should only appear if there is more than one tag #} {% if media.tags|length > 1 %} - {% trans %}or{% endtrans %} + · {% endif %} {{ tag['name'] }}. + tag=tag['slug']) }}">{{ tag['name'] }} {% elif loop.revindex == 2 %} {{ tag['name'] }}, + tag=tag['slug']) }}">{{ tag['name'] }} · {% endif %} {% endfor %}

    -- cgit v1.2.3 From 572d4f01ff3bee75574c00bc85bc8a2700ba9828 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 19 Feb 2012 12:13:26 +0100 Subject: Use task_id in generating the queue file path The task_id is created anyway as a UUID. So it is very unique per definition. The only thing needed for the queue file path is a unique part. Before the objectid of the MediaEntry was used instead. But in the sql world the objectid is only available after an "insert" on the db. And creating the queue_file_path afterwards would require an "update" on the db. We can save that. ... for now. --- mediagoblin/submit/views.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 845400ca..df5b15c0 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -78,11 +78,18 @@ def submit_start(request): # Generate a slug from the title entry.generate_slug() + # We generate this ourselves so we know what the taks id is for + # retrieval later. + + # (If we got it off the task's auto-generation, there'd be + # a risk of a race condition when we'd save after sending + # off the task) + task_id = unicode(uuid.uuid4()) # Now store generate the queueing related filename queue_filepath = request.app.queue_store.get_unique_filepath( ['media_entries', - unicode(entry._id), + task_id, secure_filename(filename)]) # queue appropriately @@ -95,14 +102,7 @@ def submit_start(request): # Add queued filename to the entry entry.queued_media_file = queue_filepath - # We generate this ourselves so we know what the taks id is for - # retrieval later. - - # (If we got it off the task's auto-generation, there'd be - # a risk of a race condition when we'd save after sending - # off the task) - task_id = unicode(uuid.uuid4()) - entry['queued_task_id'] = task_id + entry.queued_task_id = task_id # Save now so we have this data before kicking off processing entry.save(validate=True) -- cgit v1.2.3 From 15821817015868b370a5a1bf52452bd8d3c96317 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 22 Jan 2012 16:57:56 +0100 Subject: mongo to sql convert: Better Ordering Order the conversion by the "created" attribute. That way the sql ids are mostly in the order they would have been, if sql was used earlier. Makes things nicer to look at in a db dump. --- mediagoblin/db/sql/convert.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 36d6fc7f..f5c93af5 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -49,7 +49,7 @@ def copy_reference_attr(entry, new_entry, ref_attr): def convert_users(mk_db): session = Session() - for entry in mk_db.User.find(): + for entry in mk_db.User.find().sort('created'): print entry.username new_entry = User() @@ -71,7 +71,7 @@ def convert_users(mk_db): def convert_media_entries(mk_db): session = Session() - for entry in mk_db.MediaEntry.find(): + for entry in mk_db.MediaEntry.find().sort('created'): print repr(entry.title) new_entry = MediaEntry() @@ -100,7 +100,7 @@ def convert_media_tags(mk_db): session = Session() session.autoflush = False - for media in mk_db.MediaEntry.find(): + for media in mk_db.MediaEntry.find().sort('created'): print repr(media.title) for otag in media.tags: @@ -127,7 +127,7 @@ def convert_media_tags(mk_db): def convert_media_comments(mk_db): session = Session() - for entry in mk_db.MediaComment.find(): + for entry in mk_db.MediaComment.find().sort('created'): print repr(entry.content) new_entry = MediaComment() -- cgit v1.2.3 From 98913512561e10d409e1cce067b4ed42b72e337c Mon Sep 17 00:00:00 2001 From: Elrond Date: Fri, 17 Feb 2012 00:09:30 +0100 Subject: Create "gmg convert_mongo_to_sql" command Finally, to make testing of sql a bit easier, create a bin/gmg command to do the conversion from mongo to sql. It's currently named "convert_mongo_to_sql". The most important option is the gmg -cf option to give a configfile with the appropiate sql_engine definition. --- mediagoblin/db/sql/convert.py | 6 +++--- mediagoblin/gmg_commands/__init__.py | 4 ++++ mediagoblin/gmg_commands/mongosql.py | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 mediagoblin/gmg_commands/mongosql.py diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index f5c93af5..403025dc 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -145,8 +145,8 @@ def convert_media_comments(mk_db): session.close() -def main(): - global_config, app_config = setup_global_and_app_config("mediagoblin.ini") +def run_conversion(config_name): + global_config, app_config = setup_global_and_app_config(config_name) sql_conn, sql_db = sql_connect(app_config) mk_conn, mk_db = mongo_connect(app_config) @@ -164,4 +164,4 @@ def main(): if __name__ == '__main__': - main() + run_conversion("mediagoblin.ini") diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index d804376b..054e2616 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -57,6 +57,10 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.dbupdate:dbupdate_parse_setup', 'func': 'mediagoblin.gmg_commands.dbupdate:dbupdate', 'help': 'Set up or update the SQL database'}, + 'convert_mongo_to_sql': { + 'setup': 'mediagoblin.gmg_commands.mongosql:mongosql_parser_setup', + 'func': 'mediagoblin.gmg_commands.mongosql:mongosql', + 'help': 'Convert Mongo DB data to SQL DB data'}, } diff --git a/mediagoblin/gmg_commands/mongosql.py b/mediagoblin/gmg_commands/mongosql.py new file mode 100644 index 00000000..a25263e2 --- /dev/null +++ b/mediagoblin/gmg_commands/mongosql.py @@ -0,0 +1,25 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.db.sql.convert import run_conversion + + +def mongosql_parser_setup(subparser): + pass + + +def mongosql(args): + run_conversion(args.conf_file) -- cgit v1.2.3 From 58f96a13e463fb417968cc92ec2ac5d4404641e4 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 25 Dec 2011 16:01:59 +0100 Subject: Allow .id instead of ._id for the Mongo backend To allow easier migration to the SQLAlchemy style .id give the User and MediaEntry mongo classes an alias attribute of .id that maps to ['_id']. Use it in the upload process, because this was one of the last positions with a ['_id'] instead of ._id (due to a bug in mongokit). --- mediagoblin/db/mongo/models.py | 15 +++++++++++++++ mediagoblin/submit/views.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mediagoblin/db/mongo/models.py b/mediagoblin/db/mongo/models.py index 57af137d..99c7905d 100644 --- a/mediagoblin/db/mongo/models.py +++ b/mediagoblin/db/mongo/models.py @@ -25,6 +25,17 @@ from mediagoblin.tools.pagination import Pagination from mediagoblin.tools import url from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin + +class MongoPK(object): + """An alias for the _id primary key""" + def __get__(self, instance, cls): + return instance['_id'] + def __set__(self, instance, val): + instance['_id'] = val + def __delete__(self, instance): + del instance['_id'] + + ################### # Custom validators ################### @@ -87,6 +98,8 @@ class User(Document, UserMixin): 'status': u'needs_email_verification', 'is_admin': False} + id = MongoPK() + class MediaEntry(Document, MediaEntryMixin): """ @@ -205,6 +218,8 @@ class MediaEntry(Document, MediaEntryMixin): 'created': datetime.datetime.utcnow, 'state': u'unprocessed'} + id = MongoPK() + def get_comments(self, ascending=False): if ascending: order = ASCENDING diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index df5b15c0..1e145e9d 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -59,7 +59,7 @@ def submit_start(request): # create entry and save in database entry = request.db.MediaEntry() - entry['_id'] = ObjectId() + entry.id = ObjectId() entry.media_type = unicode(media_type) entry.title = ( unicode(request.POST['title']) -- cgit v1.2.3 From e629cde0b361be477c5d27cf170fef9eef1d42fe Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sat, 25 Feb 2012 22:39:08 -0600 Subject: Should be all that's needed to switch celery/kombu settings to sqlalchemy --- mediagoblin/config_spec.ini | 8 ++++++++ mediagoblin/init/celery/__init__.py | 23 +++-------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 2b4ba2f9..1fd56226 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -79,6 +79,14 @@ lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock") [celery] +# default result stuff +celery_result_backend = string(default="database") +celery_result_dburi = string(default="sqlite://%(here)s/user_dev/celery.db") + +# default kombu stuff +broker_transport = string(default="database") +broker_host = string(default="sqlite://%(here)s/user_dev/celery.db") + # known booleans celery_result_persistent = boolean() celery_create_missing_queues = boolean() diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index fb958909..6dcea239 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -47,30 +47,13 @@ def setup_celery_from_config(app_config, global_config, celery_settings = {} - # set up mongodb stuff - celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb' - if 'BROKER_BACKEND' not in celery_settings: - celery_settings['BROKER_BACKEND'] = 'mongodb' - - celery_mongo_settings = {} - - if 'db_host' in app_config: - celery_mongo_settings['host'] = app_config['db_host'] - if celery_settings['BROKER_BACKEND'] == 'mongodb': - celery_settings['BROKER_HOST'] = app_config['db_host'] - if 'db_port' in app_config: - celery_mongo_settings['port'] = app_config['db_port'] - if celery_settings['BROKER_BACKEND'] == 'mongodb': - celery_settings['BROKER_PORT'] = app_config['db_port'] - celery_mongo_settings['database'] = app_config['db_name'] - - celery_settings['CELERY_MONGODB_BACKEND_SETTINGS'] = celery_mongo_settings - - # Add anything else + # Add all celery settings from config for key, value in celery_conf.iteritems(): key = key.upper() celery_settings[key] = value + # TODO: use default result stuff here if it exists + # add mandatory celery imports celery_imports = celery_settings.setdefault('CELERY_IMPORTS', []) celery_imports.extend(MANDATORY_CELERY_IMPORTS) -- cgit v1.2.3 From 200abf856b0c2d6b05e068a2bba9c8afe35e72af Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 07:46:23 -0600 Subject: Apparently an absolute path is three slashes after sqlite:. Thx elrond. sqlite:///////////////////////////////////whaaaaaa.db --- mediagoblin/config_spec.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 1fd56226..09c5f265 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -81,11 +81,11 @@ lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock") [celery] # default result stuff celery_result_backend = string(default="database") -celery_result_dburi = string(default="sqlite://%(here)s/user_dev/celery.db") +celery_result_dburi = string(default="sqlite:///%(here)s/user_dev/celery.db") # default kombu stuff broker_transport = string(default="database") -broker_host = string(default="sqlite://%(here)s/user_dev/celery.db") +broker_host = string(default="sqlite:///%(here)s/user_dev/celery.db") # known booleans celery_result_persistent = boolean() -- cgit v1.2.3 From b94dfe4cbf6bcf3e46618b3ccf935dee2a69216b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 07:58:40 -0600 Subject: Give kombu its own db. Responding to Elrond "sqlite will lock all the time!" :) --- mediagoblin/config_spec.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 09c5f265..1eb50701 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -85,7 +85,7 @@ celery_result_dburi = string(default="sqlite:///%(here)s/user_dev/celery.db") # default kombu stuff broker_transport = string(default="database") -broker_host = string(default="sqlite:///%(here)s/user_dev/celery.db") +broker_host = string(default="sqlite:///%(here)s/user_dev/kombu.db") # known booleans celery_result_persistent = boolean() -- cgit v1.2.3 From b2a7e44c9ea241e78f8e49025b98833808200e32 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 08:20:17 -0600 Subject: Move mediagoblin dbs out of user_dev for race condition directory-creation reasons. --- mediagoblin/config_spec.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 1eb50701..4088aaa5 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -81,11 +81,11 @@ lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock") [celery] # default result stuff celery_result_backend = string(default="database") -celery_result_dburi = string(default="sqlite:///%(here)s/user_dev/celery.db") +celery_result_dburi = string(default="sqlite:///%(here)s/celery.db") # default kombu stuff broker_transport = string(default="database") -broker_host = string(default="sqlite:///%(here)s/user_dev/kombu.db") +broker_host = string(default="sqlite:///%(here)s/kombu.db") # known booleans celery_result_persistent = boolean() -- cgit v1.2.3 From ec97c937b7e3374d40624478f805694b56bc0317 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 26 Feb 2012 18:45:35 +0100 Subject: Let Main Server emit startup notice including version There was no place in the software telling the user the version in use. So start by having the main server emit a startup notice including the version string. Uses python logging, so should be easy to reconfigure, etc. --- mediagoblin/app.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 06627675..15327d39 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -16,11 +16,12 @@ import os import urllib +import logging import routes from webob import Request, exc -from mediagoblin import routing, meddleware +from mediagoblin import routing, meddleware, __version__ from mediagoblin.tools import common, translate, template from mediagoblin.tools.response import render_404 from mediagoblin.tools import request as mg_request @@ -31,6 +32,9 @@ from mediagoblin.init import (get_jinja_loader, get_staticdirector, setup_storage, setup_beaker_cache) +_log = logging.getLogger(__name__) + + class MediaGoblinApp(object): """ WSGI application of MediaGoblin @@ -47,6 +51,7 @@ class MediaGoblinApp(object): (Note: setting 'celery_setup_elsewhere' also disables setting up celery.) """ + _log.info("GNU MediaGoblin %s main server starting", __version__) ############## # Setup config ############## -- cgit v1.2.3 From 8efcd4055804f5dba99cced70fd4fb7876a88e5e Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 12 Feb 2012 23:49:37 +0100 Subject: Dot-Notation: MediaComment and some random places --- mediagoblin/tests/test_submission.py | 6 +++--- mediagoblin/user_pages/views.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 217926a4..2f11bdfb 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -140,7 +140,7 @@ class TestSubmission: context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html'] request = context['request'] media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] - assert_equal(media['tags'], + assert_equal(media.tags, [{'name': u'yin', 'slug': u'yin'}, {'name': u'yang', 'slug': u'yang'}]) @@ -255,7 +255,7 @@ class TestSubmission: {'title': 'Malicious Upload 2'}) assert_equal(entry.state, 'failed') assert_equal( - entry['fail_error'], + entry.fail_error, u'mediagoblin.processing:BadMediaFail') # Test non-supported file with .png extension @@ -275,5 +275,5 @@ class TestSubmission: {'title': 'Malicious Upload 3'}) assert_equal(entry.state, 'failed') assert_equal( - entry['fail_error'], + entry.fail_error, u'mediagoblin.processing:BadMediaFail') diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 05d07b1b..530dea64 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -142,11 +142,11 @@ def media_post_comment(request, media): assert request.method == 'POST' comment = request.db.MediaComment() - comment['media_entry'] = media._id - comment['author'] = request.user._id - comment['content'] = unicode(request.POST['comment_content']) + comment.media_entry = media.id + comment.author = request.user.id + comment.content = unicode(request.POST['comment_content']) - if not comment['content'].strip(): + if not comment.content.strip(): messages.add_message( request, messages.ERROR, -- cgit v1.2.3 From c60bbe07c558b2f13501cb16d18b61022715b380 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 19 Feb 2012 12:14:58 +0100 Subject: Let SQL objects support .setdefault() and .delete() Some parts in the code like to use .setdefault(). So make them happy and provide a minimal version. It ignores the given default and expects the attribute to already exist. Other parts use .delete() to delete a complete object. This version expects the object to live in a session and also does the final commit. --- mediagoblin/db/sql/base.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 6ed24a03..838080b0 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -67,6 +67,10 @@ class GMGTableBase(object): def get(self, key): return getattr(self, key) + def setdefault(self, key, defaultvalue): + # The key *has* to exist on sql. + return getattr(self, key) + def save(self, validate=True): assert validate sess = object_session(self) @@ -75,6 +79,12 @@ class GMGTableBase(object): sess.add(self) sess.commit() + def delete(self): + sess = object_session(self) + assert sess is not None, "Not going to delete detached %r" % self + sess.delete(self) + sess.commit() + Base = declarative_base(cls=GMGTableBase) -- cgit v1.2.3 From b594eadfbf90f09f4b2a73b7f89fed2b05ba10f3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 13:24:49 -0600 Subject: kombu-sqlalchemy a requirement in order for kombu sqlalchemy transport to work --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 1c7caf96..3e382e56 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ setup( 'Markdown', 'sqlalchemy', 'sqlalchemy-migrate', + 'kombu-sqlalchemy', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', -- cgit v1.2.3 From a68e3e8320b43f874bfea7b40e0b1d1342ef631b Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 13:26:44 -0600 Subject: Celery and kombu databases should also be .gitignore'd --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e3a83822..4c62a766 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ /paste_local.ini /mediagoblin_local.ini /mediagoblin.db +/celery.db +/kombu.db /server-log.txt # Tests -- cgit v1.2.3 From b8e1abf782edd9894974d15ea98637884d22ddf4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 13:27:09 -0600 Subject: "database" is not the sqlalchemy kombu transport... should be "sqlalchemy" --- mediagoblin/config_spec.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 4088aaa5..94e90c44 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -84,7 +84,7 @@ celery_result_backend = string(default="database") celery_result_dburi = string(default="sqlite:///%(here)s/celery.db") # default kombu stuff -broker_transport = string(default="database") +broker_transport = string(default="sqlalchemy") broker_host = string(default="sqlite:///%(here)s/kombu.db") # known booleans -- cgit v1.2.3 From a9a63a686e934e3189179dcf01faad39a330a378 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 15:45:58 -0600 Subject: Adjust unit tests to match new celery/kombu sqlalchemy setup --- mediagoblin/tests/fake_celery_conf_mgdb.ini | 14 ---------- mediagoblin/tests/test_celery_setup.py | 43 ++++++----------------------- 2 files changed, 9 insertions(+), 48 deletions(-) delete mode 100644 mediagoblin/tests/fake_celery_conf_mgdb.ini diff --git a/mediagoblin/tests/fake_celery_conf_mgdb.ini b/mediagoblin/tests/fake_celery_conf_mgdb.ini deleted file mode 100644 index 52671c14..00000000 --- a/mediagoblin/tests/fake_celery_conf_mgdb.ini +++ /dev/null @@ -1,14 +0,0 @@ -['mediagoblin'] -db_host = mongodb.example.org -db_port = 8080 -db_name = captain_lollerskates - -['something'] -or = other - -['celery'] -some_variable = poolf -mail_port = 2020 -celeryd_eta_scheduler_precision = 3.1 -celery_result_persistent = false -celery_imports = baz.bar.foo, import.is.a.this diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index c9c77821..fd600f56 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -22,8 +22,6 @@ from mediagoblin.init.config import read_mediagoblin_config TEST_CELERY_CONF_NOSPECIALDB = pkg_resources.resource_filename( 'mediagoblin.tests', 'fake_celery_conf.ini') -TEST_CELERY_CONF_MGSPECIALDB = pkg_resources.resource_filename( - 'mediagoblin.tests', 'fake_celery_conf_mgdb.ini') def test_setup_celery_from_config(): @@ -51,35 +49,12 @@ def test_setup_celery_from_config(): assert fake_celery_module.CELERY_RESULT_PERSISTENT is True assert fake_celery_module.CELERY_IMPORTS == [ 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing'] - assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { - 'database': 'mediagoblin'} - assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' - assert fake_celery_module.BROKER_BACKEND == 'mongodb' - - _wipe_testmodule_clean(fake_celery_module) - - global_config, validation_result = read_mediagoblin_config( - TEST_CELERY_CONF_MGSPECIALDB) - app_config = global_config['mediagoblin'] - - celery_setup.setup_celery_from_config( - app_config, global_config, - 'mediagoblin.tests.fake_celery_module', set_environ=False) - - from mediagoblin.tests import fake_celery_module - assert fake_celery_module.SOME_VARIABLE == 'poolf' - assert fake_celery_module.MAIL_PORT == 2020 - assert isinstance(fake_celery_module.MAIL_PORT, int) - assert fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION == 3.1 - assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float) - assert fake_celery_module.CELERY_RESULT_PERSISTENT is False - assert fake_celery_module.CELERY_IMPORTS == [ - 'baz.bar.foo', 'import.is.a.this', 'mediagoblin.processing'] - assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == { - 'database': 'captain_lollerskates', - 'host': 'mongodb.example.org', - 'port': 8080} - assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb' - assert fake_celery_module.BROKER_BACKEND == 'mongodb' - assert fake_celery_module.BROKER_HOST == 'mongodb.example.org' - assert fake_celery_module.BROKER_PORT == 8080 + assert fake_celery_module.CELERY_RESULT_BACKEND == 'database' + assert fake_celery_module.CELERY_RESULT_DBURI == ( + 'sqlite:///' + + pkg_resources.resource_filename('mediagoblin.tests', 'celery.db')) + + assert fake_celery_module.BROKER_TRANSPORT == 'sqlalchemy' + assert fake_celery_module.BROKER_HOST == ( + 'sqlite:///' + + pkg_resources.resource_filename('mediagoblin.tests', 'kombu.db')) -- cgit v1.2.3 From 42d0d8f3cd1f4f1500385006a8c8ad6e0d3deb14 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 15:51:00 -0600 Subject: Committing present MediaGoblin translations before pushing extracted messages --- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po | 102 ++++++----------------- mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 108 ++++++------------------- 2 files changed, 49 insertions(+), 161 deletions(-) diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po index 49626556..b3088b25 100644 --- a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" -"POT-Creation-Date: 2012-01-29 13:47-0600\n" -"PO-Revision-Date: 2012-02-05 21:07+0000\n" +"POT-Creation-Date: 2012-02-09 09:30-0600\n" +"PO-Revision-Date: 2012-02-26 19:34+0000\n" "Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -21,7 +21,7 @@ msgstr "" "Language: eo\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -#: mediagoblin/processing.py:143 +#: mediagoblin/processing.py:153 msgid "Invalid file given for media type." msgstr "La provizita dosiero ne konformas al la informtipo." @@ -53,9 +53,7 @@ msgstr "Ni bedaŭras, sed konto kun tiu retpoŝtadreso jam ekzistas." msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" -msgstr "" -"Via retpoŝtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian " -"profilon, kaj alŝuti bildojn!" +msgstr "Via retpoŝtadreso estas konfirmita. Vi povas nun ensaluti, redakti vian profilon, kaj alŝuti bildojn!" #: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" @@ -82,9 +80,7 @@ msgstr "Senditas retletero kun instrukcio pri kiel ŝanĝi vian pasvorton." msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." -msgstr "" -"Ni ne povas sendi pasvortsavan retleteron, ĉar aŭ via konto estas neaktiva, " -"aŭ ĝia retpoŝtadreso ne estis konfirmita." +msgstr "Ni ne povas sendi pasvortsavan retleteron, ĉar aŭ via konto estas neaktiva, aŭ ĝia retpoŝtadreso ne estis konfirmita." #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." @@ -108,10 +104,7 @@ msgid "" "You can use\n" " \n" " Markdown for formatting." -msgstr "" -"Vi povas uzi por markado la lingvon\n" -" «\n" -" Markdown»." +msgstr "Vi povas uzi por markado la lingvon\n «\n Markdown»." #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" @@ -133,9 +126,7 @@ msgstr "La distingiga adresparto ne povas esti malplena" msgid "" "The title part of this media's address. You usually don't need to change " "this." -msgstr "" -"La dosiertitol-bazita parto de la dosieradreso. Ordinare ne necesas ĝin " -"ŝanĝi." +msgstr "La dosiertitol-bazita parto de la dosieradreso. Ordinare ne necesas ĝin ŝanĝi." #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" @@ -221,9 +212,7 @@ msgstr "Verŝajne ĉe ĉi tiu adreso ne estas paĝo. Ni bedaŭras!" msgid "" "If you're sure the address is correct, maybe the page you're looking for has" " been moved or deleted." -msgstr "" -"Se vi estas certa, ke la adreso estas ĝusta, eble la serĉata de vi paĝo " -"estis movita aŭ forigita." +msgstr "Se vi estas certa, ke la adreso estas ĝusta, eble la serĉata de vi paĝo estis movita aŭ forigita." #: mediagoblin/templates/mediagoblin/base.html:46 msgid "MediaGoblin logo" @@ -252,9 +241,7 @@ msgstr "Ensaluti" msgid "" "Powered by MediaGoblin, a GNU project" -msgstr "" -"Funkcias per MediaGoblin, unu el la " -"projektoj de GNU" +msgstr "Funkcias per MediaGoblin, unu el la projektoj de GNU" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" @@ -268,18 +255,13 @@ msgstr "Saluton, kaj bonvenon al ĉi tiu MediaGoblina retpaĝaro!" msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." -msgstr "" -"Ĉi tiu retpaĝaro funkcias per MediaGoblin, eksterordinare bonega " -"programaro por gastigado de aŭd‐vid‐dosieroj." +msgstr "Ĉi tiu retpaĝaro funkcias per MediaGoblin, eksterordinare bonega programaro por gastigado de aŭd‐vid‐dosieroj." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." -msgstr "" -"Por aldoni viajn proprajn dosierojn, fari al vi liston de la plej plaĉaj, " -"ks, vi povas ensaluti je via MediaGoblina konto." +msgstr "Por aldoni viajn proprajn dosierojn, fari al vi liston de la plej plaĉaj, ks, vi povas ensaluti je via MediaGoblina konto." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" @@ -291,10 +273,7 @@ msgid "" "Create an account at this site\n" " or\n" " Set up MediaGoblin on your own server" -msgstr "" -"Kreu konton en ĉi tiu retejo\n" -" aŭ\n" -" ekfunkciigu MediaGoblin’on en via propra servilo" +msgstr "Kreu konton en ĉi tiu retejo\n aŭ\n ekfunkciigu MediaGoblin’on en via propra servilo" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -328,14 +307,7 @@ msgid "" "\n" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" -msgstr "" -"Saluton, %(username)s,\n" -"\n" -"por ŝanĝi vian pasvorton ĉe GNUa MediaGoblin, sekvu la jenan retadreson per via TTT-legilo:\n" -"\n" -"%(verification_url)s\n" -"\n" -"Se vi pensas, ke ĉi tiu retletero estas sendita erare, simple ignoru ĝin kaj plu restu feliĉa koboldo!" +msgstr "Saluton, %(username)s,\n\npor ŝanĝi vian pasvorton ĉe GNUa MediaGoblin, sekvu la jenan retadreson per via TTT-legilo:\n\n%(verification_url)s\n\nSe vi pensas, ke ĉi tiu retletero estas sendita erare, simple ignoru ĝin kaj plu restu feliĉa koboldo!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" @@ -370,12 +342,7 @@ msgid "" "your web browser:\n" "\n" "%(verification_url)s" -msgstr "" -"Sal %(username)s,\n" -"\n" -"por aktivigi vian GNU MediaGoblin konton, malfermu la sekvantan URLon en via retumilo:\n" -"\n" -"%(verification_url)s" +msgstr "Sal %(username)s,\n\npor aktivigi vian GNU MediaGoblin konton, malfermu la sekvantan URLon en via retumilo:\n\n%(verification_url)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format @@ -419,20 +386,14 @@ msgid "" "Sorry, this video will not work because \n" "\t your web browser does not support HTML5 \n" "\t video." -msgstr "" -"Bedaŭrinde ĉi tiu filmo ne spekteblas, ĉar\n" -"» via TTT-legilo ne subtenas montradon\n" -"» de filmoj laŭ HTML5." +msgstr "Bedaŭrinde ĉi tiu filmo ne spekteblas, ĉar\n» via TTT-legilo ne subtenas montradon\n» de filmoj laŭ HTML5." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" "You can get a modern web browser that \n" "\t can play this video at \n" "\t http://getfirefox.com!" -msgstr "" -"Vi povas akiri modernan TTT-legilon,\n" -"» kapablan montri ĉi tiun filmon, ĉe \n" -"» http://getfirefox.com!" +msgstr "Vi povas akiri modernan TTT-legilon,\n» kapablan montri ĉi tiun filmon, ĉe \n» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" @@ -488,9 +449,7 @@ msgid "" "You can use Markdown for" " formatting." -msgstr "" -"Vi povas uzi por markado la lingvon «<a " -"href=\"http://daringfireball.net/projects/markdown/basics\">Markdown</a>»." +msgstr "Vi povas uzi por markado la lingvon «Markdown»." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" @@ -503,8 +462,7 @@ msgstr "je" #: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " -msgstr "" -"

    ❖ Foliumado de dosieraro de %(username)s

    " +msgstr "

    ❖ Foliumado de dosieraro de %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -522,9 +480,7 @@ msgstr "Kontrolejo pri dosierpreparado." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" -"Ĉi tie vi povas informiĝi pri la stato de preparado de dosieroj por via " -"galerio." +msgstr "Ĉi tie vi povas informiĝi pri la stato de preparado de dosieroj por via galerio." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" @@ -560,8 +516,7 @@ msgstr "Preskaŭ finite! Restas nur validigi vian konton." #: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." -msgstr "" -"Post kelkaj momentoj devas veni retletero kun instrukcio pri kiel tion fari." +msgstr "Post kelkaj momentoj devas veni retletero kun instrukcio pri kiel tion fari." #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" @@ -575,18 +530,14 @@ msgstr "Resendi kontrolmesaĝon" msgid "" "Someone has registered an account with this username, but it still has to be" " activated." -msgstr "" -"Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti " -"aktivigita." +msgstr "Iu registris konton kun tiu ĉi uzantonomo, sed ĝi devas ankoraŭ esti aktivigita." #: mediagoblin/templates/mediagoblin/user_pages/user.html:79 #, python-format msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." -msgstr "" -"Se vi estas tiu sed vi perdis vian kontrolmesaĝon, vi povas ensaluti kaj resendi ĝin." +msgstr "Se vi estas tiu sed vi perdis vian kontrolmesaĝon, vi povas ensaluti kaj resendi ĝin." #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." @@ -614,8 +565,7 @@ msgstr "Rigardi ĉiujn dosierojn de %(username)s" msgid "" "This is where your media will appear, but you don't seem to have added " "anything yet." -msgstr "" -"Ĝuste ĉi tie aperos viaj dosieroj, sed vi ŝajne ankoraŭ nenion alŝutis." +msgstr "Ĝuste ĉi tie aperos viaj dosieroj, sed vi ŝajne ankoraŭ nenion alŝutis." #: mediagoblin/templates/mediagoblin/user_pages/user.html:163 #: mediagoblin/templates/mediagoblin/utils/object_gallery.html:72 @@ -690,12 +640,8 @@ msgstr "Vi forigis la dosieron." #: mediagoblin/user_pages/views.py:190 msgid "The media was not deleted because you didn't check that you were sure." -msgstr "" -"La dosiero ne estis forigita, ĉar vi ne konfirmis vian certecon per la " -"markilo." +msgstr "La dosiero ne estis forigita, ĉar vi ne konfirmis vian certecon per la markilo." #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Vi estas forigonta dosieron de alia uzanto. Estu singardema." - - diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po index d895f3bf..ea9d1dc3 100644 --- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: GNU MediaGoblin\n" "Report-Msgid-Bugs-To: http://issues.mediagoblin.org/\n" -"POT-Creation-Date: 2012-01-29 13:47-0600\n" -"PO-Revision-Date: 2012-02-05 21:04+0000\n" +"POT-Creation-Date: 2012-02-09 09:30-0600\n" +"PO-Revision-Date: 2012-02-26 19:33+0000\n" "Last-Translator: aleksejrs \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" @@ -19,7 +19,7 @@ msgstr "" "Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: mediagoblin/processing.py:143 +#: mediagoblin/processing.py:153 msgid "Invalid file given for media type." msgstr "Неправильный формат файла." @@ -45,17 +45,13 @@ msgstr "Извините, пользователь с этим именем уж #: mediagoblin/auth/views.py:77 msgid "Sorry, a user with that email address already exists." -msgstr "" -"Сожалеем, но на этот адрес электронной почты уже зарегистрирована другая " -"учётная запись." +msgstr "Сожалеем, но на этот адрес электронной почты уже зарегистрирована другая учётная запись." #: mediagoblin/auth/views.py:180 msgid "" "Your email address has been verified. You may now login, edit your profile, " "and submit images!" -msgstr "" -"Адрес вашей электронной потвержден. Вы теперь можете войти и начать " -"редактировать свой профиль и загружать новые изображения!" +msgstr "Адрес вашей электронной потвержден. Вы теперь можете войти и начать редактировать свой профиль и загружать новые изображения!" #: mediagoblin/auth/views.py:186 msgid "The verification key or user id is incorrect" @@ -82,15 +78,11 @@ msgstr "Вам отправлено электронное письмо с ин msgid "" "Could not send password recovery email as your username is inactive or your " "account's email address has not been verified." -msgstr "" -"Мы не можем отправить сообщение для восстановления пароля, потому что ваша " -"учётная запись неактивна, либо указанный в ней адрес электронной почты не " -"был подтверждён." +msgstr "Мы не можем отправить сообщение для восстановления пароля, потому что ваша учётная запись неактивна, либо указанный в ней адрес электронной почты не был подтверждён." #: mediagoblin/auth/views.py:282 msgid "Couldn't find someone with that username or email." -msgstr "" -"Не найдено никого с таким именем пользователя или адресом электронной почты." +msgstr "Не найдено никого с таким именем пользователя или адресом электронной почты." #: mediagoblin/auth/views.py:330 msgid "You can now log in using your new password." @@ -110,10 +102,7 @@ msgid "" "You can use\n" " \n" " Markdown for formatting." -msgstr "" -"Для разметки можете использовать язык\n" -" \n" -" Markdown." +msgstr "Для разметки можете использовать язык\n \n Markdown." #: mediagoblin/edit/forms.py:33 mediagoblin/submit/forms.py:36 msgid "Tags" @@ -135,9 +124,7 @@ msgstr "Отличительная часть адреса необходима" msgid "" "The title part of this media's address. You usually don't need to change " "this." -msgstr "" -"Часть адреса этого файла, производная от его названия. Её обычно не " -"требуется изменять." +msgstr "Часть адреса этого файла, производная от его названия. Её обычно не требуется изменять." #: mediagoblin/edit/forms.py:44 mediagoblin/submit/forms.py:41 msgid "License" @@ -157,9 +144,7 @@ msgstr "Старый пароль" #: mediagoblin/edit/forms.py:65 msgid "Enter your old password to prove you own this account." -msgstr "" -"Введите свой старый пароль в качестве доказательства, что это ваша учётная " -"запись." +msgstr "Введите свой старый пароль в качестве доказательства, что это ваша учётная запись." #: mediagoblin/edit/forms.py:68 msgid "New password" @@ -167,8 +152,7 @@ msgstr "Новый пароль" #: mediagoblin/edit/views.py:68 msgid "An entry with that slug already exists for this user." -msgstr "" -"У этого пользователя уже есть файл с такой отличительной частью адреса." +msgstr "У этого пользователя уже есть файл с такой отличительной частью адреса." #: mediagoblin/edit/views.py:92 msgid "You are editing another user's media. Proceed with caution." @@ -255,9 +239,7 @@ msgstr "Войти" msgid "" "Powered by MediaGoblin, a GNU project" -msgstr "" -"Работает на MediaGoblin, проекте GNU" +msgstr "Работает на MediaGoblin, проекте GNU" #: mediagoblin/templates/mediagoblin/root.html:24 msgid "Explore" @@ -271,18 +253,13 @@ msgstr "Привет! Добро пожаловать на наш MediaGoblin’ msgid "" "This site is running MediaGoblin, an " "extraordinarily great piece of media hosting software." -msgstr "" -"Этот сайт работает на MediaGoblin, " -"необыкновенно замечательном ПО для хостинга мультимедийных файлов." +msgstr "Этот сайт работает на MediaGoblin, необыкновенно замечательном ПО для хостинга мультимедийных файлов." #: mediagoblin/templates/mediagoblin/root.html:29 msgid "" "To add your own media, place comments, save your favourites and more, you " "can log in with your MediaGoblin account." -msgstr "" -"Для добавления собственных файлов, комментирования, ведения списка любимых " -"файлов и т. п. вы можете представиться с помощью вашей MediaGoblin’овой " -"учётной записи." +msgstr "Для добавления собственных файлов, комментирования, ведения списка любимых файлов и т. п. вы можете представиться с помощью вашей MediaGoblin’овой учётной записи." #: mediagoblin/templates/mediagoblin/root.html:31 msgid "Don't have one yet? It's easy!" @@ -294,10 +271,7 @@ msgid "" "Create an account at this site\n" " or\n" " Set up MediaGoblin on your own server" -msgstr "" -"<a class=\"button_action_highlight\" href=\"%(register_url)s\">Создайте учётную запись на этом сайте</a>\n" -" или\n" -" <a class=\"button_action\" href=\"http://wiki.mediagoblin.org/HackingHowto\">установите MediaGoblin на собственный сервер</a>" +msgstr "Создайте учётную запись на этом сайте\n или\n установите MediaGoblin на собственный сервер" #: mediagoblin/templates/mediagoblin/root.html:40 msgid "Most recent media" @@ -331,16 +305,7 @@ msgid "" "\n" "If you think this is an error, just ignore this email and continue being\n" "a happy goblin!" -msgstr "" -"Привет, %(username)s,\n" -"\n" -"чтобы сменить свой пароль от GNU MediaGoblin, откройте\n" -"следующий URL вашим веб‐браузером:\n" -"\n" -"%(verification_url)s\n" -"\n" -"Если вы думаете, что это какая‐то ошибка, то игнорируйте\n" -"это сообщение и продолжайте быть счастливым гоблином!" +msgstr "Привет, %(username)s,\n\nчтобы сменить свой пароль от GNU MediaGoblin, откройте\nследующий URL вашим веб‐браузером:\n\n%(verification_url)s\n\nЕсли вы думаете, что это какая‐то ошибка, то игнорируйте\nэто сообщение и продолжайте быть счастливым гоблином!" #: mediagoblin/templates/mediagoblin/auth/login.html:30 msgid "Logging in failed!" @@ -375,12 +340,7 @@ msgid "" "your web browser:\n" "\n" "%(verification_url)s" -msgstr "" -"Привет, %(username)s!\n" -"\n" -"Чтобы активировать свой аккаунт в GNU MediaGoblin, откройте в своём веб‐браузере следующую ссылку:\n" -"\n" -"%(verification_url)s" +msgstr "Привет, %(username)s!\n\nЧтобы активировать свой аккаунт в GNU MediaGoblin, откройте в своём веб‐браузере следующую ссылку:\n\n%(verification_url)s" #: mediagoblin/templates/mediagoblin/edit/edit.html:29 #, python-format @@ -424,20 +384,14 @@ msgid "" "Sorry, this video will not work because \n" "\t your web browser does not support HTML5 \n" "\t video." -msgstr "" -"Сожалеем, этот ролик не проиграется, ⏎\n" -"» потому что ваш браузер не поддерживает ⏎\n" -"» видео в соответствии со стандартом HTML5." +msgstr "Сожалеем, этот ролик не проиграется, ⏎\n» потому что ваш браузер не поддерживает ⏎\n» видео в соответствии со стандартом HTML5." #: mediagoblin/templates/mediagoblin/media_displays/video.html:36 msgid "" "You can get a modern web browser that \n" "\t can play this video at \n" "\t http://getfirefox.com!" -msgstr "" -"Вы можете скачать современный браузер,\n" -"» способный воспроизводить это видео, с \n" -"» http://getfirefox.com!" +msgstr "Вы можете скачать современный браузер,\n» способный воспроизводить это видео, с \n» http://getfirefox.com!" #: mediagoblin/templates/mediagoblin/submit/start.html:26 msgid "Add your media" @@ -493,9 +447,7 @@ msgid "" "You can use Markdown for" " formatting." -msgstr "" -"Для разметки можете использовать язык Markdown." +msgstr "Для разметки можете использовать язык Markdown." #: mediagoblin/templates/mediagoblin/user_pages/media.html:116 msgid "Add this comment" @@ -508,9 +460,7 @@ msgstr "в" #: mediagoblin/templates/mediagoblin/user_pages/media.html:153 #, python-format msgid "

    ❖ Browsing media by %(username)s

    " -msgstr "" -"

    ❖ Просмотр файлов пользователя %(username)s

    " +msgstr "

    ❖ Просмотр файлов пользователя %(username)s

    " #: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30 #, python-format @@ -528,8 +478,7 @@ msgstr "Панель обработки файлов" #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25 msgid "" "You can track the state of media being processed for your gallery here." -msgstr "" -"Вы можете следить за статусом обработки файлов для вашей галереи здесь." +msgstr "Вы можете следить за статусом обработки файлов для вашей галереи здесь." #: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28 msgid "Media in-processing" @@ -565,9 +514,7 @@ msgstr "Почти закончили! Теперь надо активиров #: mediagoblin/templates/mediagoblin/user_pages/user.html:58 msgid "" "An email should arrive in a few moments with instructions on how to do so." -msgstr "" -"Через пару мгновений на адрес вашей электронной почты должно прийти " -"сообщение с дальнейшими инструкциями." +msgstr "Через пару мгновений на адрес вашей электронной почты должно прийти сообщение с дальнейшими инструкциями." #: mediagoblin/templates/mediagoblin/user_pages/user.html:62 msgid "In case it doesn't:" @@ -575,8 +522,7 @@ msgstr "А если нет, то:" #: mediagoblin/templates/mediagoblin/user_pages/user.html:65 msgid "Resend verification email" -msgstr "" -"Повторно отправить сообщение для подверждения адреса электронной почты" +msgstr "Повторно отправить сообщение для подверждения адреса электронной почты" #: mediagoblin/templates/mediagoblin/user_pages/user.html:73 msgid "" @@ -589,9 +535,7 @@ msgstr "Кто‐то создал аккаунт с этим именем, но msgid "" "If you are that person but you've lost your verification email, you can log in and resend it." -msgstr "" -"Если это были вы, и если вы потеряли сообщение для подтверждения аккаунта, " -"то вы можете войти и отправить его повторно." +msgstr "Если это были вы, и если вы потеряли сообщение для подтверждения аккаунта, то вы можете войти и отправить его повторно." #: mediagoblin/templates/mediagoblin/user_pages/user.html:96 msgid "Here's a spot to tell others about yourself." @@ -699,5 +643,3 @@ msgstr "Файл не удалён, так как вы не подтвердил #: mediagoblin/user_pages/views.py:198 msgid "You are about to delete another user's media. Proceed with caution." msgstr "Вы на пороге удаления файла другого пользователя. Будьте осторожны." - - -- cgit v1.2.3 From 6b38a38a91a72e24362a0f7760942958096b6fce Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Sun, 26 Feb 2012 15:51:11 -0600 Subject: Committing extracted and compiled translations --- mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 46 ++++++++++++------------- mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo | Bin 13840 -> 13828 bytes mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 18051 -> 18027 bytes 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po index b5832fe4..7c64c09f 100644 --- a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-02-09 09:30-0600\n" +"POT-Creation-Date: 2012-02-26 15:51-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -37,51 +37,51 @@ msgstr "" msgid "Sorry, registration is disabled on this instance." msgstr "" -#: mediagoblin/auth/views.py:73 +#: mediagoblin/auth/views.py:75 msgid "Sorry, a user with that name already exists." msgstr "" -#: mediagoblin/auth/views.py:77 +#: mediagoblin/auth/views.py:79 msgid "Sorry, a user with that email address already exists." msgstr "" -#: mediagoblin/auth/views.py:180 +#: mediagoblin/auth/views.py:182 msgid "" "Your email address has been verified. You may now login, edit your " "profile, and submit images!" msgstr "" -#: mediagoblin/auth/views.py:186 +#: mediagoblin/auth/views.py:188 msgid "The verification key or user id is incorrect" msgstr "" -#: mediagoblin/auth/views.py:204 +#: mediagoblin/auth/views.py:206 msgid "You must be logged in so we know who to send the email to!" msgstr "" -#: mediagoblin/auth/views.py:212 +#: mediagoblin/auth/views.py:214 msgid "You've already verified your email address!" msgstr "" -#: mediagoblin/auth/views.py:225 +#: mediagoblin/auth/views.py:227 msgid "Resent your verification email." msgstr "" -#: mediagoblin/auth/views.py:260 +#: mediagoblin/auth/views.py:262 msgid "An email has been sent with instructions on how to change your password." msgstr "" -#: mediagoblin/auth/views.py:270 +#: mediagoblin/auth/views.py:272 msgid "" "Could not send password recovery email as your username is inactive or " "your account's email address has not been verified." msgstr "" -#: mediagoblin/auth/views.py:282 +#: mediagoblin/auth/views.py:284 msgid "Couldn't find someone with that username or email." msgstr "" -#: mediagoblin/auth/views.py:330 +#: mediagoblin/auth/views.py:332 msgid "You can now log in using your new password." msgstr "" @@ -152,23 +152,23 @@ msgstr "" msgid "An entry with that slug already exists for this user." msgstr "" -#: mediagoblin/edit/views.py:92 +#: mediagoblin/edit/views.py:89 msgid "You are editing another user's media. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:162 +#: mediagoblin/edit/views.py:159 msgid "You are editing a user's profile. Proceed with caution." msgstr "" -#: mediagoblin/edit/views.py:180 +#: mediagoblin/edit/views.py:175 msgid "Profile changes saved" msgstr "" -#: mediagoblin/edit/views.py:206 +#: mediagoblin/edit/views.py:201 msgid "Wrong password" msgstr "" -#: mediagoblin/edit/views.py:222 +#: mediagoblin/edit/views.py:217 msgid "Account settings saved" msgstr "" @@ -188,7 +188,7 @@ msgstr "" msgid "You must provide a file." msgstr "" -#: mediagoblin/submit/views.py:158 +#: mediagoblin/submit/views.py:156 msgid "Woohoo! Submitted!" msgstr "" @@ -623,23 +623,23 @@ msgstr "" msgid "I am sure I want to delete this" msgstr "" -#: mediagoblin/user_pages/views.py:155 +#: mediagoblin/user_pages/views.py:153 msgid "Oops, your comment was empty." msgstr "" -#: mediagoblin/user_pages/views.py:161 +#: mediagoblin/user_pages/views.py:159 msgid "Your comment has been posted!" msgstr "" -#: mediagoblin/user_pages/views.py:183 +#: mediagoblin/user_pages/views.py:181 msgid "You deleted the media." msgstr "" -#: mediagoblin/user_pages/views.py:190 +#: mediagoblin/user_pages/views.py:188 msgid "The media was not deleted because you didn't check that you were sure." msgstr "" -#: mediagoblin/user_pages/views.py:198 +#: mediagoblin/user_pages/views.py:196 msgid "You are about to delete another user's media. Proceed with caution." msgstr "" diff --git a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo index 25ab5836..f5a660d9 100644 Binary files a/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/eo/LC_MESSAGES/mediagoblin.mo differ diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo index dd7735fd..eb6cc942 100644 Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ -- cgit v1.2.3 From baae1578dae4ccf6538baa1f362409e16f94f266 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sun, 19 Feb 2012 12:13:48 +0100 Subject: Let mark_entry_failed log unknown exceptions I don't know exactly why, but an exception during processing hasn't found its way up. The entry was marked as failed and that was it. So I decided to add a _log.warn to the part of mark_entry_failed that handles general exceptions. --- mediagoblin/processing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/processing.py b/mediagoblin/processing.py index 9e57380d..a07de869 100644 --- a/mediagoblin/processing.py +++ b/mediagoblin/processing.py @@ -114,6 +114,7 @@ def mark_entry_failed(entry_id, exc): u'fail_error': exc.exception_path, u'fail_metadata': exc.metadata}}) else: + _log.warn("No idea what happened here, but it failed: %r", exc) # Looks like no, so just mark it as failed and don't record a # failure_error (we'll assume it wasn't handled) and don't record # metadata (in fact overwrite it if somehow it had previous info -- cgit v1.2.3 From 6bcdd4dc7043bc1fdff66c7b7a9fbb96ce5d29dc Mon Sep 17 00:00:00 2001 From: Luke Slater Date: Tue, 28 Feb 2012 16:40:37 +0000 Subject: Changed celery config keys to upper case and removed upper casing of keys when initialising the config as per issue #214 --- mediagoblin/config_spec.ini | 80 ++++++++++++++++++------------------- mediagoblin/init/celery/__init__.py | 57 +------------------------- 2 files changed, 41 insertions(+), 96 deletions(-) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 94e90c44..10828536 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -80,53 +80,53 @@ lock_dir = string(default="%(here)s/user_dev/beaker/cache/lock") [celery] # default result stuff -celery_result_backend = string(default="database") -celery_result_dburi = string(default="sqlite:///%(here)s/celery.db") +CELERY_RESULT_BACKEND = string(default="database") +CELERY_RESULT_DBURI = string(default="sqlite:///%(here)s/celery.db") # default kombu stuff -broker_transport = string(default="sqlalchemy") -broker_host = string(default="sqlite:///%(here)s/kombu.db") +BROKER_TRANSPORT = string(default="sqlalchemy") +BROKER_HOST = string(default="sqlite:///%(here)s/kombu.db") # known booleans -celery_result_persistent = boolean() -celery_create_missing_queues = boolean() -broker_use_ssl = boolean() -broker_connection_retry = boolean() -celery_always_eager = boolean() -celery_eager_propagates_exceptions = boolean() -celery_ignore_result = boolean() -celery_track_started = boolean() -celery_disable_rate_limits = boolean() -celery_acks_late = boolean() -celery_store_errors_even_if_ignored = boolean() -celery_send_task_error_emails = boolean() -celery_send_events = boolean() -celery_send_task_sent_event = boolean() -celeryd_log_color = boolean() -celery_redirect_stdouts = boolean() +CELERY_RESULT_PERSISTENT = boolean() +CELERY_CREATE_MISSING_QUEUES = boolean() +BROKER_USE_SSL = boolean() +BROKER_CONNECTION_RETRY = boolean() +CELERY_ALWAYS_EAGER = boolean() +CELERY_EAGER_PROPAGATES_EXCEPTIONS = boolean() +CELERY_IGNORE_RESULT = boolean() +CELERY_TRACK_STARTED = boolean() +CELERY_DISABLE_RATE_LIMITS = boolean() +CELERY_ACKS_LATE = boolean() +CELERY_STORE_ERRORS_EVEN_IF_IGNORED = boolean() +CELERY_SEND_TASK_ERROR_EMAILS = boolean() +CELERY_SEND_EVENTS = boolean() +CELERY_SEND_TASK_SENT_EVENT = boolean() +CELERYD_LOG_COLOR = boolean() +CELERY_REDIRECT_STDOUTS = boolean() # known ints -celeryd_concurrency = integer() -celeryd_prefetch_multiplier = integer() -celery_amqp_task_result_expires = integer() -celery_amqp_task_result_connection_max = integer() -redis_port = integer() -redis_db = integer() -broker_port = integer() -broker_connection_timeout = integer() -celery_broker_connection_max_retries = integer() -celery_task_result_expires = integer() -celery_max_cached_results = integer() -celery_default_rate_limit = integer() -celeryd_max_tasks_per_child = integer() -celeryd_task_time_limit = integer() -celeryd_task_soft_time_limit = integer() -mail_port = integer() -celerybeat_max_loop_interval = integer() +CELERYD_CONCURRENCY = integer() +CELERYD_PREFETCH_MULTIPLIER = integer() +CELERY_AMQP_TASK_RESULT_EXPIRES = integer() +CELERY_AMQP_TASK_RESULT_CONNECTION_MAX = integer() +REDIS_PORT = integer() +REDIS_DB = integer() +BROKER_PORT = integer() +BROKER_CONNECTION_TIMEOUT = integer() +CELERY_BROKER_CONNECTION_MAX_RETRIES = integer() +CELERY_TASK_RESULT_EXPIRES = integer() +CELERY_MAX_CACHED_RESULTS = integer() +CELERY_DEFAULT_RATE_LIMIT = integer() +CELERYD_MAX_TASKS_PER_CHILD = integer() +CELERYD_TASK_TIME_LIMIT = integer() +CELERYD_TASK_SOFT_TIME_LIMIT = integer() +MAIL_PORT = integer() +CELERYBEAT_MAX_LOOP_INTERVAL = integer() # known floats -celeryd_eta_scheduler_precision = float() +CELERYD_ETA_SCHEDULER_PRECISION = float() # known lists -celery_routes = string_list() -celery_imports = string_list() +CELERY_ROUTES = string_list() +CELERY_IMPORTS = string_list() diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index 6dcea239..88dedd28 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -14,59 +14,4 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import os -import sys - - -MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing'] - -DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module' - - -def setup_celery_from_config(app_config, global_config, - settings_module=DEFAULT_SETTINGS_MODULE, - force_celery_always_eager=False, - set_environ=True): - """ - Take a mediagoblin app config and try to set up a celery settings - module from this. - - Args: - - app_config: the application config section - - global_config: the entire ConfigObj loaded config, all sections - - settings_module: the module to populate, as a string - - force_celery_always_eager: whether or not to force celery into - always eager mode; good for development and small installs - - set_environ: if set, this will CELERY_CONFIG_MODULE to the - settings_module - """ - if 'celery' in global_config: - celery_conf = global_config['celery'] - else: - celery_conf = {} - - celery_settings = {} - - # Add all celery settings from config - for key, value in celery_conf.iteritems(): - key = key.upper() - celery_settings[key] = value - - # TODO: use default result stuff here if it exists - - # add mandatory celery imports - celery_imports = celery_settings.setdefault('CELERY_IMPORTS', []) - celery_imports.extend(MANDATORY_CELERY_IMPORTS) - - if force_celery_always_eager: - celery_settings['CELERY_ALWAYS_EAGER'] = True - celery_settings['CELERY_EAGER_PROPAGATES_EXCEPTIONS'] = True - - __import__(settings_module) - this_module = sys.modules[settings_module] - - for key, value in celery_settings.iteritems(): - setattr(this_module, key, value) - - if set_environ: - os.environ['CELERY_CONFIG_MODULE'] = settings_module +from mediagoblin._version import __version__ -- cgit v1.2.3 From 4f9f969dece472d1175db5a9508dfa3957c90529 Mon Sep 17 00:00:00 2001 From: Luke Slater Date: Tue, 28 Feb 2012 16:47:38 +0000 Subject: Accidentally overwrote the celery/__init__.py, fixed this and removed the upper correctly --- mediagoblin/init/celery/__init__.py | 56 ++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py index 88dedd28..29ccd83a 100644 --- a/mediagoblin/init/celery/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -14,4 +14,58 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from mediagoblin._version import __version__ +import os +import sys + + +MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing'] + +DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module' + + +def setup_celery_from_config(app_config, global_config, + settings_module=DEFAULT_SETTINGS_MODULE, + force_celery_always_eager=False, + set_environ=True): + """ + Take a mediagoblin app config and try to set up a celery settings + module from this. + + Args: + - app_config: the application config section + - global_config: the entire ConfigObj loaded config, all sections + - settings_module: the module to populate, as a string + - force_celery_always_eager: whether or not to force celery into + always eager mode; good for development and small installs + - set_environ: if set, this will CELERY_CONFIG_MODULE to the + settings_module + """ + if 'celery' in global_config: + celery_conf = global_config['celery'] + else: + celery_conf = {} + + celery_settings = {} + + # Add all celery settings from config + for key, value in celery_conf.iteritems(): + celery_settings[key] = value + + # TODO: use default result stuff here if it exists + + # add mandatory celery imports + celery_imports = celery_settings.setdefault('CELERY_IMPORTS', []) + celery_imports.extend(MANDATORY_CELERY_IMPORTS) + + if force_celery_always_eager: + celery_settings['CELERY_ALWAYS_EAGER'] = True + celery_settings['CELERY_EAGER_PROPAGATES_EXCEPTIONS'] = True + + __import__(settings_module) + this_module = sys.modules[settings_module] + + for key, value in celery_settings.iteritems(): + setattr(this_module, key, value) + + if set_environ: + os.environ['CELERY_CONFIG_MODULE'] = settings_module -- cgit v1.2.3 From e9f87f728ce67467272d9484b711e2a518537cb4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 28 Feb 2012 13:31:03 -0600 Subject: Fix tests given recent celery "case" change --- mediagoblin/tests/fake_carrot_conf_bad.ini | 2 +- mediagoblin/tests/fake_carrot_conf_good.ini | 2 +- mediagoblin/tests/fake_celery_conf.ini | 14 +++++++------- mediagoblin/tests/fake_config_spec.ini | 2 +- mediagoblin/tests/test_config.py | 8 ++++---- mediagoblin/tests/test_mgoblin_app.ini | 2 +- mediagoblin/tests/test_paste.ini | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mediagoblin/tests/fake_carrot_conf_bad.ini b/mediagoblin/tests/fake_carrot_conf_bad.ini index 0c79b354..9d8cf518 100644 --- a/mediagoblin/tests/fake_carrot_conf_bad.ini +++ b/mediagoblin/tests/fake_carrot_conf_bad.ini @@ -11,4 +11,4 @@ encouragement_phrase = 586956856856 # shouldn't throw error blah_blah = "blah!" # shouldn't throw error either [celery] -eat_celery_with_carrots = pants # yeah that's def an error right there. +EAT_CELERY_WITH_CARROTS = pants # yeah that's def an error right there. diff --git a/mediagoblin/tests/fake_carrot_conf_good.ini b/mediagoblin/tests/fake_carrot_conf_good.ini index fed14d07..1377907b 100644 --- a/mediagoblin/tests/fake_carrot_conf_good.ini +++ b/mediagoblin/tests/fake_carrot_conf_good.ini @@ -10,4 +10,4 @@ encouragement_phrase = "I'd love it if you eat your carrots!" blah_blah = "blah!" [celery] -eat_celery_with_carrots = False +EAT_CELERY_WITH_CARROTS = False diff --git a/mediagoblin/tests/fake_celery_conf.ini b/mediagoblin/tests/fake_celery_conf.ini index 3e52ac3a..67b0cba6 100644 --- a/mediagoblin/tests/fake_celery_conf.ini +++ b/mediagoblin/tests/fake_celery_conf.ini @@ -1,9 +1,9 @@ -['mediagoblin'] +[mediagoblin] # I got nothin' in this file! -['celery'] -some_variable = floop -mail_port = 2000 -celeryd_eta_scheduler_precision = 1.3 -celery_result_persistent = true -celery_imports = foo.bar.baz, this.is.an.import +[celery] +SOME_VARIABLE = floop +MAIL_PORT = 2000 +CELERYD_ETA_SCHEDULER_PRECISION = 1.3 +CELERY_RESULT_PERSISTENT = true +CELERY_IMPORTS = foo.bar.baz, this.is.an.import diff --git a/mediagoblin/tests/fake_config_spec.ini b/mediagoblin/tests/fake_config_spec.ini index 9421ce36..43f2e236 100644 --- a/mediagoblin/tests/fake_config_spec.ini +++ b/mediagoblin/tests/fake_config_spec.ini @@ -7,4 +7,4 @@ num_carrots = integer(default=1) encouragement_phrase = string() [celery] -eat_celery_with_carrots = boolean(default=True) \ No newline at end of file +EAT_CELERY_WITH_CARROTS = boolean(default=True) \ No newline at end of file diff --git a/mediagoblin/tests/test_config.py b/mediagoblin/tests/test_config.py index c596f6a6..7d8c65c1 100644 --- a/mediagoblin/tests/test_config.py +++ b/mediagoblin/tests/test_config.py @@ -37,7 +37,7 @@ def test_read_mediagoblin_config(): assert this_conf['carrotapp']['carrotcake'] == False assert this_conf['carrotapp']['num_carrots'] == 1 assert not this_conf['carrotapp'].has_key('encouragement_phrase') - assert this_conf['celery']['eat_celery_with_carrots'] == True + assert this_conf['celery']['EAT_CELERY_WITH_CARROTS'] == True # A good file this_conf, validation_results = config.read_mediagoblin_config( @@ -48,7 +48,7 @@ def test_read_mediagoblin_config(): assert this_conf['carrotapp']['encouragement_phrase'] == \ "I'd love it if you eat your carrots!" assert this_conf['carrotapp']['blah_blah'] == "blah!" - assert this_conf['celery']['eat_celery_with_carrots'] == False + assert this_conf['celery']['EAT_CELERY_WITH_CARROTS'] == False # A bad file this_conf, validation_results = config.read_mediagoblin_config( @@ -61,7 +61,7 @@ def test_read_mediagoblin_config(): assert this_conf['carrotapp']['encouragement_phrase'] == \ "586956856856" assert this_conf['carrotapp']['blah_blah'] == "blah!" - assert this_conf['celery']['eat_celery_with_carrots'] == "pants" + assert this_conf['celery']['EAT_CELERY_WITH_CARROTS'] == "pants" def test_generate_validation_report(): @@ -89,7 +89,7 @@ There were validation problems loading this config file: expected_warnings = [ 'carrotapp:carrotcake = the value "slobber" is of the wrong type.', 'carrotapp:num_carrots = the value "GROSS" is of the wrong type.', - 'celery:eat_celery_with_carrots = the value "pants" is of the wrong type.'] + 'celery:EAT_CELERY_WITH_CARROTS = the value "pants" is of the wrong type.'] warnings = report.splitlines()[2:] assert len(warnings) == 3 diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index c91ed92b..01bf0972 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -26,4 +26,4 @@ data_dir = %(here)s/test_user_dev/beaker/cache/data lock_dir = %(here)s/test_user_dev/beaker/cache/lock [celery] -celery_always_eager = true +CELERY_ALWAYS_EAGER = true diff --git a/mediagoblin/tests/test_paste.ini b/mediagoblin/tests/test_paste.ini index bd57994b..d7c18642 100644 --- a/mediagoblin/tests/test_paste.ini +++ b/mediagoblin/tests/test_paste.ini @@ -29,7 +29,7 @@ beaker.session.data_dir = %(here)s/test_user_dev/beaker/sessions/data beaker.session.lock_dir = %(here)s/test_user_dev/beaker/sessions/lock [celery] -celery_always_eager = true +CELERY_ALWAYS_EAGER = true [server:main] use = egg:Paste#http -- cgit v1.2.3 From 3502958113c09c80830b7bee63c3d82b5ff72eb9 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 25 Feb 2012 23:53:11 +0100 Subject: Attachment support in the SQL backend attachments working with the sql backend. - SQL Schema for attachment files, ordering attachments by their name, not by the submission order (as earlier). - Dot-Notation for attachments, where missing. - convert existing attachments over from mongo -> sql --- mediagoblin/db/sql/convert.py | 11 ++++++++++- mediagoblin/db/sql/models.py | 27 ++++++++++++++++++++++++++- mediagoblin/edit/views.py | 2 +- mediagoblin/tools/files.py | 2 +- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/mediagoblin/db/sql/convert.py b/mediagoblin/db/sql/convert.py index 403025dc..79717913 100644 --- a/mediagoblin/db/sql/convert.py +++ b/mediagoblin/db/sql/convert.py @@ -19,7 +19,7 @@ from mediagoblin.init import setup_global_and_app_config, setup_database from mediagoblin.db.mongo.util import ObjectId from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment, - Tag, MediaTag, MediaFile) + Tag, MediaTag, MediaFile, MediaAttachmentFile) from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \ sql_connect from mediagoblin.db.mongo.open import setup_connection_and_db_from_config as \ @@ -92,6 +92,15 @@ def convert_media_entries(mk_db): new_file.media_entry = new_entry.id Session.add(new_file) + for attachment in entry.attachment_files: + new_attach = MediaAttachmentFile( + name=attachment["name"], + filepath=attachment["filepath"], + created=attachment["created"] + ) + new_attach.media_entry = new_entry.id + Session.add(new_attach) + session.commit() session.close() diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 699dbf33..b52eac76 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -118,6 +118,15 @@ class MediaEntry(Base, MediaEntryMixin): creator=lambda k, v: MediaFile(name=k, file_path=v) ) + attachment_files_helper = relationship("MediaAttachmentFile", + cascade="all, delete-orphan", + order_by="MediaAttachmentFile.created" + ) + attachment_files = association_proxy("attachment_files_helper", "dict_view", + creator=lambda v: MediaAttachmentFile( + name=v["name"], filepath=v["filepath"]) + ) + tags_helper = relationship("MediaTag", cascade="all, delete-orphan" ) @@ -127,7 +136,6 @@ class MediaEntry(Base, MediaEntryMixin): ## TODO # media_data - # attachment_files # fail_error _id = SimpleFieldAlias("id") @@ -177,6 +185,23 @@ class MediaFile(Base): return "" % (self.name, self.file_path) +class MediaAttachmentFile(Base): + __tablename__ = "core__attachment_files" + + id = Column(Integer, primary_key=True) + media_entry = Column( + Integer, ForeignKey(MediaEntry.id), + nullable=False) + name = Column(Unicode, nullable=False) + filepath = Column(PathTupleWithSlashes) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + + @property + def dict_view(self): + """A dict like view on this object""" + return DictReadAttrProxy(self) + + class Tag(Base): __tablename__ = "tags" diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 3df36e8e..d21ef03a 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -120,7 +120,7 @@ def edit_attachments(request, media): finally: request.POST['attachment_file'].file.close() - media['attachment_files'].append(dict( + media.attachment_files.append(dict( name=request.POST['attachment_name'] \ or request.POST['attachment_file'].filename, filepath=attachment_public_filepath, diff --git a/mediagoblin/tools/files.py b/mediagoblin/tools/files.py index b2f316b2..25c1a6e6 100644 --- a/mediagoblin/tools/files.py +++ b/mediagoblin/tools/files.py @@ -27,6 +27,6 @@ def delete_media_files(media): mg_globals.public_store.delete_file( listpath) - for attachment in media['attachment_files']: + for attachment in media.attachment_files: mg_globals.public_store.delete_file( attachment['filepath']) -- cgit v1.2.3 From 2bc8ff0d63188f2168553d39ebf8756ae83053e1 Mon Sep 17 00:00:00 2001 From: Elrond Date: Sat, 28 Jan 2012 13:10:01 +0100 Subject: Cleanup Session after each request. It's good practice to cleanup the SQL session after each request so that the next request gets a fresh one. It's an application decision whether one wants a just-in-case ROLLBACK or COMMIT. There are two ideas behind it, really. I have decided for ROLLBACK. The idea is "if you forget to commit your changes yourself, there's something broken. Maybe you got an exception?". --- mediagoblin/app.py | 8 ++++++++ mediagoblin/db/sql/open.py | 1 + 2 files changed, 9 insertions(+) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 15327d39..0a57c091 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -184,6 +184,14 @@ class MediaGoblinApp(object): for m in self.meddleware[::-1]: m.process_response(request, response) + # Reset the sql session, so that the next request + # gets a fresh session + try: + self.db.reset_after_request() + except TypeError: + # We're still on mongo + pass + return response(environ, start_response) diff --git a/mediagoblin/db/sql/open.py b/mediagoblin/db/sql/open.py index 1bfc5538..a8677bcb 100644 --- a/mediagoblin/db/sql/open.py +++ b/mediagoblin/db/sql/open.py @@ -36,6 +36,7 @@ class DatabaseMaster(object): Session.flush() def reset_after_request(self): + Session.rollback() Session.remove() -- cgit v1.2.3 From 10085b77391c0ca0b33a6ba82ca46da1babbea8f Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 28 Feb 2012 21:59:38 +0100 Subject: Audio thumbnailing & spectrograms, media plugins use sniffing * Added extlib/freesound/audioprocessing.py * config_spec * Added create_spectrogram setting * Added media:medium and media:thumb max_{width,height} settings * Added sniffing logic to - audio.processing:sniff_handler - video.processing:sniff_handler * Changed audio.processing:sniff_handler logic * Added audio thumbnailing functionality to audio.processing (works only with create_spectrogram enabled) * Refractored contexts in audio.processing * Added audio.transcoders:AudioThumbnailer Used for creating spectrograms and spectrogram thumbnails - Wadsworth's Constant, we meet again :) * audio.transcoders:AudioTranscoder - Added mux_string kwarg - Delete self.pipeline on self.halt() * Changed str.format formatting in image.processing:sniff_handler Had {1} without an {0}, changed to {0} * Refractored VideoTranscoder to use transcode() for transcoding instead of __init__() * Added discover() method to video.transcoders:VideoTranscoder * Added spectrogram display to media_displays/audio.html * Updated test_submission to reflect changes in media plugin delegation --- extlib/freesound/audioprocessing.py | 616 +++++++++++++++++++++ mediagoblin/config_spec.ini | 9 + mediagoblin/media_types/ascii/processing.py | 9 + mediagoblin/media_types/audio/audioprocessing.py | 1 + mediagoblin/media_types/audio/processing.py | 65 ++- mediagoblin/media_types/audio/transcoders.py | 90 ++- mediagoblin/media_types/image/processing.py | 2 +- mediagoblin/media_types/video/processing.py | 15 +- mediagoblin/media_types/video/transcoders.py | 53 +- .../mediagoblin/media_displays/audio.html | 9 +- mediagoblin/tests/test_submission.py | 3 +- 11 files changed, 844 insertions(+), 28 deletions(-) create mode 100644 extlib/freesound/audioprocessing.py create mode 120000 mediagoblin/media_types/audio/audioprocessing.py diff --git a/extlib/freesound/audioprocessing.py b/extlib/freesound/audioprocessing.py new file mode 100644 index 00000000..2c2b35b5 --- /dev/null +++ b/extlib/freesound/audioprocessing.py @@ -0,0 +1,616 @@ +#!/usr/bin/env python +# processing.py -- various audio processing functions +# Copyright (C) 2008 MUSIC TECHNOLOGY GROUP (MTG) +# UNIVERSITAT POMPEU FABRA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Authors: +# Bram de Jong +# 2012, Joar Wandborg + +from PIL import Image, ImageDraw, ImageColor #@UnresolvedImport +from functools import partial +import math +import numpy +import os +import re +import signal + + +def get_sound_type(input_filename): + sound_type = os.path.splitext(input_filename.lower())[1].strip(".") + + if sound_type == "fla": + sound_type = "flac" + elif sound_type == "aif": + sound_type = "aiff" + + return sound_type + + +try: + import scikits.audiolab as audiolab +except ImportError: + print "WARNING: audiolab is not installed so wav2png will not work" +import subprocess + +class AudioProcessingException(Exception): + pass + +class TestAudioFile(object): + """A class that mimics audiolab.sndfile but generates noise instead of reading + a wave file. Additionally it can be told to have a "broken" header and thus crashing + in the middle of the file. Also useful for testing ultra-short files of 20 samples.""" + def __init__(self, num_frames, has_broken_header=False): + self.seekpoint = 0 + self.nframes = num_frames + self.samplerate = 44100 + self.channels = 1 + self.has_broken_header = has_broken_header + + def seek(self, seekpoint): + self.seekpoint = seekpoint + + def read_frames(self, frames_to_read): + if self.has_broken_header and self.seekpoint + frames_to_read > self.num_frames / 2: + raise RuntimeError() + + num_frames_left = self.num_frames - self.seekpoint + will_read = num_frames_left if num_frames_left < frames_to_read else frames_to_read + self.seekpoint += will_read + return numpy.random.random(will_read)*2 - 1 + + +def get_max_level(filename): + max_value = 0 + buffer_size = 4096 + audio_file = audiolab.Sndfile(filename, 'r') + n_samples_left = audio_file.nframes + + while n_samples_left: + to_read = min(buffer_size, n_samples_left) + + try: + samples = audio_file.read_frames(to_read) + except RuntimeError: + # this can happen with a broken header + break + + # convert to mono by selecting left channel only + if audio_file.channels > 1: + samples = samples[:,0] + + max_value = max(max_value, numpy.abs(samples).max()) + + n_samples_left -= to_read + + audio_file.close() + + return max_value + +class AudioProcessor(object): + """ + The audio processor processes chunks of audio an calculates the spectrac centroid and the peak + samples in that chunk of audio. + """ + def __init__(self, input_filename, fft_size, window_function=numpy.hanning): + max_level = get_max_level(input_filename) + + self.audio_file = audiolab.Sndfile(input_filename, 'r') + self.fft_size = fft_size + self.window = window_function(self.fft_size) + self.spectrum_range = None + self.lower = 100 + self.higher = 22050 + self.lower_log = math.log10(self.lower) + self.higher_log = math.log10(self.higher) + self.clip = lambda val, low, high: min(high, max(low, val)) + + # figure out what the maximum value is for an FFT doing the FFT of a DC signal + fft = numpy.fft.rfft(numpy.ones(fft_size) * self.window) + max_fft = (numpy.abs(fft)).max() + # set the scale to normalized audio and normalized FFT + self.scale = 1.0/max_level/max_fft if max_level > 0 else 1 + + def read(self, start, size, resize_if_less=False): + """ read size samples starting at start, if resize_if_less is True and less than size + samples are read, resize the array to size and fill with zeros """ + + # number of zeros to add to start and end of the buffer + add_to_start = 0 + add_to_end = 0 + + if start < 0: + # the first FFT window starts centered around zero + if size + start <= 0: + return numpy.zeros(size) if resize_if_less else numpy.array([]) + else: + self.audio_file.seek(0) + + add_to_start = -start # remember: start is negative! + to_read = size + start + + if to_read > self.audio_file.nframes: + add_to_end = to_read - self.audio_file.nframes + to_read = self.audio_file.nframes + else: + self.audio_file.seek(start) + + to_read = size + if start + to_read >= self.audio_file.nframes: + to_read = self.audio_file.nframes - start + add_to_end = size - to_read + + try: + samples = self.audio_file.read_frames(to_read) + except RuntimeError: + # this can happen for wave files with broken headers... + return numpy.zeros(size) if resize_if_less else numpy.zeros(2) + + # convert to mono by selecting left channel only + if self.audio_file.channels > 1: + samples = samples[:,0] + + if resize_if_less and (add_to_start > 0 or add_to_end > 0): + if add_to_start > 0: + samples = numpy.concatenate((numpy.zeros(add_to_start), samples), axis=1) + + if add_to_end > 0: + samples = numpy.resize(samples, size) + samples[size - add_to_end:] = 0 + + return samples + + + def spectral_centroid(self, seek_point, spec_range=110.0): + """ starting at seek_point read fft_size samples, and calculate the spectral centroid """ + + samples = self.read(seek_point - self.fft_size/2, self.fft_size, True) + + samples *= self.window + fft = numpy.fft.rfft(samples) + spectrum = self.scale * numpy.abs(fft) # normalized abs(FFT) between 0 and 1 + length = numpy.float64(spectrum.shape[0]) + + # scale the db spectrum from [- spec_range db ... 0 db] > [0..1] + db_spectrum = ((20*(numpy.log10(spectrum + 1e-60))).clip(-spec_range, 0.0) + spec_range)/spec_range + + energy = spectrum.sum() + spectral_centroid = 0 + + if energy > 1e-60: + # calculate the spectral centroid + + if self.spectrum_range == None: + self.spectrum_range = numpy.arange(length) + + spectral_centroid = (spectrum * self.spectrum_range).sum() / (energy * (length - 1)) * self.audio_file.samplerate * 0.5 + + # clip > log10 > scale between 0 and 1 + spectral_centroid = (math.log10(self.clip(spectral_centroid, self.lower, self.higher)) - self.lower_log) / (self.higher_log - self.lower_log) + + return (spectral_centroid, db_spectrum) + + + def peaks(self, start_seek, end_seek): + """ read all samples between start_seek and end_seek, then find the minimum and maximum peak + in that range. Returns that pair in the order they were found. So if min was found first, + it returns (min, max) else the other way around. """ + + # larger blocksizes are faster but take more mem... + # Aha, Watson, a clue, a tradeof! + block_size = 4096 + + max_index = -1 + max_value = -1 + min_index = -1 + min_value = 1 + + if start_seek < 0: + start_seek = 0 + + if end_seek > self.audio_file.nframes: + end_seek = self.audio_file.nframes + + if end_seek <= start_seek: + samples = self.read(start_seek, 1) + return (samples[0], samples[0]) + + if block_size > end_seek - start_seek: + block_size = end_seek - start_seek + + for i in range(start_seek, end_seek, block_size): + samples = self.read(i, block_size) + + local_max_index = numpy.argmax(samples) + local_max_value = samples[local_max_index] + + if local_max_value > max_value: + max_value = local_max_value + max_index = local_max_index + + local_min_index = numpy.argmin(samples) + local_min_value = samples[local_min_index] + + if local_min_value < min_value: + min_value = local_min_value + min_index = local_min_index + + return (min_value, max_value) if min_index < max_index else (max_value, min_value) + + +def interpolate_colors(colors, flat=False, num_colors=256): + """ given a list of colors, create a larger list of colors interpolating + the first one. If flatten is True a list of numers will be returned. If + False, a list of (r,g,b) tuples. num_colors is the number of colors wanted + in the final list """ + + palette = [] + + for i in range(num_colors): + index = (i * (len(colors) - 1))/(num_colors - 1.0) + index_int = int(index) + alpha = index - float(index_int) + + if alpha > 0: + r = (1.0 - alpha) * colors[index_int][0] + alpha * colors[index_int + 1][0] + g = (1.0 - alpha) * colors[index_int][1] + alpha * colors[index_int + 1][1] + b = (1.0 - alpha) * colors[index_int][2] + alpha * colors[index_int + 1][2] + else: + r = (1.0 - alpha) * colors[index_int][0] + g = (1.0 - alpha) * colors[index_int][1] + b = (1.0 - alpha) * colors[index_int][2] + + if flat: + palette.extend((int(r), int(g), int(b))) + else: + palette.append((int(r), int(g), int(b))) + + return palette + + +def desaturate(rgb, amount): + """ + desaturate colors by amount + amount == 0, no change + amount == 1, grey + """ + luminosity = sum(rgb) / 3.0 + desat = lambda color: color - amount * (color - luminosity) + + return tuple(map(int, map(desat, rgb))) + + +class WaveformImage(object): + """ + Given peaks and spectral centroids from the AudioProcessor, this class will construct + a wavefile image which can be saved as PNG. + """ + def __init__(self, image_width, image_height, palette=1): + if image_height % 2 == 0: + raise AudioProcessingException, "Height should be uneven: images look much better at uneven height" + + if palette == 1: + background_color = (0,0,0) + colors = [ + (50,0,200), + (0,220,80), + (255,224,0), + (255,70,0), + ] + elif palette == 2: + background_color = (0,0,0) + colors = [self.color_from_value(value/29.0) for value in range(0,30)] + elif palette == 3: + background_color = (213, 217, 221) + colors = map( partial(desaturate, amount=0.7), [ + (50,0,200), + (0,220,80), + (255,224,0), + ]) + elif palette == 4: + background_color = (213, 217, 221) + colors = map( partial(desaturate, amount=0.8), [self.color_from_value(value/29.0) for value in range(0,30)]) + + self.image = Image.new("RGB", (image_width, image_height), background_color) + + self.image_width = image_width + self.image_height = image_height + + self.draw = ImageDraw.Draw(self.image) + self.previous_x, self.previous_y = None, None + + self.color_lookup = interpolate_colors(colors) + self.pix = self.image.load() + + def color_from_value(self, value): + """ given a value between 0 and 1, return an (r,g,b) tuple """ + + return ImageColor.getrgb("hsl(%d,%d%%,%d%%)" % (int( (1.0 - value) * 360 ), 80, 50)) + + def draw_peaks(self, x, peaks, spectral_centroid): + """ draw 2 peaks at x using the spectral_centroid for color """ + + y1 = self.image_height * 0.5 - peaks[0] * (self.image_height - 4) * 0.5 + y2 = self.image_height * 0.5 - peaks[1] * (self.image_height - 4) * 0.5 + + line_color = self.color_lookup[int(spectral_centroid*255.0)] + + if self.previous_y != None: + self.draw.line([self.previous_x, self.previous_y, x, y1, x, y2], line_color) + else: + self.draw.line([x, y1, x, y2], line_color) + + self.previous_x, self.previous_y = x, y2 + + self.draw_anti_aliased_pixels(x, y1, y2, line_color) + + def draw_anti_aliased_pixels(self, x, y1, y2, color): + """ vertical anti-aliasing at y1 and y2 """ + + y_max = max(y1, y2) + y_max_int = int(y_max) + alpha = y_max - y_max_int + + if alpha > 0.0 and alpha < 1.0 and y_max_int + 1 < self.image_height: + current_pix = self.pix[x, y_max_int + 1] + + r = int((1-alpha)*current_pix[0] + alpha*color[0]) + g = int((1-alpha)*current_pix[1] + alpha*color[1]) + b = int((1-alpha)*current_pix[2] + alpha*color[2]) + + self.pix[x, y_max_int + 1] = (r,g,b) + + y_min = min(y1, y2) + y_min_int = int(y_min) + alpha = 1.0 - (y_min - y_min_int) + + if alpha > 0.0 and alpha < 1.0 and y_min_int - 1 >= 0: + current_pix = self.pix[x, y_min_int - 1] + + r = int((1-alpha)*current_pix[0] + alpha*color[0]) + g = int((1-alpha)*current_pix[1] + alpha*color[1]) + b = int((1-alpha)*current_pix[2] + alpha*color[2]) + + self.pix[x, y_min_int - 1] = (r,g,b) + + def save(self, filename): + # draw a zero "zero" line + a = 25 + for x in range(self.image_width): + self.pix[x, self.image_height/2] = tuple(map(lambda p: p+a, self.pix[x, self.image_height/2])) + + self.image.save(filename) + + +class SpectrogramImage(object): + """ + Given spectra from the AudioProcessor, this class will construct a wavefile image which + can be saved as PNG. + """ + def __init__(self, image_width, image_height, fft_size): + self.image_width = image_width + self.image_height = image_height + self.fft_size = fft_size + + self.image = Image.new("RGBA", (image_height, image_width)) + + colors = [ + (0, 0, 0, 0), + (58/4, 68/4, 65/4, 255), + (80/2, 100/2, 153/2, 255), + (90, 180, 100, 255), + (224, 224, 44, 255), + (255, 60, 30, 255), + (255, 255, 255, 255) + ] + self.palette = interpolate_colors(colors) + + # generate the lookup which translates y-coordinate to fft-bin + self.y_to_bin = [] + f_min = 100.0 + f_max = 22050.0 + y_min = math.log10(f_min) + y_max = math.log10(f_max) + for y in range(self.image_height): + freq = math.pow(10.0, y_min + y / (image_height - 1.0) *(y_max - y_min)) + bin = freq / 22050.0 * (self.fft_size/2 + 1) + + if bin < self.fft_size/2: + alpha = bin - int(bin) + + self.y_to_bin.append((int(bin), alpha * 255)) + + # this is a bit strange, but using image.load()[x,y] = ... is + # a lot slower than using image.putadata and then rotating the image + # so we store all the pixels in an array and then create the image when saving + self.pixels = [] + + def draw_spectrum(self, x, spectrum): + # for all frequencies, draw the pixels + for (index, alpha) in self.y_to_bin: + self.pixels.append( self.palette[int((255.0-alpha) * spectrum[index] + alpha * spectrum[index + 1])] ) + + # if the FFT is too small to fill up the image, fill with black to the top + for y in range(len(self.y_to_bin), self.image_height): #@UnusedVariable + self.pixels.append(self.palette[0]) + + def save(self, filename, quality=80): + assert filename.lower().endswith(".jpg") + self.image.putdata(self.pixels) + self.image.transpose(Image.ROTATE_90).save(filename, quality=quality) + + +def create_wave_images(input_filename, output_filename_w, output_filename_s, image_width, image_height, fft_size, progress_callback=None): + """ + Utility function for creating both wavefile and spectrum images from an audio input file. + """ + processor = AudioProcessor(input_filename, fft_size, numpy.hanning) + samples_per_pixel = processor.audio_file.nframes / float(image_width) + + waveform = WaveformImage(image_width, image_height) + spectrogram = SpectrogramImage(image_width, image_height, fft_size) + + for x in range(image_width): + + if progress_callback and x % (image_width/10) == 0: + progress_callback((x*100)/image_width) + + seek_point = int(x * samples_per_pixel) + next_seek_point = int((x + 1) * samples_per_pixel) + + (spectral_centroid, db_spectrum) = processor.spectral_centroid(seek_point) + peaks = processor.peaks(seek_point, next_seek_point) + + waveform.draw_peaks(x, peaks, spectral_centroid) + spectrogram.draw_spectrum(x, db_spectrum) + + if progress_callback: + progress_callback(100) + + waveform.save(output_filename_w) + spectrogram.save(output_filename_s) + + +class NoSpaceLeftException(Exception): + pass + +def convert_to_pcm(input_filename, output_filename): + """ + converts any audio file type to pcm audio + """ + + if not os.path.exists(input_filename): + raise AudioProcessingException, "file %s does not exist" % input_filename + + sound_type = get_sound_type(input_filename) + + if sound_type == "mp3": + cmd = ["lame", "--decode", input_filename, output_filename] + elif sound_type == "ogg": + cmd = ["oggdec", input_filename, "-o", output_filename] + elif sound_type == "flac": + cmd = ["flac", "-f", "-d", "-s", "-o", output_filename, input_filename] + else: + return False + + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = process.communicate() + + if process.returncode != 0 or not os.path.exists(output_filename): + if "No space left on device" in stderr + " " + stdout: + raise NoSpaceLeftException + raise AudioProcessingException, "failed converting to pcm data:\n" + " ".join(cmd) + "\n" + stderr + "\n" + stdout + + return True + + +def stereofy_and_find_info(stereofy_executble_path, input_filename, output_filename): + """ + converts a pcm wave file to two channel, 16 bit integer + """ + + if not os.path.exists(input_filename): + raise AudioProcessingException, "file %s does not exist" % input_filename + + cmd = [stereofy_executble_path, "--input", input_filename, "--output", output_filename] + + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = process.communicate() + + if process.returncode != 0 or not os.path.exists(output_filename): + if "No space left on device" in stderr + " " + stdout: + raise NoSpaceLeftException + raise AudioProcessingException, "failed calling stereofy data:\n" + " ".join(cmd) + "\n" + stderr + "\n" + stdout + + stdout = (stdout + " " + stderr).replace("\n", " ") + + duration = 0 + m = re.match(r".*#duration (?P[\d\.]+).*", stdout) + if m != None: + duration = float(m.group("duration")) + + channels = 0 + m = re.match(r".*#channels (?P\d+).*", stdout) + if m != None: + channels = float(m.group("channels")) + + samplerate = 0 + m = re.match(r".*#samplerate (?P\d+).*", stdout) + if m != None: + samplerate = float(m.group("samplerate")) + + bitdepth = None + m = re.match(r".*#bitdepth (?P\d+).*", stdout) + if m != None: + bitdepth = float(m.group("bitdepth")) + + bitrate = (os.path.getsize(input_filename) * 8.0) / 1024.0 / duration if duration > 0 else 0 + + return dict(duration=duration, channels=channels, samplerate=samplerate, bitrate=bitrate, bitdepth=bitdepth) + + +def convert_to_mp3(input_filename, output_filename, quality=70): + """ + converts the incoming wave file to a mp3 file + """ + + if not os.path.exists(input_filename): + raise AudioProcessingException, "file %s does not exist" % input_filename + + command = ["lame", "--silent", "--abr", str(quality), input_filename, output_filename] + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = process.communicate() + + if process.returncode != 0 or not os.path.exists(output_filename): + raise AudioProcessingException, stdout + +def convert_to_ogg(input_filename, output_filename, quality=1): + """ + converts the incoming wave file to n ogg file + """ + + if not os.path.exists(input_filename): + raise AudioProcessingException, "file %s does not exist" % input_filename + + command = ["oggenc", "-q", str(quality), input_filename, "-o", output_filename] + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = process.communicate() + + if process.returncode != 0 or not os.path.exists(output_filename): + raise AudioProcessingException, stdout + +def convert_using_ffmpeg(input_filename, output_filename): + """ + converts the incoming wave file to stereo pcm using fffmpeg + """ + TIMEOUT = 3 * 60 + def alarm_handler(signum, frame): + raise AudioProcessingException, "timeout while waiting for ffmpeg" + + if not os.path.exists(input_filename): + raise AudioProcessingException, "file %s does not exist" % input_filename + + command = ["ffmpeg", "-y", "-i", input_filename, "-ac","1","-acodec", "pcm_s16le", "-ar", "44100", output_filename] + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + signal.signal(signal.SIGALRM,alarm_handler) + signal.alarm(TIMEOUT) + (stdout, stderr) = process.communicate() + signal.alarm(0) + if process.returncode != 0 or not os.path.exists(output_filename): + raise AudioProcessingException, stdout diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 452d9745..b429677c 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -65,6 +65,14 @@ base_url = string(default="/mgoblin_media/") storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") base_dir = string(default="%(here)s/user_dev/media/queue") +[media:medium] +max_width = integer(default=640) +max_height = integer(default=640) + +[media:thumb] +max_width = integer(default=180) +max_height = integer(default=180) + [media_type:mediagoblin.media_types.video] # Should we keep the original file? keep_original = boolean(default=False) @@ -72,6 +80,7 @@ keep_original = boolean(default=False) [media_type:mediagoblin.media_types.audio] # vorbisenc qualiy quality = float(default=0.3) +create_spectrogram = boolean(default=False) [beaker.cache] diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py index f698b97a..75184c1f 100644 --- a/mediagoblin/media_types/ascii/processing.py +++ b/mediagoblin/media_types/ascii/processing.py @@ -24,7 +24,16 @@ from mediagoblin.media_types.ascii import asciitoimage _log = logging.getLogger(__name__) +SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo'] + def sniff_handler(media_file, **kw): + if not kw.get('media') == None: + name, ext = os.path.splitext(kw['media'].filename) + clean_ext = ext[1:].lower() + + if clean_ext in SUPPORTED_EXTENSIONS: + return True + return False def process_ascii(entry): diff --git a/mediagoblin/media_types/audio/audioprocessing.py b/mediagoblin/media_types/audio/audioprocessing.py new file mode 120000 index 00000000..c5e3c52c --- /dev/null +++ b/mediagoblin/media_types/audio/audioprocessing.py @@ -0,0 +1 @@ +../../../extlib/freesound/audioprocessing.py \ No newline at end of file diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py index 7aa7ace8..6769f605 100644 --- a/mediagoblin/media_types/audio/processing.py +++ b/mediagoblin/media_types/audio/processing.py @@ -21,9 +21,10 @@ import os from mediagoblin import mg_globals as mgg from mediagoblin.processing import create_pub_filepath -from mediagoblin.media_types.audio.transcoders import AudioTranscoder +from mediagoblin.media_types.audio.transcoders import AudioTranscoder, \ + AudioThumbnailer -_log = logging.getLogger() +_log = logging.getLogger(__name__) def sniff_handler(media_file, **kw): transcoder = AudioTranscoder() @@ -33,7 +34,9 @@ def sniff_handler(media_file, **kw): if data.is_audio == True and data.is_video == False: return True except: - return False + pass + + return False def process_audio(entry): audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio'] @@ -51,10 +54,9 @@ def process_audio(entry): original=os.path.splitext( queued_filepath[-1])[0])) - ogg_tmp = tempfile.NamedTemporaryFile() + transcoder = AudioTranscoder() - with ogg_tmp: - transcoder = AudioTranscoder() + with tempfile.NamedTemporaryFile() as ogg_tmp: transcoder.transcode( queued_filename, @@ -72,11 +74,54 @@ def process_audio(entry): entry.media_data['audio'] = { u'length': int(data.audiolength)} - thumbnail_tmp = tempfile.NamedTemporaryFile() - - with thumbnail_tmp: + if audio_config['create_spectrogram']: + spectrogram_filepath = create_pub_filepath( + entry, + '{original}-spectrogram.jpg'.format( + original=os.path.splitext( + queued_filepath[-1])[0])) + + with tempfile.NamedTemporaryFile(suffix='.wav') as wav_tmp: + _log.info('Creating WAV source for spectrogram') + transcoder.transcode( + queued_filename, + wav_tmp.name, + mux_string='wavenc') + + thumbnailer = AudioThumbnailer() + + with tempfile.NamedTemporaryFile(suffix='.jpg') as spectrogram_tmp: + thumbnailer.spectrogram( + wav_tmp.name, + spectrogram_tmp.name, + width=mgg.global_config['media:medium']['max_width']) + + _log.debug('Saving spectrogram...') + mgg.public_store.get_file(spectrogram_filepath, 'wb').write( + spectrogram_tmp.read()) + + entry.media_files['spectrogram'] = spectrogram_filepath + + with tempfile.NamedTemporaryFile(suffix='.jpg') as thumb_tmp: + thumbnailer.thumbnail_spectrogram( + spectrogram_tmp.name, + thumb_tmp.name, + (mgg.global_config['media:thumb']['max_width'], + mgg.global_config['media:thumb']['max_height'])) + + thumb_filepath = create_pub_filepath( + entry, + '{original}-thumbnail.jpg'.format( + original=os.path.splitext( + queued_filepath[-1])[0])) + + mgg.public_store.get_file(thumb_filepath, 'wb').write( + thumb_tmp.read()) + + entry.media_files['thumb'] = thumb_filepath + else: entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] - + mgg.queue_store.delete_file(queued_filepath) entry.save() diff --git a/mediagoblin/media_types/audio/transcoders.py b/mediagoblin/media_types/audio/transcoders.py index c5634964..7649309c 100644 --- a/mediagoblin/media_types/audio/transcoders.py +++ b/mediagoblin/media_types/audio/transcoders.py @@ -16,8 +16,10 @@ import pdb import logging +from PIL import Image from mediagoblin.processing import BadMediaFail +from mediagoblin.media_types.audio import audioprocessing _log = logging.getLogger(__name__) @@ -56,6 +58,73 @@ try: except ImportError: raise Exception('gst/pygst >= 0.10 could not be imported') +import numpy + +class AudioThumbnailer(object): + def __init__(self): + _log.info('Initializing {0}'.format(self.__class__.__name__)) + + def spectrogram(self, src, dst, **kw): + width = kw['width'] + height = int(kw.get('height', float(width) * 0.3)) + fft_size = kw.get('fft_size', 2048) + callback = kw.get('progress_callback') + + processor = audioprocessing.AudioProcessor( + src, + fft_size, + numpy.hanning) + + samples_per_pixel = processor.audio_file.nframes / float(width) + + spectrogram = audioprocessing.SpectrogramImage(width, height, fft_size) + + for x in range(width): + if callback and x % (width / 10) == 0: + callback((x * 100) / width) + + seek_point = int(x * samples_per_pixel) + + (spectral_centroid, db_spectrum) = processor.spectral_centroid( + seek_point) + + spectrogram.draw_spectrum(x, db_spectrum) + + if callback: + callback(100) + + spectrogram.save(dst) + + def thumbnail_spectrogram(self, src, dst, thumb_size): + ''' + Takes a spectrogram and creates a thumbnail from it + ''' + if not (type(thumb_size) == tuple and len(thumb_size) == 2): + raise Exception('size argument should be a tuple(width, height)') + + im = Image.open(src) + + im_w, im_h = [float(i) for i in im.size] + th_w, th_h = [float(i) for i in thumb_size] + + wadsworth_position = im_w * 0.3 + + start_x = max(( + wadsworth_position - (th_w / 2.0), + 0.0)) + + stop_x = start_x + (im_h * (th_w / th_h)) + + th = im.crop(( + int(start_x), 0, + int(stop_x), int(im_h))) + + if th.size[0] > th_w or th.size[1] > th_h: + th.thumbnail(thumb_size, Image.ANTIALIAS) + + th.save(dst) + + class AudioTranscoder(object): def __init__(self): _log.info('Initializing {0}'.format(self.__class__.__name__)) @@ -103,17 +172,21 @@ class AudioTranscoder(object): quality = kw.get('quality', 0.3) + mux_string = kw.get( + 'mux_string', + 'vorbisenc quality={0} ! webmmux'.format(quality)) + # Set up pipeline self.pipeline = gst.parse_launch( 'filesrc location="{src}" ! ' 'decodebin2 ! queue ! audiorate tolerance={tolerance} ! ' 'audioconvert ! audio/x-raw-float,channels=2 ! ' - 'vorbisenc quality={quality} ! webmmux ! ' + '{mux_string} ! ' 'progressreport silent=true ! ' 'filesink location="{dst}"'.format( src=src, tolerance=80000000, - quality=quality, + mux_string=mux_string, dst=dst)) self.bus = self.pipeline.get_bus() @@ -141,6 +214,9 @@ class AudioTranscoder(object): self.halt() def halt(self): + if getattr(self, 'pipeline', False): + self.pipeline.set_state(gst.STATE_NULL) + del self.pipeline _log.info('Quitting MainLoop gracefully...') gobject.idle_add(self._loop.quit) @@ -149,8 +225,12 @@ if __name__ == '__main__': logging.basicConfig() _log.setLevel(logging.INFO) - transcoder = AudioTranscoder() - data = transcoder.discover(sys.argv[1]) - res = transcoder.transcode(*sys.argv[1:3]) + #transcoder = AudioTranscoder() + #data = transcoder.discover(sys.argv[1]) + #res = transcoder.transcode(*sys.argv[1:3]) + + thumbnailer = AudioThumbnailer() + + thumbnailer.spectrogram(*sys.argv[1:], width=640) pdb.set_trace() diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 364a5afa..28cde2aa 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -42,7 +42,7 @@ def sniff_handler(media_file, **kw): _log.info('Found file extension in supported filetypes') return True else: - _log.debug('Media present, extension not found in {1}'.format( + _log.debug('Media present, extension not found in {0}'.format( SUPPORTED_FILETYPES)) else: _log.warning('Need additional information (keyword argument \'media\')' diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 1890ef0c..d2562e3b 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -29,6 +29,18 @@ _log = logging.getLogger(__name__) _log.setLevel(logging.DEBUG) def sniff_handler(media_file, **kw): + transcoder = transcoders.VideoTranscoder() + try: + data = transcoder.discover(media_file.name) + + _log.debug('Discovered: {0}'.format(data.__dict__)) + + if data.is_video == True: + return True + except: + _log.error('Exception caught when trying to discover {0}'.format( + kw.get('media'))) + return False def process_video(entry): @@ -61,7 +73,8 @@ def process_video(entry): with tmp_dst: # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square - transcoder = transcoders.VideoTranscoder(queued_filename, tmp_dst.name) + transcoder = transcoders.VideoTranscoder() + transcoder.transcode(queued_filename, tmp_dst.name) # Push transcoded video to public storage _log.debug('Saving medium...') diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 903bd810..6c2e885e 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -25,8 +25,6 @@ import pdb import urllib _log = logging.getLogger(__name__) -logging.basicConfig() -_log.setLevel(logging.DEBUG) CPU_COUNT = 2 try: @@ -340,10 +338,15 @@ class VideoTranscoder: that it was refined afterwards and therefore is done more correctly. ''' - def __init__(self, src, dst, **kwargs): + def __init__(self): _log.info('Initializing VideoTranscoder...') self.loop = gobject.MainLoop() + + def transcode(self, src, dst, **kwargs): + ''' + Transcode a video file into a 'medium'-sized version. + ''' self.source_path = src self.destination_path = dst @@ -357,6 +360,30 @@ class VideoTranscoder: self._setup() self._run() + def discover(self, src): + ''' + Discover properties about a media file + ''' + _log.info('Discovering {0}'.format(src)) + + self.source_path = src + self._setup_discover(discovered_callback=self.__on_discovered) + + self.discoverer.discover() + + self.loop.run() + + return self._discovered_data + + def __on_discovered(self, data, is_media): + if not is_media: + self.__stop() + raise Exception('Could not discover {0}'.format(self.source_path)) + + self._discovered_data = data + + self.__stop_mainloop() + def _setup(self): self._setup_discover() self._setup_pipeline() @@ -369,12 +396,14 @@ class VideoTranscoder: _log.debug('Initializing MainLoop()') self.loop.run() - def _setup_discover(self): + def _setup_discover(self, **kw): _log.debug('Setting up discoverer') self.discoverer = discoverer.Discoverer(self.source_path) # Connect self.__discovered to the 'discovered' event - self.discoverer.connect('discovered', self.__discovered) + self.discoverer.connect( + 'discovered', + kw.get('discovered_callback', self.__discovered)) def __discovered(self, data, is_media): ''' @@ -614,14 +643,15 @@ class VideoTranscoder: if __name__ == '__main__': os.nice(19) + logging.basicConfig() from optparse import OptionParser parser = OptionParser( - usage='%prog [-v] -a [ video | thumbnail ] SRC DEST') + usage='%prog [-v] -a [ video | thumbnail | discover ] SRC [ DEST ]') parser.add_option('-a', '--action', dest='action', - help='One of "video" or "thumbnail"') + help='One of "video", "discover" or "thumbnail"') parser.add_option('-v', dest='verbose', @@ -645,13 +675,18 @@ if __name__ == '__main__': _log.debug(args) - if not len(args) == 2: + if not len(args) == 2 and not options.action == 'discover': parser.print_help() sys.exit() + transcoder = VideoTranscoder() + if options.action == 'thumbnail': VideoThumbnailer(*args) elif options.action == 'video': def cb(data): print('I\'m a callback!') - transcoder = VideoTranscoder(*args, progress_callback=cb) + transcoder.transcode(*args, progress_callback=cb) + elif options.action == 'discover': + print transcoder.discover(*args).__dict__ + diff --git a/mediagoblin/templates/mediagoblin/media_displays/audio.html b/mediagoblin/templates/mediagoblin/media_displays/audio.html index 802a85c1..f130e323 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/audio.html +++ b/mediagoblin/templates/mediagoblin/media_displays/audio.html @@ -20,7 +20,14 @@ {% block mediagoblin_media %}
    -
    + {% endif %} +