10 Commits

Author SHA1 Message Date
tr4ck3ur b7e2ea559e Latest fix on thumbnail generation 2020-09-29 22:49:30 +02:00
tr4ck3ur e62ff8b5b7 Fixed map to list 2020-09-29 01:14:11 +02:00
tr4ck3ur ce61e2c258 Fixed home page 2020-09-29 00:26:20 +02:00
tr4ck3ur a8399d0646 wsgi for python3 2020-09-28 23:41:02 +02:00
tr4ck3ur 3e22a6a890 Latest fixes for python 3 branch 2020-09-28 23:34:25 +02:00
tr4ck3ur be2441096d Latest Fixes 2020-09-13 12:20:43 +02:00
luna 442d18ab3b Added Images file 2020-09-13 12:18:51 +02:00
tr4ck3ur 2b3e8116d5 Fixing python3 issues 2020-08-08 17:02:12 +02:00
tr4ck3ur 588ce76eee Misc Fixes 2020-08-08 01:17:55 +02:00
tr4ck3ur ad9883ae09 Migration to python 3 2020-07-26 17:38:55 +02:00
65 changed files with 42673 additions and 2320 deletions
+11
View File
@@ -36,3 +36,14 @@ If no error occurs, the webserver should be available on http://localhost:8080/
pserve development.ini pserve development.ini
Enjoy ! Enjoy !
sudo apt install virtualenv git python3-virtualenv imagemagick
sudo mkdir -p /srv/jm2l
cd /srv/jm2l/
cd /srv
sudo chown luna jm2l
cd jm2l/
virtualenv -p python3 .venv_jm2l
-1
View File
@@ -15,7 +15,6 @@ pyramid.debug_notfound = false
pyramid.debug_routematch = false pyramid.debug_routematch = false
pyramid.default_locale_name = en pyramid.default_locale_name = en
pyramid.includes = pyramid.includes =
pyramid_mailer.testing
pyramid_debugtoolbar pyramid_debugtoolbar
pyramid_tm pyramid_tm
pyramid_mako pyramid_mako
+19 -12
View File
@@ -3,10 +3,12 @@ try:
except ImportError: except ImportError:
from cgi import escape from cgi import escape
#from wtforms import widgets # from wtforms import widgets
from wtforms.widgets import HTMLString, html_params from wtforms.widgets import html_params
from wtforms.fields.core import Field from wtforms.fields.core import Field
from wtforms.compat import text_type, izip from wtforms.compat import text_type, izip
from markupsafe import Markup
class MySelect(object): class MySelect(object):
""" """
@@ -19,6 +21,7 @@ class MySelect(object):
call on rendering; this method must yield tuples of call on rendering; this method must yield tuples of
`(value, label, selected)`. `(value, label, selected)`.
""" """
def __init__(self, multiple=False): def __init__(self, multiple=False):
self.multiple = multiple self.multiple = multiple
@@ -34,13 +37,13 @@ class MySelect(object):
elif last_group != group: elif last_group != group:
html.append(self.render_optgroup(last_group, group)) html.append(self.render_optgroup(last_group, group))
html.append(self.render_option(val, label, selected)) html.append(self.render_option(val, label, selected))
last_group=group last_group = group
else: else:
html.append(self.render_option(val, label, selected)) html.append(self.render_option(val, label, selected))
if last_group: if last_group:
html.append(self.render_optgroup(last_group, None)) html.append(self.render_optgroup(last_group, None))
html.append('</select>') html.append('</select>')
return HTMLString(''.join(html)) return Markup(''.join(html))
@classmethod @classmethod
def render_option(cls, value, label, selected, **kwargs): def render_option(cls, value, label, selected, **kwargs):
@@ -51,17 +54,19 @@ class MySelect(object):
options = dict(kwargs, value=value) options = dict(kwargs, value=value)
if selected: if selected:
options['selected'] = True options['selected'] = True
return HTMLString('<option %s>%s</option>' % (html_params(**options), escape(text_type(label), quote=False))) return Markup('<option %s>%s</option>' % (html_params(**options), escape(text_type(label), quote=False)))
@classmethod @classmethod
def render_optgroup(cls, previous_label, label, **kwargs): def render_optgroup(cls, previous_label, label, **kwargs):
options = dict(kwargs) options = dict(kwargs)
if previous_label is None: if previous_label is None:
return HTMLString('<optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False))) return Markup(
'<optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
elif label is None: elif label is None:
return HTMLString('</optgroup>') return Markup('</optgroup>')
else: else:
return HTMLString('</optgroup><optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False))) return Markup(
'</optgroup><optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
class MyOption(object): class MyOption(object):
@@ -71,12 +76,13 @@ class MyOption(object):
This is just a convenience for various custom rendering situations, and an This is just a convenience for various custom rendering situations, and an
option by itself does not constitute an entire field. option by itself does not constitute an entire field.
""" """
def __call__(self, field, **kwargs): def __call__(self, field, **kwargs):
return MySelect.render_option(field._value(), field.label.text, field.checked, **kwargs) return MySelect.render_option(field._value(), field.label.text, field.checked, **kwargs)
class MySelectFieldBase(Field): class MySelectFieldBase(Field):
#option_widget = widgets.Option() # option_widget = widgets.Option()
option_widget = MyOption() option_widget = MyOption()
""" """
@@ -85,6 +91,7 @@ class MySelectFieldBase(Field):
This isn't a field, but an abstract base class for fields which want to This isn't a field, but an abstract base class for fields which want to
provide this functionality. provide this functionality.
""" """
def __init__(self, label=None, validators=None, option_widget=None, **kwargs): def __init__(self, label=None, validators=None, option_widget=None, **kwargs):
super(MySelectFieldBase, self).__init__(label, validators, **kwargs) super(MySelectFieldBase, self).__init__(label, validators, **kwargs)
@@ -114,7 +121,7 @@ class MySelectFieldBase(Field):
class MySelectField(MySelectFieldBase): class MySelectField(MySelectFieldBase):
#widget = widgets.Select() # widget = widgets.Select()
widget = MySelect() widget = MySelect()
def __init__(self, label=None, validators=None, coerce=text_type, choices=None, **kwargs): def __init__(self, label=None, validators=None, coerce=text_type, choices=None, **kwargs):
@@ -128,11 +135,11 @@ class MySelectField(MySelectFieldBase):
# We should consider choiceA as an optgroup label # We should consider choiceA as an optgroup label
group_label = choiceA group_label = choiceA
for value, label in choiceB: for value, label in choiceB:
yield (group_label, value, label, self.coerce(value) == self.data) yield group_label, value, label, self.coerce(value) == self.data
else: else:
value, label = choiceA, choiceB value, label = choiceA, choiceB
# Not an optgroup, let's fallback to classic usage # Not an optgroup, let's fallback to classic usage
yield (None, value, label, self.coerce(value) == self.data) yield None, value, label, self.coerce(value) == self.data
def process_data(self, value): def process_data(self, value):
try: try:
+70 -68
View File
@@ -19,51 +19,53 @@ from pyramid.request import Request
from mako.template import Template from mako.template import Template
from .models import User from .models import User
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
from models import JM2L_Year from .models import JM2L_Year
import logging import logging
def add_renderer_globals(event): def add_renderer_globals(event):
event['mytrip'] = Sejour_helpers(event) event['mytrip'] = Sejour_helpers(event)
event['myorga'] = Orga_helpers(event) event['myorga'] = Orga_helpers(event)
event['SelectedYear'] = CurrentYear event['SelectedYear'] = CurrentYear
event['CurrentYear'] = CurrentYear event['CurrentYear'] = CurrentYear
#@sched.scheduled_job('cron', day_of_week='sun', hour=22, minute=07)
# @sched.scheduled_job('cron', day_of_week='sun', hour=22, minute=7)
def mailer_tasks(config): def mailer_tasks(config):
# Send the Welcome Mail # Send the Welcome Mail
mailer = config.registry['mailer'] contact = DBSession.query(User).filter(User.uid == 1).one()
Contact = DBSession.query(User).filter(User.uid==1).one()
request = Request.blank('/', base_url='http://jm2l.linux-azur.org') request = Request.blank('/', base_url='http://jm2l.linux-azur.org')
request.registry = config.registry request.registry = config.registry
for StaffUser in DBSession.query(User).filter(User.Staff == True): mailer = request.mailer
for staff_user in DBSession.query(User).filter(User.Staff is True):
# Skip mail to contact # Skip mail to contact
if StaffUser==Contact: if staff_user == contact:
continue continue
# Skip those that have no task assigned # Skip those that have no task assigned
if len(filter(lambda k:not k.closed, StaffUser.task_assoc))==0: if len(filter(lambda k: not k.closed, staff_user.task_assoc)) == 0:
continue continue
# Prepare Plain Text Message : # Prepare Plain Text Message :
Mail_template = Template(filename='jm2l/templates/mail_plain.mako') mail_template = Template(filename='jm2l/templates/mail_plain.mako')
mail_plain = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks") mail_plain = mail_template.render(request=request, User=staff_user, Contact=contact, action="Tasks")
# Prepare HTML Message : # Prepare HTML Message :
Mail_template = Template(filename='jm2l/templates/mail_html.mako') mail_template = Template(filename='jm2l/templates/mail_html.mako')
mail_html = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks") mail_html = mail_template.render(request=request, User=staff_user, Contact=contact, action="Tasks")
# Prepare Message # Prepare Message
message = Message(subject="[JM2L] Le mail de rappel pour les JM2L !", message = Message(subject="[JM2L] Le mail de rappel pour les JM2L !",
sender="contact@jm2l.linux-azur.org", sender="contact@jm2l.linux-azur.org",
recipients=[StaffUser.mail], recipients=[staff_user.mail],
body=mail_plain, html=mail_html) body=mail_plain, html=mail_html)
message.add_bcc("spam@style-python.fr") message.add_bcc("spam@style-python.fr")
mailer.send_immediately(message) mailer.send_immediately(message)
def main(global_config, **settings): def main(global_config, **settings):
""" This function returns a Pyramid WSGI application. """ This function returns a Pyramid WSGI application.
""" """
#locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8") # locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8")
locale.setlocale(locale.LC_ALL, "fr_FR.utf8") locale.setlocale(locale.LC_ALL, "fr_FR.utf8")
engine = engine_from_config(settings, 'sqlalchemy.') engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine) DBSession.configure(bind=engine)
@@ -72,19 +74,21 @@ def main(global_config, **settings):
AuthTktPasswd = settings.get('secret_AuthTkt', 'itsthesecondseekreet') AuthTktPasswd = settings.get('secret_AuthTkt', 'itsthesecondseekreet')
my_session_factory = SignedCookieSessionFactory(CookiesPasswd) my_session_factory = SignedCookieSessionFactory(CookiesPasswd)
authentication_policy = AuthTktAuthenticationPolicy(AuthTktPasswd, authentication_policy = AuthTktAuthenticationPolicy(AuthTktPasswd,
callback=groupfinder, hashalg='sha512', debug=True) callback=groupfinder, hashalg='sha512', debug=True)
authorization_policy = ACLAuthorizationPolicy() authorization_policy = ACLAuthorizationPolicy()
config = Configurator(settings=settings, config = Configurator(settings=settings,
root_factory='.security.RootFactory', root_factory='.security.RootFactory',
authentication_policy=authentication_policy, authentication_policy=authentication_policy,
authorization_policy=authorization_policy authorization_policy=authorization_policy
) )
config.include('pyramid_mailer')
config.add_subscriber(add_renderer_globals, BeforeRender) config.add_subscriber(add_renderer_globals, BeforeRender)
config.registry['mailer'] = mailer_factory_from_settings(settings) print(settings)
# config.registry['mailer'] = mailer_factory_from_settings(settings)
config.registry['event_date'] = JM2L_Year.get_latest_jm2l_startdate() config.registry['event_date'] = JM2L_Year.get_latest_jm2l_startdate()
sched = BackgroundScheduler() sched = BackgroundScheduler()
sched.add_job(mailer_tasks, 'cron', day_of_week='fri', hour=18, args=[ config ]) sched.add_job(mailer_tasks, 'cron', day_of_week='fri', hour=18, args=[config])
sched.start() # start the scheduler sched.start() # start the scheduler
config.add_renderer('json', JSON(indent=4)) config.add_renderer('json', JSON(indent=4))
config.add_renderer('jsonp', JSONP(param_name='callback')) config.add_renderer('jsonp', JSONP(param_name='callback'))
config.set_session_factory(my_session_factory) config.set_session_factory(my_session_factory)
@@ -100,85 +104,85 @@ def main(global_config, **settings):
config.add_static_view('resources', 'resources', cache_max_age=3600) config.add_static_view('resources', 'resources', cache_max_age=3600)
# ICal Routes # ICal Routes
config.add_route('progr_iCal', '/{year:\d+}/JM2L.ics') config.add_route('progr_iCal', r'/{year:\d+}/JM2L.ics')
config.add_route('progr_dyn_iCal', '/{year:\d+}/JM2L_dyn.ics') config.add_route('progr_dyn_iCal', r'/{year:\d+}/JM2L_dyn.ics')
# JSON Routes # JSON Routes
config.add_route('users_json', '/json-users') config.add_route('users_json', '/json-users')
config.add_route('tiers_json', '/json-tiers') config.add_route('tiers_json', '/json-tiers')
config.add_route('progr_json', '/{year:\d+}/le-prog-json') config.add_route('progr_json', r'/{year:\d+}/le-prog-json')
config.add_route('timeline_json', '/{year:\d+}/timeline-json') config.add_route('timeline_json', r'/{year:\d+}/timeline-json')
# Session setting Routes # Session setting Routes
config.add_route('year', '/year/{year:\d+}') config.add_route('year', r'/year/{year:\d+}')
config.add_route('vote_logo', '/vote_logo/{num:\d+}') config.add_route('vote_logo', r'/vote_logo/{num:\d+}')
# HTML Routes - Staff # HTML Routes - Staff
config.add_route('Live', '/Live') config.add_route('Live', '/Live')
config.add_route('list_expenses', '/{year:\d+}/Staff/compta') config.add_route('list_expenses', r'/{year:\d+}/Staff/compta')
config.add_route('list_task', '/{year:\d+}/Staff') config.add_route('list_task', r'/{year:\d+}/Staff')
config.add_route('handle_pole', '/{year:\d+}/Staff/poles{sep:/*}{pole_id:(\d+)?}') config.add_route('handle_pole', r'/{year:\d+}/Staff/poles{sep:/*}{pole_id:(\d+)?}')
config.add_route('handle_task', '/{year:\d+}/Staff/tasks{sep:/*}{task_id:(\d+)?}') config.add_route('handle_task', r'/{year:\d+}/Staff/tasks{sep:/*}{task_id:(\d+)?}')
config.add_route('action_task', '/{year:\d+}/Staff/{action:(\w+)}/{task_id:(\d+)}') config.add_route('action_task', r'/{year:\d+}/Staff/{action:(\w+)}/{task_id:(\d+)}')
config.add_route('action_task_area', '/{year:\d+}/Staff/pole/{action:(\w+)}/{pole_id:(\d+)}') config.add_route('action_task_area', r'/{year:\d+}/Staff/pole/{action:(\w+)}/{pole_id:(\d+)}')
config.add_route('list_salles', '/ListSalles') config.add_route('list_salles', '/ListSalles')
config.add_route('list_salles_phy', '/ListSallesPhy') config.add_route('list_salles_phy', '/ListSallesPhy')
config.add_route('handle_salle', '/Salles{sep:/*}{salle_id:(\d+)?}') config.add_route('handle_salle', r'/Salles{sep:/*}{salle_id:(\d+)?}')
config.add_route('handle_salle_phy', '/PhySalles{sep:/*}{salle_id:(\d+)?}') config.add_route('handle_salle_phy', r'/PhySalles{sep:/*}{salle_id:(\d+)?}')
config.add_route('action_salle', '/Salles/{action:(\w+)}/{salle_id:(\d+)}') config.add_route('action_salle', r'/Salles/{action:(\w+)}/{salle_id:(\d+)}')
config.add_route('pict_salle', '/salle_picture/{salle_id:(\d+)}') config.add_route('pict_salle', r'/salle_picture/{salle_id:(\d+)}')
config.add_route('list_users', '/{year:\d+}/ListParticipant') config.add_route('list_users', r'/{year:\d+}/ListParticipant')
config.add_route('list_users_csv', '/{year:\d+}/ListParticipant.csv') config.add_route('list_users_csv', r'/{year:\d+}/ListParticipant.csv')
config.add_route('list_orga', '/{year:\d+}/ListOrga') config.add_route('list_orga', r'/{year:\d+}/ListOrga')
# HTML Routes - Public # HTML Routes - Public
config.add_route('home', '/{year:(\d+/)?}') config.add_route('home', r'/{year:(\d+/)?}')
config.add_route('edit_index', '/{year:\d+}/edit') config.add_route('edit_index', r'/{year:\d+}/edit')
config.add_route('presse', '/{year:\d+}/dossier-de-presse') config.add_route('presse', r'/{year:\d+}/dossier-de-presse')
config.add_route('edit_presse', '/{year:\d+}/dossier-de-presse/edit') config.add_route('edit_presse', r'/{year:\d+}/dossier-de-presse/edit')
config.add_route('programme', '/{year:\d+}/le-programme') config.add_route('programme', r'/{year:\d+}/le-programme')
config.add_route('plan', 'nous-rejoindre') config.add_route('plan', 'nous-rejoindre')
config.add_route('participer', 'participer-l-evenement') config.add_route('participer', 'participer-l-evenement')
config.add_route('captcha', '/captcha') config.add_route('captcha', '/captcha')
## Events ## Events
config.add_route('event', '/event/{year:\d+}/{event_id:([\w-]+)?}') config.add_route('event', r'/event/{year:\d+}/{event_id:([\w-]+)?}')
config.add_route('link_event_user', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/link_user') config.add_route('link_event_user', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/link_user')
config.add_route('delete_link_u', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/delete_link_user') config.add_route('delete_link_u', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/delete_link_user')
config.add_route('link_event_tiers', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/link_tiers') config.add_route('link_event_tiers', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/link_tiers')
config.add_route('delete_link_t', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/delete_link_tiers') config.add_route('delete_link_t', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}/delete_link_tiers')
config.add_route('edit_event', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}') config.add_route('edit_event', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}')
config.add_route('delete_event', '/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}/delete') config.add_route('delete_event', r'/MesJM2L/{year:\d+}/{intervention:[\s\w]+}{sep:/*}{event_id:([\w-]+)?}/delete')
## Entities # Entities
config.add_route('entities', '/entities') #{sep:/*}{Nature:\w+?}') config.add_route('entities', '/entities') # {sep:/*}{Nature:\w+?}')
config.add_route('add_entity', '/entity') config.add_route('add_entity', '/entity')
config.add_route('delete_entity', '/entity/{entity_id:(\d+)}/delete') config.add_route('delete_entity', r'/entity/{entity_id:(\d+)}/delete')
config.add_route('show_entity', '/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)?}') config.add_route('show_entity', r'/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)?}')
config.add_route('edit_entity', '/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)}/edit') config.add_route('edit_entity', r'/entity/{tiers_type:(\w+)}/{entity_id:([\w-]+)}/edit')
config.add_route('edit_entity_cat', '/categorie/entity') config.add_route('edit_entity_cat', '/categorie/entity')
## Users # Users
config.add_route('pict_user', '/user_picture') config.add_route('pict_user', '/user_picture')
config.add_route('show_user', '/user/{user_slug:([\w-]+)?}') config.add_route('show_user', r'/user/{user_slug:([\w-]+)?}')
config.add_route('badge_user', '/user/{user_slug:([\w-]+)?}/badge') config.add_route('badge_user', r'/user/{user_slug:([\w-]+)?}/badge')
config.add_route('all_badges', '/badges') config.add_route('all_badges', '/badges')
config.add_route('place_print', '/place_print') config.add_route('place_print', '/place_print')
config.add_route('stand_print', '/stand_print') config.add_route('stand_print', '/stand_print')
# HTML Routes - Logged # HTML Routes - Logged
#config.add_route('profil', 'MesJM2L') # config.add_route('profil', 'MesJM2L')
config.add_route('jm2l', '/MesJM2L') config.add_route('jm2l', '/MesJM2L')
config.add_route('drop_sejour', '/DropSejour') config.add_route('drop_sejour', '/DropSejour')
config.add_route('miam', '/MonMiam') config.add_route('miam', '/MonMiam')
config.add_route('sejour', '/MonSejour') config.add_route('sejour', '/MonSejour')
config.add_route('orga', '/MonOrga') config.add_route('orga', '/MonOrga')
config.add_route('modal', '/{year:\d+}/modal/{modtype:\w+}/{id:(\d+)}') config.add_route('modal', r'/{year:\d+}/modal/{modtype:\w+}/{id:(\d+)}')
# Handle exchanges # Handle exchanges
config.add_route('exchange', '/{year:\d+}/exchange/{modtype:\w+}/{id:(\d+)}/{action:\w+}') config.add_route('exchange', r'/{year:\d+}/exchange/{modtype:\w+}/{id:(\d+)}/{action:\w+}')
# Handle authentication # Handle authentication
config.add_route('register', '/register') config.add_route('register', '/register')
@@ -186,10 +190,8 @@ def main(global_config, **settings):
config.add_route('bymail', '/sign/jm2l/{hash}') config.add_route('bymail', '/sign/jm2l/{hash}')
# Handle Multimedia and Uploads # Handle Multimedia and Uploads
config.add_route('media_view', '/image/{media_table:\w+}/{uid:\d+}/{name:.+}') config.add_route('media_view', r'/image/{media_table:\w+}/{uid:\d+}/{name:.+}')
config.add_route('media_upload', '/uploader/{media_table:\w+}/{uid:\d+}/proceed{sep:/*}{name:.*}') config.add_route('media_upload', r'/uploader/{media_table:\w+}/{uid:\d+}/proceed{sep:/*}{name:.*}')
config.scan() config.scan()
return config.make_wsgi_app() return config.make_wsgi_app()
+4 -2
View File
@@ -8,14 +8,16 @@ from pyramid_mailer import get_mailer
from pyramid_mailer.message import Attachment, Message from pyramid_mailer.message import Attachment, Message
from .forms import UserPasswordForm from .forms import UserPasswordForm
from passlib.hash import argon2 from passlib.hash import argon2
from security import check_logged from .security import check_logged
import datetime import datetime
import re import re
@view_config(route_name='auth', match_param="action=login", renderer="jm2l:templates/login.mako") @view_config(route_name='auth', match_param="action=login", renderer="jm2l:templates/login.mako")
def login(request): def login(request):
return {"comefrom":request.GET.get('from', "")} return {"comefrom":request.GET.get('from', "")}
@view_config(route_name='auth', match_param="action=forgot", renderer="jm2l:templates/login.mako") @view_config(route_name='auth', match_param="action=forgot", renderer="jm2l:templates/login.mako")
def forgot(request): def forgot(request):
if request.method == 'POST' and request.POST: if request.method == 'POST' and request.POST:
@@ -31,7 +33,7 @@ def forgot(request):
return { 'forgot': True } return { 'forgot': True }
else: else:
# Send the Forgot Mail # Send the Forgot Mail
mailer = request.registry['mailer'] mailer = request.mailer
# Prepare Plain Text Message : # Prepare Plain Text Message :
Mail_template = Template(filename='jm2l/templates/mail_plain.mako') Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
mail_plain = Mail_template.render(request=request, User=UserFound, action="Forgot") mail_plain = Mail_template.render(request=request, User=UserFound, action="Forgot")
+142 -129
View File
@@ -1,7 +1,12 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden from pyramid.httpexceptions import HTTPNotFound, HTTPForbidden
from pyramid.response import Response from pyramid.response import Response
import cStringIO as StringIO
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import io
from pyramid.view import view_config from pyramid.view import view_config
from .models import DBSession, User from .models import DBSession, User
from reportlab.pdfgen import canvas from reportlab.pdfgen import canvas
@@ -12,78 +17,86 @@ import qrcode
import subprocess import subprocess
from .upload import MediaPath from .upload import MediaPath
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
# Create PDF container # Create PDF container
EXPIRATION_TIME = 300 # seconds EXPIRATION_TIME = 300 # seconds
WIDTH = 85 * mm WIDTH = 85 * mm
HEIGHT = 60 * mm HEIGHT = 60 * mm
ICONSIZE = 10 * mm ICONSIZE = 10 * mm
def JM2L_Logo(canvas, Offset=(0,0)):
OffX, OffY = Offset
logoobject = canvas.beginText()
logoobject.setFont('Logo', 32)
logoobject.setFillColorRGB(.83,0,.33)
logoobject.setTextOrigin(OffX+5, OffY+17)
logoobject.textLines("JM2L")
canvas.drawText(logoobject)
yearobject = canvas.beginText() def JM2L_Logo(canvas, Offset=(0, 0)):
yearobject.setFont("Helvetica-Bold", 10) off_x, off_y = Offset
yearobject.setFillColorRGB(1,1,1) logo_object = canvas.beginText()
yearobject.setTextRenderMode(0) logo_object.setFont('Logo', 32)
yearobject.setTextOrigin(OffX+12 , OffY+35) logo_object.setFillColorRGB(.83, 0, .33)
yearobject.setWordSpace(13) logo_object.setTextOrigin(off_x + 5, off_y + 17)
yearobject.textLines(" ".join(str(CurrentYear))) logo_object.textLines("JM2L")
canvas.drawText(yearobject) canvas.drawText(logo_object)
def Tiers_Logo(canvas, DispUser, StartPos=None, Offset=(0,0)): year_object = canvas.beginText()
Border = 0 year_object.setFont("Helvetica-Bold", 10)
OffX, OffY = Offset year_object.setFillColorRGB(1, 1, 1)
if StartPos is None: year_object.setTextRenderMode(0)
StartPos = ( 30 * mm, 2 ) year_object.setTextOrigin(off_x + 12, off_y + 35)
StartX, StartY = StartPos year_object.setWordSpace(13)
MaxX, MaxY = 34*mm, 18*mm year_object.textLines(" ".join(str(CurrentYear)))
canvas.drawText(year_object)
def Tiers_Logo(canvas, DispUser, start_pos=None, Offset=(0, 0)):
border = 0
off_x, off_y = Offset
if start_pos is None:
start_pos = (30 * mm, 2)
start_x, start_y = start_pos
max_x, max_y = 34 * mm, 18 * mm
num = 0 num = 0
canvas.setStrokeColorRGB(0.5,0.5,0.5) canvas.setStrokeColorRGB(0.5, 0.5, 0.5)
Logos = filter(lambda x:x.ThumbLinks, DispUser.tiers)[:3] list_logos = list()
for thumb in DispUser.tiers:
if thumb.ThumbLinks:
list_logos.append(thumb.ThumbLinks[:3])
# list_logos = list(filter(lambda x: x.ThumbLinks, DispUser.tiers)[:3])
# Should We compute a better positionning for logos ? # Should We compute a better positionning for logos ?
DicPos = {} DicPos = {}
DicPos[1] = { 0:(1./2, 1./2) } DicPos[1] = {0: (1. / 2, 1. / 2)}
DicPos[2] = { 0:(1./3, 1./2), 1:(2./3, 1./2) } DicPos[2] = {0: (1. / 3, 1. / 2), 1: (2. / 3, 1. / 2)}
DicPos[3] = { 0:(1./2, 1./4), 1:(1./3, 3./4), 2:(2./3, 3./4) } DicPos[3] = {0: (1. / 2, 1. / 4), 1: (1. / 3, 3. / 4), 2: (2. / 3, 3. / 4)}
DicPos[4] = { 0:(1./3, 1./4), 1:(2./3, 1./4), 2:(1./3, 3./4), DicPos[4] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 3, 3. / 4),
3:(2./3, 3./4) } 3: (2. / 3, 3. / 4)}
DicPos[5] = { 0:(1./3, 1./4), 1:(2./3, 1./4), 2:(1./6, 3./4), DicPos[5] = {0: (1. / 3, 1. / 4), 1: (2. / 3, 1. / 4), 2: (1. / 6, 3. / 4),
3:(3./6, 3./4), 4:(5./6, 3./4) } 3: (3. / 6, 3. / 4), 4: (5. / 6, 3. / 4)}
DicPos[6] = { 0:(1./6, 1./4), 1:(3./6, 1./4), 2:(5./6, 1./4), DicPos[6] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
3:(1./6, 3./4), 4:(3./6, 3./4), 5:(5./6, 3./4) } 3: (1. / 6, 3. / 4), 4: (3. / 6, 3. / 4), 5: (5. / 6, 3. / 4)}
DicPos[7] = { 0:(1./6, 1./4), 1:(3./6, 1./4), 2:(5./6, 1./4), DicPos[7] = {0: (1. / 6, 1. / 4), 1: (3. / 6, 1. / 4), 2: (5. / 6, 1. / 4),
3:(1./8, 3./4), 4:(3./8, 3./4), 5:(5./8, 3./4), 3: (1. / 8, 3. / 4), 4: (3. / 8, 3. / 4), 5: (5. / 8, 3. / 4),
6:(7./8, 3./4) } 6: (7. / 8, 3. / 4)}
DicPos[8] = { 0:(1./8, 1./4), 1:(3./8, 1./4), 2:(5./8, 1./4), DicPos[8] = {0: (1. / 8, 1. / 4), 1: (3. / 8, 1. / 4), 2: (5. / 8, 1. / 4),
3:(7./8, 1./4), 4:(1./8, 3./4), 5:(3./8, 3./4), 3: (7. / 8, 1. / 4), 4: (1. / 8, 3. / 4), 5: (3. / 8, 3. / 4),
6:(5./8, 3./4), 7:(7./8, 3./4) } 6: (5. / 8, 3. / 4), 7: (7. / 8, 3. / 4)}
# draw overall border # draw overall border
# canvas.roundRect(StartX, StartY, MaxX, MaxY, radius=2, stroke=True) # canvas.roundRect(start_x, start_y, max_x, max_y, radius=2, stroke=True)
for tiers in Logos: for tiers in list_logos:
FileName = tiers.ThumbLinks.pop().split("/")[-1] file_name = tiers.ThumbLinks.pop().split("/")[-1]
ImagePath = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, FileName) image_path = "jm2l/upload/images/tiers/%s/%s" % (tiers.slug, file_name)
PosX = OffX+StartX + DicPos[len(Logos)][num][0] * MaxX - (ICONSIZE+Border)/2 pos_x = off_x + start_x + DicPos[len(list_logos)][num][0] * max_x - (ICONSIZE + border) / 2
PosY = OffY+StartY + DicPos[len(Logos)][num][1] * MaxY - (ICONSIZE+Border)/2 pos_y = off_y + start_y + DicPos[len(list_logos)][num][1] * max_y - (ICONSIZE + border) / 2
canvas.setLineWidth(.1) canvas.setLineWidth(.1)
if len(Logos)>1: if len(list_logos) > 1:
size = ICONSIZE size = ICONSIZE
else: else:
size = ICONSIZE*1.5 size = ICONSIZE * 1.5
canvas.drawImage(ImagePath, canvas.drawImage(image_path,
PosX, PosY, size, size,\ pos_x, pos_y, size, size,
preserveAspectRatio=True, preserveAspectRatio=True,
anchor='c', anchor='c',
mask='auto' mask='auto'
) )
# draw icon border # draw icon border
# canvas.roundRect(PosX, PosY, ICONSIZE, ICONSIZE, radius=2, stroke=True) # canvas.roundRect(pos_x, pos_y, ICONSIZE, ICONSIZE, radius=2, stroke=True)
num+=1 num += 1
def QRCode(DispUser): def QRCode(DispUser):
qr = qrcode.QRCode( qr = qrcode.QRCode(
@@ -98,78 +111,79 @@ def QRCode(DispUser):
return qr.make_image() return qr.make_image()
def one_badge(c, DispUser, Offset=(0,0)):
def one_badge(c, DispUser, Offset=(0, 0)):
# Logo on Top # Logo on Top
JM2L_Logo(c, Offset) JM2L_Logo(c, Offset)
OffX, OffY = Offset off_x, off_y = Offset
c.rect(OffX-3, OffY-3, WIDTH+6, HEIGHT+6, fill=0, stroke=1) c.rect(off_x - 3, off_y - 3, WIDTH + 6, HEIGHT + 6, fill=0, stroke=1)
if DispUser.Staff: if DispUser.Staff:
# Staff # Staff
c.setFillColorRGB(.83,0,.33) c.setFillColorRGB(.83, 0, .33)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0) c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1) c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30) c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "STAFF") c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "STAFF")
elif DispUser.is_Intervenant: elif DispUser.is_Intervenant:
# Intervenant # Intervenant
c.setFillColorRGB(.21,.67,.78) c.setFillColorRGB(.21, .67, .78)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0) c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1) c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30) c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Intervenant") c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Intervenant")
elif DispUser.is_crew: elif DispUser.is_crew:
# Benevole # Benevole
c.setFillColorRGB(.18,.76,.23) c.setFillColorRGB(.18, .76, .23)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0) c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1) c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30) c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Bénévole") c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Bénévole")
else: else:
# Visiteur # Visiteur
c.setFillColorRGB(.8,.8,.8) c.setFillColorRGB(.8, .8, .8)
c.rect(OffX-3, OffY+HEIGHT-30, WIDTH+6, 33, fill=1, stroke=0) c.rect(off_x - 3, off_y + HEIGHT - 30, WIDTH + 6, 33, fill=1, stroke=0)
c.setFillColorRGB(1,1,1) c.setFillColorRGB(1, 1, 1)
c.setFont('Liberation', 30) c.setFont('Liberation', 30)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT-24, "Visiteur") c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT - 24, "Visiteur")
c.restoreState() c.restoreState()
c.setFont('Liberation', 18) c.setFont('Liberation', 18)
c.setStrokeColorRGB(0,0,0) c.setStrokeColorRGB(0, 0, 0)
c.setFillColorRGB(0,0,0) c.setFillColorRGB(0, 0, 0)
# Feed Name and SurName # Feed Name and SurName
if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom)>18: if DispUser.prenom and DispUser.nom and len(DispUser.prenom) + len(DispUser.nom) > 18:
if DispUser.pseudo: if DispUser.pseudo:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 0 * mm , "%s" % DispUser.prenom ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 0 * mm, "%s" % DispUser.prenom)
#c.setFont('Courier', 17) # c.setFont('Courier', 17)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 - 8 * mm , "%s" % DispUser.nom ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
else: else:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 4 * mm , "%s" % DispUser.prenom ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 4 * mm, "%s" % DispUser.prenom)
#c.setFont('Courier', 17) # c.setFont('Courier', 17)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 - 8 * mm , "%s" % DispUser.nom ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 - 8 * mm, "%s" % DispUser.nom)
else: else:
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 0 * mm , "%s %s" % (DispUser.prenom, DispUser.nom) ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 0 * mm, "%s %s" % (DispUser.prenom, DispUser.nom))
if DispUser.pseudo: if DispUser.pseudo:
c.setFont("Helvetica-Oblique", 18) c.setFont("Helvetica-Oblique", 18)
c.drawCentredString(OffX+WIDTH/2, OffY+HEIGHT/2 + 10 * mm , "%s" % DispUser.pseudo ) c.drawCentredString(off_x + WIDTH / 2, off_y + HEIGHT / 2 + 10 * mm, "%s" % DispUser.pseudo)
# Put QR code to user profile #  Put QR code to user profile
c.drawInlineImage(QRCode(DispUser), \ c.drawInlineImage(QRCode(DispUser),
OffX+WIDTH - 20 * mm -5, OffY+5, \ off_x + WIDTH - 20 * mm - 5, off_y + 5,
20 * mm, 20 * mm, \ 20 * mm, 20 * mm,
preserveAspectRatio=True, \ preserveAspectRatio=True,
anchor='s') anchor='s')
Tiers_Logo(c, DispUser, None, Offset) Tiers_Logo(c, DispUser, None, Offset)
@view_config(route_name='badge_user', http_cache = (EXPIRATION_TIME, {'public':True})) @view_config(route_name='badge_user') # , http_cache=(EXPIRATION_TIME, {'public': True}))
def badge_user(request): def badge_user(request):
isoutpng = request.params.get('png') isoutpng = request.params.get('png')
user_slug = request.matchdict.get('user_slug', None) user_slug = request.matchdict.get('user_slug', None)
if user_slug is None or len(user_slug)==0: if user_slug is None or len(user_slug) == 0:
raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu") raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
# Query database # Query database
DispUser = User.by_slug(user_slug) DispUser = User.by_slug(user_slug)
@@ -179,16 +193,16 @@ def badge_user(request):
# Ok let's generate a PDF Badge # Ok let's generate a PDF Badge
# Register LiberationMono font # Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
# Import font #  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = StringIO.StringIO() pdf = io.BytesIO()
out_img = StringIO.StringIO() out_img = io.BytesIO()
c = canvas.Canvas( pdf, pagesize=(WIDTH, HEIGHT) ) c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
c.translate(mm, mm) c.translate(mm, mm)
# Feed some metadata # Feed some metadata
@@ -198,27 +212,26 @@ def badge_user(request):
c.saveState() c.saveState()
one_badge(c, DispUser) one_badge(c, DispUser)
out_pdf = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf')
c.showPage() c.showPage()
c.save() c.save()
pdf.seek(0) pdf.seek(0)
if isoutpng: if isoutpng:
OutPDF = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.pdf') out_png = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png')
OutPNG = MediaPath().get_mediapath("badge", DispUser.uid, 'badge.png') #  Let's generate a png file for website
# Let's generate a png file for website with open("./%s" % out_pdf, 'wb') as pdff:
with open( OutPDF ,'wb') as pdff:
pdff.write(pdf.read()) pdff.write(pdf.read())
Command = ["convert","-density","150x150", OutPDF, OutPNG] Command = ["convert", "-density", "150x150", out_pdf, out_png]
subprocess.call(Command) subprocess.call(Command)
with open( OutPNG, 'rb') as pngfile: with open("./%s" % out_png, 'rb') as pngfile:
out_img.write(pngfile.read()) out_img.write(pngfile.read()) # pngfile.read(), "utf8"))
out_img.seek(0) out_img.seek(0)
return Response(app_iter=out_img, content_type = 'image/png' ) return Response(app_iter=out_img, content_type='image/png')
else: else:
return Response(app_iter=pdf, content_type = 'application/pdf' ) return Response(app_iter=pdf, content_type='application/pdf')
@view_config(route_name='all_badges') @view_config(route_name='all_badges')
@@ -232,34 +245,34 @@ def planche_badge(request):
# .filter(User_Event.year_uid == year) # .filter(User_Event.year_uid == year)
# Register LiberationMono font # Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
# Import font #  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = StringIO.StringIO() pdf = io.BytesIO()
FULLWIDTH = 210 * mm FULLWIDTH = 210 * mm
FULLHEIGHT = 297 * mm FULLHEIGHT = 297 * mm
c = canvas.Canvas( pdf, pagesize=(FULLWIDTH, FULLHEIGHT) ) c = canvas.Canvas(pdf, pagesize=(FULLWIDTH, FULLHEIGHT))
c.translate(mm, mm) c.translate(mm, mm)
# Feed some metadata # Feed some metadata
c.setCreator("linux-azur.org") c.setCreator("linux-azur.org")
c.setTitle("Badge") c.setTitle("Badge")
t=0 t = 0
ListUser = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users) list_user = filter(lambda x: x.is_Intervenant or x.Staff or x.is_crew, Users)
for num, DispUser in enumerate(ListUser): for num, disp_user in enumerate(list_user):
c.saveState() c.saveState()
Offsets = (((num-t)%2)*(WIDTH+40)+40, ((num-t)/2)*(HEIGHT+25)+40) offsets = (((num - t) % 2) * (WIDTH + 40) + 40, int(((num - t) / 2)) * (HEIGHT + 25) + 40)
one_badge(c, DispUser, Offsets) one_badge(c, disp_user, offsets)
if num%8==7: if num % 8 == 7:
t=num+1 t = num + 1
c.showPage() c.showPage()
c.showPage() c.showPage()
c.save() c.save()
pdf.seek(0) pdf.seek(0)
return Response(app_iter=pdf, content_type = 'application/pdf' ) return Response(app_iter=pdf, content_type='application/pdf')
+52 -47
View File
@@ -3,18 +3,20 @@
import random import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter from PIL import Image, ImageDraw, ImageFont, ImageFilter
import cStringIO as StringIO import io
# from io import StringIO
import math import math
from pyramid.view import view_config from pyramid.view import view_config
from .words import TabMots from .words import TabMots
from pyramid.response import Response from pyramid.response import Response
class Captcha_Img(object): class Captcha_Img(object):
def __init__( self, width, height): def __init__(self, width, height):
self.width = width self.width = width
self.height = height self.height = height
self._layers = [ self._layers = [
_PyCaptcha_SineWarp(amplitudeRange = (4, 8) , periodRange=(0.65,0.73) ), _PyCaptcha_SineWarp(amplitudeRange=(4, 8), periodRange=(0.65, 0.73)),
] ]
def getImg(self): def getImg(self):
@@ -25,14 +27,15 @@ class Captcha_Img(object):
def render(self): def render(self):
"""Render this CAPTCHA, returning a PIL image""" """Render this CAPTCHA, returning a PIL image"""
size = (self.width,self.height) size = (self.width, self.height)
#img = Image.new("RGB", size ) # img = Image.new("RGB", size )
img = self._image img = self._image
for layer in self._layers: for layer in self._layers:
img = layer.render( img ) or img img = layer.render(img) or img
self._image = img self._image = img
return self._image return self._image
class _PyCaptcha_WarpBase(object): class _PyCaptcha_WarpBase(object):
"""Abstract base class for image warping. Subclasses define a """Abstract base class for image warping. Subclasses define a
function that maps points in the output image to points in the input image. function that maps points in the output image to points in the input image.
@@ -55,15 +58,15 @@ class _PyCaptcha_WarpBase(object):
# Create a list of arrays with transformed points # Create a list of arrays with transformed points
xRows = [] xRows = []
yRows = [] yRows = []
for j in xrange(yPoints): for j in range(int(yPoints)):
xRow = [] xRow = []
yRow = [] yRow = []
for i in xrange(xPoints): for i in range(int(xPoints)):
x, y = f(i*r, j*r) x, y = f(i * r, j * r)
# Clamp the edges so we don't get black undefined areas # Clamp the edges so we don't get black undefined areas
x = max(0, min(image.size[0]-1, x)) x = max(0, min(image.size[0] - 1, x))
y = max(0, min(image.size[1]-1, y)) y = max(0, min(image.size[1] - 1, y))
xRow.append(x) xRow.append(x)
yRow.append(y) yRow.append(y)
@@ -73,27 +76,28 @@ class _PyCaptcha_WarpBase(object):
# Create the mesh list, with a transformation for # Create the mesh list, with a transformation for
# each square between points on the grid # each square between points on the grid
mesh = [] mesh = []
for j in xrange(yPoints-1): for j in range(int(yPoints - 1)):
for i in xrange(xPoints-1): for i in range(int(xPoints - 1)):
mesh.append(( mesh.append((
# Destination rectangle # Destination rectangle
(i*r, j*r, (i * r, j * r,
(i+1)*r, (j+1)*r), (i + 1) * r, (j + 1) * r),
# Source quadrilateral # Source quadrilateral
(xRows[j ][i ], yRows[j ][i ], (xRows[j][i], yRows[j][i],
xRows[j+1][i ], yRows[j+1][i ], xRows[j + 1][i], yRows[j + 1][i],
xRows[j+1][i+1], yRows[j+1][i+1], xRows[j + 1][i + 1], yRows[j + 1][i + 1],
xRows[j ][i+1], yRows[j ][i+1]), xRows[j][i + 1], yRows[j][i + 1]),
)) ))
return image.transform(image.size, Image.MESH, mesh, self.filtering) return image.transform(image.size, Image.MESH, mesh, self.filtering)
class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase): class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase):
"""Warp the image using a random composition of sine waves""" """Warp the image using a random composition of sine waves"""
def __init__(self, def __init__(self,
amplitudeRange = (1,1),#(2, 6), amplitudeRange=(1, 1), # (2, 6),
periodRange = (1,1)#(0.65, 0.73), periodRange=(1, 1) # (0.65, 0.73),
): ):
self.amplitude = random.uniform(*amplitudeRange) self.amplitude = random.uniform(*amplitudeRange)
self.period = random.uniform(*periodRange) self.period = random.uniform(*periodRange)
@@ -102,50 +106,51 @@ class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase):
def get_transform(self, image): def get_transform(self, image):
return (lambda x, y, return (lambda x, y,
a = self.amplitude, a=self.amplitude,
p = self.period, p=self.period,
o = self.offset: o=self.offset:
(math.sin( (y+o[0])*p )*a + x, (math.sin((y + o[0]) * p) * a + x,
math.sin( (x+o[1])*p )*a + y)) math.sin((x + o[1]) * p) * a + y))
@view_config(route_name='captcha') @view_config(route_name='captcha')
def DoCaptcha(request): def DoCaptcha(request):
ImgSize = (230,100) img_size = (230, 100)
WorkImg = Image.new( 'RGBA', ImgSize, (255, 255, 255, 0) ) work_img = Image.new('RGBA', img_size, (255, 255, 255, 0))
Xmax, Ymax = WorkImg.size Xmax, Ymax = work_img.size
# Write something on it # Write something on it
draw = ImageDraw.Draw(WorkImg) draw = ImageDraw.Draw(work_img)
# use a truetype font # use a truetype font
#font = ImageFont.truetype("/var/lib/defoma/gs.d/dirs/fonts/LiberationMono-Regular.ttf", 40) # font = ImageFont.truetype("/var/lib/defoma/gs.d/dirs/fonts/LiberationMono-Regular.ttf", 40)
# use it # use it
font = ImageFont.truetype("jm2l/static/fonts/LiberationMono-Regular.ttf",40) font = ImageFont.truetype("jm2l/static/fonts/LiberationMono-Regular.ttf", 40)
# Re-position # Re-position
# Choose a word for captcha # Choose a word for captcha
text = random.choice(TabMots) text = random.choice(TabMots)
Xt, Yt = font.getsize(text) Xt, Yt = font.getsize(text)
OrX, OrY = (ImgSize[0]-Xt)/2, (ImgSize[1]-Yt)/2 OrX, OrY = (img_size[0] - Xt) / 2, (img_size[1] - Yt) / 2
draw.text((OrX, OrY), text, font=font, fill="#000000") draw.text((OrX, OrY), text, font=font, fill="#000000")
# Apply a Blur # Apply a Blur
# WorkImg=WorkImg.filter(ImageFilter.BLUR) # work_img=work_img.filter(ImageFilter.BLUR)
# Apply a DETAIL # Apply a DETAIL
WorkImg=WorkImg.filter(ImageFilter.DETAIL) work_img = work_img.filter(ImageFilter.DETAIL)
# randomize parameters for perspective # randomize parameters for perspective
ax, ay = (random.uniform(0.9,1.2) , random.uniform(0.9,1.2)) ax, ay = (random.uniform(0.9, 1.2), random.uniform(0.9, 1.2))
tx, ty = (random.uniform(0,0.0003),random.uniform(0,0.0003)) tx, ty = (random.uniform(0, 0.0003), random.uniform(0, 0.0003))
bx, by = (random.uniform(0.5,0.8),random.uniform(0,0.2)) bx, by = (random.uniform(0.5, 0.8), random.uniform(0, 0.2))
# Apply perspective to Captcha # Apply perspective to Captcha
WorkImg= WorkImg.transform(ImgSize, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty)) work_img = work_img.transform(img_size, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
# Apply SinWarp to Captcha # Apply SinWarp to Captcha
tr = Captcha_Img(Xmax, Ymax) tr = Captcha_Img(Xmax, Ymax)
tr._image = WorkImg tr._image = work_img
WorkImg = tr.render() work_img = tr.render()
# Apply a Smooth on it # Apply a Smooth on it
WorkImg=WorkImg.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE])) work_img = work_img.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE]))
# Save Result # Save Result
request.session['Captcha'] = text request.session['Captcha'] = text
#session.save() # session.save()
ImgHandle = StringIO.StringIO() ImgHandle = io.BytesIO()
WorkImg.save(ImgHandle,'png') work_img.save(ImgHandle, 'png')
ImgHandle.seek(0) ImgHandle.seek(0)
return Response(app_iter=ImgHandle, content_type = 'image/png') return Response(app_iter=ImgHandle, content_type='image/png')
+1 -1
View File
@@ -1 +1 @@
CurrentYear = 2018 CurrentYear = 2020
+394 -323
View File
@@ -1,101 +1,131 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
import random
import string
from wtforms import Form, BooleanField, StringField, TextAreaField, SelectField from wtforms import Form, BooleanField, StringField, TextAreaField, SelectField
from wtforms import SubmitField, validators, FieldList, PasswordField from wtforms import SubmitField, validators, FieldList, PasswordField
#import .ExtWforms # import .ExtWforms
from .ExtWtforms import MySelectField from .ExtWtforms import MySelectField
from wtforms import HiddenField, DecimalField, DateTimeField, FormField, DateField from wtforms import HiddenField, DecimalField, DateTimeField, FormField, DateField
from wtforms.validators import ValidationError from wtforms.validators import ValidationError
strip_filter = lambda x: x.strip() if x else None
from wtforms.csrf.session import SessionCSRF from wtforms.csrf.session import SessionCSRF
from datetime import timedelta from datetime import timedelta
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
# What about an helper function
def strip_filter(x):
# strip_filter = lambda x: x.strip() if x else None
if x:
return x.strip()
return None
# get random string password with letters, digits, and symbols
def get_random_string(length):
csrf_characters = string.ascii_letters + string.digits + string.punctuation
csrf = ''.join(random.choice(csrf_characters) for i in range(length))
return bytes(csrf, 'utf8')
class MyBaseForm(Form): class MyBaseForm(Form):
class Meta: class Meta:
csrf = True csrf = True
csrf_class = SessionCSRF csrf_class = SessionCSRF
csrf_secret = b'lJDQtOAMC2qe89doIn8u3Mch_DgeLSKO' # csrf_secret = b'lJDQtOAMC2qe89doIn8u3Mch_DgeLSKO'
csrf_secret = get_random_string(32)
csrf_time_limit = timedelta(minutes=60) csrf_time_limit = timedelta(minutes=60)
class BlogCreateForm(MyBaseForm): class BlogCreateForm(MyBaseForm):
title = StringField('Entry title', [validators.Length(min=1, max=255)], title = StringField('Entry title', [validators.Length(min=1, max=255)],
filters=[strip_filter]) filters=[strip_filter])
body = TextAreaField('Entry body', [validators.Length(min=1)], body = TextAreaField('Entry body', [validators.Length(min=1)],
filters=[strip_filter]) filters=[strip_filter])
class BlogUpdateForm(BlogCreateForm): class BlogUpdateForm(BlogCreateForm):
id = HiddenField() id = HiddenField()
PLACE_TYPE = [('Aeroport', u'Aéroport'), ('Gare','Gare'), ('JM2L','JM2L'), PLACE_TYPE = [('Aeroport', u'Aéroport'), ('Gare', 'Gare'), ('JM2L', 'JM2L'),
('Hotel',u'Hôtel'), ('Habitant','Habitant'), ('Hotel', u'Hôtel'), ('Habitant', 'Habitant'),
('Restaurant','Restaurant'), ('Autres','Autres')] ('Restaurant', 'Restaurant'), ('Autres', 'Autres')]
TIERS_ROLE = [('Exposant','Exposant'), ('Sponsor','Sponsor'), TIERS_ROLE = [('Exposant', 'Exposant'), ('Sponsor', 'Sponsor'),
('Donateur','Donateur')] ('Donateur', 'Donateur')]
YESNO = [("0","Non"), ("1","Oui")] YESNO = [("0", "Non"), ("1", "Oui")]
EVENT_TYPE = ['Stand', 'Table ronde', 'Atelier', 'Concert', 'Conference', 'Repas'] EVENT_TYPE = ['Stand', 'Table ronde', 'Atelier', 'Concert', 'Conference', 'Repas']
CONF_DURATION = [ (15,u'Lighting talk ( 5 min)'), CONF_DURATION = [(15, u'Lighting talk ( 5 min)'),
(30,u'Conférence (20 min)'), (30, u'Conférence (20 min)'),
(60,u'Conférence (50 min)'), (60, u'Conférence (50 min)'),
(90,u'Conférence (75 min)'),] (90, u'Conférence (75 min)'), ]
ATELIER_DURATION = [ (15,u'Lighting talk ( 5 min)'), ATELIER_DURATION = [(15, u'Lighting talk ( 5 min)'),
(30,u'Conférence (20 min)'), (30, u'Conférence (20 min)'),
(60,u'Conférence (50 min)'), (60, u'Conférence (50 min)'),
(90,u'Conférence (75 min)'),] (90, u'Conférence (75 min)'), ]
class StaffArea(MyBaseForm): class StaffArea(MyBaseForm):
name = StringField(u'Pôle') name = StringField(u'Pôle')
description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)], description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter] filters=[strip_filter]
) )
year_uid = HiddenField('year', default=str(CurrentYear)) year_uid = HiddenField('year', default=str(CurrentYear))
class EditStaffArea(StaffArea): class EditStaffArea(StaffArea):
uid = HiddenField() uid = HiddenField()
class StaffTasks(MyBaseForm): class StaffTasks(MyBaseForm):
name = StringField(u'Nom de la tâche', [validators.Required()]) name = StringField(u'Nom de la tâche', [validators.Required()])
area_uid = SelectField(u'Pôle concerné', coerce=int ) area_uid = SelectField(u'Pôle concerné', coerce=int)
closed_by = SelectField(u'Assigné à', coerce=int ) closed_by = SelectField(u'Assigné à', coerce=int)
due_date = DateField(u'Date prévue', format='%d/%m/%Y') due_date = DateField(u'Date prévue', format='%d/%m/%Y')
description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)], description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter]) filters=[strip_filter])
year_uid = HiddenField('year', default=str(CurrentYear)) year_uid = HiddenField('year', default=str(CurrentYear))
class EditStaffTasks(StaffTasks): class EditStaffTasks(StaffTasks):
uid = HiddenField() uid = HiddenField()
class DossPresse(MyBaseForm): class DossPresse(MyBaseForm):
year_uid = HiddenField() year_uid = HiddenField()
doss_presse = TextAreaField('Dossier de Presse', [validators.optional(), validators.Length(max=1000000)], doss_presse = TextAreaField('Dossier de Presse', [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter]) filters=[strip_filter])
class IndexForm(MyBaseForm): class IndexForm(MyBaseForm):
year_uid = HiddenField() year_uid = HiddenField()
description = TextAreaField('Index', [validators.optional(), validators.Length(max=1000000)], description = TextAreaField('Index', [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter]) filters=[strip_filter])
class TiersMember(MyBaseForm): class TiersMember(MyBaseForm):
class Meta: class Meta:
csrf = False csrf = False
year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,CurrentYear+1),range(2006,CurrentYear+1))) year_uid = SelectField(u'Année', coerce=int,
choices=list(zip(range(2006, CurrentYear + 1), range(2006, CurrentYear + 1))))
user_uid = StringField(u'user') user_uid = StringField(u'user')
role = StringField(u'Role') role = StringField(u'Role')
class TiersRole(MyBaseForm): class TiersRole(MyBaseForm):
class Meta: class Meta:
csrf = False csrf = False
year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,CurrentYear+1),range(2006,CurrentYear+1))) year_uid = SelectField(u'Année', coerce=int,
choices=list(zip(range(2006, CurrentYear + 1), range(2006, CurrentYear + 1))))
tiers_role = SelectField(u'Role', choices=TIERS_ROLE) tiers_role = SelectField(u'Role', choices=TIERS_ROLE)
class TiersChoice(MyBaseForm): class TiersChoice(MyBaseForm):
class Meta: class Meta:
csrf = False csrf = False
@@ -105,202 +135,221 @@ class TiersChoice(MyBaseForm):
tiers_uid = StringField(u'Entité') tiers_uid = StringField(u'Entité')
role = StringField(u'Role') role = StringField(u'Role')
class AddIntervenant(MyBaseForm): class AddIntervenant(MyBaseForm):
class Meta: class Meta:
csrf = False csrf = False
event_uid = HiddenField() event_uid = HiddenField()
intervenant = SelectField(u'Intervenant', coerce=int ) intervenant = SelectField(u'Intervenant', coerce=int)
class AddTiers(MyBaseForm): class AddTiers(MyBaseForm):
class Meta: class Meta:
csrf = False csrf = False
event_uid = HiddenField() event_uid = HiddenField()
tiers = SelectField(u'Entité', coerce=int ) tiers = SelectField(u'Entité', coerce=int)
class ConfCreateForm(MyBaseForm): class ConfCreateForm(MyBaseForm):
event_type = HiddenField() event_type = HiddenField()
for_year = HiddenField() for_year = HiddenField()
start_time = HiddenField() start_time = HiddenField()
end_time = HiddenField() end_time = HiddenField()
start_sel = SelectField(u'Début', coerce=int, start_sel = SelectField(
description=u"C'est une heure indicative correspondant au mieux à vos préférences "+ u'Début', coerce=int,
u"personnelles. Vous pouvez prendre un créneau horaire déjà réservé si vous avez des contraintes " description=u"C'est une heure indicative correspondant au mieux à vos préférences "
u"particulières. L'équipe des JM2L mettra à disposition plus de salle si nécessaire. En cas de conflit,"+ u"personnelles. Vous pouvez prendre un créneau horaire déjà réservé si vous avez des contraintes "
u"l'organisation se réserve le droit de changer la salle et l'heure avec votre accord." u"particulières. L'équipe des JM2L mettra à disposition plus de salle si nécessaire. "
) u"En cas de conflit,"
duration = SelectField(u'Durée', coerce=int, u"l'organisation se réserve le droit de changer la salle et l'heure avec votre accord."
description=u"Précisez ici la durée de votre intervention"
) )
salle_uid = SelectField(u'Salle', coerce=int, duration = SelectField(
description=u"Choisissez ici la salle en fonction " u'Durée', coerce=int,
u"du nombres de personnes potentiellement intéressé par votre intervention "+ description=u"Précisez ici la durée de votre intervention")
u"l'organisation se réserve le droit de changer la salle (avec votre accord)."
salle_uid = SelectField(
u'Salle', coerce=int,
description=u"Choisissez ici la salle en fonction du nombres de personnes potentiellement "
u"intéressé par votre intervention l'organisation se réserve le droit de changer"
u" la salle (avec votre accord)."
) )
name = StringField(u'Le nom de votre ', name = StringField(
[validators.DataRequired(u'Vous devez spécifier un nom pour votre intérvention'), u'Le nom de votre ',
validators.Length(min=1, max=80, message='entre 1 et 80 car')], [validators.DataRequired(u'Vous devez spécifier un nom pour votre intérvention'),
filters=[strip_filter]) validators.Length(min=1, max=80, message='entre 1 et 80 car')],
filters=[strip_filter]
)
description = TextAreaField(
u'Décrivez ici quelques détails à propos de votre intervention ',
[validators.Optional(), validators.Length(max=1000000)],
filters=[strip_filter]
)
description = TextAreaField(u'Décrivez ici quelques détails à propos de votre intervention ',
[validators.Optional(), validators.Length(max=1000000)],
filters=[strip_filter]
)
class ConfUpdateForm(ConfCreateForm): class ConfUpdateForm(ConfCreateForm):
uid = HiddenField() uid = HiddenField()
class SalleForm(MyBaseForm): class SalleForm(MyBaseForm):
year_uid = SelectField(u'Année', coerce=int) year_uid = SelectField(u'Année', coerce=int)
phy_salle_id = SelectField('Salle Physique', coerce=int) phy_salle_id = SelectField('Salle Physique', coerce=int)
place_type = SelectField('Type', choices=[('Conference',u'Conférence'), place_type = SelectField('Type', choices=[('Conference', u'Conférence'),
('Stand','Stand'), ('Atelier','Atelier'), ('Table ronde','Table ronde'), ('Stand', 'Stand'), ('Atelier', 'Atelier'),
('MAO','MAO'), ('Repas','Repas / Snack'), ('Autres','Autres') ]) ('Table ronde', 'Table ronde'),
name = StringField('Nom de la salle', [validators.Length(min=1, max=40)], ('MAO', 'MAO'), ('Repas', 'Repas / Snack'), ('Autres', 'Autres')])
filters=[strip_filter]) name = StringField('Nom de la salle', [validators.Length(min=1, max=40)],
description = TextAreaField('Description', filters=[strip_filter])
filters=[strip_filter]) description = TextAreaField('Description',
filters=[strip_filter])
class EditSalleForm(SalleForm): class EditSalleForm(SalleForm):
salle_id = HiddenField() salle_id = HiddenField()
class SallePhyForm(MyBaseForm): class SallePhyForm(MyBaseForm):
name = StringField('Nom de la salle', [validators.Length(min=1, max=40)], name = StringField('Nom de la salle', [validators.Length(min=1, max=40)],
filters=[strip_filter]) filters=[strip_filter])
nb_places = StringField('Nombre de places', [validators.Length(max=4)]) nb_places = StringField('Nombre de places', [validators.Length(max=4)])
description = TextAreaField('Description', description = TextAreaField('Description',
filters=[strip_filter]) filters=[strip_filter])
class EditSallePhyForm(SallePhyForm): class EditSallePhyForm(SallePhyForm):
uid = HiddenField() uid = HiddenField()
class PlaceCreateForm(MyBaseForm): class PlaceCreateForm(MyBaseForm):
place_type = SelectField('Type', choices=PLACE_TYPE) place_type = SelectField('Type', choices=PLACE_TYPE)
display_name = StringField(u'Nom affiché', [validators.Length(min=1, max=20)], display_name = StringField(u'Nom affiché', [validators.Length(min=1, max=20)],
filters=[strip_filter]) filters=[strip_filter])
name = StringField('Nom Complet', [validators.Length(min=1, max=80)], name = StringField('Nom Complet', [validators.Length(min=1, max=80)],
filters=[strip_filter]) filters=[strip_filter])
gps_coord = StringField(u'Coordonnées GPS', [validators.Length(max=30), gps_coord = StringField(u'Coordonnées GPS',
validators.Regexp( "^[0-9]+\.?[0-9]+,[0-9]+\.?[0-9]+$", [validators.Length(max=30),
message=u"Le GPS devrait être sous la forme 43.6158372,7.0723401")], validators.Regexp("^[0-9]+\.?[0-9]+,[0-9]+\.?[0-9]+$",
filters=[strip_filter]) message=u"Le GPS devrait être sous la forme 43.6158372,7.0723401")],
filters=[strip_filter])
adresse = TextAreaField('Adresse', [validators.Length(max=100)], adresse = TextAreaField('Adresse', [validators.Length(max=100)],
filters=[strip_filter]) filters=[strip_filter])
codePostal = StringField('Code Postal', [validators.Length(max=5)], codePostal = StringField('Code Postal', [validators.Length(max=5)],
filters=[strip_filter]) filters=[strip_filter])
ville = StringField('Ville', [validators.Length(max=40)], ville = StringField('Ville', [validators.Length(max=40)],
filters=[strip_filter]) filters=[strip_filter])
website = StringField('Site Web', [validators.Length(max=100)], website = StringField('Site Web', [validators.Length(max=100)],
filters=[strip_filter]) filters=[strip_filter])
description = TextAreaField('Description', description = TextAreaField('Description',
filters=[strip_filter]) filters=[strip_filter])
created_by = HiddenField() created_by = HiddenField()
class PlaceUpdateForm(PlaceCreateForm): class PlaceUpdateForm(PlaceCreateForm):
place_id = HiddenField() place_id = HiddenField()
def captcha_check(form, field): def captcha_check(form, field):
if form.meta.csrf_context.get('Captcha')!=field.data: if form.meta.csrf_context.get('Captcha') != field.data:
raise ValidationError(u"la vérification captcha est invalide.") raise ValidationError(u"la vérification captcha est invalide.")
class UserPasswordForm(MyBaseForm): class UserPasswordForm(MyBaseForm):
uid = HiddenField() uid = HiddenField()
password = PasswordField("Mot de passe",[ password = PasswordField("Mot de passe", [
validators.Length(max=128, message=u"128 car. maximum"), validators.Length(max=128, message=u"128 car. maximum"),
validators.required(message=u"Ce champ est obligatoire"), validators.required(message=u"Ce champ est obligatoire"),
validators.EqualTo('confirm', message=u'Les password ne sont pas équivalents') ], validators.EqualTo('confirm', message=u'Les password ne sont pas équivalents')],
filters=[strip_filter] filters=[strip_filter]
) )
confirm = PasswordField('Confirmez') confirm = PasswordField('Confirmez')
class UserRegisterForm(MyBaseForm): class UserRegisterForm(MyBaseForm):
nom = StringField(u'Nom', [ nom = StringField(u'Nom', [
validators.Length(max=80, message=u"80 car. maximum"), validators.Length(max=80, message=u"80 car. maximum"),
validators.required(message=u"Ce champ est obligatoire") ], validators.required(message=u"Ce champ est obligatoire")],
filters=[strip_filter] filters=[strip_filter]
) )
prenom = StringField(u'Prénom', [ prenom = StringField(u'Prénom', [
validators.Length(max=80, message=u"80 car. maximum"), validators.Length(max=80, message=u"80 car. maximum"),
validators.required(message=u"Ce champ est obligatoire"), validators.required(message=u"Ce champ est obligatoire"),
validators.Length(max=80)], filters=[strip_filter] validators.Length(max=80)], filters=[strip_filter]
) )
mail = StringField(u'Adresse électronique', [ mail = StringField(u'Adresse électronique', [
validators.required(message=u"Ce champ est obligatoire"), validators.required(message=u"Ce champ est obligatoire"),
validators.Email(message=u"Essayez aussi avec une adresse e-mail valide"), validators.Email(message=u"Essayez aussi avec une adresse e-mail valide"),
validators.Length(max=100)], validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = u"Une adresse e-mail valide." + description=u"Une adresse e-mail valide." +
u"Cette adresse ne sera pas rendue publique, "+ u"Cette adresse ne sera pas rendue publique, " +
u"et ne sera pas divulguée à des tiers." u"et ne sera pas divulguée à des tiers."
) )
captcha = StringField(u'Captcha', [validators.Length(max=8), captcha_check], captcha = StringField(u'Captcha', [validators.Length(max=8), captcha_check],
filters=[strip_filter] filters=[strip_filter]
) )
class ProfilForm(MyBaseForm): class ProfilForm(MyBaseForm):
id = HiddenField() id = HiddenField()
user_id = HiddenField() user_id = HiddenField()
nom = StringField(u'Nom', [validators.Length(max=80)], nom = StringField(u'Nom', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = u"Les espaces sont autorisés, la ponctuation n'est " + description=u"Les espaces sont autorisés, la ponctuation n'est " +
u"pas autorisée à l'exception des points, traits d'union, " + u"pas autorisée à l'exception des points, traits d'union, " +
u"apostrophes et tirets bas." u"apostrophes et tirets bas."
) )
prenom = StringField(u'Prénom', [validators.Length(max=80)], prenom = StringField(u'Prénom', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = u"Les espaces sont autorisés, la ponctuation n'est " + description=u"Les espaces sont autorisés, la ponctuation n'est " +
u"pas autorisée à l'exception des points, traits d'union, " + u"pas autorisée à l'exception des points, traits d'union, " +
u"apostrophes et tirets bas." u"apostrophes et tirets bas."
) )
pseudo = StringField(u'Pseudo', [validators.Length(max=80)], pseudo = StringField(u'Pseudo', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = "Votre pseudo d'usage sur la toile." description="Votre pseudo d'usage sur la toile."
) )
mail = StringField(u'Adresse électronique', [validators.optional(), validators.Email(), validators.Length(max=100)], mail = StringField(u'Adresse électronique', [validators.optional(), validators.Email(), validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = u"Une adresse e-mail valide. Tous les messages de ce système" + description=u"Une adresse e-mail valide. Tous les messages de ce système" +
u"seront envoyés à cette adresse. Cette adresse ne sera pas rendue publique,"+ u"seront envoyés à cette adresse. Cette adresse ne sera pas rendue publique," +
u"et ne sera utilisée que si vous désirez obtenir un nouveau mot de passe ou" + u"et ne sera utilisée que si vous désirez obtenir un nouveau mot de passe ou" +
u"recevoir personnellement certaines nouvelles ou avertissements." u"recevoir personnellement certaines nouvelles ou avertissements."
) )
phone = StringField(u'Mobile', [validators.optional(), validators.Length(max=10), phone = StringField(u'Mobile', [validators.optional(), validators.Length(max=10),
validators.Regexp("\d+", message=u"Le numéro de téléphone mobile ne doit contenir que des chiffres")], validators.Regexp("\d+",
message=u"Le numéro de téléphone mobile ne doit contenir que des chiffres")],
filters=[strip_filter], filters=[strip_filter],
description = u"Un numéro de mobile valide. Afin de pouvoir rester en" + description=u"Un numéro de mobile valide. Afin de pouvoir rester en" +
u"contact avec les personne de l'organisation, et pour vos échanges. " + u"contact avec les personne de l'organisation, et pour vos échanges. " +
u"Ce numéro ne sera pas publié, et ne sera utilisé que si " + u"Ce numéro ne sera pas publié, et ne sera utilisé que si " +
u"vous désirez recevoir personnellement certaines nouvelles ou alertes." u"vous désirez recevoir personnellement certaines nouvelles ou alertes."
) )
website = StringField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)], website = StringField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = "Renseignez ici votre site Web." description="Renseignez ici votre site Web."
) )
gpg_key = TextAreaField(u'Ma clé GPG', gpg_key = TextAreaField(u'Ma clé GPG',
[validators.optional(), validators.Length(max=9000)], [validators.optional(), validators.Length(max=9000)],
filters=[strip_filter], filters=[strip_filter],
description = u"Vous pouvez insérer votre clé GPG publique pour " + description=u"Vous pouvez insérer votre clé GPG publique pour " +
u"échanger des données sécurisées." u"échanger des données sécurisées."
) )
soc_link = TextAreaField('Mes autres identifiants', soc_link = TextAreaField('Mes autres identifiants',
[validators.optional(), validators.Length(max=1000000)], [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter], filters=[strip_filter],
description = u"Vous pouvez insérer ici d'autres identifiants " + description=u"Vous pouvez insérer ici d'autres identifiants " +
u"permettant aux autres de vous retrouver sur la toile (IRC, jabber, réseaux sociaux etc)." u"permettant aux autres de vous retrouver sur la toile (IRC, jabber, réseaux sociaux etc)."
) )
bio = TextAreaField('Biographie', [validators.optional(), validators.Length(max=1000000)], bio = TextAreaField('Biographie', [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter] filters=[strip_filter]
@@ -311,124 +360,128 @@ class ProfilForm(MyBaseForm):
class MiamForm(MyBaseForm): class MiamForm(MyBaseForm):
RepasVendredi = SelectField(u'Je viens au dîner convivial vendredi soir', RepasVendredi = SelectField(u'Je viens au dîner convivial vendredi soir',
choices=YESNO, choices=YESNO,
description = u"L'organisation réserve le " + description=u"L'organisation réserve le " +
u"restaurant pour ce dîner convivial. De petites " + u"restaurant pour ce dîner convivial. De petites " +
u"animations vous seront proposées. " + u"animations vous seront proposées. " +
u"Il nous faut savoir si on vous réserve une place !" u"Il nous faut savoir si on vous réserve une place !"
) )
RepasSamediMidi = SelectField(u'Je déjeune sur place samedi midi', choices=YESNO ) RepasSamediMidi = SelectField(u'Je déjeune sur place samedi midi', choices=YESNO)
RepasSamediSoir = SelectField(u'Je viens au repas de clôture samedi soir', choices=YESNO, RepasSamediSoir = SelectField(u'Je viens au repas de clôture samedi soir', choices=YESNO,
description = u"L'organisation réserve le " + description=u"L'organisation réserve le " +
u"restaurant pour le dîner de clôture. De petites " + u"restaurant pour le dîner de clôture. De petites " +
u"animations vous seront proposées. " + u"animations vous seront proposées. " +
u"Il nous faut savoir si on vous réserve une place !" u"Il nous faut savoir si on vous réserve une place !"
) )
Allergies = TextAreaField(u'Allergies', [validators.Length(max=100)], Allergies = TextAreaField(u'Allergies', [validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = u"Entrez ici vos allergies éventuelles, " + description=u"Entrez ici vos allergies éventuelles, " +
u"Ce que votre organisme ne supporte absolument pas." + u"Ce que votre organisme ne supporte absolument pas." +
u"L'organisation fera alors en sorte de les éviter ou " + u"L'organisation fera alors en sorte de les éviter ou " +
u"de les identifier explicitement." u"de les identifier explicitement."
) )
Contraintes = TextAreaField(u'Contraintes', [validators.Length(max=100)], Contraintes = TextAreaField(u'Contraintes', [validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = u"Entrez ici ce que vous n'aimez pas, " + description=u"Entrez ici ce que vous n'aimez pas, " +
u"Cela ne consititue pas pour vous un allérgène, " + u"Cela ne consititue pas pour vous un allérgène, " +
u"mais vous n'aimez simplement pas. (Gluten / Laitage etc ...)" u"mais vous n'aimez simplement pas. (Gluten / Laitage etc ...)"
) )
class DateStartConfidenceForm(MyBaseForm): class DateStartConfidenceForm(MyBaseForm):
ConfidenceLevel = [ ConfidenceLevel = [
("0",u"exactement à"), ("0", u"exactement à"),
("1",u"approximativement à"), ("1", u"approximativement à"),
("2",u"à peu près (5 à 15 min) vers"), ("2", u"à peu près (5 à 15 min) vers"),
("3",u"à une vache près (1h) vers") ("3", u"à une vache près (1h) vers")
] ]
DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")] DayChoice = [("4", "Jeudi"), ("5", "Vendredi"), ("6", "Samedi"), ("0", "Dimanche"), ("1", "Lundi")]
Day = SelectField(u'Jour', choices=DayChoice ) Day = SelectField(u'Jour', choices=DayChoice)
Confidence = SelectField(u'Confiance', choices=ConfidenceLevel) Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
Hour = StringField(u'Heure', [validators.Length(max=5, Hour = StringField(u'Heure', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
start_time = HiddenField() start_time = HiddenField()
class ItineraireForm(Form): class ItineraireForm(Form):
start_place = SelectField(u'En partant de', coerce=int) start_place = SelectField(u'En partant de', coerce=int)
arrival_place = SelectField(u'et à destination de', coerce=int) arrival_place = SelectField(u'et à destination de', coerce=int)
itin_id = HiddenField() itin_id = HiddenField()
class AddItineraireForm(Form): class AddItineraireForm(Form):
itin = FormField(ItineraireForm)
distance = DecimalField(u'Distance', [validators.Length(min=1, max=4)],
filters=[strip_filter])
duration = DateTimeField(u'Durée', [validators.Length(min=4, max=5)],
filters=[strip_filter])
price = DecimalField(u'Prix approx.', [validators.Length(min=1, max=5)],
filters=[strip_filter])
tr_pied = BooleanField(u'à pied')
tr_velo = BooleanField(u'à vélo')
tr_moto = BooleanField(u'à moto')
tr_voiture = BooleanField(u'en voiture')
tr_taxi = BooleanField(u'en taxi')
tr_bus = BooleanField(u'en bus')
tr_avion = BooleanField(u'en avion')
description = TextAreaField(u'Description de l\'itinéraire')
itin = FormField(ItineraireForm)
distance = DecimalField(u'Distance', [validators.Length(min=1, max=4)],
filters=[strip_filter])
duration = DateTimeField(u'Durée', [validators.Length(min=4, max=5)],
filters=[strip_filter])
price = DecimalField(u'Prix approx.', [validators.Length(min=1, max=5)],
filters=[strip_filter])
tr_pied = BooleanField(u'à pied')
tr_velo = BooleanField(u'à vélo')
tr_moto = BooleanField(u'à moto')
tr_voiture = BooleanField(u'en voiture')
tr_taxi = BooleanField(u'en taxi')
tr_bus = BooleanField(u'en bus')
tr_avion = BooleanField(u'en avion')
description = TextAreaField(u'Description de l\'itinéraire')
class AddMember(MyBaseForm): class AddMember(MyBaseForm):
tiers_uid = HiddenField() tiers_uid = HiddenField()
nom = StringField(u'Nom', [validators.Length(max=80)], nom = StringField(u'Nom', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = u"Les espaces sont autorisés, la ponctuation n'est " + description=u"Les espaces sont autorisés, la ponctuation n'est " +
u"pas autorisée à l'exception des points, traits d'union, " + u"pas autorisée à l'exception des points, traits d'union, " +
u"apostrophes et tirets bas." u"apostrophes et tirets bas."
) )
prenom = StringField(u'Prénom', [validators.Length(max=80)], prenom = StringField(u'Prénom', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = u"Les espaces sont autorisés, la ponctuation n'est " + description=u"Les espaces sont autorisés, la ponctuation n'est " +
u"pas autorisée à l'exception des points, traits d'union, " + u"pas autorisée à l'exception des points, traits d'union, " +
u"apostrophes et tirets bas." u"apostrophes et tirets bas."
) )
email = StringField(u'Email', [validators.required(), email = StringField(u'Email', [validators.required(),
validators.length(max=10), validators.length(max=10),
validators.Email(message='Ceci ne ressemble pas à une adresse valide')], validators.Email(message='Ceci ne ressemble pas à une adresse valide')],
description=u"Afin d'éviter la duplication d'information et les doublons inutile, "+ description=u"Afin d'éviter la duplication d'information et les doublons inutile, " +
u"pensez d'abord à lui demander de confirmer le mail qu'il a utilisé lors de "+ u"pensez d'abord à lui demander de confirmer le mail qu'il a utilisé lors de " +
u"son inscription sur le site.") u"son inscription sur le site.")
add = SubmitField('Ajouter des membres') add = SubmitField('Ajouter des membres')
class TiersForm(MyBaseForm): class TiersForm(MyBaseForm):
name = StringField(u'Nom', [validators.Length(max=100)], name = StringField(u'Nom', [validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = u"Les espaces sont autorisés, la ponctuation n'est " + description=u"Les espaces sont autorisés, la ponctuation n'est " +
u"pas autorisée à l'exception des points, traits d'union, " + u"pas autorisée à l'exception des points, traits d'union, " +
u"apostrophes et tirets bas." u"apostrophes et tirets bas."
) )
tiers_type = MySelectField('Nature', coerce=int) tiers_type = MySelectField('Nature', coerce=int)
website = StringField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)], website = StringField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)],
filters=[strip_filter], filters=[strip_filter],
description = "Renseignez ici le site Web." description="Renseignez ici le site Web."
) )
description = TextAreaField('Descriptif', description = TextAreaField('Descriptif',
[validators.optional(), validators.Length(max=1000000)], [validators.optional(), validators.Length(max=1000000)],
filters=[strip_filter], filters=[strip_filter],
description = u"Vous pouvez insérer les détails" description=u"Vous pouvez insérer les détails"
) )
membership = FieldList(FormField(TiersMember)) membership = FieldList(FormField(TiersMember))
roles = FieldList(FormField(TiersRole)) roles = FieldList(FormField(TiersRole))
class UpdateTiersForm(TiersForm): class UpdateTiersForm(TiersForm):
uid = HiddenField() uid = HiddenField()
tiers_id = HiddenField() tiers_id = HiddenField()
@@ -437,139 +490,157 @@ class UpdateTiersForm(TiersForm):
class ExchCateg(MyBaseForm): class ExchCateg(MyBaseForm):
exch_type = HiddenField() exch_type = HiddenField()
exch_subtype = StringField(u'Catégorie', [validators.Length(max=80)], exch_subtype = StringField(u'Catégorie', [validators.Length(max=80)],
filters=[strip_filter], filters=[strip_filter],
description = "Le nom de la categorie" description="Le nom de la categorie"
) )
description = TextAreaField('Description', description = TextAreaField('Description',
filters=[strip_filter]) filters=[strip_filter])
class UpdateExchangeForm(MyBaseForm): class UpdateExchangeForm(MyBaseForm):
exch_id = HiddenField() exch_id = HiddenField()
class AskCForm(ItineraireForm): class AskCForm(ItineraireForm):
ConfidenceLevel = [ ConfidenceLevel = [
("0",u"exactement à"), ("0", u"exactement à"),
("1",u"approximativement à"), ("1", u"approximativement à"),
("2",u"à peu près (5 à 15 min) vers"), ("2", u"à peu près (5 à 15 min) vers"),
("3",u"à une vache près (1h) vers") ("3", u"à une vache près (1h) vers")
] ]
DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")] DayChoice = [("4", "Jeudi"), ("5", "Vendredi"), ("6", "Samedi"), ("0", "Dimanche"), ("1", "Lundi")]
Day_start = SelectField(u'Jour', choices=DayChoice ) Day_start = SelectField(u'Jour', choices=DayChoice)
Confidence = SelectField(u'Confiance', choices=ConfidenceLevel) Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
Hour_start = StringField(u'Heure', [validators.Length(max=5, Hour_start = StringField(u'Heure', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
start_time = HiddenField() start_time = HiddenField()
start_place = SelectField(u'En partant de', coerce=int) start_place = SelectField(u'En partant de', coerce=int)
arrival_place = SelectField(u'et à destination de', coerce=int) arrival_place = SelectField(u'et à destination de', coerce=int)
itin_id = HiddenField() itin_id = HiddenField()
class AskHForm(MyBaseForm): class AskHForm(MyBaseForm):
DayChoice = [("4",u"Jeudi à Vendredi"), ("5",u"Vendredi à Samedi"), ("6",u"Samedi à Dimanche"), ("0",u"Dimanche à Lundi")] DayChoice = [("4", u"Jeudi à Vendredi"), ("5", u"Vendredi à Samedi"), ("6", u"Samedi à Dimanche"),
Day_start = SelectField(u'Pour la nuit de', choices=DayChoice ) ("0", u"Dimanche à Lundi")]
start_time = HiddenField() Day_start = SelectField(u'Pour la nuit de', choices=DayChoice)
description = TextAreaField(u'Description de vos contraintes éventuelles', filters=[strip_filter], start_time = HiddenField()
description = u"Décrivez ici vos souhaits et éventuellement " description = TextAreaField(u'Description de vos contraintes éventuelles', filters=[strip_filter],
+ u"les contraintes à prendre en compte. N'hésitez pas à donner des détails." description=u"Décrivez ici vos souhaits et éventuellement "
) + u"les contraintes à prendre en compte. N'hésitez pas à donner des détails."
)
class AskMForm(MyBaseForm): class AskMForm(MyBaseForm):
DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")] DayChoice = [("4", "Jeudi"), ("5", "Vendredi"), ("6", "Samedi"), ("0", "Dimanche"), ("1", "Lundi")]
Day_start = SelectField(u"à partir de", choices=DayChoice ) Day_start = SelectField(u"à partir de", choices=DayChoice)
Hour_start = StringField(u'vers', [validators.Length(max=5, Hour_start = StringField(u'vers', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
start_time = HiddenField() start_time = HiddenField()
Day_end = SelectField(u"Jusqu'à", choices=DayChoice ) Day_end = SelectField(u"Jusqu'à", choices=DayChoice)
Hour_end = StringField(u'vers', [validators.Length(max=5, Hour_end = StringField(u'vers', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
end_time = HiddenField() end_time = HiddenField()
exch_categ = SelectField(u'Catégorie de matériel', coerce=int, exch_categ = SelectField(u'Catégorie de matériel', coerce=int,
description = u"Choisissez une catégorie de bien" description=u"Choisissez une catégorie de bien"
) )
description = TextAreaField(u'Description du bien', filters=[strip_filter], description = TextAreaField(u'Description du bien', filters=[strip_filter],
description = u"Décrivez ici les biens que vous souhaitez" description=u"Décrivez ici les biens que vous souhaitez"
+ u"échanger. N'hésitez pas à donner des détails." + u"échanger. N'hésitez pas à donner des détails."
) )
class PropCForm(ItineraireForm): class PropCForm(ItineraireForm):
ConfidenceLevel = [ ConfidenceLevel = [
("0",u"exactement à"), ("0", u"exactement à"),
("1",u"approximativement à"), ("1", u"approximativement à"),
("2",u"à peu près (5 à 15 min) vers"), ("2", u"à peu près (5 à 15 min) vers"),
("3",u"à une vache près (1h) vers") ("3", u"à une vache près (1h) vers")
] ]
DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")] DayChoice = [("4", "Jeudi"), ("5", "Vendredi"), ("6", "Samedi"), ("0", "Dimanche"), ("1", "Lundi")]
Day_start = SelectField(u'Jour', choices=DayChoice ) Day_start = SelectField(u'Jour', choices=DayChoice)
Confidence = SelectField(u'Confiance', choices=ConfidenceLevel) Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
Hour_start = StringField(u'Heure', [validators.Length(max=5, Hour_start = StringField(u'Heure', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
start_time = HiddenField() start_time = HiddenField()
start_place = SelectField(u'En partant de', coerce=int) start_place = SelectField(u'En partant de', coerce=int)
arrival_place = SelectField(u'et à destination de', coerce=int) arrival_place = SelectField(u'et à destination de', coerce=int)
itin_id = HiddenField() itin_id = HiddenField()
class PropHForm(MyBaseForm): class PropHForm(MyBaseForm):
DayChoice = [("4",u"Jeudi à Vendredi"), ("5",u"Vendredi à Samedi"), ("6",u"Samedi à Dimanche"), ("0",u"Dimanche à Lundi")] DayChoice = [("4", u"Jeudi à Vendredi"), ("5", u"Vendredi à Samedi"), ("6", u"Samedi à Dimanche"),
Day_start = SelectField(u'Pour la nuit de', choices=DayChoice ) ("0", u"Dimanche à Lundi")]
start_time = HiddenField() Day_start = SelectField(u'Pour la nuit de', choices=DayChoice)
exch_categ = SelectField(u'Type de couchage', coerce=int, start_time = HiddenField()
description = u"Indiquez ici le type de couchage proposé") exch_categ = SelectField(u'Type de couchage', coerce=int,
description = TextAreaField(u'Quelques mots autour du logement que vous proposez', filters=[strip_filter], description=u"Indiquez ici le type de couchage proposé")
description = u"Décrivez ici quelques détails sur le logement que vous souhaitez " description = TextAreaField(u'Quelques mots autour du logement que vous proposez', filters=[strip_filter],
+ u"proposer, les contraintes à prendre en compte. N'hésitez pas à donner des détails." description=u"Décrivez ici quelques détails sur le logement que vous souhaitez "
) + u"proposer, les contraintes à prendre en compte. N'hésitez pas à donner des détails."
place_id = SelectField(u'Emplacement', coerce=int, )
description = u"Indiquez ici une des adresses que vous avez proposé") place_id = SelectField(u'Emplacement', coerce=int,
description=u"Indiquez ici une des adresses que vous avez proposé")
class PropMForm(MyBaseForm): class PropMForm(MyBaseForm):
DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")] DayChoice = [("4", "Jeudi"), ("5", "Vendredi"), ("6", "Samedi"), ("0", "Dimanche"), ("1", "Lundi")]
Day_start = SelectField(u"à partir de", choices=DayChoice ) Day_start = SelectField(u"à partir de", choices=DayChoice)
Hour_start = StringField(u'vers', [validators.Length(max=5, Hour_start = StringField(u'vers', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
start_time = HiddenField() start_time = HiddenField()
Day_end = SelectField(u"Jusqu'a ", choices=DayChoice ) Day_end = SelectField(u"Jusqu'a ", choices=DayChoice)
Hour_end = StringField(u'vers', [validators.Length(max=5, Hour_end = StringField(u'vers', [validators.Length(max=5,
message=u"doit faire au maximum 5 caractères"), message=u"doit faire au maximum 5 caractères"),
validators.Regexp("\d+:\d+", validators.Regexp("\d+:\d+",
message=u"doit être sous la forme HH:MM")], message=u"doit être sous la forme HH:MM")],
filters=[strip_filter]) filters=[strip_filter])
end_time = HiddenField() end_time = HiddenField()
exch_categ = SelectField(u'Catégorie de matériel', coerce=int, exch_categ = SelectField(
description = u"Choisissez une catégorie de bien matériel" u'Catégorie de matériel', coerce=int,
) description=u"Choisissez une catégorie de bien matériel"
description = TextAreaField(u'Ajoutez quelques mots autour du matériel que vous proposez', filters=[strip_filter], )
description = u"Décrivez ici quelques détails sur le matériel que vous souhaitez " description = TextAreaField(
+ u"proposer. N'hésitez pas à donner des détails." u'Ajoutez quelques mots autour du matériel que vous proposez',
) filters=[strip_filter],
description=u"Décrivez ici quelques détails sur le matériel "
u"que vous souhaitez proposer. N'hésitez pas à donner des détails."
)
class UpdateAskCForm(AskCForm, UpdateExchangeForm): class UpdateAskCForm(AskCForm, UpdateExchangeForm):
pass pass
class UpdateAskHForm(AskHForm, UpdateExchangeForm): class UpdateAskHForm(AskHForm, UpdateExchangeForm):
pass pass
class UpdateAskMForm(AskMForm, UpdateExchangeForm): class UpdateAskMForm(AskMForm, UpdateExchangeForm):
pass pass
class UpdatePropCForm(PropCForm, UpdateExchangeForm): class UpdatePropCForm(PropCForm, UpdateExchangeForm):
pass pass
class UpdatePropHForm(PropHForm, UpdateExchangeForm): class UpdatePropHForm(PropHForm, UpdateExchangeForm):
pass pass
class UpdatePropMForm(PropMForm, UpdateExchangeForm): class UpdatePropMForm(PropMForm, UpdateExchangeForm):
pass pass
+62 -54
View File
@@ -4,18 +4,25 @@ from datetime import timedelta, datetime
import itertools import itertools
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
def get_current_year():
""" This function is intended to return the year of the next edition """
return CurrentYear
class DummySejour(object): class DummySejour(object):
def __init__(self, event): def __init__(self, event):
self.Me = event['request'].user self.Me = event['request'].user
self.CurrentEventYear = DBSession.query(JM2L_Year).filter(JM2L_Year.state=='Ongoing').first() self.CurrentEventYear = DBSession.query(JM2L_Year).filter(JM2L_Year.state == 'Ongoing').first()
self.Sejour = None self.Sejour = None
if self.Me: if self.Me:
self.Sejour = DBSession.query(Sejour)\ self.Sejour = DBSession.query(Sejour) \
.filter(Sejour.user_id==self.Me.uid)\ .filter(Sejour.user_id == self.Me.uid) \
.filter(Sejour.for_year==self.CurrentEventYear.year_uid)\ .filter(Sejour.for_year == self.CurrentEventYear.year_uid) \
.first() .first()
class Sejour_helpers(DummySejour): class Sejour_helpers(DummySejour):
def __init__(self, event): def __init__(self, event):
@@ -27,78 +34,78 @@ class Sejour_helpers(DummySejour):
# This function return the start of the event # This function return the start of the event
return self.CurrentYear return self.CurrentYear
def PossibleDate(self, typedate="arrival"): def PossibleDate(self, type_date="arrival"):
arrival, departure = False, False arrival, departure = False, False
TabResult = list() tab_result = list()
if typedate == "arrival": if type_date == "arrival":
# Let's say people should arrive until 2 day before # Let's say people should arrive until 2 day before
arrival = True arrival = True
myDayRange = xrange(2,-1,-1) my_day_range = range(2, -1, -1)
elif typedate == "departure": elif type_date == "departure":
# Let's say people should go back home until 2 day after # Let's say people should go back home until 2 day after
departure = True departure = True
myDayRange = xrange(3) my_day_range = range(3)
else: else:
return TabResult return tab_result
if self.Sejour: if self.Sejour:
ArrDate = datetime.strftime(self.Sejour.arrival_time,"%d %B %Y").decode('utf-8') arr_date = datetime.strftime(self.Sejour.arrival_time, "%d %B %Y")
DepDate = datetime.strftime(self.Sejour.depart_time,"%d %B %Y").decode('utf-8') dep_date = datetime.strftime(self.Sejour.depart_time, "%d %B %Y")
else: else:
ArrDate = datetime.strftime( self.CurrentEventYear.start_time,"%d %B %Y" ).decode('utf-8') arr_date = datetime.strftime(self.CurrentEventYear.start_time, "%d %B %Y")
DepDate = datetime.strftime( self.CurrentEventYear.end_time,"%d %B %Y" ).decode('utf-8') dep_date = datetime.strftime(self.CurrentEventYear.end_time, "%d %B %Y")
for oneday in myDayRange: for one_day in my_day_range:
if arrival: if arrival:
TmpDay = self.CurrentEventYear.end_time - timedelta(days=oneday) tmp_day = self.CurrentEventYear.end_time - timedelta(days=one_day)
elif departure: elif departure:
TmpDay = self.CurrentEventYear.start_time + timedelta(days=oneday) tmp_day = self.CurrentEventYear.start_time + timedelta(days=one_day)
DayName = datetime.strftime(TmpDay,"%A") day_name = datetime.strftime(tmp_day, "%A")
DayNum = datetime.strftime(TmpDay,"%d/%m/%y") day_num = datetime.strftime(tmp_day, "%d/%m/%y")
DayString = datetime.strftime(TmpDay,"%d %B %Y").decode('utf-8') day_string = datetime.strftime(tmp_day, "%d %B %Y")
if arrival and ArrDate==DayString: if arrival and arr_date == day_string:
TabResult.append((DayNum, DayName, 'selected="selected"')) tab_result.append((day_num, day_name, 'selected="selected"'))
elif departure and DepDate==DayString: elif departure and dep_date == day_string:
TabResult.append((DayNum, DayName, 'selected="selected"')) tab_result.append((day_num, day_name, 'selected="selected"'))
else: else:
TabResult.append((DayNum, DayName, "")) tab_result.append((day_num, day_name, ""))
return TabResult return tab_result
def PossibleTime(self, typedate="arrival"): def PossibleTime(self, type_date="arrival"):
ArrTime, DepTime = "10:00", "19:00" arr_time, dep_time = "10:00", "19:00"
TabResult = list() tab_result = list()
if self.Sejour: if self.Sejour:
ArrTime = datetime.strftime(self.Sejour.arrival_time,"%H:%M") arr_time = datetime.strftime(self.Sejour.arrival_time, "%H:%M")
DepTime = datetime.strftime(self.Sejour.depart_time,"%H:%M") dep_time = datetime.strftime(self.Sejour.depart_time, "%H:%M")
for hour in range(24): for hour in range(24):
for minutes in range(0,60,10): for minutes in range(0, 60, 10):
StrTime = "%.2d:%.2d" % (hour, minutes) str_time = "%.2d:%.2d" % (hour, minutes)
DispTime = "%dh%.2d" % (hour, minutes) disp_time = "%dh%.2d" % (hour, minutes)
if typedate == "arrival" and StrTime==ArrTime: if type_date == "arrival" and str_time == arr_time:
TabResult.append( (StrTime, DispTime, 'selected="selected"') ) tab_result.append((str_time, disp_time, 'selected="selected"'))
elif typedate == "departure" and StrTime==DepTime: elif type_date == "departure" and str_time == dep_time:
TabResult.append( (StrTime, DispTime, 'selected="selected"') ) tab_result.append((str_time, disp_time, 'selected="selected"'))
else: else:
TabResult.append( (StrTime, DispTime, "") ) tab_result.append((str_time, disp_time, ""))
return TabResult return tab_result
def IsCheck(self, InputControl): def IsCheck(self, InputControl):
ListControlA = ['Arrival', 'Departure'] list_control_a = ['Arrival', 'Departure']
ListControlB = ['PMR', 'Cov', 'Bras', 'Other'] list_control_b = ['PMR', 'Cov', 'Bras', 'Other']
if InputControl not in map(':'.join, itertools.product(ListControlA, ListControlB)): if InputControl not in map(':'.join, itertools.product(list_control_a, list_control_b)):
return "" return ""
if self.Sejour: if self.Sejour:
if InputControl.startswith('Arrival'): if InputControl.startswith('Arrival'):
CtrlVal = 2**ListControlB.index(InputControl[8:]) ctrl_val = 2 ** list_control_b.index(InputControl[8:])
if self.Sejour.arrival_check & CtrlVal == CtrlVal: if self.Sejour.arrival_check & ctrl_val == ctrl_val:
return "checked=\"checked\"" return "checked=\"checked\""
else: else:
return "" return ""
elif InputControl.startswith('Departure'): elif InputControl.startswith('Departure'):
CtrlVal = 2**ListControlB.index(InputControl[10:]) ctrl_val = 2 ** list_control_b.index(InputControl[10:])
if self.Sejour.depart_check & CtrlVal == CtrlVal: if self.Sejour.depart_check & ctrl_val == ctrl_val:
return "checked=\"checked\"" return "checked=\"checked\""
else: else:
return "" return ""
@@ -107,6 +114,7 @@ class Sejour_helpers(DummySejour):
else: else:
return "" return ""
class Orga_helpers(DummySejour): class Orga_helpers(DummySejour):
def __init__(self, event): def __init__(self, event):
@@ -132,7 +140,7 @@ class Orga_helpers(DummySejour):
] ]
def IsChecked(self, nb): def IsChecked(self, nb):
nb = 2**nb nb = 2 ** nb
if self.Sejour and self.Sejour.orga_part: if self.Sejour and self.Sejour.orga_part:
if self.Sejour.orga_part & nb == nb: if self.Sejour.orga_part & nb == nb:
return "checked=\"checked\"" return "checked=\"checked\""
@@ -143,9 +151,9 @@ class Orga_helpers(DummySejour):
def ChoosedList(self): def ChoosedList(self):
""" Return choice validated by user """ """ Return choice validated by user """
ListOrga = [] list_orga = []
for num in range(0,len(self.Orga_tasks)): for num in range(0, len(self.Orga_tasks)):
curs = 2**num curs = 2 ** num
if self.Sejour.orga_part & curs == curs: if self.Sejour.orga_part & curs == curs:
ListOrga.append(self.Orga_tasks[num]) list_orga.append(self.Orga_tasks[num])
return ListOrga return list_orga
+351 -324
View File
@@ -15,85 +15,98 @@ from sqlalchemy import (
Enum, Enum,
Boolean, Boolean,
ForeignKey ForeignKey
) )
from slugify import slugify from slugify import slugify
from webhelpers.text import urlify # from webhelpers.text import urlify
from webhelpers.paginate import PageURL_WebOb, Page from paginate import Page # PageURL_WebOb
from webhelpers.date import time_ago_in_words
from webhelpers2.date import time_ago_in_words
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import ( from sqlalchemy.orm import (
scoped_session, scoped_session,
sessionmaker sessionmaker
) )
from zope.sqlalchemy import ZopeTransactionExtension # from zope.sqlalchemy import ZopeTransactionExtension
from zope.sqlalchemy import register
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
from passlib.hash import argon2 from passlib.hash import argon2
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
def urlify(in_string, in_string_length):
return ''.join('%20' if c == ' ' else c for c in in_string[:in_string_length])
DBSession = scoped_session(sessionmaker(autoflush=False))
register(DBSession)
# DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base() Base = declarative_base()
class TasksArea(Base): class TasksArea(Base):
__tablename__ = 'staff_tasks_area' __tablename__ = 'staff_tasks_area'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
name = Column(Unicode(80)) name = Column(Unicode(80))
description = Column(UnicodeText) description = Column(UnicodeText)
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
return DBSession.query(cls).filter(cls.uid == uid).first() return DBSession.query(cls).filter(cls.uid == uid).first()
class Tasks(Base): class Tasks(Base):
__tablename__ = 'staff_tasks' __tablename__ = 'staff_tasks'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
area_uid = Column(Integer, ForeignKey('staff_tasks_area.uid') ) area_uid = Column(Integer, ForeignKey('staff_tasks_area.uid'))
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
due_date = Column(DateTime, default=None) due_date = Column(DateTime, default=None)
closed_by = Column(Integer, ForeignKey('users.uid') ) closed_by = Column(Integer, ForeignKey('users.uid'))
closed_date = Column(DateTime, default=None) closed_date = Column(DateTime, default=None)
closed = Column(Integer, default=0) closed = Column(Integer, default=0)
name = Column(Unicode(80)) name = Column(Unicode(80))
description = Column(UnicodeText) description = Column(UnicodeText)
area = relationship(TasksArea, backref=backref("tasks") ) area = relationship(TasksArea, backref=backref("tasks"))
assignee = relationship('User', backref=backref("task_assoc") ) assignee = relationship('User', backref=backref("task_assoc"))
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
return DBSession.query(cls).filter(cls.uid == uid).first() return DBSession.query(cls).filter(cls.uid == uid).first()
class User_Event(Base): class User_Event(Base):
""" Créer le lien entre la personne et l' évenement en fonction de l'année""" """ Créer le lien entre la personne et l' évenement en fonction de l'année"""
__tablename__ = 'user_event_link' __tablename__ = 'user_event_link'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
event_uid = Column(Integer, ForeignKey('events.uid') ) event_uid = Column(Integer, ForeignKey('events.uid'))
#, primary_key=True) # , primary_key=True)
# #
user_uid = Column(Integer, ForeignKey('users.uid') ) user_uid = Column(Integer, ForeignKey('users.uid'))
#, primary_key=True) # , primary_key=True)
# #
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
role = Column(Unicode(80)) role = Column(Unicode(80))
# Define some relation # Define some relation
#user = relationship('User', backref=backref("events_assoc") ) # user = relationship('User', backref=backref("events_assoc") )
#event = relationship('events', backref=backref("users_assoc") ) # event = relationship('events', backref=backref("users_assoc") )
class JM2L_Year(Base): class JM2L_Year(Base):
__tablename__ = 'jm2l_year' __tablename__ = 'jm2l_year'
year_uid = Column(Integer, primary_key=True) year_uid = Column(Integer, primary_key=True)
description = Column(UnicodeText) description = Column(UnicodeText)
doss_presse = Column(UnicodeText) doss_presse = Column(UnicodeText)
state = Column(Enum('Archived', 'Cancelled', 'Ongoing')) state = Column(Enum('Archived', 'Cancelled', 'Ongoing'))
start_time = Column(DateTime, default=datetime.datetime.now) start_time = Column(DateTime, default=datetime.datetime.now)
end_time = Column(DateTime, default=datetime.datetime.now) end_time = Column(DateTime, default=datetime.datetime.now)
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
@classmethod @classmethod
def get_latest_jm2l_startdate(cls, fakeparam=None): def get_latest_jm2l_startdate(cls, fakeparam=None):
@@ -102,59 +115,60 @@ class JM2L_Year(Base):
.filter(JM2L_Year.start_time == .filter(JM2L_Year.start_time ==
DBSession.query(func.max(JM2L_Year.start_time)) DBSession.query(func.max(JM2L_Year.start_time))
).one() ).one()
return last_record.start_time.strftime("%A %d %B %Y").decode('utf-8') return last_record.start_time.strftime("%A %d %B %Y") # .decode('utf-8')
@property @property
def AvailableTimeSlots(self, TimeStep=30): def AvailableTimeSlots(self, TimeStep=30):
Available = self.end_time - self.start_time available = self.end_time - self.start_time
NbMinutes = Available.total_seconds()/60 nb_minutes = available.total_seconds() / 60
NbSteps = NbMinutes/TimeStep nb_steps = nb_minutes / TimeStep
# Create the range of date each 30min # Create the range of date each 30min
date_list = [self.start_time + datetime.timedelta(minutes=TimeStep*x) for x in range(0, int(NbSteps))] date_list = [self.start_time + datetime.timedelta(minutes=TimeStep * x) for x in range(0, int(nb_steps))]
# Remove out of range datetime # Remove out of range datetime
# Remove hours > 19h # Remove hours > 19h
date_list = filter(lambda x:x.hour < 19, date_list) date_list = filter(lambda x: x.hour < 19, date_list)
# Remove hours < 10h # Remove hours < 10h
date_list = filter(lambda x:x.hour >= 10, date_list) date_list = filter(lambda x: x.hour >= 10, date_list)
# Remove 12h < hours < 13h # Remove 12h < hours < 13h
date_list = filter(lambda x: x.hour<12 or x.hour>=13, date_list) date_list = filter(lambda x: x.hour < 12 or x.hour >= 13, date_list)
return date_list return list(date_list)
@property @property
def DocLinks(self): def DocLinks(self):
from .upload import MediaPath from .upload import MediaPath
return sorted(MediaPath().get_all('presse', self.year_uid)) return sorted(MediaPath().get_all('presse', self.year_uid))
class User(Base): class User(Base):
__tablename__ = 'users' __tablename__ = 'users'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
user_id = Column(Integer) user_id = Column(Integer)
nom = Column(Unicode(80)) nom = Column(Unicode(80))
prenom = Column(Unicode(80)) prenom = Column(Unicode(80))
pseudo = Column(Unicode(80)) pseudo = Column(Unicode(80))
slug = Column(Unicode(164)) slug = Column(Unicode(164))
mail = Column(Unicode(100)) mail = Column(Unicode(100))
password = Column(Unicode(100), nullable=False) password = Column(Unicode(100), nullable=False)
fonction = Column(Unicode(80)) fonction = Column(Unicode(80))
website = Column(Unicode(100)) website = Column(Unicode(100))
phone = Column(Unicode(10)) phone = Column(Unicode(10))
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_logged = Column(DateTime, default=datetime.datetime.now) last_logged = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
active = Column(Integer, default=1) active = Column(Integer, default=1)
bio = Column(UnicodeText) bio = Column(UnicodeText)
gpg_key = Column(UnicodeText) gpg_key = Column(UnicodeText)
soc_link = Column(UnicodeText) soc_link = Column(UnicodeText)
Staff = Column(Integer, default=0) Staff = Column(Integer, default=0)
vote_logo = Column(Integer, default=0) vote_logo = Column(Integer, default=0)
wifi_user = Column(Unicode(80), nullable=True) wifi_user = Column(Unicode(80), nullable=True)
wifi_pass = Column(Unicode(80), nullable=True) wifi_pass = Column(Unicode(80), nullable=True)
# relations # relations
tiers = relationship('Tiers', secondary='user_tiers_link' ) tiers = relationship('Tiers', secondary='user_tiers_link')
events = relationship('Event', secondary='user_event_link' ) events = relationship('Event', secondary='user_event_link')
tiersship = relationship('User_Tiers', backref="matching_users") tiersship = relationship('User_Tiers', backref="matching_users")
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
@@ -179,61 +193,59 @@ class User(Base):
@classmethod @classmethod
def by_hash(cls, tsthash): def by_hash(cls, tsthash):
for u in DBSession.query(cls): for u in DBSession.query(cls):
if u.my_hash==tsthash: if u.my_hash == tsthash:
return u return u
return None return None
@property @property
def is_Intervenant(self): def is_Intervenant(self):
""" This property will return if User do an event on specified year """ """ This property will return if User do an event on specified year """
return DBSession.query(Event).join(User_Event) \ return DBSession.query(Event).join(User_Event) \
.filter(User_Event.user_uid==self.uid) \ .filter(User_Event.user_uid == self.uid) \
.filter(Event.for_year==CurrentYear).count() .filter(Event.for_year == CurrentYear).count()
def is_IntervenantOnYear(self, year=CurrentYear): def is_IntervenantOnYear(self, year=CurrentYear):
""" This property will return if User do an event on specified year """ """ This property will return if User do an event on specified year """
return DBSession.query(Event).join(User_Event) \ return DBSession.query(Event).join(User_Event) \
.filter(User_Event.user_uid==self.uid) \ .filter(User_Event.user_uid == self.uid) \
.filter(Event.for_year==year).count() .filter(Event.for_year == year).count()
@property @property
def is_crew(self, year=CurrentYear): def is_crew(self, year=CurrentYear):
""" This property will return if User subscribe orga task on specified year """ """ This property will return if User subscribe orga task on specified year """
orga_checked = DBSession.query(User, Sejour.orga_part)\ orga_checked = DBSession.query(User, Sejour.orga_part) \
.outerjoin(Sejour) \ .outerjoin(Sejour) \
.filter(Sejour.for_year == year)\ .filter(Sejour.for_year == year) \
.filter(User.uid == self.uid).first() .filter(User.uid == self.uid).first()
if orga_checked: if orga_checked:
return orga_checked return orga_checked
else: else:
return False return False
def year_events(self, EventType='All', year=CurrentYear): def year_events(self, EventType='All', year=CurrentYear):
if EventType=='All': if EventType == 'All':
return filter(lambda e: e.for_year==year, self.events) return list(filter(lambda e: e.for_year == year, self.events))
else: else:
return filter(lambda e: e.for_year==year and e.event_type==EventType, self.events) return list(filter(lambda e: e.for_year == year and e.event_type == EventType, self.events))
@property @property
def my_hash(self): def my_hash(self):
m = hashlib.sha1() m = hashlib.sha1()
m.update("Nobody inspects ") m.update("Nobody inspects ".encode('utf-8'))
if self.nom: if self.nom:
m.update(unicode.encode(self.nom,'utf8')) m.update(self.nom.encode('utf-8')) # unicode.encode(self.nom, 'utf8'))
if self.pseudo: if self.pseudo:
m.update(unicode.encode(self.pseudo,'utf8')) m.update(self.pseudo.encode('utf-8')) # unicode.encode(self.pseudo, 'utf8'))
if self.prenom: if self.prenom:
m.update(unicode.encode(self.prenom,'utf8')) m.update(self.prenom.encode('utf-8')) # unicode.encode(self.prenom, 'utf8'))
m.update(" the spammish repetition") m.update(" the spammish repetition".encode('utf-8'))
return m.hexdigest() return m.hexdigest()
@property @property
def Photos(self): def Photos(self):
return DBSession.query(Media.filename) \ return DBSession.query(Media.filename) \
.filter(Media.media_table=='users') \ .filter(Media.media_table == 'users') \
.filter(Media.media_type=='Image') \ .filter(Media.media_type == 'Image') \
.filter(Media.link_id == self.user_id).all() .filter(Media.link_id == self.user_id).all()
@property @property
@@ -247,18 +259,19 @@ class User(Base):
return MediaPath().get_thumb('users', self.uid) return MediaPath().get_thumb('users', self.uid)
def verify_password(self, password): def verify_password(self, password):
if not argon2.identify(self.password): # Update existing clear-text password if not argon2.identify(self.password): # Update existing clear-text password
self.password = argon2.using(rounds=4).hash(self.password) self.password = argon2.using(rounds=4).hash(self.password)
DBSession.merge(self) DBSession.merge(self)
return argon2.verify(password, self.password) return argon2.verify(password, self.password)
class TiersOpt(Base): class TiersOpt(Base):
__tablename__ = 'tiers_opt' __tablename__ = 'tiers_opt'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
entity_type = Column(Unicode(80), nullable=False) entity_type = Column(Unicode(80), nullable=False)
entity_subtype = Column(Unicode(80)) entity_subtype = Column(Unicode(80))
entity_role = Column(Unicode(80)) entity_role = Column(Unicode(80))
@property @property
def slug_entity_type(self): def slug_entity_type(self):
@@ -270,42 +283,43 @@ class TiersOpt(Base):
@classmethod @classmethod
def get_entity_type(cls): def get_entity_type(cls):
return DBSession.query(cls, func.count(Tiers.ent_type).label('count'))\ return DBSession.query(cls, func.count(Tiers.ent_type).label('count')) \
.outerjoin(Tiers)\ .outerjoin(Tiers) \
.group_by(cls.entity_type).all() .group_by(cls.entity_type).all()
@classmethod @classmethod
def get_entity_sub_type(cls, entity_type): def get_entity_sub_type(cls, entity_type):
return DBSession.query(cls, func.count(Tiers.ent_type).label('count'))\ return DBSession.query(cls, func.count(Tiers.ent_type).label('count')) \
.outerjoin(Tiers)\ .outerjoin(Tiers) \
.filter(cls.entity_type == entity_type)\ .filter(cls.entity_type == entity_type) \
.group_by(cls.entity_subtype).all() .group_by(cls.entity_subtype).all()
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
return DBSession.query(cls).filter(cls.uid == uid).first() return DBSession.query(cls).filter(cls.uid == uid).first()
class Tiers(Base): class Tiers(Base):
__tablename__ = 'tiers' __tablename__ = 'tiers'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
tiers_id = Column(Integer) tiers_id = Column(Integer)
name = Column(Unicode(100), nullable=False) name = Column(Unicode(100), nullable=False)
slug = Column(Unicode(100)) slug = Column(Unicode(100))
description = Column(UnicodeText) description = Column(UnicodeText)
website = Column(Unicode(100)) website = Column(Unicode(100))
tiers_type = Column(Integer, ForeignKey('tiers_opt.uid'), default=1) tiers_type = Column(Integer, ForeignKey('tiers_opt.uid'), default=1)
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
# relations # relations
ent_type = relationship('TiersOpt') ent_type = relationship('TiersOpt')
#members = relationship('User', secondary='user_tiers_link' ) # members = relationship('User', secondary='user_tiers_link' )
members = relationship(User, members = relationship(User,
secondary='user_tiers_link', secondary='user_tiers_link',
backref=backref('associate', uselist=False), backref=backref('associate', uselist=False),
lazy='dynamic') lazy='dynamic')
creator_id = Column(Integer) creator_id = Column(Integer)
membership = relationship('User_Tiers', backref="matching_tiers") membership = relationship('User_Tiers', backref="matching_tiers")
roles = relationship('Role_Tiers', backref="roles_tiers") #secondary='role_tiers_link' ) roles = relationship('Role_Tiers', backref="roles_tiers") # secondary='role_tiers_link' )
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
@@ -317,7 +331,7 @@ class Tiers(Base):
@property @property
def get_entity_type(self): def get_entity_type(self):
return DBSession.query(TiersOpt)\ return DBSession.query(TiersOpt) \
.filter(TiersOpt.uid == self.tiers_type).first() .filter(TiersOpt.uid == self.tiers_type).first()
@property @property
@@ -330,9 +344,9 @@ class Tiers(Base):
@property @property
def DocLinks(self): def DocLinks(self):
from .upload import MediaPath from .upload import MediaPath
return zip( sorted( MediaPath().get_list('tiers', self.uid, 'Other') ), return zip(sorted(MediaPath().get_list('tiers', self.uid, 'Other')),
sorted( MediaPath().get_thumb('tiers', self.uid, 'Other') ) sorted(MediaPath().get_thumb('tiers', self.uid, 'Other'))
) )
@property @property
def PhotosLinks(self): def PhotosLinks(self):
@@ -344,55 +358,59 @@ class Tiers(Base):
from .upload import MediaPath from .upload import MediaPath
return MediaPath().get_thumb('tiers', self.uid) return MediaPath().get_thumb('tiers', self.uid)
class Role_Tiers(Base): class Role_Tiers(Base):
""" Créer le lien entre le tiers et son rôle dans l'évenement en fonction de l'année""" """ Créer le lien entre le tiers et son rôle dans l'évenement en fonction de l'année"""
__tablename__ = 'role_tiers_link' __tablename__ = 'role_tiers_link'
uid_role = Column(Integer, primary_key=True) uid_role = Column(Integer, primary_key=True)
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
tiers_uid = Column(Integer, ForeignKey('tiers.uid')) tiers_uid = Column(Integer, ForeignKey('tiers.uid'))
tiers = relationship(Tiers, backref=backref("roles_assoc") ) tiers = relationship(Tiers, backref=backref("roles_assoc"))
tiers_role = Column(Enum('Exposant', 'Sponsor', 'Donateur')) tiers_role = Column(Enum('Exposant', 'Sponsor', 'Donateur'))
event_uid = Column(Integer, default=None) # Optionnal link with Event event_uid = Column(Integer, default=None) # Optionnal link with Event
class User_Tiers(Base): class User_Tiers(Base):
""" Créer le lien entre la personne et le tiers en fonction de l'année""" """ Créer le lien entre la personne et le tiers en fonction de l'année"""
__tablename__ = 'user_tiers_link' __tablename__ = 'user_tiers_link'
uid_tiers = Column(Integer, primary_key=True) uid_tiers = Column(Integer, primary_key=True)
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
tiers_uid = Column(Integer, ForeignKey('tiers.uid')) tiers_uid = Column(Integer, ForeignKey('tiers.uid'))
tiers = relationship(Tiers, backref=backref("users_assoc") ) tiers = relationship(Tiers, backref=backref("users_assoc"))
user_uid = Column(Integer, ForeignKey('users.uid')) user_uid = Column(Integer, ForeignKey('users.uid'))
user = relationship(User, backref=backref("tiers_assoc") ) user = relationship(User, backref=backref("tiers_assoc"))
role = Column(Unicode(80)) role = Column(Unicode(80))
class Media(Base): class Media(Base):
__tablename__ = 'medias' __tablename__ = 'medias'
media_id = Column(Integer, primary_key=True) media_id = Column(Integer, primary_key=True)
for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) for_year = Column(Integer, ForeignKey('jm2l_year.year_uid'))
media_table = Column(Enum('users', 'tiers', 'place', 'salle', 'RIB', 'Justif', 'event' )) media_table = Column(Enum('users', 'tiers', 'place', 'salle', 'RIB', 'Justif', 'event'))
media_type = Column(Enum('Image', 'Video', 'Pres', 'Document')) media_type = Column(Enum('Image', 'Video', 'Pres', 'Document'))
link_id = Column(Integer) link_id = Column(Integer)
mime_type = Column(Unicode(20)) mime_type = Column(Unicode(20))
size = Column(Integer) size = Column(Integer)
width = Column(Integer) width = Column(Integer)
height = Column(Integer) height = Column(Integer)
length = Column(Integer) length = Column(Integer)
filename = Column(UnicodeText) filename = Column(UnicodeText)
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
@property @property
def get_path(self): def get_path(self):
#return '/upload/%s/%s/%s' % (self.media_type, self.media_table, self.filename) # return '/upload/%s/%s/%s' % (self.media_type, self.media_table, self.filename)
return '/resources/%s/%s/%s' % (self.for_year, self.media_type, self.filename) return '/resources/%s/%s/%s' % (self.for_year, self.media_type, self.filename)
class SallePhy(Base): class SallePhy(Base):
""" Représente une salle dans les locaux """ """ Représente une salle dans les locaux """
__tablename__ = 'phy_salle' __tablename__ = 'phy_salle'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
name = Column(Unicode(40)) # Numéro de salle vu de polytech name = Column(Unicode(40)) # Numéro de salle vu de polytech
slug = Column(Unicode(40)) slug = Column(Unicode(40))
description = Column(UnicodeText) # Description du matériel disponible description = Column(UnicodeText) # Description du matériel disponible
nb_places = Column(Integer, default=0) # Nombre de places assises nb_places = Column(Integer, default=0) # Nombre de places assises
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
@@ -403,41 +421,44 @@ class SallePhy(Base):
from .upload import MediaPath from .upload import MediaPath
return MediaPath().get_list('salle', self.uid, 'Image') return MediaPath().get_list('salle', self.uid, 'Image')
class Salles(Base): class Salles(Base):
__tablename__ = 'salle' __tablename__ = 'salle'
salle_id = Column(Integer, primary_key=True) salle_id = Column(Integer, primary_key=True)
phy_salle_id = Column(Integer, ForeignKey('phy_salle.uid')) phy_salle_id = Column(Integer, ForeignKey('phy_salle.uid'))
year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear) year_uid = Column(Integer, ForeignKey('jm2l_year.year_uid'), default=CurrentYear)
name = Column(Unicode(40)) name = Column(Unicode(40))
place_type = Column(Enum('Conference', 'Stand', 'Atelier', 'Table ronde', 'MAO', 'Repas', 'Autres')) place_type = Column(Enum('Conference', 'Stand', 'Atelier', 'Table ronde', 'MAO', 'Repas', 'Autres'))
description = Column(UnicodeText) # Description du matériel disponible description = Column(UnicodeText) # Description du matériel disponible
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
phy = relationship(SallePhy)
phy = relationship(SallePhy)
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
return DBSession.query(cls).filter(cls.salle_id == uid).first() return DBSession.query(cls).filter(cls.salle_id == uid).first()
class Place(Base): class Place(Base):
__tablename__ = 'place' __tablename__ = 'place'
place_id = Column(Integer, primary_key=True) place_id = Column(Integer, primary_key=True)
usage = Column(Boolean, default=False) # By Default / Extended usage = Column(Boolean, default=False) # By Default / Extended
place_type = Column(Enum('Aeroport', 'Gare', 'JM2L', \ place_type = Column(Enum('Aeroport', 'Gare', 'JM2L', \
'Hotel', 'Habitant', 'Restaurant', 'Autres')) 'Hotel', 'Habitant', 'Restaurant', 'Autres'))
display_name = Column(Unicode(20)) display_name = Column(Unicode(20))
name = Column(Unicode(80)) name = Column(Unicode(80))
slug = Column(Unicode(80)) slug = Column(Unicode(80))
specific = Column(Unicode(80)) # eg Terminal 2 specific = Column(Unicode(80)) # eg Terminal 2
gps_coord = Column(Unicode(30)) gps_coord = Column(Unicode(30))
adresse = Column(Unicode(100)) adresse = Column(Unicode(100))
codePostal = Column(Unicode(5)) codePostal = Column(Unicode(5))
ville = Column(Unicode(40)) ville = Column(Unicode(40))
website = Column(Unicode(100)) website = Column(Unicode(100))
description = Column(UnicodeText) description = Column(UnicodeText)
created_by = Column(Integer, ForeignKey('users.user_id')) created_by = Column(Integer, ForeignKey('users.user_id'))
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
@@ -448,67 +469,70 @@ class Place(Base):
if All: if All:
return DBSession.query(cls).all() return DBSession.query(cls).all()
else: else:
return DBSession.query(cls).filter(cls.usage==True).all() return DBSession.query(cls).filter(cls.usage == True).all()
class Itineraire(Base): class Itineraire(Base):
__tablename__ = 'itineraire' __tablename__ = 'itineraire'
itin_id = Column(Integer, primary_key=True) itin_id = Column(Integer, primary_key=True)
start_place = Column(Integer, ForeignKey('place.place_id')) # Place link start_place = Column(Integer, ForeignKey('place.place_id')) # Place link
arrival_place = Column(Integer, ForeignKey('place.place_id')) # Place link arrival_place = Column(Integer, ForeignKey('place.place_id')) # Place link
distance = Column(Integer) distance = Column(Integer)
duration = Column(Integer) duration = Column(Integer)
price = Column(Integer) price = Column(Integer)
tr_pied = Column(Boolean, default=False) tr_pied = Column(Boolean, default=False)
tr_velo = Column(Boolean, default=False) tr_velo = Column(Boolean, default=False)
tr_moto = Column(Boolean, default=False) tr_moto = Column(Boolean, default=False)
tr_voiture = Column(Boolean, default=False) tr_voiture = Column(Boolean, default=False)
tr_bus = Column(Boolean, default=False) tr_bus = Column(Boolean, default=False)
tr_taxi = Column(Boolean, default=False) tr_taxi = Column(Boolean, default=False)
tr_avion = Column(Boolean, default=False) tr_avion = Column(Boolean, default=False)
description = Column(UnicodeText) description = Column(UnicodeText)
created_by = Column(Integer, ForeignKey('users.user_id')) # User link created_by = Column(Integer, ForeignKey('users.user_id')) # User link
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
# relations # relations
start = relationship(Place, foreign_keys=[start_place]) start = relationship(Place, foreign_keys=[start_place])
arrival = relationship(Place, foreign_keys=[arrival_place]) arrival = relationship(Place, foreign_keys=[arrival_place])
class Exchange_Cat(Base): class Exchange_Cat(Base):
__tablename__ = 'exchange_category' __tablename__ = 'exchange_category'
cat_id = Column(Integer, primary_key=True) cat_id = Column(Integer, primary_key=True)
exch_type = Column(Enum('H', 'C', 'M')) # Heberg, Co-voit, Materiel exch_type = Column(Enum('H', 'C', 'M')) # Heberg, Co-voit, Materiel
exch_subtype = Column(Unicode(80)) exch_subtype = Column(Unicode(80))
description = Column(UnicodeText) description = Column(UnicodeText)
class Exchange(Base): class Exchange(Base):
__tablename__ = 'exchanges' __tablename__ = 'exchanges'
exch_id = Column(Integer, primary_key=True) exch_id = Column(Integer, primary_key=True)
for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year
exch_done = Column(Boolean, default=False) exch_done = Column(Boolean, default=False)
exch_state = Column(Enum('Ask', 'Proposal')) exch_state = Column(Enum('Ask', 'Proposal'))
exch_type = Column(Enum('H', 'C', 'M')) # Heberg, Co-Voit, Materiel exch_type = Column(Enum('H', 'C', 'M')) # Heberg, Co-Voit, Materiel
exch_categ = Column(Integer, ForeignKey('exchange_category.cat_id')) # Exchange_Cat link exch_categ = Column(Integer, ForeignKey('exchange_category.cat_id')) # Exchange_Cat link
# Users # Users
asker_id = Column(Integer, ForeignKey('users.uid')) # User link asker_id = Column(Integer, ForeignKey('users.uid')) # User link
provider_id = Column(Integer, ForeignKey('users.uid')) # User link provider_id = Column(Integer, ForeignKey('users.uid')) # User link
start_time = Column(DateTime, default=datetime.datetime.now) start_time = Column(DateTime, default=datetime.datetime.now)
end_time = Column(DateTime, default=datetime.datetime.now) end_time = Column(DateTime, default=datetime.datetime.now)
# Co-voiturage # Co-voiturage
itin_id = Column(Integer, ForeignKey('itineraire.itin_id')) # Itineraire link itin_id = Column(Integer, ForeignKey('itineraire.itin_id')) # Itineraire link
# Hebergement # Hebergement
place_id = Column(Integer, ForeignKey('place.place_id')) # Place link place_id = Column(Integer, ForeignKey('place.place_id')) # Place link
# Materiel # Materiel
duration = Column(Integer) duration = Column(Integer)
description = Column(UnicodeText) description = Column(UnicodeText)
pictures = Column(Unicode(80)) pictures = Column(Unicode(80))
created_by = Column(Integer) # User link created_by = Column(Integer) # User link
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
# relations # relations
Category = relationship(Exchange_Cat, backref="exchanges") Category = relationship(Exchange_Cat, backref="exchanges")
Itin = relationship(Itineraire, backref="exchanged") Itin = relationship(Itineraire, backref="exchanged")
asker = relationship(User, foreign_keys=[asker_id], backref="asked") asker = relationship(User, foreign_keys=[asker_id], backref="asked")
provider = relationship(User, foreign_keys=[provider_id], backref="provided") provider = relationship(User, foreign_keys=[provider_id], backref="provided")
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
@@ -516,44 +540,44 @@ class Exchange(Base):
@classmethod @classmethod
def get_counters(cls): def get_counters(cls):
return DBSession.query(cls.exch_state, cls.exch_type, cls.exch_done, func.count(cls.exch_id))\ return DBSession.query(cls.exch_state, cls.exch_type, cls.exch_done, func.count(cls.exch_id)) \
.filter(cls.for_year==CurrentYear)\ .filter(cls.for_year == CurrentYear) \
.group_by(cls.exch_state, cls.exch_type, cls.exch_done) .group_by(cls.exch_state, cls.exch_type, cls.exch_done)
@classmethod @classmethod
def get_my_counters(cls, uid): def get_my_counters(cls, uid):
return DBSession.query(cls.exch_state, cls.exch_type, cls.exch_done, func.count(cls.exch_id))\ return DBSession.query(cls.exch_state, cls.exch_type, cls.exch_done, func.count(cls.exch_id)) \
.filter(cls.for_year==CurrentYear)\ .filter(cls.for_year == CurrentYear) \
.filter( or_(cls.asker_id==uid, cls.provider_id==uid) )\ .filter(or_(cls.asker_id == uid, cls.provider_id == uid)) \
.group_by(cls.exch_state, cls.exch_type, cls.exch_done) .group_by(cls.exch_state, cls.exch_type, cls.exch_done)
@classmethod @classmethod
def get_overview(cls, uid): def get_overview(cls, uid):
# Build a Dic with all exchange to save database access # Build a Dic with all exchange to save database access
DicResult= {} DicResult = {}
for extype in ['F','C','H','M']: for extype in ['F', 'C', 'H', 'M']:
DicResult[extype] = {} DicResult[extype] = {}
for exstate in ['Ask','Proposal','Missing','Agree']: for exstate in ['Ask', 'Proposal', 'Missing', 'Agree']:
DicResult[extype][exstate]=[] DicResult[extype][exstate] = []
DicResult[extype]['Counters']={'AllAsk':0, 'AllProp':0, 'AllAgree':0} DicResult[extype]['Counters'] = {'AllAsk': 0, 'AllProp': 0, 'AllAgree': 0}
Query = DBSession.query(cls)\ Query = DBSession.query(cls) \
.filter(cls.for_year==CurrentYear)\ .filter(cls.for_year == CurrentYear) \
.order_by(cls.start_time).all() .order_by(cls.start_time).all()
for item in Query: for item in Query:
if item.exch_done: if item.exch_done:
DicResult[item.exch_type]['Counters']['AllAgree']+=1 DicResult[item.exch_type]['Counters']['AllAgree'] += 1
if item.exch_state=='Ask': if item.exch_state == 'Ask':
DicResult[item.exch_type]['Counters']['AllAsk']+=1 DicResult[item.exch_type]['Counters']['AllAsk'] += 1
if item.exch_state=='Proposal': if item.exch_state == 'Proposal':
DicResult[item.exch_type]['Counters']['AllProp']+=1 DicResult[item.exch_type]['Counters']['AllProp'] += 1
if item.asker_id==uid or item.provider_id==uid: if item.asker_id == uid or item.provider_id == uid:
if item.asker_id==uid and item.exch_state=='Ask': if item.asker_id == uid and item.exch_state == 'Ask':
DicResult[item.exch_type]['Ask'].append(item) DicResult[item.exch_type]['Ask'].append(item)
if item.provider_id==uid and item.exch_state=='Ask': if item.provider_id == uid and item.exch_state == 'Ask':
DicResult[item.exch_type]['Proposal'].append(item) DicResult[item.exch_type]['Proposal'].append(item)
if item.asker_id==uid and item.exch_state=='Proposal': if item.asker_id == uid and item.exch_state == 'Proposal':
DicResult[item.exch_type]['Ask'].append(item) DicResult[item.exch_type]['Ask'].append(item)
if item.provider_id==uid and item.exch_state=='Proposal': if item.provider_id == uid and item.exch_state == 'Proposal':
DicResult[item.exch_type]['Proposal'].append(item) DicResult[item.exch_type]['Proposal'].append(item)
if item.exch_done: if item.exch_done:
DicResult[item.exch_type]['Agree'].append(item) DicResult[item.exch_type]['Agree'].append(item)
@@ -564,99 +588,100 @@ class Exchange(Base):
@classmethod @classmethod
def get_pub_list(cls, exch_type): def get_pub_list(cls, exch_type):
return DBSession.query(cls).filter(cls.for_year==CurrentYear and cls.exch_state in ['Ask','Proposal'])\ return DBSession.query(cls).filter(cls.for_year == CurrentYear and cls.exch_state in ['Ask', 'Proposal']) \
.filter(cls.exch_type=='%s' % exch_type)\ .filter(cls.exch_type == '%s' % exch_type) \
.filter(cls.exch_done==False)\ .filter(cls.exch_done == False) \
.all() .all()
@classmethod @classmethod
def get_my_list(cls, uid, exch_type): def get_my_list(cls, uid, exch_type):
DicResult = {} DicResult = {}
DicResult['Ask']=DBSession.query(cls)\ DicResult['Ask'] = DBSession.query(cls) \
.filter(cls.for_year==CurrentYear)\ .filter(cls.for_year == CurrentYear) \
.filter( or_(cls.asker_id==uid, cls.provider_id==uid) )\ .filter(or_(cls.asker_id == uid, cls.provider_id == uid)) \
.filter(cls.exch_type=='%s' % exch_type)\ .filter(cls.exch_type == '%s' % exch_type) \
.filter(cls.exch_state=='Ask')\ .filter(cls.exch_state == 'Ask') \
.order_by(cls.start_time).all() .order_by(cls.start_time).all()
DicResult['Proposal']=DBSession.query(cls)\ DicResult['Proposal'] = DBSession.query(cls) \
.filter(cls.for_year==CurrentYear)\ .filter(cls.for_year == CurrentYear) \
.filter( or_(cls.asker_id==uid, cls.provider_id==uid) )\ .filter(or_(cls.asker_id == uid, cls.provider_id == uid)) \
.filter(cls.exch_type=='%s' % exch_type)\ .filter(cls.exch_type == '%s' % exch_type) \
.filter(cls.exch_state=='Proposal')\ .filter(cls.exch_state == 'Proposal') \
.order_by(cls.start_time).all() .order_by(cls.start_time).all()
return DicResult return DicResult
class Sejour(Base): class Sejour(Base):
__tablename__ = 'sejour' __tablename__ = 'sejour'
sej_id = Column(Integer, primary_key=True) sej_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.uid')) # User link user_id = Column(Integer, ForeignKey('users.uid')) # User link
for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year
arrival_time = Column(DateTime) arrival_time = Column(DateTime)
arrival_place = Column(Integer, ForeignKey('place.place_id')) # Place link arrival_place = Column(Integer, ForeignKey('place.place_id')) # Place link
arrival_check = Column(Integer, default=0) arrival_check = Column(Integer, default=0)
arrival_text = Column(Unicode(100)) arrival_text = Column(Unicode(100))
depart_time = Column(DateTime) depart_time = Column(DateTime)
depart_place = Column(Integer, ForeignKey('place.place_id')) # Place link depart_place = Column(Integer, ForeignKey('place.place_id')) # Place link
depart_check = Column(Integer, default=0) depart_check = Column(Integer, default=0)
depart_text = Column(Unicode(100)) depart_text = Column(Unicode(100))
repas = Column(Integer) repas = Column(Integer)
repas_allerg = Column(Unicode(100)) repas_allerg = Column(Unicode(100))
repas_contr = Column(Unicode(100)) repas_contr = Column(Unicode(100))
orga_part = Column(Integer, default=0) orga_part = Column(Integer, default=0)
travel_detail = Column(UnicodeText) travel_detail = Column(UnicodeText)
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
@classmethod @classmethod
def by_user(cls, uid, year): def by_user(cls, uid, year):
return DBSession.query(cls)\ return DBSession.query(cls) \
.filter(cls.user_id == uid)\ .filter(cls.user_id == uid) \
.filter(cls.for_year == year)\ .filter(cls.for_year == year) \
.first() .first()
class Event(Base): class Event(Base):
__tablename__ = 'events' __tablename__ = 'events'
uid = Column(Integer, primary_key=True) uid = Column(Integer, primary_key=True)
salle_uid = Column(Integer, ForeignKey('salle.salle_id')) salle_uid = Column(Integer, ForeignKey('salle.salle_id'))
event_uid = Column(Integer) event_uid = Column(Integer)
for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year for_year = Column(Integer, ForeignKey('jm2l_year.year_uid')) # link JM2L_Year
name = Column(Unicode(100), nullable=False) name = Column(Unicode(100), nullable=False)
slug = Column(Unicode(100)) slug = Column(Unicode(100))
event_type = Column(Enum('Conference', 'Stand', 'Atelier', 'Table ronde', 'MAO', 'Repas', 'Autres')) event_type = Column(Enum('Conference', 'Stand', 'Atelier', 'Table ronde', 'MAO', 'Repas', 'Autres'))
start_time = Column(DateTime, default=datetime.datetime.now) start_time = Column(DateTime, default=datetime.datetime.now)
end_time = Column(DateTime, default=datetime.datetime.now) end_time = Column(DateTime, default=datetime.datetime.now)
description = Column(UnicodeText) description = Column(UnicodeText)
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
last_change = Column(DateTime, default=datetime.datetime.now) last_change = Column(DateTime, default=datetime.datetime.now)
intervenants = relationship(User, intervenants = relationship(User,
secondary='user_event_link', secondary='user_event_link',
backref=backref('participate', uselist=False), backref=backref('participate', uselist=False),
lazy='dynamic') lazy='subquery')
interventions = relationship(User_Event, backref="matching_events") interventions = relationship(User_Event, backref="matching_events")
Salle = relationship(Salles, backref='allevents') Salle = relationship(Salles, backref='allevents')
@classmethod @classmethod
def by_id(cls, uid): def by_id(cls, uid):
return DBSession.query(cls)\ return DBSession.query(cls) \
.filter(cls.uid == uid).first() .filter(cls.uid == uid).first()
@classmethod @classmethod
def by_slug(cls, slug, year=None): def by_slug(cls, slug, year=None):
if not year is None: if not year is None:
return DBSession.query(cls)\ return DBSession.query(cls) \
.filter(cls.for_year==year)\ .filter(cls.for_year == year) \
.filter(cls.slug == slug).first() .filter(cls.slug == slug).first()
else: else:
return DBSession.query(cls)\ return DBSession.query(cls) \
.filter(cls.slug == slug).first() .filter(cls.slug == slug).first()
def get_linked_tiers(self): def get_linked_tiers(self):
ListLink = DBSession.query(Role_Tiers.tiers_uid) \ ListLink = DBSession.query(Role_Tiers.tiers_uid) \
.filter(Role_Tiers.year_uid==self.for_year) \ .filter(Role_Tiers.year_uid == self.for_year) \
.filter(Role_Tiers.tiers_role=="Exposant") \ .filter(Role_Tiers.tiers_role == "Exposant") \
.filter(Role_Tiers.event_uid==self.uid) .filter(Role_Tiers.event_uid == self.uid)
return DBSession.query(Tiers).filter( Tiers.uid.in_( ListLink ) ) return DBSession.query(Tiers).filter(Tiers.uid.in_(ListLink))
@property @property
def video(self): def video(self):
@@ -676,14 +701,15 @@ class Event(Base):
def created_in_words(self): def created_in_words(self):
return time_ago_in_words(self.created) return time_ago_in_words(self.created)
class Entry(Base): class Entry(Base):
__tablename__ = 'entries' __tablename__ = 'entries'
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
active = Column(Integer, default=True) active = Column(Integer, default=True)
title = Column(Unicode(255), unique=True, nullable=False) title = Column(Unicode(255), unique=True, nullable=False)
body = Column(UnicodeText, default=u'') body = Column(UnicodeText, default=u'')
created = Column(DateTime, default=datetime.datetime.now) created = Column(DateTime, default=datetime.datetime.now)
edited = Column(DateTime, default=datetime.datetime.now) edited = Column(DateTime, default=datetime.datetime.now)
@classmethod @classmethod
def all(cls): def all(cls):
@@ -706,7 +732,8 @@ class Entry(Base):
page_url = PageURL_WebOb(request) page_url = PageURL_WebOb(request)
return Page(Entry.all(), page, url=page_url, items_per_page=5) return Page(Entry.all(), page, url=page_url, items_per_page=5)
#class Seances(Base):
# class Seances(Base):
# __tablename__ = 'seances' # __tablename__ = 'seances'
def get_user(request): def get_user(request):
# the below line is just an example, use your own method of # the below line is just an example, use your own method of
@@ -717,28 +744,28 @@ def get_user(request):
if userid is not None: if userid is not None:
# this should return None if the user doesn't exist # this should return None if the user doesn't exist
# in the database # in the database
return DBSession.query(User).filter(User.uid==userid).first() return DBSession.query(User).filter(User.uid == userid).first()
def get_sponsors(request, Year): def get_sponsors(request, Year):
if Year: if Year:
return DBSession.query(Tiers)\ return DBSession.query(Tiers) \
.join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid )\ .join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid) \
.filter( Role_Tiers.tiers_role == 'Sponsor')\ .filter(Role_Tiers.tiers_role == 'Sponsor') \
.filter( Role_Tiers.year_uid == Year) .filter(Role_Tiers.year_uid == Year)
else: else:
return DBSession.query(Tiers)\ return DBSession.query(Tiers) \
.join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid )\ .join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid) \
.filter( Role_Tiers.tiers_role == 'Sponsor') .filter(Role_Tiers.tiers_role == 'Sponsor')
def get_exposants(request, Year): def get_exposants(request, Year):
if Year: if Year:
return DBSession.query(Tiers)\ return DBSession.query(Tiers) \
.join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid )\ .join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid) \
.filter( Role_Tiers.tiers_role == 'Exposant')\ .filter(Role_Tiers.tiers_role == 'Exposant') \
.filter( Role_Tiers.year_uid == Year) .filter(Role_Tiers.year_uid == Year)
else: else:
return DBSession.query(Tiers)\ return DBSession.query(Tiers) \
.join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid )\ .join(Role_Tiers, Role_Tiers.tiers_uid == Tiers.uid) \
.filter( Role_Tiers.tiers_role == 'Exposant') .filter(Role_Tiers.tiers_role == 'Exposant')
+12 -13
View File
@@ -48,14 +48,14 @@ def pull_data(from_db, to_db, tables):
destination, dengine = make_session(to_db) destination, dengine = make_session(to_db)
for table_name in tables: for table_name in tables:
print 'Processing', table_name print('Processing', table_name)
print 'Pulling schema from source server' print('Pulling schema from source server')
table = Table(table_name, smeta, autoload=True) table = Table(table_name, smeta, autoload=True)
print 'Creating table on destination server' print('Creating table on destination server')
table.metadata.create_all(dengine) table.metadata.create_all(dengine)
NewRecord = quick_mapper(table) NewRecord = quick_mapper(table)
columns = table.columns.keys() columns = table.columns.keys()
print 'Transferring records' print('Transferring records')
for record in source.query(table).all(): for record in source.query(table).all():
data = dict( data = dict(
[(str(column), getattr(record, column)) for column in columns] [(str(column), getattr(record, column)) for column in columns]
@@ -69,20 +69,20 @@ def pull_data(from_db, to_db, tables):
try: try:
destination.merge(NewRecord(**data)) destination.merge(NewRecord(**data))
except: except:
print data print(data)
pass pass
print 'Committing changes' print('Committing changes')
destination.commit() destination.commit()
def main(argv=sys.argv): def main(argv=sys.argv):
connection_string = "sqlite:////home/tr4ck3ur/Dev/jm2l/JM2L.sqlite" connection_string = "sqlite:////home/tr4ck3ur/git_repository/jm2l/JM2L.sqlite"
engine = create_engine(connection_string, echo=False, convert_unicode=True) engine = create_engine(connection_string, echo=False, convert_unicode=True)
DBSession.configure(bind=engine) DBSession.configure(bind=engine)
Users = DBSession.query(User) Users = DBSession.query(User)
ListUser = filter(lambda x: x.is_Intervenant, Users) ListUser = filter(lambda x: x.is_Intervenant, Users)
for i in ListUser: for i in ListUser:
print i.mail print(i.mail)
def main4(argv=sys.argv): def main4(argv=sys.argv):
import csv import csv
@@ -116,7 +116,7 @@ def main4(argv=sys.argv):
u.wifi_user = w_user u.wifi_user = w_user
u.wifi_pass = w_pass u.wifi_pass = w_pass
DBSession.merge(u) DBSession.merge(u)
print row, u print(row, u)
finally: finally:
f.close() f.close()
@@ -130,7 +130,7 @@ def main_3(argv=sys.argv):
connection_string = "sqlite:////home/tr4ck3ur/Dev/jm2l/JM2L.sqlite" connection_string = "sqlite:////home/tr4ck3ur/Dev/jm2l/JM2L.sqlite"
engine = create_engine(connection_string, echo=True, convert_unicode=True) engine = create_engine(connection_string, echo=True, convert_unicode=True)
DBSession.configure(bind=engine) DBSession.configure(bind=engine)
p0, p1 = orm.aliased(User,name="p0"), orm.aliased(User ,name="p1") p0, p1 = orm.aliased(User, name="p0"), orm.aliased(User , name="p1")
import pprint import pprint
## permtation ## permtation
@@ -141,7 +141,7 @@ def main_3(argv=sys.argv):
.filter(p0.last_logged<p1.last_logged)\ .filter(p0.last_logged<p1.last_logged)\
.with_entities(p0.slug,p0.uid,p1.uid).all() .with_entities(p0.slug,p0.uid,p1.uid).all()
for slug, idsrc, iddst in Datas: for slug, idsrc, iddst in Datas:
print slug print(slug)
# Events # Events
Events = DBSession.query(User_Event)\ Events = DBSession.query(User_Event)\
.filter(User_Event.user_uid==idsrc) .filter(User_Event.user_uid==idsrc)
@@ -238,5 +238,4 @@ def Initialize():
u.password = password u.password = password
u.Staff = 0 u.Staff = 0
DBSession.merge(u) DBSession.merge(u)
print u.nom, u.prenom, u.Staff print(u.nom, u.prenom, u.Staff)
+1
View File
@@ -15,6 +15,7 @@ def check_logged(request):
# Don't answer to users that aren't logged # Don't answer to users that aren't logged
raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.') raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
def check_staff(request): def check_staff(request):
""" This function is intended to raise an exception if the user is not a Staff member""" """ This function is intended to raise an exception if the user is not a Staff member"""
check_logged(request) check_logged(request)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1224px" height="792px" viewBox="0 0 1224 792" enable-background="new 0 0 1224 792" xml:space="preserve">
<g>
<path d="M833.556,367.574c-7.753-7.955-18.586-12.155-29.656-11.549l-133.981,7.458l73.733-83.975 c10.504-11.962,13.505-27.908,9.444-42.157c-2.143-9.764-8.056-18.648-17.14-24.324c-0.279-0.199-176.247-102.423-176.247-102.423 c-14.369-8.347-32.475-6.508-44.875,4.552l-85.958,76.676c-15.837,14.126-17.224,38.416-3.097,54.254 c14.128,15.836,38.419,17.227,54.255,3.096l65.168-58.131l53.874,31.285l-95.096,108.305 c-39.433,6.431-74.913,24.602-102.765,50.801l49.66,49.66c22.449-20.412,52.256-32.871,84.918-32.871 c69.667,0,126.346,56.68,126.346,126.348c0,32.662-12.459,62.467-32.869,84.916l49.657,49.66 c33.08-35.166,53.382-82.484,53.382-134.576c0-31.035-7.205-60.384-20.016-86.482l51.861-2.889l-12.616,154.75 c-1.725,21.152,14.027,39.695,35.18,41.422c1.059,0.086,2.116,0.127,3.163,0.127c19.806,0,36.621-15.219,38.257-35.306 l16.193-198.685C845.235,386.445,841.305,375.527,833.556,367.574z"/>
<path d="M762.384,202.965c35.523,0,64.317-28.797,64.317-64.322c0-35.523-28.794-64.323-64.317-64.323 c-35.527,0-64.323,28.8-64.323,64.323C698.061,174.168,726.856,202.965,762.384,202.965z"/>
<path d="M535.794,650.926c-69.668,0-126.348-56.68-126.348-126.348c0-26.256,8.056-50.66,21.817-70.887l-50.196-50.195 c-26.155,33.377-41.791,75.393-41.791,121.082c0,108.535,87.983,196.517,196.518,196.517c45.691,0,87.703-15.636,121.079-41.792 l-50.195-50.193C586.452,642.867,562.048,650.926,535.794,650.926z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+58
View File
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" viewBox="0 0 325.9702 172.35009" id="Layer_1" xml:space="preserve" inkscape:version="0.48.5 r10040" sodipodi:docname="Gamepad White.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1088" inkscape:window-height="1061" id="namedview30" showgrid="false" inkscape:zoom="1" inkscape:cx="92.633449" inkscape:cy="40.468773" inkscape:window-x="1920" inkscape:window-y="139" inkscape:window-maximized="0" inkscape:current-layer="Layer_1" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0"/>
<defs id="defs3059"/>
<metadata id="metadata3055">
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
<path style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1d1d1d;stroke-width:3.00000024;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path5307" d="m 52.919904,8.1875 c -6.031842,0 -11.470893,2.407417 -15.4375,6.3125 -0.04088,0.04024 -0.08444,0.08444 -0.125,0.125 -4.29211,3.308693 -7.596781,7.816291 -9.15625,13.4375 l -25.0312496,90.25 c -4.73921,17.08279 0.48564,36.23227 17.3124996,41.8125 l 26.65625,8.8125 c 16.82685,5.58022 34.179421,-1.29707 41.78125,-17.3125 l 21.031246,-44.28125 106.0625,0 21.03125,44.28125 c 7.60183,16.01543 24.9544,22.89272 41.78125,17.3125 l 26.65625,-8.8125 c 16.82686,-5.58023 22.05171,-24.72971 17.3125,-41.8125 l -25.03125,-90.25 c -2.7742,-9.999793 -11.01427,-16.522009 -20.65625,-18.875 -0.13603,-0.042133 -0.26909,-0.085439 -0.40625,-0.125 -0.01,-0.00229 -0.0213,0.00228 -0.0312,0 -1.94068,-0.5568486 -4.00056,-0.875 -6.125,-0.875 l -1.8125,0 -211.499996,0 -4.3125,0 z" inkscape:connector-curvature="0"/>
<rect width="62.578949" height="31.466251" rx="8" ry="8" x="41.378765" y="0.73722839" id="rect4249" style="fill:#5e5e5e;fill-opacity:1;fill-rule:nonzero;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"/>
<rect width="62.578949" height="31.466251" rx="8" ry="8" x="219.53084" y="0.73722839" id="rect4267" style="fill:#5e5e5e;fill-opacity:1;fill-rule:nonzero;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"/>
<path d="m 52.919904,8.1875 c -6.031842,0 -11.470893,2.407417 -15.4375,6.3125 -0.04088,0.04024 -0.08444,0.08444 -0.125,0.125 -4.29211,3.308693 -7.596781,7.816291 -9.15625,13.4375 l -25.0312496,90.25 c -4.73921,17.08279 0.48564,36.23227 17.3124996,41.8125 l 26.65625,8.8125 c 16.82685,5.58022 34.179421,-1.29707 41.78125,-17.3125 l 21.031246,-44.28125 106.0625,0 21.03125,44.28125 c 7.60183,16.01543 24.9544,22.89272 41.78125,17.3125 l 26.65625,-8.8125 c 16.82686,-5.58023 22.05171,-24.72971 17.3125,-41.8125 l -25.03125,-90.25 c -2.7742,-9.999793 -11.01427,-16.522009 -20.65625,-18.875 -0.13603,-0.042133 -0.26909,-0.085439 -0.40625,-0.125 -0.01,-0.00229 -0.0213,0.00228 -0.0312,0 -1.94068,-0.5568486 -4.00056,-0.875 -6.125,-0.875 l -1.8125,0 -211.499996,0 -4.3125,0 z" id="rect4151" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" inkscape:connector-curvature="0"/>
<g id="g4358" style="fill:#bdbdbd;fill-opacity:1" transform="translate(1.5007304,0)">
<path d="m 238.20531,32.84774 c -2.18572,0 -3.97143,1.78571 -3.97143,3.97143 v 20.94285 h -20.98571 c -2.18572,0 -3.92858,1.78572 -3.92858,3.97143 v 22.27143 c 0,2.2 1.74286,3.98571 3.92858,3.98571 h 20.98571 v 20.92858 c 0,2.2 1.78571,3.97142 3.97143,3.97142 h 22.28571 c 2.18572,0 3.92857,-1.77142 3.92857,-3.97142 V 87.99059 h 20.97143 c 2.2,0 3.92857,-1.78571 3.92857,-3.98571 V 61.73345 c 0,-2.18571 -1.72857,-3.97143 -3.92857,-3.97143 H 264.41959 V 36.81917 c 0,-2.18572 -1.74285,-3.97143 -3.92857,-3.97143 h -22.28571 z" id="path3219" style="fill:#bdbdbd;fill-opacity:1;fill-rule:evenodd" inkscape:connector-curvature="0"/>
</g>
<g id="g4361" style="fill:#bdbdbd;fill-opacity:1" transform="translate(1.5007304,0)">
<path d="m 60.053224,32.84773 c -2.185714,0 -3.971428,1.78571 -3.971428,3.97143 V 57.76202 H 35.110367 c -2.2,0 -3.942857,1.77142 -3.942857,3.97142 v 22.27143 c 0,2.2 1.742857,3.97143 3.942857,3.97143 h 20.971429 v 20.94286 c 0,2.2 1.785714,3.97143 3.971428,3.97143 h 22.285714 c 2.185714,0 3.928568,-1.77143 3.928568,-3.97143 V 87.9763 h 20.985714 c 2.18572,0 3.91429,-1.77143 3.91429,-3.97143 V 61.73344 c 0,-2.2 -1.72857,-3.97142 -3.91429,-3.97142 H 86.267506 V 36.81916 c 0,-2.18572 -1.742854,-3.97143 -3.928568,-3.97143 H 60.053224 z" id="rect3214" style="fill:#bdbdbd;fill-opacity:1;fill-rule:evenodd" inkscape:connector-curvature="0"/>
</g>
<g transform="matrix(1.4285714,0,0,1.4285714,-369.64604,-683.22368)" id="g3289" style="fill:#3f3f3f"/>
<g id="g5309" style="fill:#e9e9e9;fill-opacity:1" transform="translate(1.5007304,0)">
<path inkscape:connector-curvature="0" style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none" id="path3273" d="m 71.235854,36.203603 -6.448691,5.915291 12.897383,0 z"/>
<path inkscape:connector-curvature="0" style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none" id="path3295" d="m 71.107253,109.53472 -6.448691,-5.91529 12.897382,0 z"/>
<path inkscape:connector-curvature="0" style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none" id="path3303" d="m 107.88086,72.933449 -5.96234,-6.500001 0,13.000001 z"/>
<path inkscape:connector-curvature="0" style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none" id="path3305" d="m 34.45415,72.806518 5.962355,-6.500001 0,13.000001 z"/>
</g>
<path inkscape:connector-curvature="0" d="m 135.05424,57.754875 c -2.18571,0 -3.92857,1.78572 -3.92857,3.97143 l 0,22.27143 c 0,2.2 1.74286,3.98571 3.92857,3.98571 l 56.14286,0 c 2.2,0 3.92857,-1.78571 3.92857,-3.98571 l 0,-22.27143 c 0,-2.18571 -1.72857,-3.97143 -3.92857,-3.97143 z" id="path4221" style="fill:#bdbdbd;fill-opacity:1;fill-rule:evenodd"/>
<rect style="fill:#ff4872;fill-opacity:1;fill-rule:nonzero;stroke:none" id="rect3804" width="13.258252" height="4.9497476" x="141.42738" y="45.693382" rx="2" ry="2"/>
<rect ry="2" rx="2" y="45.693382" x="171.56569" height="4.9497476" width="13.258252" id="rect3806" style="fill:#84f446;fill-opacity:1;fill-rule:nonzero;stroke:none"/>
<g id="g3810" style="fill:#bdbdbd;fill-opacity:1" transform="translate(1.5007304,0)">
<path inkscape:connector-curvature="0" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path3244" d="m 261.0903,49.663078 a 11.76471,11.76471 0 0 1 -23.52942,0 11.76471,11.76471 0 1 1 23.52942,0 z"/>
<path inkscape:connector-curvature="0" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path3246" d="m 261.0903,96.270368 a 11.76471,11.76471 0 0 1 -23.52942,0 11.76471,11.76471 0 1 1 23.52942,0 z"/>
<path inkscape:connector-curvature="0" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path3248" d="m 260.8644,73.000822 a 11.76471,11.76471 0 1 1 23.52942,0 11.76471,11.76471 0 0 1 -23.52942,0 z"/>
<path inkscape:connector-curvature="0" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" id="path3250" d="m 214.2644,73.000822 a 11.76471,11.76471 0 1 1 23.52942,0 11.76471,11.76471 0 0 1 -23.52942,0 z"/>
<path d="m 84.480854,64.854219 a 1.6842051,1.6842056 0 0 0 -1.205367,0.669649 l -5.000042,6.339341 a 1.6842051,1.6842056 0 0 0 0,2.053589 l 5.000042,6.383984 a 1.6842051,1.6842056 0 0 0 1.339297,0.669649 l 11.607241,0.04457 a 1.6842051,1.6842056 0 0 0 1.696443,-1.696372 l 0,-12.544752 a 1.6842051,1.6842056 0 0 0 -1.6518,-1.696444 L 84.659427,64.854219 a 1.6842051,1.6842056 0 0 0 -0.178573,0 z" id="path3322" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
<path d="m 57.854166,64.727289 a 1.6842051,1.6842056 0 0 1 1.205367,0.669649 l 5.000042,6.339341 a 1.6842051,1.6842056 0 0 1 0,2.053589 l -5.000042,6.383984 a 1.6842051,1.6842056 0 0 1 -1.339297,0.669649 l -11.607241,0.04457 a 1.6842051,1.6842056 0 0 1 -1.696443,-1.696372 l 0,-12.544752 a 1.6842051,1.6842056 0 0 1 1.6518,-1.696444 l 11.607241,-0.223216 a 1.6842051,1.6842056 0 0 1 0.178573,0 z" id="path3324" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
<path d="m 79.18648,86.181762 a 1.6842051,1.6842056 0 0 0 -0.669648,-1.205368 l -6.339339,-5.000043 a 1.6842051,1.6842056 0 0 0 -2.053589,0 l -6.383983,5.000043 a 1.6842051,1.6842056 0 0 0 -0.669648,1.339298 l -0.04457,11.607244 a 1.6842051,1.6842056 0 0 0 1.696371,1.696443 l 12.544749,0 a 1.6842051,1.6842056 0 0 0 1.696443,-1.6518 L 79.18648,86.360335 a 1.6842051,1.6842056 0 0 0 0,-0.178573 z" id="path3332" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
<path d="m 79.31508,59.556558 a 1.6842051,1.6842056 0 0 1 -0.669648,1.205368 l -6.339339,5.000043 a 1.6842051,1.6842056 0 0 1 -2.053589,0 l -6.383983,-5.000043 a 1.6842051,1.6842056 0 0 1 -0.669648,-1.339298 l -0.04457,-11.607244 a 1.6842051,1.6842056 0 0 1 1.696371,-1.696443 l 12.544749,0 a 1.6842051,1.6842056 0 0 1 1.696443,1.6518 l 0.223216,11.607244 a 1.6842051,1.6842056 0 0 1 0,0.178573 z" id="path3334" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
<path d="m 181.49066,64.984512 c 0.46409,0.03977 0.90674,0.285619 1.18563,0.658684 l 4.91818,6.235545 c 0.44145,0.573965 0.44145,1.446 0,2.019966 l -4.91818,6.279457 c -0.30647,0.406087 -0.80862,0.657167 -1.31737,0.658684 l -14.22758,0.04384 c -0.87542,0.007 -1.67502,-0.793175 -1.66867,-1.668596 l 0,-12.339354 c -0.007,-0.860892 0.764,-1.652128 1.62476,-1.668667 l 14.22758,-0.219561 c 0.0584,-0.0028 0.11719,-0.0028 0.17565,0 z" id="path4289" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
<path d="m 141.75921,64.859662 c -0.46409,0.03977 -0.90674,0.285619 -1.18563,0.658684 l -4.91818,6.235545 c -0.44145,0.573965 -0.44145,1.446 0,2.019966 l 4.91818,6.279457 c 0.30647,0.406087 0.80862,0.657167 1.31737,0.658684 l 14.22758,0.04384 c 0.87542,0.007 1.67502,-0.793175 1.66867,-1.668596 l 0,-12.339354 c 0.007,-0.860892 -0.764,-1.652128 -1.62476,-1.668667 L 141.93486,64.85966 c -0.0584,-0.0028 -0.11719,-0.0028 -0.17565,0 z" id="path4291" style="fill:#5e5e5e;fill-opacity:1;fill-rule:evenodd;stroke:#1d1d1d;stroke-width:1.50000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" inkscape:connector-curvature="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,812 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1920 1920" enable-background="new 0 0 1920 1920" xml:space="preserve">
<g id="_x23_000000ff">
<path stroke="#000000" stroke-width="0.0938" d="M1698.9879,12.1671c11.09-4.64,23.5599-2.62,34.89,0.1
c2.8099,0.87,6.13,1.12,8.23,3.46c2.5599,2.35,5.1699,4.8,6.5499,8.08c7.77,1.18,14.1901-4.6,21.8101-4.77
c2.6699,3.37,5.6699,6.73,6.41,11.13c-6.91,4.62-15.67,2.78-23.1101,5.82c8.64,3.21,17.4601-2.02,26.2401-0.31
c3.6599,0.72,6.74,3.01,9.5099,5.42c-1.5599,3.97-5.23,6.38-7.99,9.43c3.2301,2.22,7.49,3.18,9.5801,6.79
c-4.0901,5.09-5.85,12.08-2.87,18.17c-2.6801,1.13-5.49,2.22-7.38,4.54c2.51,1.14,6.4199,0.64,7.5599,3.76
c-1.33,4.12-3.95,7.63-6.0599,11.35c2.1699,2.21,4.6699,4.16,6.3199,6.85c-2.15,2.3-4.4399,4.45-6.49,6.82
c2.05,2.84,4.6901,5.22,6.61,8.18c-3.3099,4.91-9.52,5.26-14.78,6.17c5.26,1.72,11.03,2.63,15.2301,6.59
c-1.65,1.88-3.6101,3.75-4.03,6.32c-0.71,4.02,0.6799,7.95,1.5499,11.82c-3.5,3.77-8.6899,4.24-13.47,4.86
c5.39,3.12,13.1,2.91,16.26,9.13c-2.29,5.87-9.15,5.45-14.2,6.85c3.58,3.71,9.76,2.69,13.08,6.96
c-4.5699,5.95-1.62,13.45,1.6901,19.18c-6.01,3.7-13.3201,1.68-19.7201,3.97c3.2101,1.97,6.9701,2.01,10.61,2.37
c3.2101,0.22,5.4601,2.78,7.5901,4.91c-1.03,4.6-5.5,6.63-9.36,8.38c3.5699,0.72,9.49,0.56,10.0299,5.34
c0.5601,4.8-4.25,6.99-7.08,9.84c0.91,2.93,4.89,2.52,7.21,3.93c-0.3199,3.94-1.74,8.04-5.5399,9.88c2.24,2.15,3.96,4.74,5.51,7.42
c-2.39,2.78-5.1001,5.58-8.77,6.5c-4.9301,1.15-9.98-0.27-14.9501,0.26c-0.76,2.49-0.23,5.75-2.46,7.52
c-3.62,2.55-7.8199-0.6-11.74-0.41c-1.87,4.96,0.09,10.05-0.1,15.1c-0.17,4.59-4.61,6.92-6.87,10.41
c-4.39,7.04-6.5901,15.39-6.4,23.68c0.13,10.52,3.46,20.61,6.1,30.69c6.35,22.84,6.75,46.77,6.5,70.31
c-0.26,13.33-0.62,26.66-0.9,39.99c0.3,26.01-1.6799,51.98-1.6699,77.99c-0.8101,14.33-2.7001,28.59-3.05,42.95
c-0.71,7.77-0.61,16.29-5.22,22.96c-5.51,6.68-14.51,9.12-22.8,9.89c-7.97,0.62-17.11,0.09-23.1-5.91
c-7.45-6.77-9.47-17.32-9.74-26.95c0.0599-23.96-0.27-47.93,0.03-71.9c0.11-32.35-1.11-64.71,0.0499-97.05
c0.53-13.11-1.47-26.76,3.25-39.33c2.6-7.33,2.3-15.26,4.25-22.74c2.9301-11.82,7.0701-23.61,6.74-35.94
c-0.1-6.29-2.01-12.6-5.88-17.6c-3.59-4.77-8.38-9.26-9.09-15.51c-1.12-5.29,3.84-9.72,2.59-15.01c-0.7-1.49-2.73-1.41-4.0499-1.86
c-9.73-2.14-19.3,2.05-29.01,1.82c-5.35-3.81-8.5601-10.96-6.48-17.42c0.99-3.26,3.75-5.44,6.25-7.56
c-1.49-1.94-3.62-3.19-5.35-4.87c-0.0601-4.35,0.2999-9.12,3.7899-12.21c-2.23-2.04-4.39-4.19-5.96-6.79
c1.95-3.35,4.64-6.38,8.52-7.44c-2.2201-2.77-5.23-5.72-4.8201-9.57c0.55-2.54,2.92-3.99,4.77-5.57
c-3.0599-1.83-6.13-3.96-7.5499-7.38c1.9099-2.34,4.4099-4.54,7.6699-4.32c3.28,0.16,6.6-0.68,8.76-3.34
c-3.74-3.53-9.63-0.44-13.1799-4.08c-2.4901-1.72-0.79-5.16,0.9099-6.83c4.04-3.14,9.55-2.49,14.1901-4.22
c-3.61-3.82-9.6-1.33-13.55-4.45c-0.74-0.55-1.4399-1.12-2.11-1.71c0.4-3.03,1.26-6.01,1.41-9.07c0.11-2.67-1.85-4.71-2.9401-6.96
c3.3101-5.7,10.66-5.09,16.14-7.04c-4.6-3.01-10.7999-1.17-15.09-4.72c-2.26-1.41-0.8-4.68,0.5-6.33
c3.47-3.14,8.5599-2.77,12.85-3.97c-4.3-3.29-11.65-3.1-13.42-9.13c-1.1399-4.44,4.8401-4.77,7.38-6.8
c-2.14-1.53-4.83-2.34-6.5399-4.4c-0.04-2.34,0.5699-4.63,0.7899-6.95c2.54-3.28,6.74-3.39,10.55-3.36
c-3.13-1.95-6.96-1.46-10.27-2.79c-2.1899-0.99-4.11-4.27-1.86-6.18c3.83-3.83,9.99-2.35,14.42-5.14
c-2.42-4.18-7.36-2.16-11.1801-2.95c-2.3099-0.63-5.21-2.86-4.0599-5.55c1.1599-2.27,3.2799-3.84,4.88-5.79
c-2.14-2.26-4.28-4.79-4.7201-7.99c-0.9399-6.66,1.63-13.08,2.9601-19.5c11.0499-4.77,24.2699-6.08,35.1399-0.09
C1687.6678,21.3471,1692.2079,14.9471,1698.9879,12.1671 M1704.4579,569.4371c-1.51,2.24-1.54,5.02-1.83,7.61
c2.3099,2.69,4.8199,5.61,8.3999,6.56c7.17,2.37,15.39-5.47,13.4701-12.69
C1721.3079,563.2671,1708.7778,562.3671,1704.4579,569.4371z"/>
<path stroke="#000000" stroke-width="0.0938" d="M40.8578,32.8271c15.2-3.81,31.07-2.27,46.51-1.16c4.55,0.3,9.84,0.93,12.49,5.18
c-1.83,1.17-3.8,2.26-6.02,2.43c-8.95,0.81-17.96,0.57-26.95,0.83c-5.31,0.2-10.84,0.45-15.65,2.98
c10.24,1.14,20.5-0.66,30.73-1.06c1.45-0.16,2.27,1.24,3.29,1.98c-8.04,1.29-16.17,2.36-24.33,2.04c-3.28-0.27-6.43,0.78-9.27,2.34
c11.78-0.02,23.54-1.14,35.32-1.44c4.65,0.02,9.87-1.86,13.94,1.27c-16.05,2.83-32.57,1.17-48.62,4.11
c6.13,1.26,12.43,1.13,18.64,0.73c5.16-0.44,11.01-2.48,15.57,1c-11.31,2.36-23.1,0.43-34.33,3.33
c16.18,2.38,32.48-2.02,48.68-0.04c-1.52,0.8-2.99,2.02-4.8,1.97c-10.72-0.34-21.33,1.67-32.03,1.88
c-3.69-0.12-7.62-0.54-10.9,1.53c10.62,0.07,21.28-0.28,31.87-0.98c0.22,0.52,0.66,1.55,0.88,2.06
c-10.63,2.75-21.85,0.67-32.47,3.52c16,1.88,32.07-1.85,48.06-0.15c-1.68,1.05-3.46,2.32-5.56,2.1
c-9.67-0.44-19.28,1.19-28.94,1.44c-4.71,0.33-9.83-0.88-14.08,1.78c10.38,0.84,20.8-1.11,31.18-0.13c1,0.19,1.93,0.57,2.8,1.11
c-4.74,1.94-10.01,1.12-14.98,1.9c-6.15,0.91-13.55-2.22-18.61,2.62c16.26-0.49,32.51-1.5,48.78-1.14
c-3.62,3.88-9.09,1.74-13.69,2.22c-11.3,0.69-22.73,0.54-33.9,2.66c10.98,1.57,22.1-1.14,33.03,0.83
c-6.25,3.43-13.66,2.83-20.54,2.88c-4.11-0.12-8.49-0.62-12.23,1.5c15.66,0.9,31.33-0.55,46.99-0.38
c-3.28,3.69-8.46,1.67-12.72,2.09c-9.01,0.57-18.05,0.66-27.06,1.24c-2.62,0.04-5.04,1.07-7.27,2.37
c10.84,0.56,21.75-1.77,32.55,0.1c-9.98,5.44-21.83,0.52-32.2,4.05c11.61,0.77,23.31,0.13,34.96,0.38
c4.24,0.42,9.54-2.85,12.7,1.34c-15.79,1.99-31.93-0.22-47.57,3.18c10.84,1.43,21.8-1.26,32.6,0.71c-2.58,1.71-5.66,2.44-8.74,2.2
c-7.84-0.43-15.77-0.29-23.48,1.33c15.71,2.31,31.63-0.3,47.41,0.71c-1.47,1.02-2.98,2.35-4.89,2.24
c-12.03-0.73-24.02,1.25-36.05,0.65c-2.42-0.25-4.7,0.67-6.75,1.86c10.98,1.48,22.11-0.84,33.07,0.9
c-10.06,4.98-21.82-0.69-32.1,3.47c11.21,0.79,22.48,0.58,33.72,0.9c4.44,0.4,9.47-2.33,13.22,1.13
c-15.44,2.43-31.3-0.22-46.68,2.84c8.42,1.63,17.03,0.49,25.52,0.21c2.44-0.18,4.73,0.77,6.77,2.02
c-10.79,2.73-22.32-0.85-32.94,2.71c14.02,1.78,28.14-0.78,42.2,0.02c2.08,0.04,3.9,1.14,5.68,2.1c-15.19,2.4-30.79-0.67-45.89,2.6
c6.67,0.22,13.37,1.38,20.04,0.53c3.64-0.39,7.78-1.03,10.75,1.66c-10.46,2.45-21.39-0.5-31.83,2.16
c11.31,1.51,22.76,1.24,34.15,1.47c4.22,0.34,9.11-2.19,12.6,1.28c-15.16,2.16-30.58-0.13-45.73,1.99
c10.44,2.11,21.19-0.69,31.63,1.46c-1.95,1.16-4,2.36-6.36,2.29c-8.52,0.06-17.4-1.61-25.65,1.28c13.81,1.44,27.71,0.03,41.56,0.56
c1.94-0.04,3.44,1.32,4.93,2.35c-13.62,0.72-27.28,0.62-40.92,0.56c-1.7,0.02-3.34,0.49-4.96,0.95
c10.52,1.72,21.27,0.25,31.83,1.69c-9.9,5.57-21.78-0.92-31.91,3.7c15.31,0.96,30.67,0.32,46,1c-1.24,0.8-2.31,2.14-3.9,2.26
c-14.04,1.01-28.31-1.79-42.19,1.26c10.55,1.56,21.32-0.78,31.8,1.51c-10.06,4.64-21.54-0.34-31.92,2.81
c15.49,2.24,31.23,0.5,46.77,2.13c-3.91,3.24-8.99,0.83-13.51,1.27c-11.13,0.46-22.37-0.06-33.42,1.51
c10.69,2.04,22.3-2.21,32.51,2.74c-10.72,2.18-21.88-1.01-32.5,1.99c15.51,1.96,31.26-0.1,46.73,2.25
c-4.29,3.08-9.56,0.72-14.36,1.11c-10.79,0.28-21.71-0.95-32.38,1.16c10.78,1.94,21.83,0.15,32.67,1.72
c-1.64,0.89-3.26,2.01-5.16,2.22c-9.04,0.83-18.7-2.48-27.33,1.36c13.75,1.24,27.57-0.06,41.33,0.69c2.02,0.12,3.81,1.12,5.48,2.16
c-11.19,0.64-22.41,0.67-33.61,0.68c-4.44,0.11-9.16-1.58-13.29,0.82c10.98,0.83,22.1-0.1,32.97,1.95
c-8.1,3.36-17.08,1.64-25.54,1.17c-2.54-0.25-5,0.45-7.35,1.34c15.59,1.42,31.28,1.16,46.9,2c-1.38,1.08-2.78,2.43-4.68,2.33
c-12,0.31-24.01-0.43-35.99-0.98c-1.93-0.1-3.77,0.53-5.59,1.04c9.06,1.77,18.34,0.47,27.49,1.12c1.72-0.12,3.2,0.71,4.51,1.73
c-2.49,1.68-5.62,1.4-8.47,1.28c-7.8-0.46-15.81-1.46-23.42,0.88c1.82,0.31,3.65,0.63,5.51,0.7c13.78,0.33,27.56,0.72,41.3,1.82
c-3.57,3.06-8.18,1.16-12.34,1.27c-7,0.05-13.99,0.41-20.99,0.33c-4.33,0.07-8.9-1.39-12.96,0.74c10.63,0.5,21.33,0.37,31.9,1.81
c-4.85,2.72-10.58,2.1-15.92,1.96c-5.59-0.29-11.55-2.23-16.87,0.48c15.52,2.14,31.36,0.56,46.84,3.18
c-2.2,0.9-4.54,1.63-6.95,1.39c-11.01-0.59-22.05-0.44-33.04-1.3c-2.09-0.34-4.07,0.5-5.92,1.37c10.55,1.15,21.29,0.34,31.72,2.56
c-6.19,3.31-13.18,0.4-19.77,0.96c-4.43,0.51-9.02-1.3-13.27,0.53c15.72,3.79,32.11,1.19,48.03,3.45
c-4.04,3.2-9.18,0.89-13.79,1.13c-11.04,0.01-22.1-0.69-33.11,0.17c10.76,2.18,21.84,1.01,32.65,2.74
c-1.98,1.11-4.1,2.14-6.43,2.08c-5.7,0.11-11.38-0.48-17.07-0.41c-3.54,0.18-7.36-1.51-10.57,0.66c15.94,2.21,32.4-0.16,48.07,4.14
c-8.12,0.69-16.27,0.25-24.4-0.01c-0.7,0.6-1.4,1.2-2.11,1.79c4.14,0.18,8.31,0.49,12.34,1.5c-6.73,3.53-14.24,0.05-21.37,0.88
c-3.9,0.62-8.27-2.12-11.69,0.69c14.62,1.23,29.28,2.28,43.93,2.74c1.39,0.21,2.44,1.25,3.6,1.95c-15.5,1.71-31.13-2.65-46.6-0.04
c10.56,1.8,21.36,0.81,31.94,2.45c-5.11,3.8-11.43,0.89-17.14,0.98c-5.31,0.17-10.99-0.98-15.96,1.38
c15.86,1.39,31.88,1.27,47.69,3.42c-1.75,0.96-3.65,1.84-5.7,1.56c-10.09-0.73-20.22-0.53-30.32-1.11
c-3.53-0.41-7.33-1.29-10.57,0.75c8.33,0.44,16.62,1.47,24.98,1.31c2.69-0.1,5.25,0.86,7.5,2.28c-10.93,1.86-21.98-1.84-32.9,0.14
c13.94,2.54,28.18,2.55,42.28,3.34c1.77-0.03,3.2,1.09,4.62,1.98c-11.21,0.9-22.42-0.62-33.62-0.99
c-4.44-0.06-9.29-1.77-13.31,0.94c11.01,0.49,22.01,1.25,32.94,2.69c-2.07,1.11-4.27,2.2-6.7,1.89
c-8.57-0.54-17.32-2.46-25.83-0.36c15.41,2.78,31.4,0.91,46.65,4.9c-15.13,1.85-30.29-2.27-45.44-0.47c0,0.13,0,0.38,0,0.51
c9.51,0.99,19.1,0.89,28.61,1.88c1.02,0.39,1.71,1.31,2.55,1.98c-10.67,1.79-21.48-2.02-32.11,0.23
c11.48,1.15,23.01,1.96,34.49,3.23c4.05,0.55,8.73-1.03,12.04,2.12c-7.66,0.18-15.34,0.08-23.01-0.14
c-7.5-0.2-15.18-2.85-22.59-0.57c10.39,1.54,21.34,0.25,31.29,4.2c-10.59,1.85-21.28-2.12-31.85,0.11
c15.32,2.09,30.84,2.49,46.16,4.67c-4.6,2.38-9.87,1.28-14.81,1.16c-10.27-0.88-20.53-2.23-30.86-1.7
c10.27,2.88,21.24,1.46,31.67,3.74c-1.81,0.95-3.71,1.86-5.79,1.9c-8.41-0.04-16.9-2.39-25.28-0.78
c14.87,2.4,29.97,2.76,44.92,4.51c-3.31,3.11-7.86,1.35-11.82,1.15c-9.68-0.46-19.31-1.69-29-1.84c-1.94-0.14-3.81,0.44-5.62,1.09
c10.84,0.49,21.62,1.74,32.41,2.85c-1.98,1.3-4.27,2.25-6.69,1.99c-8.43-0.64-16.92-2.28-25.38-1.11
c15.21,3.09,31.28,1.2,46.07,6.48c-15.03,0.59-29.95-3.06-44.97-1.71c10.17,2.26,20.87,0.97,30.89,4.02
c-2.46,0.99-5.09,1.77-7.76,1.2c-7.39-1.19-14.97-1.69-22.38-0.38c14.62,2.25,29.79,1.16,44.02,5.64
c-14.68,1.26-29.23-3.02-43.92-1.7c9.93,1.64,20.05,2.01,29.91,4.07c-1.76,0.74-3.58,1.57-5.55,1.4
c-7.68-0.42-15.29-1.65-22.97-2.13c-1.69-0.27-3.17,0.62-4.6,1.35c16.04,1.57,32.13,3.08,48.08,5.36c-1.36,0.78-2.76,1.7-4.42,1.54
c-10.4-0.01-20.71-1.65-31.06-2.5c-4.42-0.17-8.96-2.2-13.27-0.23c11.19,1.55,22.5,2.21,33.63,4.14c-9.65,3.81-19.8-1.7-29.64,0.39
c14.44,3.42,29.76,1.78,43.88,6.79c-3.06,4.9-9.17,4.25-14.13,4.86c-10.03,1.96-20.19,5.97-27.13,13.75
c-5.39,5.9-8.1,13.76-8.99,21.6c-2.44,19.92-2.45,40.01-3.32,60.03c-3.03,53.66-5.55,107.34-7.92,161.03
c-1.01,16.6801-2.04,33.4-4.98,49.8701c-5.56-3.42-3.99-10.41-3.74-15.82c-0.48-24.67-0.34-49.34-0.23-74
c0.51-155.36,0.23-310.78-6.55-466.02c-0.49-13.56-3.85-27.21-1.21-40.73C28.6578,41.1071,33.6378,34.5071,40.8578,32.8271
M58.5178,232.4071c6,1.02,12.11,0.74,18.16,1.25c0.79-0.59,1.59-1.17,2.39-1.75
C72.2178,232.5071,65.1678,230.1671,58.5178,232.4071z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1479.7878,41.2271c0.03-3.7-0.0399-7.56,1.75-10.93
c2.62,0.25,5.55,0.53,7.51,2.55c3.25,3.26,4.48,7.87,6.88,11.72c8.98,0.84,15.6901,7.7,20.8,14.53
c9.11,12.61,14.9399,27.51,17.37,42.84c1.63,11.19,1.26,23.57-5.4501,33.16c0.99,5.95,2.7201,11.89,1.88,17.98
c-2.34,0.63-5.01,1.98-7.2799,0.45c-2.03-1.53-2.8601-4.04-4.12-6.15c-1.66,3.46-1.77,7.65-4.29,10.66
c-5.48,1.41-7.26-5.32-11.3101-7.42c-0.21,3.5,0.4501,7.08-0.36,10.53c-1.13,3.77-6.83,2.95-8.46,0.01
c-2.05-3.53-2.4401-8.04-5.92-10.65c-2.7,5.69,3.51,11.11,0.73,16.82c-2.3999,0.16-5.1599,0.91-7.23-0.66
c-3.5299-2.93-3.2999-9.13-8.34-10.42c0.4399,5.59,4.5699,10.6,2.8,16.41c-3,0.19-6.4301,0.46-8.74-1.84
c-2.9901-3.12-3.9501-7.52-6.1001-11.16c-3.1499,3.77-0.2799,8.25,0.3101,12.36c0.46,2.16,0.0599,5.09-2.21,6.07
c-2.7401,0.58-5.9801-0.54-7.05-3.28c-1.91-4.1-2.1-9.92-7.2-11.5c-0.2101,4.72,1.73,9.02,2.96,13.46c0.98,2.72-1.01,5-2.63,6.91
c-2.4401-0.35-5.2001-0.97-6.37-3.39c-2.0801-3.98-2.5-9.14-6.6801-11.68c-3.88,6.12,4.2001,11.88,1.8201,18.14
c-1.1801,3.69-6.64,2.21-8.39-0.32c-2.8101-4.31-2.6801-9.87-5.6901-14.11c-1.1699,0.94-3.1599,1.68-2.7799,3.56
c0.2,4.96,4.1899,9.58,2.38,14.62c-1.2201,3.39-6.28,2.34-8.03-0.04c-2.38-3.54-2.62-8.38-6.3-11.04
c-1.36,2.67-1.24,5.71,0.13,8.34c1.39,3.11,3.05,7.59-0.11,10.19c-2.8199,0.54-6.24,0.34-8.04-2.19
c-2.21-3.26-2.64-7.32-4.33-10.83c-3.6,4.11-0.27,9.34-0.03,13.96c0.3101,2.87-3.12,5.37-5.6699,3.82
c-6.38-2.69-4.9401-11.84-10.76-15.13c-1.66-1-3.5901-0.06-5.25,0.32c-4.75,1.52-9.3201,3.59-14.2101,4.64
c0.01,4.15,0,8.3,0.02,12.45c-18.77,7.63-37.39,17.05-57.88,18.79c-9.89,1.06-19.97-1.14-28.61-6.01
c-19.08-2.33-38.11,2.87-55.75,9.76c-20.7999,8.14-41.98,15.25-62.91,23.03c-35.76,13.03-71.59,25.97-108.0699,36.85
c-5.59,1.42-12.09,3.93-17.3301,0.16c-7.46-5.1-10.34-14.33-12.59-22.64c-1.88-7.31-2.91-14.79-4.09-22.23
c45.08-20.78,91.7-37.97,138.3101-54.95c16.6499-6.06,33.3099-12.07,50.1-17.74c17.03-6.01,34.8199-13.19,46.6599-27.45
c1.39-4.48,3.3401-8.8,4.41-13.38c19.25-15.06,42.76-23.15,65.86-30.22c6.1801-1.78,7.0901,7.8,12.99,7.12
c6.62,0.25,11.9401-4.39,18.2101-5.7c-0.4401-6.66-3.1901-13.09-2.01-19.84c2.14,0.74,4.49,1.37,6.1,3.11
c3.1,3.16,4.27,7.57,6.5,11.31c2.05-0.7,2.24-3.33,1.89-5.14c-0.58-4.07-3.15-8.05-1.9301-12.23c1.0601-2.35,4.6801-4.6,6.87-2.32
c3.3201,3.99,3.11,10.5,8.17,13.09c2.58-4.4-1.42-8.35-2.47-12.49c-0.79-2.24,0.5499-4.28,1.6699-6.09
c2.3601,0.22,5.4401-0.16,6.9,2.22c2.62,4.01,2.01,9.68,6.12,12.83c4.97-2.58,0.8301-8.01,0.0901-11.88
c-1.4701-3.24-0.3401-8.03,3.75-8.37c7.48,1.17,4.0599,11.77,10.25,14.58c1.21-1.24,2.23-3.06,1.37-4.8
c-1.8-4.06-4.4601-8.05-3.63-12.73c1.86-0.55,3.63-1.39,5.1599-2.62c7.74,1.14,5.9501,11.04,11.38,14.93
c4.53-5.65-3.85-12.16-0.4299-18.09c1.47-2.84,5.2999-2.05,7.1,0.02c3.25,3.66,3.15,9.2,6.7,12.69
c3.54-6.61-4.23-14.27,1.0901-20.42c2.13,0.57,4.72,0.95,5.9099,3.1c2.2101,3.7,2.66,8.17,4.99,11.84
c1.28-0.74,3.0801-1.39,3.0701-3.19c-0.0701-5.08-3.3201-10.61,0.1699-15.28c2.4,0.28,5.3501,0.14,7.03,2.27
c2.4601,3.1,2.8301,7.23,4.38,10.78c5.14-5.35-3.7899-12.95,1.42-18.17c2.36-0.52,5.24-0.25,6.9,1.74
c2.48,2.98,3.14,7.25,6.5499,9.5c0.8101-5.28-4.2-9.61-2.75-15.05c2.6901-0.15,5.6-0.62,8.12,0.71
C1475.8679,37.6371,1477.7579,39.5371,1479.7878,41.2271z"/>
<path stroke="#000000" stroke-width="0.0938" d="M193.4378,55.2971c5.26-3.95,12.09-5.14,18.52-4.48c14.77,1.45,29.15,5.64,44,6.51
c11.25,1.07,23.23,1.15,33.28,7c-8.17,3.83-17.33,4.87-26.25,4.72c-13.55-0.49-27.39-2.6-40.71,1.01
c18.55,5.34,37.89-1.54,56.6,2.35c3.58,0.69,7.02,1.93,10.36,3.38c-6.12,2.54-12.63,4.11-19.26,4.39
c-15.85,0.8-31.95-3.05-47.58,1.08c17.54,5.11,35.85-0.71,53.64,2.02c4.56,0.63,8.96,2.02,13.21,3.75
c-8.93,6.18-20.21,4.61-30.37,3.66c-13-0.37-26.19-0.69-38.98,2.07c9.13,5.37,20.04,2.42,29.99,2.3
c13.11-0.15,26.75-1.38,39.3,3.24c-10.37,5.92-22.73,4.9-34.21,4.65c-12.38,0.13-25.04-2.63-37.17,0.99
c23.15,8.28,48.35-2.66,71.49,5.75c-2.79,1.97-5.89,3.61-9.31,4.08c-8.97,1.42-17.96-0.82-26.96-0.7
c-11.86,0.16-23.85-0.05-35.51,2.39c1.81,1.25,3.68,2.55,5.91,2.9c21.88,1.85,44.47-4.2,65.88,2.59c-2.34,2.2-5.02,4.21-8.25,4.82
c-9.91,2.31-20-1.2-29.98-0.06c-11.97,1.37-24.07-0.76-36.01,1.03c1.78,2.67,4.82,3.46,7.87,2.79c4.32-0.93,8.63,0.39,12.96-0.12
c4.32-0.41,8.66,0.37,12.98-0.15c4.35-0.64,8.67,0.74,13.04,0.34c9.13-0.48,18.84-1.74,27.32,2.58c-3.36,3.09-7.68,4.96-12.21,5.4
c-9.72,0.98-19.39-1.26-29.11-0.79c-10.88,0.42-21.78,0.47-32.63,1.37c3.03,3.22,7.61,3.44,11.69,2.6
c9.61-1.83,19.26,1.05,28.92,0.4c8.3-0.34,16.75-2.13,24.97-0.13c3.22,0.71,5.97,2.63,8.37,4.82c-24.39,7.41-50.18-1.19-74.75,4.67
c18.72,4.23,37.86-0.32,56.78,0.84c6.25,0.37,14.16-0.29,18.05,5.74c-25.11,7.63-51.57-1.1-76.93,4.54
c12.98,4.67,27.02,3.19,40.55,3.34c12.05-0.21,25.59-4.08,36.33,3.36c-25.17,7.77-51.83-1.08-77.27,4.71
c2.94,3.5,7.8,3.54,11.94,2.75c9.95-1.87,19.95,1.25,29.96,0.36c11.75-0.76,24.66-3.11,35.27,3.49
c-25.19,7.96-51.96-1.41-77.37,4.87c3.22,3.15,7.87,3.45,12.06,2.59c9.98-1.9,20.01,1.25,30.05,0.34
c11.78-0.72,24.68-2.87,35.37,3.56c-25.24,7.88-51.98-1.37-77.47,4.73c5.52,5.61,13.45,1.62,20.13,1.98
c8.62,0.6,17.28,1.71,25.93,0.75c10.49-0.98,21.97-2.02,31.35,3.81c-25.01,9.7-52.19-0.16-77.79,5.67
c25.54,6.31,52.83-4.44,77.76,5.74c-8.36,3.19-17.31,4.58-26.24,4.52c-16.44,0.15-33.18-3.07-49.37,1.1
c24.86,6.13,51.38-4.4,75.62,5.63c-9.3,3.49-19.3,4.66-29.19,4.58c-15.2,0.07-30.5-2.43-45.63,0.05
c10.05,5.41,21.8,2.35,32.62,2.18c14.1-0.02,29.03-1.77,42.2,4.41c-24.21,10.18-50.84-0.54-75.69,5.75
c24.61,8.23,51.11-2.76,75.69,5.62c-10.83,4.39-22.72,5.01-34.27,4.5c-13.85-0.72-27.97-2.16-41.62,1.14
c24.71,8.2,51.28-2.64,75.99,5.67c-10.1,6.52-22.51,4.44-33.77,3.57c-13.36-0.12-26.91-0.65-40.05,2.21
c9.69,5.22,21.04,2.53,31.47,2.2c14.11-0.08,28.66-1.37,42.28,3.22c-5.73,6.01-14.6,6.22-22.3,5.63
c-16.83-1.81-33.77-0.5-50.62,0.28c23.7,7.92,49.34-2.85,72.96,5.59c-8.8,7.08-20.82,5.62-31.35,5.66
c-13.39,0.25-26.82-1.86-40.16-0.05c6.67,4.03,14.75,3.26,22.2,2.93c9.29-0.87,18.64-0.87,27.97-1.02
c7.43-0.01,15.53,0.8,21.35,5.94c-22.57,6.88-46.27,0.38-69.24,3.5c2.75,1.57,5.76,2.71,8.94,2.94c8.69,0.77,17.34-0.91,26.03-0.86
c11.46,0.01,23.25-0.39,34.23,3.43c-7.61,8.04-19.58,5.53-29.39,4.82c-13.48-0.3-27.18-0.75-40.46,2.02
c11.02,2.34,22.37,2.22,33.58,2.25c8.86,0.17,17.72-2.12,26.56-0.66c3.71,0.58,7,2.56,9.62,5.19c-20.9,6.86-42.99,0.32-64.3,3.5
c8.35,2.94,17.34,2.12,26,1.49c13.25-1.02,27.6-1.86,39.49,5.18c-9.35,5.14-20.25,6.35-30.75,5.71c0.02,0.35,0.07,1.06,0.1,1.41
c10.33-1.07,21.16-0.21,30.7,4.19c-2.25,2.63-4.99,5-8.42,5.87c-8.22,2.37-16.68-0.24-25.01-0.22
c-11.39,0.02-22.76,0.73-34.13,1.14c15.36,4.81,31.42-0.01,47.08,1.07c7.12,0.36,14.17,2.25,20.4,5.74
c-5.17,2.43-10.63,4.34-16.32,5.06c-17.48,2.68-35.2-2.83-52.61,0.66c11.95,3.52,24.4,0.79,36.58,0.94
c10.92-0.25,22.67-1.19,32.47,4.6c-5.41,5.89-13.94,6.3-21.38,5.53c-15.79-1.94-31.71-0.39-47.53,0.26
c11.85,3.8,24.35,0.48,36.48,0.92c10.91-0.14,24.14-2.22,32.35,6.77c-23.17,9.46-48.39,0.99-72.37,4.61
c19.46,5.52,39.71-1.78,59.33,2.26c4.55,0.87,8.92,2.5,13.07,4.55c-10.42,7.04-23.51,6.07-35.46,5.68
c-12.65,0.15-25.33-1.75-37.95-0.07c12.16,2.46,24.64,2.19,36.99,2.23c9.12,0.11,18.37-2.64,27.4-0.24
c3.59,0.85,6.51,3.22,8.98,5.86c-23.79,9.36-49.57,0.96-74.1,4.66c19.94,5.63,40.7-2.16,60.78,2.14c4.65,0.88,9.11,2.54,13.34,4.62
c-3.46,2.23-7.21,4.12-11.31,4.84c-9.32,1.88-18.75-0.42-28.13-0.31c-12.07,0.04-24.13,0.59-36.18,1.18
c24.91,5.93,51.41-4.43,75.67,5.56c-3,2.72-6.48,5.04-10.49,5.93c-9.84,2.35-19.99,0.68-29.97,0.8c-11.16-0.08-22.4-1.5-33.52,0.06
c11.97,2.5,24.3,2.09,36.46,2.21c9.44,0.11,18.94-2.59,28.32-0.51c3.51,0.68,6.55,2.7,9.14,5.09c-11.23,5.8-24.19,4.87-36.41,4.57
c-13.08,0.25-26.45-2.77-39.27,1.02c12.54,3.01,25.55,1.93,38.3,1.38c9.34-0.53,18.71-0.36,28.06-0.23
c3.69,0.02,6.82,2.33,8.35,5.63c-9.68,6.24-21.63,4.68-32.47,3.69c-14.07-0.6-28.16,0.46-42.22,0.98
c7.92,2.11,16.19,2.03,24.31,1.57c9.63-0.71,19.3-0.66,28.95-0.95c7.97-0.25,16.56,1.23,22.42,7.09
c-24.64,9.47-51.19,1.04-76.6,4.59c12.24,2.45,24.79,2.21,37.21,2.24c9.65-0.01,19.4-2.43,28.97-0.28
c3.71,0.86,7.28,2.45,10.23,4.88c-6.76,5.38-15.84,6.2-24.16,5.5c-17.03-1.94-34.18-0.41-51.24,0.23
c12.93,2.3,26.11,2.15,39.19,2.03c8.96-0.14,18.05-2.51,26.92-0.24c3.21,0.77,5.9,2.77,8.4,4.85c-6.17,6.14-15.38,6.09-23.45,5.46
c-16.35-1.75-32.82-0.41-49.18,0.35c11.23,2.54,22.85,1.94,34.29,2.07c9.53,0.08,19.11-2.48,28.59-0.51
c3.97,0.75,7.64,2.62,10.81,5.12c-3.31,2.15-6.88,3.98-10.78,4.74c-9.81,2.07-19.76-0.41-29.63-0.21
c-11.55,0.19-23.11,0.44-34.63,1.27c13.41,2.27,27.08,2.19,40.63,1.93c11.49-0.78,24.17-3.11,34.49,3.53
c-2.85,2.53-6.2,4.6-10.01,5.24c-9.13,1.66-18.3-0.75-27.45-0.68c-12.39,0.05-24.91-0.24-37.11,2.24
c12.88,2.61,26.09,2.07,39.15,2.12c8.76-0.03,17.58-2.36,26.28-0.4c3.45,0.71,6.39,2.73,9.06,4.94c-23.9,9.56-49.81,1-74.51,4.63
c18.09,5.05,36.81-0.53,55.16,1.38c6.72,0.61,13.32,2.47,19.38,5.45c-10.05,7-22.79,6.23-34.42,5.71
c-13.05,0.15-26.14-1.83-39.15-0.07c20.28,5.19,41.22-1.48,61.64,2.18c4.08,0.72,8.06,1.93,11.93,3.43
c-2.59,3.02-5.9,5.53-9.87,6.31c-8.82,2-17.73-0.75-26.6-0.64c-11.85,0.09-23.7,0.68-35.54,1.18c16.89,4.85,34.43-0.29,51.59,1.12
c7.07,0.49,14.06,2.34,20.36,5.63c-14.28,7.38-30.81,6.05-46.3,4.95c-8.27-0.5-16.61-0.68-24.83,0.58
c19.65,5.51,40.14-1.5099,59.99,2.38c3.84,0.72,7.56,1.93,11.21,3.34c-5.38,5.94-13.81,7.17-21.41,7.12
c-8.02-0.41-16.06-0.16-24.08-0.58c-8.13-0.31-16.33-0.94-24.41,0.31c14.17,4.09,29,1.06,43.44,0.77
c9.08,0.13,18.43,1.5,26.42,6.08c-5.66,3.81-12.63,5.02-19.34,4.37c-15.44-1.87-31.04-0.7-46.49,0.31
c9.73,5.38,20.97,1.92,31.43,1.93c11.6,0.03,24.31-1.76,34.68,4.75c-5.6,2.45-11.74,3.13-17.73,4.01
c-15.43,2.07-30.97,3.42-46.54,3.69c4.46,0.88,9.04,0.86,13.57,0.93c13.19,0.24,26.41-0.1,39.57,1.06
c3.84,0.47,8.03,0.77,11.11,3.42c-4.3,3.12-9.45,4.73-14.61,5.74c-14.18,2.74-28.8,2.17-42.93,5.26
c-11.35,2.15-23.42,5.01-34.73,1.19c-7.47-2.55-12.71-9.19-15.37-16.4c-4.81-12.7599-6.1-26.47-7.44-39.93
c-1.86-23.36-4.47-46.64-6.19-70.01c-9.6-122.45-8.92-245.88,5.23-367.96c2.08-17.37,1.67-35.15,6.44-52.11
C183.2078,68.1071,186.8078,60.2371,193.4378,55.2971 M225.7078,333.5371c10.15,3.14,20.89,1.82,31.3,1.22
c0.49-0.64,1-1.26,1.53-1.87c-2.19,0.7-4.5,0.24-6.73,0.19C243.1278,332.3671,234.2978,331.7471,225.7078,333.5371z"/>
<path stroke="#000000" stroke-width="0.0938" d="M375.5478,88.5971c6.09-4.49,13.94-5.82,21.35-5.14
c17.61,1.45,34.54,6.86,51.62,11.01c5.19,1.03,12.08,0.5,14.75,6.18c-2.21,1.89-4.81,3.3-7.73,3.66
c-17.88,2.33-36.15,0.14-53.88,3.85c19.82,3.55,40.35-0.36,59.96,4.62c-2.77,1.21-5.64,2.27-8.65,2.71
c-17.03,2.62-34.47-2.3-51.37,1.73c19.26,4.38,39.31-1.02,58.59,3.31c-1.52,1.69-2.99,3.71-5.32,4.29
c-7.19,2.07-14.68,0.22-21.99,0.29c-10.46,0.15-21.17-1.47-31.4,1.41c16.07,5.17,33.14-1.67,49.43,2.04
c2.89,0.59,5.41,2.2,7.58,4.14c-19.15,4.57-39.11-1.36-58.26,3.06c18.58,4.49,37.99-1.51,56.58,3.03c-2.43,1.81-5.23,3.08-8.2,3.69
c-15.94,3.31-32.51-1.63-48.32,2.49c18.59,4.56,38.05-1.6,56.67,2.97c-2.35,1.84-4.99,3.35-7.95,3.92
c-15.62,3.46-31.9-2.08-47.41,2.31c17.66,4.72,36.25-1.78,53.89,3.07c-4.19,4.58-10.86,4.17-16.52,4.6
c-13.54,1.1-27.1-0.73-40.65,0.01c6.6,3.57,14.33,3.54,21.62,3.42c11.8-0.18,23.95-2.3,35.48,1.15c-8,3.49-16.83,4.13-25.44,4.55
c-11.05,0.3-22.11-0.22-33.15,0.29c8.4,4.07,17.99,3.35,27.04,3c10.01-0.34,20.38-1.75,30.11,1.44
c-6.56,6.19-16.04,2.52-23.97,3.03c-11.46,1.07-22.94,2.28-34.46,1.83c7.85,3.52,16.64,3.25,25.06,2.99
c11.12-0.25,22.56-1.82,33.44,1.3c-2.26,2.06-5.1,3.47-8.21,3.52c-8.27,0.42-16.57-1-24.83-0.02c-7.94,0.95-15.92,1.85-23.93,1.39
c5.53,2.76,11.79,3.15,17.85,3.26c8.34-0.21,16.68-0.89,25.02-0.91c4.75,0.11,9.63,0.31,14.06,2.2
c-4.08,5.43-11.35,2.86-17.04,2.94c-13.26,0.27-26.53,0.56-39.76,1.57c5.52,2.64,11.71,3.19,17.74,3.34
c13.02,0.27,26.03-1.65,39.04-0.44c-1.01,1.91-2.07,4.18-4.41,4.7c-5.48,1.45-11.11-0.3-16.66,0.02
c-11.94,0.44-23.98-0.37-35.82,1.49c6.04,2.25,12.53,2.8,18.92,3.12c12.65,0.37,25.29-0.72,37.95-0.21
c-2.23,4.46-7.44,5.61-12,5.47c-6.7,0.03-13.36-0.91-20.06-0.71c-8.36-0.07-16.87-0.7-25.03,1.46c18.79,4.21,38.34-0.98,57.12,3.27
c-2.96,5.39-9.68,5.45-15.05,5.12c-8.66-0.67-17.34-0.74-26.02-0.83c-4.92-0.07-9.9,0.21-14.62,1.7
c15.5,4.79,31.87-1.31,47.57,1.95c3,0.61,5.68,2.19,8.04,4.1c-17.62,4.95-36.26-1.54-53.92,3.22c15.51,4.71,31.86-1.38,47.57,1.91
c2.98,0.59,5.59,2.24,7.91,4.15c-18.21,4.13-37.14-1.08-55.34,3.1c17.68,4.45,36.21-1.53,53.88,3.07
c-2.07,1.81-4.36,3.53-7.11,4.11c-13.97,3.18-28.62-2.57-42.4,1.96c16.67,4.65,34.3-1.55,50.99,3.05c-2.7,2.38-6.03,3.92-9.59,4.44
c-14.22,2.29-28.61-1.37-42.87,0.33c6.94,3.84,15.16,3.53,22.85,3.26c10.33-0.3,21.04-2.05,31.09,1.27
c-2.46,2.02-5.35,3.51-8.51,4.03c-13.06,2.19-26.55-1.62-39.46,1.95c16.12,4.82,33.28-1.53,49.45,3.11
c-16.53,7.02-34.92,3.29-52.3,4.94c7.58,4.05,16.45,3.23,24.73,2.98c9.19-0.32,18.74-1.7,27.62,1.42
c-16.1,6.89-34.06,3.58-51.04,4.71c2.28,1.36,4.7,2.61,7.37,2.95c12.01,1.74,24.1-1.96,36.12-0.26c3.51,0.4,6.67,2.15,9.15,4.63
c-16.99-0.13-33.99,0.58-50.93,1.91c2.1,1.05,4.25,2.09,6.58,2.54c14.71,2.53,29.96-2.65,44.43,1.83c-1.84,1.5-3.89,2.88-6.3,3.19
c-9.64,1.53-19.4-1.13-29.03,0.47c-4.54,0.8-9.09,1.41-13.68,1.77c16.2,6.38,33.95-1.29,50.38,3.76c-2.33,1.38-4.86,2.51-7.56,2.9
c-13.85,2.3-28.11-1.94-41.8,1.77c6.5,3.97,14.47,3.48,21.79,3.3c9.73-0.23,19.89-1.93,29.26,1.46c-3.63,2.38-7.95,3.3-12.23,3.42
c-9.01,0.22-18.01-1.41-27.01-0.59c-3.17,0.21-6.13,1.4-8.86,2.96c16.17,6.93,34.82-0.64,51.02,6.33c-4.25,4-9.6,6.49-15.13,8.15
c-13.59,3.79-23.71,15.22-29.5,27.65c-7.81,16.93-9.2,36-8.67,54.4c1.08,27.79,6.8,55.17,13.96,81.96
c4.6,16.66,9.39,33.31,15.71,49.41c2.52,6.8,5.11,14.42,2.2,21.53c-3.11,9.08-12.77,13.94-21.87,14.5
c-14.08,0.98-28.88-3.4-39.44-12.93c-8.37-8.32-12.12-19.9901-14.86-31.18c-4.89-21.72-5.35-44.17-4.3-66.32
c1.04-26,9.65-50.99,11.12-76.94c1.49-24.87-1.88-49.71-6.54-74.09c-6.03-31.57-14.28-62.8-17.35-94.88
c-1.72-19.96-2.12-40.01-1.66-60.04c0.73-20.16,1.94-40.65,8.42-59.92C361.6678,104.9871,366.7978,94.9471,375.5478,88.5971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M573.9678,88.6071c18.35-0.51,36.63-2.86,55.01-2.59
c2.46,0.15,5.24-0.01,7.2599,1.68c1.51,2.13-0.48,4.35-2.7,4.51c-21.66,3.82-43.69,4.9-65.46,7.83c-0.08,1.85-0.13,3.7-0.16,5.56
c21.69-0.69,43.3101-3.98,65.05-2.87c2.07-0.18,4.38,1.79,3.71,3.98c-0.04,1.32-1.77,1.46-2.73,1.81
c-21.81,3.95-43.98,5.16-65.94,7.92c-0.03,1.92-0.02,3.84,0.02,5.76c13.25-0.89,26.54-1.32,39.77-2.6
c8.06-0.9,16.16,0.19,24.22-0.62c3-0.65,4.33,2.54,4.48,4.97c-4.62,1.85-9.65,2.14-14.49,3.11c-12.21,2.42-24.73,2.21-37.06,3.78
c-5.76,0.82-11.6,0.88-17.34,1.79c-0.06,1.92-0.08,3.83-0.06,5.75c21.81-0.8,43.55-3.46,65.4-3.18c1.83,0.17,2.81,2.01,3.05,3.65
c-0.22,1.8-2.11,1.99-3.52,2.3c-14.09,2.23-28.2401,4.18-42.45,5.48c-7.46,0.86-15,1.08-22.39,2.44c-0.08,1.76-0.11,3.51-0.08,5.27
c17.15-0.05,34.2-2.29,51.35-2.43c4.91,0.07,9.96-0.96,14.77,0.34c2.21,0.53,3.36,4.48,0.55,4.95
c-22.09,4.35-44.64,5.73-66.9901,8.25c-0.06,1.77-0.09,3.55-0.09,5.33c12.3,0.33,24.58-0.98,36.88-1.11
c8.31-0.18,16.6-0.94,24.91-1c2.25-0.01,4.94,0.12,6.31,2.23c0.81,2.22-1.24,3.68-3.2,3.88c-21.56,3.51-43.5,3.76-65.14,6.59
c-0.26,1.97-0.2,3.96-0.17,5.95c20.4-0.81,40.86-0.62,61.23-2.18c2.5-0.02,5.31-0.07,7.34,1.66c0.65,1.53,0.23,3.57-1.71,3.68
c-4.52,0.77-9.07,1.4-13.6,2.19c-17.86,1.44-35.74,3.04-53.57,4.81c-0.1,1.97-0.14,3.95-0.14,5.93
c22.5699,0.04,45.11-1.52,67.67-1.71c0.91,1.55,2.51,4.24,0.02,5.24c-3.94,1-8.09,0.62-12.09,1.25
c-18.47,2.18-37.02,3.52-55.5,5.55c-0.08,2-0.1,4.02-0.06,6.03c20.54-0.06,41.09-0.64,61.62-1.49c2.52-0.08,5.84-0.21,6.88,2.67
c1.27,1.58-0.74,3.34-2.33,3.3c-22.19,2.07-44.43,3.4-66.62,5.39c-0.05,2.18-0.03,4.37,0.13,6.55c21.64-0.7,43.31-0.59,64.93-1.87
c3.31-0.27,4.98,6.1,0.97,6.17c-21.91,2.22-43.97,3.24-65.83,5.94c-0.13,1.9-0.23,3.8-0.27,5.71c21.4,0.05,42.79-0.84,64.19-1.14
c2.89-0.33,4.29,2.63,4.5,5.05c-1.54,0.48-3.06,1.07-4.65,1.29c-21.4301,1.83-42.89,3.19-64.3,5.12c-0.06,2.06-0.06,4.13,0.01,6.19
c18.46,0.17,36.91-0.74,55.37-0.67c3.3,0.09,6.66-0.71,9.93-0.04c2.21,0.61,2.2401,3.26,2.56,5.1c-1.78,0.49-3.56,1.05-5.41,1.18
c-20.8,1.44-41.6,2.87-62.38,4.59c-0.13,1.96-0.21,3.93-0.21,5.9c20.8701,0.28,41.75-0.67,62.6201-0.53
c2.64-0.25,4.41,1.7,5.55,3.85c-0.93,1.25-2.06,2.48-3.75,2.44c-11.34,0.76-22.66,1.76-34.01,2.47c-10.24,0.64-20.5,1.05-30.7,2.22
c-0.03,1.97-0.02,3.94,0.04,5.91c20.26,0,40.54,0.12,60.8-0.16c2.99-0.28,5.52,1.32,6.59,4.11c-0.86,0.92-1.5,2.38-2.97,2.31
c-14.56,0.51-29.09,1.73-43.64,2.4c-7.07,0.48-14.18,0.48-21.21,1.46c-0.07,2.08-0.08,4.16,0,6.24c20.75,0.01,41.52-0.2,62.27-0.24
c2.89-0.05,5.48,1.95,5.58,4.98c-2.33,1.34-5.01,1.75-7.65,1.75c-13.35,0.46-26.63,1.98-39.97,2.41
c-6.57,0.35-13.17,0.5-19.67,1.55c-0.33,1.78-0.42,3.59-0.53,5.41c10.4,0.47,20.8-0.26,31.2-0.23c10.33,0.12,20.66-0.83,30.99-0.27
c2.2,0.06,5.56,1.16,4.84,4.01c0.2,1.65-1.91,1.45-2.95,1.82c-19.66,2.26-39.32,4.51-58.98,6.71c-2.18,0.19-4.47,1.05-5.57,3.07
c-2.37,4.04-1.7599,8.97-1.58,13.45c1.74,28.65,2.82,57.33,4.78,85.96c0.34,13.71,1.83,27.34,2.21,41.05
c1.01,12.71,1.46,25.46,2.57,38.16c1.71,14.59,2.66,29.25,3.77,43.9c0.12,4.03,0.51,8.63-2.0699,12.03
c-1.86,2.45-5.16,2.5-7.94,2.72c-10.4,0.76-20.73,2.38-31.13,3.1c-6.13,0.56-11.8-4.67-11.85-10.79
c-0.72-20.99-0.84-42.01-1.31-63.01c0.35-55.01-0.66-110.03,0.29-165.05c0.29-13.66-0.04-27.33,0.5099-40.99
c0.85-18,0.6-36.02,1.58-54.02c-0.03-15.02,0.74-30.03,1.3-45.04c0.02-22.34,1.86-44.62,2.36-66.94
c0.54-12.65,0.91-25.3,1.81-37.93c0.56-4.56,1.37-11.21,6.81-12.34C548.9378,91.3871,561.3578,88.9671,573.9678,88.6071z"/>
<path stroke="#000000" stroke-width="0.0938" d="M907.9178,176.1771c6.3-0.93,12.72-2.67,19.1-1.23
c7.43,1.59,14.83,3.64,21.76,6.83c-3.44,7.01-11.54,9.34-18.74,9.85c-11.28,0.76-22.38,2.95-33.54,4.65
c-4.79,0.85-10.07,1.11-14.11,4.1c-2.22,1.78-2.06,5.1-0.55,7.29c19.7,1.93,39.48-0.92,59.17-1.59c2.73,0.11,6.98,1.36,6.63,4.81
c0.04,3.79-3.74,5.93-7,6.58c-13.84,2.72-27.77,4.93-41.74,6.87c-5.83,0.6-12.01,0.49-17.17,3.71c-0.17,2.46-0.01,4.93,0.45,7.36
c16.57,1.5,33.19-0.06,49.77-0.53c5.5-0.23,12.03-1.7,16.58,2.31c0.36,1.95,0.15,4.35-1.51,5.68c-2.49,2.08-5.89,2.12-8.93,2.57
c-15.69,2.3-31.27,5.34-47.02,7.09c-2.7,0.42-5.62,0.94-7.71,2.83c-1.74,1.68-1.4,4.47-0.47,6.49c2.38,1.45,5.3,1.64,8.03,1.83
c17,0.47,33.96-1.39,50.96-1.22c2.86,0.19,6.37,1.22,7.4,4.25c0.07,3.44-2.87,5.95-6.08,6.36c-14.71,1.99-29.42,4.08-44.19,5.59
c-4.55,0.54-9.26,0.88-13.48,2.81c-2.41,1.05-3.95,3.82-3.41,6.42c0.92,2.33,3.71,2.91,5.91,3.34c6.6,1,13.26-0.16,19.9,0.04
c11.33-0.24,22.7,0.69,34.01-0.44c2.85-0.09,7.45,0.53,7.91,4.02c0.74,4.56-4.06,6.73-7.77,7.24c-16.77,2.84-33.82,3.61-50.62,6.19
c-2.91,0.57-6.87,1.15-7.82,4.5c-0.01,1.98,0.81,3.84,1.35,5.73c12.27,1.42,24.64,1.2,36.97,1.12c9.75-0.34,19.76-0.85,29.17,2.29
c0.17,3.48-1.7,7.07-5.43,7.57c-13.83,2.1-27.84,2.82-41.75,4.3c-5.79,0.68-11.97,0.14-17.31,2.83c-2.74,1.47-4.63,6.2-1.46,8.19
c3.85,2.13,8.49,1.75,12.74,1.64c15.35-1,30.7,1.71,46.03,0.45c2.57-0.1,4.94,1.04,7.21,2.13c0.52,6.08-5.59,8.78-10.12,10.98
c-6.1801,3.16-13.22,3.6-20.02,3.69c-7.51,0.02-14.54,3.04-21.96,3.7c-7.79,0.75-15.73,0.38-23.33,2.51
c1.65,63.64,2.68,127.31,4.9,190.94c0.14,9.39,1.77,18.86,0.12,28.2c-0.32,1.04-0.19,2.64-1.52,3c-9.11,3.77-18.98-0.85-28.35,1.23
c-1.94-3.09-2.22-6.71-2.08-10.25c-3.58-95.36-6.5-190.74-9.5099-286.12c-1.09-38.63-3.2-77.28-2.08-115.93
c4.99-1.93,10.32-2.63,15.65-2.77c11.73-0.39,23.34-3.57,35.13-2.43C894.5978,176.3371,901.2978,177.2171,907.9178,176.1771z"/>
<path stroke="#000000" stroke-width="0.0938" d="M777.1978,258.6471c2.4-0.28,4.8-0.48,7.22-0.63
c4.09,13.91,3.6801,28.54,5.17,42.83c1.95,19.82,2.61,39.74,4.6,59.55c1.67,19.46,1.66,39.02,2.83,58.51
c1.28,22.65,2.39,45.46-0.27,68.07c-3.29,26.7-7.96,53.24-10.61,80.02c-0.51,2.43-0.67,5.6-3.21,6.85
c-4.33,2.05-9.28,1.98-13.97,2.14c-15.99-0.13-32,0.4-47.97-0.75c-3.05-0.03-4.87-2.87-5.9-5.38c-3.26-7.83-3.51-16.46-5.75-24.57
c-6.21-22.66-12.44-45.36-16.76-68.47c-4.4-24.21-5.44-48.86-6.4-73.39c-1.33-36.18-4.22-72.33-3.5-108.55
c0.06-8.7-0.73-17.57,1.59-26.07c2.42-0.65,5.5-1.97,7.52,0.28c2.64,3.14,2.9,7.49,3.42,11.39c3.13,36.09,5.54,72.25,7.13,108.45
c0.18,4.79,1.11,9.54,2.7,14.07c0.49-1.33,0.89-2.69,1.19-4.07c-1.27-23.99-2.1201-48.02-2.6-72.05c-0.15-13.99-0.65-28,0.49-41.96
c0.5-5.46-1.37-11.09,0.49-16.4c0.9-3.26,5.86-3.45,7.22-0.45c2.09,4.61,1.21,9.86,1.75,14.77c2.91,33.3,5.53,66.64,7.03,100.04
c0.34,6.29-0.91,12.84,1.72,18.81c1.14-0.89,2.39-2.06,1.95-3.68c-1.07-6.29-0.88-12.68-1.24-19.02
c-1.23-25.32-1.9901-50.67-1.88-76.02c-0.01-9.73-0.02-19.46-0.77-29.16c-0.11-2.75-0.2-5.77,1.33-8.19
c1.76-2.45,6.19-1.54,7.03,1.33c1.76,4.74,1.04,9.93,1.54,14.88c3.17,36.66,7.08,73.29,8.29,110.09c0.14,3.1,0.93,6.12,2.04,9.01
c2.05-2.87,2.4-6.52,1.77-9.92c-1.12-5.96-1.39-12.02-1.74-18.06c-0.65-12.02-1.4-24.03-1.58-36.07
c-0.58-13.67,0.07-27.36-0.43-41.04c-0.33-7.99-0.46-15.98-0.83-23.97c0.06-2.88-0.05-6.04,1.54-8.56
c1.66-2.62,6.22-1.89,7.19,0.97c1.84,4.59,1.16,9.68,1.64,14.5c1.28,15.05,3.77,29.96,4.97,45.01c1.27,21.69,2.83,43.37,3.4,65.09
c0.07,3.99,0.76,7.97,2.31,11.66c2.11-3.55,2.41-7.73,1.9901-11.75c-1.9-21.92-3.21-43.92-2.73-65.93c0-17.34-0.22-34.69-0.9-52.02
c0.11-3.48-0.03-7.48,2.37-10.28c1.57-1.58,3.79-0.47,5.64-0.14c2.61,5.16,1.81,11.05,2.31,16.61
c3.03,34.93,6.91,69.81,8.2599,104.85c0.19,5.81-1.44,12.12,1.7401,17.42c4.16-6.15,1.1-13.58,1.17-20.34
c-0.68-16.05-1.81-32.08-2.14-48.14c-0.36-14.31-0.05-28.62-0.58-42.92C775.6478,278.1371,775.4478,268.2871,777.1978,258.6471z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1420.7179,259.5871c0.4399-2.27,3.02-0.94,4.61-1.05
c1.26,6.29-1.6801,12.56-0.15,18.83c4.5,0.44,9.23,1.02,13.59-0.61c1.7201-0.95,3.4701,0.09,5.17,0.57c1.86-4.44,2.28-9.26,2.65-14
c0.25-1.24,0.02-2.82,1.14-3.68c1.6799-0.11,3.7999,0.44,4.25,2.34c-0.3401,0.94-0.76,1.85-1.25,2.71
c-2.6901,4.07-1.4401,9.17-1.5,13.73c3.76,1.19,8.39,1.26,10.9199-2.29c1.3,0.69,2.5801,1.4,3.9,2.09
c1.66-5.09,1.79-10.39,1.97-15.67c1.4401-0.08,2.91-0.12,4.39-0.11c0.8301,6.05-2.4199,11.65-2.3099,17.67
c4.8099,1.95,10.0399,2.14,15.15,2.56c2.0399-4.68,3.6-9.74,2.6599-14.89c-0.21-2.95,3.26-1.68,4.74-0.64
c0.0601,5.02-1.48,9.9-2.08,14.86c0.77,2.41,3.4,3.1,5.61,3.59c4.5801,0.88,9.0701,2.24,13.7001,2.92
c1.12-2.15,2.24-4.31,3.23-6.53c1.26-2.7,0.65-5.78,1.3099-8.62c1.28-0.25,2.61-0.22,3.9501-0.24
c1.64,6.12-4.28,10.67-4.1001,16.67c4.9801,2.27,10.3201,3.66,15.6101,5.04c2.75-2.46,3.6-6.34,3.6499-9.89
c0.02-1.68,1.67-2.95,3.3301-2.72c2.49-0.16,4.1,3.19,2.36,5c-2.01,2.62-3.3301,5.64-3.9301,8.87
c6.92,4.86,15.55,6.34,22.9401,10.4c1.09-1.33,2.0399-2.83,3.46-3.88c1.35,0.3,2.71,0.66,4.0701,1.09
c-0.16,1.9-0.88,3.67-1.7201,5.36c2.7201,2.21,5.7201,4.41,6.91,7.87c3.65,9.16,5.8199,19.04,5.74,28.92
c0.24,2.42,2.47,4,3.6901,5.97c-1,1.73-2.3401,3.28-3.0901,5.14c-0.59,4.29,0.48,8.63-0.1899,12.92
c-1.16,8.68-2.4301,17.67-6.73,25.43c-4.67,7.23-13.88,8.42-20.76,12.63c0.3099,2.16,1.1599,5.43-1.6901,6.26
c-2.34,0.53-3.48-1.79-4.77-3.21c-7.98,2.11-15.71,5.11-23.22,8.51c1.41,2.1,3.7001,3.76,4.28,6.34
c-0.23,2.67-3.6901,4.38-5.66,2.29c-0.7899-2.24-0.9299-4.63-1.38-6.94c-7.08-0.33-13.71,2.38-20.22,4.75
c1.12,1.97,2.5601,3.77,3.39,5.9c0.49,2.98-3.0601,4.57-5.41,3.23c-1.34-2.39-0.7-5.34-1.23-7.95c-6.65,0.04-13.14,1.68-19.52,3.34
c0.36,2.46,1.1901,4.93,0.85,7.45c-0.61,1.86-2.6599,1.38-4.11,1.15c-1.45-2.1-1.02-4.75-1.26-7.13
c-5.95-1.57-11.86,0.85-17.8099,1.11c0.2,1.6,0.51,3.21,0.5499,4.85c0.29,2.22-2.85,1.75-4.0299,2.51
c-0.65-2.07-0.8201-4.23-0.9401-6.37c-5.39-0.98-10.7999,0.26-16.1899,0.11c0.2799,2.4,2.0699,7.83-2.3101,7.05
c-3.08-0.8-2-4.43-1.8199-6.7c-5.79-1.18-11.6801-0.36-17.51-0.43c0.0499,2.49,0.26,4.98,0.22,7.48c-1.77,0.08-3.99,1.28-5.17-0.61
c-0.24-2.24,0.4701-4.45,0.6801-6.65c-5.6801-1.98-12-1.88-17.95-1.55c0.21,2.31,1.11,4.62,0.61,6.96
c-1.5601,1.28-3.8401,1.36-5.53,0.36c-0.3201-2.54,0.92-4.89,1.23-7.36c-1.59-1.79-4.09-2.02-6.28-2.44
c-4.87-0.66-9.6599-1.89-14.5699-2.04c-0.4,2.47-0.11,5.1-1,7.48c-1.0601,1.73-3.5701,1-4.98,0.18
c-1.3301-2.96,3.15-5.62,1.64-8.58c-3.24-2.55-7.62-2.47-11.4-3.67c-1.7101-0.33-3.36-1.45-5.11-1.07
c-3.66,1.7-0.0601,7.83-4.1001,9.17c-1.9299,1.35-3.99-0.87-3.48-2.82c0.8201-2.64,2.17-5.09,2.8201-7.8
c-8-3.68-16.67-5.66-24.55-9.62c-3.4399,2.09-6.3199,4.9-9.39,7.47c-0.62,1.35-0.49,3.56-2.36,3.85c-2.25,0.97-4.71-1.7-3.62-3.86
c0.38-1.57,2.23-1.64,3.4401-2.27c1.5299-2.61,3.1-5.21,4.23-8.02c-12.87-7.03-25.61-14.43-38.65-21.17
c-3.3-1.96-7.23-1.09-10.77-2.07c-5.1-1.45-10.4-0.2-15.5599,0.11c-23.8601,0.06-47.39,4.52-70.9701,7.55
c-29.62,3.97-59.5699,4.81-89.4199,4.42c-16.26-0.26-32.52-0.86-48.7101-2.39c-10.02-1.05-19.83-3.78-29.93-3.99
c-2.98,0-5.9-0.62-8.68-1.62c-2.42-0.81-5.33,0.41-7.35-1.49c-2.98-2.5-6.4-5.81-5.64-10.1c0.6801-7.01-0.41-14.01-0.23-21.03
c-0.05-4.34,0.49-8.66,0.49-13c-0.68-5.47,3.62-9.74,7.25-13.19c3.31-1.41,7.08-1.25,10.52-2.31c4.34-1.43,9.04-0.24,13.37-1.75
c7.57-2.29,15.5001-2.94,23.34-3.73c35.1801-3.58,70.63-4.52,105.9401-2.51c22.7999,0.94,45.35,4.65,68.01,7.09
c6.3099,0.64,12.64,1.32,19,1.26c1.71-0.08,3.34,0.56,4.96,1.1c8.63-1.94,17.73,1.77,26.13-1.55
c3.6801-1.24,7.6899-1.32,11.21-3.08c7.74-3.63,14.42-9.07,21.8101-13.3c-1.52-2.51-4.3201-3.92-5.79-6.4
c-0.89-2,1.34-3.29,2.67-4.25c2.51,1.78,3.71,4.68,5.63,6.99c1.6599,2,4.3199,0.18,6.21-0.54c5.5699-3.05,11.3-5.78,16.89-8.79
c-0.6801-3.46-2.39-6.5-4.5601-9.23c-1.7699-1.77,0.51-4.95,2.76-3.96c2.0601,0.3,2.65,2.42,2.86,4.18
c0.3,2.84,1.9801,5.22,3.63,7.45c6.9401-2.47,13.8401-5.08,20.8301-7.4c0.1799-5.44-2.22-10.55-2.0601-15.98
c1.66,0.07,3.3301,0.27,4.99,0.58c-0.6899,4.67-0.4099,9.46,1.41,13.86c5.34-0.98,10.9-1.67,15.6801-4.47
c-0.26-3.66,0.08-7.47-1.26-10.95c-0.5-1.57-1.4-3.22-0.62-4.86c1.4399-1.61,3.1699,0.01,4.74,0.54
c0.0399,4.26-0.37,9.1,2.45,12.67c3.5,3.53,8.7001,0.02,12.85-0.44c-0.02-3.3,0.12-6.61-0.0699-9.91
c-0.21-3.21-1.99-6.12-1.87-9.38c1.49,0.2,3.99-0.95,4.9299,0.81c1.1801,1.36,0.27,3.1,0.13,4.66
c-0.9399,4.43,1.02,8.74,2.2001,12.93c2.1799-1.01,4.38-3.14,6.89-1.66c2.88,1.46,6.0399,0.77,9.0499,0.12
c1.13-5.48,0.98-11.13,0.0701-16.63c-0.62-1.44,1.12-2.07,1.7999-3.02c0.9301,0.66,1.87,1.31,2.8301,1.97
c0.4299,6.01-1.39,12.45,1.3999,18.09c1.8101-0.77,3.4601-1.91,5.3-2.65c3.0601,0.35,5.87,1.98,9.05,1.86
C1422.6179,272.1071,1419.3679,265.6871,1420.7179,259.5871z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1037.7379,448.7771c14.63-2.47,29.48-0.18,44.2-0.07
c24.6801,0.09,49.36,0.01,74.04,0.04c29.97-0.12,59.96-0.3,89.9099,0.99c12.54,0.51,25.2001-1.55,37.65,0.77
c12.65,2.24,24.8201,6.59,37.48,8.83c9.8301,1.92,19.9,2.02,29.89,2.12c30.12,0.27,59.98-4.3,90-5.89
c22.7101-1.07,45.6801-1,68.1001,3.21c7.1799,1.55,14.5399,3.32,20.7999,7.33c9.96,6.42,10.6901,23.6,0.34,29.99
c-7.6499,4.5-16.6,5.93-25.24,7.26c-25.1699,3.2-50.6799,2.35-75.85-0.42c-28.64-2.99-57.26-7.19-86.12-7.14
c-15.33,0.28-30.95,1.6-45.33,7.31c-2.51,5.84-6.5601,11.09-11.98,14.49c-5.2101,3.41-11.28,5.12-17.3201,6.31
c-1.37,6.55-0.6,13.26-0.99,19.89c-1.26,9.11-3.83,18.55-10.37,25.37c-1.02-1.08-2.46-2.02-2.45-3.65
c-0.4-5.65-1.24-11.45-3.87-16.53c-2.25,6.89-1.6101,14.32-3.7001,21.25c-5.3099-8.12-6.26-18.18-7.9399-27.52
c-0.86,9.16,0.37,18.54-2.05,27.51c-1.1-1.04-2.34-1.99-2.99-3.36c-3.58-7.5-3.66-16.07-6.62-23.76
c-2.02,8.98,1.6,18.31-1.0699,27.2c-6.55-5.41-5.63-14.91-9.1001-22.03c-1.5399,7.58,0.8401,15.4-1.08,22.93
c-5.73-7.11-4.45-16.95-8.22-24.92c-2.48,7.58,0.5299,15.91-2.28,23.38c-1.15,2.29-2.88-0.68-3.23-2
c-1.48-7.17-3.79-14.12-6.2101-21.01c-3.11,7.94,2.01,16.53-1.23,24.44c-1.34-1.09-2.7999-2.27-3.0599-4.09
c-1.14-4.92-2.1-9.9-3.74-14.68c-1.24-0.95-1.29,1.11-1.7201,1.78c-1.6,5.56,0.9501,11.5-1.23,17.02
c-6.45-6.34-3.46-16.39-6.7799-24.1c-1.63-0.44-1.64,1.41-2.02,2.47c-1.75,7.11,1.7999,15.1-2.38,21.67
c-4.35-8.13-5.05-17.49-5.8401-26.49c-4.22,8.27-0.47,18.02-3.8199,26.47c-6.99-5.69-1.88-16.56-8.4399-22.48
c-2.8,7.28,2.1499,15.94-2.77,22.51c-5.2001-7.15-2.3-16.84-6.5601-24.23c-4.8199,7.35,1.5,16.94-3.59,24.21
c-5.3201-7.35-1.9301-17.31-6.46-25.02c-2.64,8.09,0.6599,17.1-3.12,24.93c-6.7101-7.08-2.4-17.74-6.41-25.95
c-4.64,7.98,0.29,18.0099-4.59,25.9c-5.4901-6.48-1.4801-15.66-4.4801-23.01c-0.5399-1-1.0299-2.56-2.4399-1.94
c-2.54,8.13,2.3,17.92-3.48,25.05c-5.63-7.96-1.5701-18.27-4.72-26.9901c-6.26,7.34-0.6201,17.82-4.4501,26.1201
c-1.71-0.95-3.5699-2.1201-3.79-4.25c-1.5699-7.22,0.0801-14.78-2.0199-21.94c-6.5701,7.58-0.3501,18.65-5.3401,26.92
c-2.71-2.19-3.6499-5.63-3.6499-8.99c-0.4501-5.95,0.6699-12.28-2.16-17.8c-3.3201,8.59-1.63,18.03-3.8301,26.86
c-3.7699-2.45-4.47-7.03-4.47-11.17c-0.22-5.0099,0.5-10.17-0.99-15.04c-1.85-0.12-2.79,1.78-3.25,3.29
c-1.88,7.22,1.64,15.3-2.42,22.05c-6.7899-7.34-1.7599-18.15-4.87-26.8c-6.75,7.05,0.37,18.45-5.75,25.8701
c-6.5299-7.09-0.21-18.1-5.58-25.46c-3.17,8.16-0.92,17.21-3.59,25.49c-1.52-1.22-3.51-2.37-3.62-4.54
c-0.29-13.62-1.9401-27.21-3.8101-40.71c-4.99-0.13-10.1699-0.06-14.84-2.03c-4.1-8.78-7.7801-17.82-11.0801-26.95
c-3.35-10.74-2.62-22.84,2.53-32.89C1023.7478,455.4071,1030.1179,450.0171,1037.7379,448.7771z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1064.0979,626.1671c6.76-1.98,14.97-4.08,21.1699,0.47
c5.3601,4.11,5.88,11.38,8.9801,16.96c2.23,4.9,6.4399,10.03,12.4399,9.3c2.21,9.37,4.2,18.78,6.3201,28.17
c-3.9401,2.02-7.64,5.19-8.51,9.76c-1.53,7.82,1.1,16.18-2.04,23.74c-1.0701,2.64-3.75,4.09-6.42,4.6201
c-24.01,5.84-48.6599,8.1299-73.04,11.89c-21.67,3.64-43.3,7.51-65.01,10.92c-62.94,9.89-125.54,21.7599-188.08,33.86
c-14.35,3-28.96,4.95-43.02,9.24c-6.2,1.67-12.51,3.53-18.99,3.47c-4.73-0.47-6.94-5.36-9.93-8.39
c-9.05,2.59-18.57,5.56-28.04,3.79c-4.43-0.84-5.61-5.57-7.24-9.06c-1.05-2.39-3.83-3.24-6.23-2.67
c-8.9,1.49-17.69,3.51-26.46,5.62c-0.32,4.29,2.15,9.35-1.04,13.01c-0.42-0.04-1.25-0.12-1.67-0.16
c-1.6801-3.07-1.7-6.71-3.22-9.82c-1.77-2.55-5.09-0.77-7.48-0.37c-0.08,4.55,3.03,11.45-2.56,13.87
c-1.12-3.93-1.29-8.37-3.88-11.69c-1.84-2.35-4.7-0.44-6.59,0.78c-0.18,4.45,2.45,9.95-1.72,13.31c-2.9-2.87-2.6-7.12-4.02-10.66
c-1.22-2.74-5.08-1.7599-6.86-0.18c-1.77,2.64-0.28,6.01-0.37,8.96c0.35,1.95-1.03,4.7-3.33,3.78c-1.24-3.08-1.16-6.53-2.46-9.57
c-1.48-3.38-7.66-1.88-7.69,1.71c-0.18,3.96,1.86,9.33-2.81,11.38c-1.49-3.42-1.42-7.3-3.1-10.62c-1.42-2.39-4.95-1.76-6.76-0.19
c-1.96,2.51,0.02,5.74,0.03,8.56c0.57,2.34-1.43,4.63-3.79,4.5c-1.29-3.24-1-6.88-2.38-10.07c-1.37-2.7-6.87-3.12-7.24,0.49
c-0.66,4.21,1.51,9.9-3.23,12.41c-2.09-4.76-2.8-10.87-7.61-13.8c-3.62,3.31-2.43,8.21-2.52,12.55c0.1,1.87-1.77,2.86-2.86,4.07
c-2.43-4.03-2.09-9.56-5.83-12.76c-1.96-0.34-3.58,1.01-5.26,1.74c0.48,4.59,3.21,10.95-2.06,13.76
c-2.24-3.74-2.38-8.36-4.81-11.98c-1.81-2.7401-6.89-0.14-6.01,2.93c0.34,4.06,1.95,9.73-2.92,11.75c-1.94-3.84-2.01-8.49-4.55-12
c-1.84-2.17-4.44,0.26-6.3,1.18c0.98,4.49,3.15,11.31-2.51,13.54c-1.61-3.7-1.36-8.07-3.64-11.47c-1.91-1.54-4.7-0.62-6.3,0.92
c-1.24,2.97,1.16,6.11,0.36,9.13c-0.39,1.31-1.48,2.96-3.09,2.59c-2.07-3-2.29-6.9901-4.83-9.6801
c-1.65-1.75-5.16-1.13-5.85,1.2401c-0.52,3.18,0.84,6.36,0.3,9.55c-0.28,1.82-2.33,2.3-3.63,3.21c-1.69-3.43-1.76-7.35-3.15-10.85
c-1.16-2.61-4.54-1.08-6.65-0.88c0.18,3.62,1.09,7.31,0.19,10.9c-0.34,1.96-2.41,2.55-3.92,3.37c-0.88-3.44-0.81-7.13-2.31-10.38
c-1.28-3.35-6.63-2.35-7.35,0.87c-0.19,3.31,1.59,6.67,0.37,9.91c-1.03,0.8-2.12,1.52-3.28,2.14c-2.28-2.82-2.3-6.5-3.02-9.86
c-0.53-2.63-3.84-2.4-5.85-1.96c-8.55,1.59-17.37,1.63-25.73,4.19c-8.86,2.31-18.13,3.81-27.28,2.73
c-4.62-0.57-10.16-2.76-11.11-7.9c-0.94-5.14-1.85-11.26,1.62-15.67c2.84-2.84,6.96-3.72,10.57-5.17
c15.67-5.13,31.8-8.71,47.8-12.61c3.39-0.68,1.24-4.52,1.05-6.72c-1.08-2.93,0.21-6.33,3.52-6.88c1.84,3.14,1.8,6.92,3.24,10.21
c1.41,2.92,6.47,1.65,6.91-1.34c0.15-2.66-0.72-5.29-0.45-7.93c0.12-1.85,2.17-2.22,3.45-3.06c1.79,3.4,2.22,7.2599,3.3,10.91
c1.94-0.21,4.12,0.12,5.85-0.98c1.49-1.65,0.62-4,0.73-5.96c-0.18-2.4,0.56-6,3.54-6.07c1.83,3.15,1.81,7.13,4.16,10.01
c1.42,1.61,4.08,1.11,5.54-0.2c1.87-3.42,1.26-7.51,1.72-11.24c2.59,2.94,4.04,6.74,6.78,9.55c1.26,1.62,2.84-0.27,3.28-1.53
c1.83-4.25,1.95-9.11,4.46-13.09c2,3.76,2.36,8.34,5.14,11.66c1.84,1.9,4.26-0.25,6.05-1.11c-0.3-3.2-1.22-6.41-0.73-9.62
c0.19-1.91,2.35-2.17,3.7-2.96c1.01,3.08,1.25,6.35,2.2,9.45c0.84,3.23,5.18,1.9,7.1,0.47c1.35-3.27-0.4-6.86,0.29-10.25
c0.88-0.93,2.09-1.41,3.19-2.02c1.53,2.88,1.94,6.15,2.94,9.22c0.88,2.03,3.71,2.14,5.39,1.1c1.81-4.18,2.27-8.9,4.82-12.78
c1.93,3.81,2.58,8.6,6.12,11.37c2.1,1.76,4.1-1.15,4.58-2.98c0.25-4.04-2.59-9.68,2.29-11.95c1.75,3.64,2.33,7.85,4.69,11.19
c1.38,2.35,4.37,1.0099,5.8-0.58c1.04-3.32-0.74-6.76-0.03-10.12c0.43-1.47,2.14-1.56,3.33-2.09c1.36,2.88,1.84,6.04,2.93,9.02
c1.24,2.64,5.09,2.03,6.79,0.23c2.37-3.25-1.13-7.65,1.02-10.91c0.6-0.32,1.81-0.95,2.42-1.26c1.6201,2.99,1.76,6.43,2.8101,9.6
c2.06,2.15,5.97,1.58,8.04-0.28c1.2-3.08-1-7.03,2.1-9.47c1.52,1.08,3.14,2.29,3.46,4.29c0.76,1.45,0.43,4.41,2.71,4.23
c1.85-0.09,3.52-1.03,5.24-1.61c-0.11-4.26-3.24-10.27,1.75-12.91c2.06,3.09,2,6.95,3.53,10.25c1.45,2.18,4.55,1.85,6.64,0.85
c2.5-2.55,0.31-6.33,0.41-9.39c-0.41-2.08,1.38-3.34,2.83-4.38c1.62,3.15,1.77,6.76,2.9,10.07c1.51,2.44,4.95,1.63,7.16,0.72
c2.69-1.5699,0.63-4.97,0.6-7.36c-0.6801-2.03,0.52-3.8,1.68-5.32c1.73,2.68,2.75,5.7,3.77,8.71c0.42,1.92,2.7,2.22,4.34,2.27
c6.1-0.14,11.79-2.8,17.86-3.29c3.65-0.69,8.33-0.95,10.47-4.48c0.49-3.77-0.65-7.9,1.34-11.37c1.65-1.72,3.86-2.77,5.81-4.13
c6.81-4.92,16.01-1.94,23.23-5.79c1.86-1.44,3.63-2.9901,5.58-4.31c0.05-2.54,0.25-5.08,0.94-7.53c8.13-1.59,16.41-1.96,24.68-2.06
c17.42-1.42,33.92-7.73,51.01-10.97c53.67-10.78,107.23-22.17,161.13-31.8
C973.7678,649.4471,1019.7878,640.9071,1064.0979,626.1671z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1262.7778,646.9071c6.2101-3.03,13.4-2.85,20.14-2.37
c14.23,1.34,28.0701,5.13,41.89,8.63c12.52,3.13,25.09,6.79,38.1,6.96c7.9601,0.42,16.24-0.8799,23.92,1.88
c3.5,1.19,6.3099,3.72,8.66,6.51c51.4199,2.9,102.98,4.79,154.47,2.39c26.85-1.34,53.72-3.75,80.16-8.76
c31.5-6.26,62.5399-15.96,94.84-17.28c11.4399-0.21,23.27-1.01,34.28,2.75c8.71,2.93,17.84,4.18,26.77,6.24
c9.85,2.14,19.6499,4.58,29.22,7.75c13.12,4.24,25.4199,10.56,38,16.12c15.1,7.26,30.88,14.96,41.61,28.28
c9.23,12.51,13.16,28.45,12.66,43.86c-0.5,12.14-3.9301,24.45-11.3201,34.25c-3.9399,5.5-9.96,8.9-15.52,12.52
c-14.49,8.77-29.4199,17.11-45.5699,22.43c-21.0601,7.07-43.22,9.7-65.12,12.75c-4.64,4.9901-8.09,11.31-8.48,18.22
c-0.76,10.72,3.5499,20.91,7.7899,30.51c4.65,9.82,8.62,19.94,13.25,29.77c7.8201,17.01,15.87,34.13,19.9701,52.5
c8.22,35.17,5.7899,71.81,0.22,107.19c-1.48,10.91-5.98,21.15-7.51,32.05c-0.8101,4.26,1.29,8.41,4.25,11.37
c6.5,6.77,15.8199,11.16,19.87,20.0599c5.02,14.2001,2.02,31.24-8.5699,42.2001c-8.7101,9.35-21.02,14.65-33.5,16.58
c-1.63,10.7001-2.75,21.5601-6.05,31.91c-2.01,6-4.88,12.0499-9.8201,16.1899c-1.73,0.8201-3.98,0.76-5.61-0.23
c-2.9099-2.95-1.84-7.5-1.9299-11.21c0.48-3.05-1.99-5.34-2.7101-8.12c-2.8099-9.01-1.8799-18.62-1.3099-27.88
c0.95-11.99,2.77-23.97,2.29-36.01c-0.12-5.79-3.7101-10.58-5.25-15.97c-0.87-3.12,1.71-5.89,1.6-8.9501
c-0.53-2.1-1.66-3.96-2.3-5.99c0.9-1.1899,1.9501-2.24,3.01-3.2999c-2.16-1.37-6.22-1.38-6.08-4.6901
c0.2999-2.25,2.23-3.72,3.5599-5.38c-2.8999-4.66-7.6799-8.22-8.9399-13.79c-5.34-19.5699-5.2001-40.0499-8.74-59.9199
c-2.17-12.4-5.6-24.87-12.4501-35.56c-4.59-7.22-9.7899-14.15-12.89-22.19c-2.8799-7.69-4.7999-16.22-2.47-24.31
c1.99-7.18,0-14.62-2.87-21.25c-3.41-7.6-6.49-15.34-10.1699-22.81c-2.27-5-4.9701-10.36-3.8601-16.02
c1.42-7.26,7.3301-13.31,6.79-20.98c-0.97-8.4301-9.54-13.04-11.71-20.9301c-1.1801-4.74,1.78-8.99,4.5399-12.52
c-5.4099-12.52-15.59-22.52-27.5399-28.86c-17.51-9.3701-37.04-13.78-56-19.2c-48.5601-13.37-98.23-22.88-148.39-27.61
c-35.22-3.19-70.73-4.09-105.97-0.84c-22.36,2.28-44.11,8.62-66.53,10.36c-9.85,0.73-19.85,0.38-29.5-1.83
c-4.4401-21.89,1.74-43.87,3.75-65.66c1.73-16.31,1.8099-32.83,4.97-48.97
C1259.6779,655.3771,1260.5879,650.8571,1262.7778,646.9071 M1789.8779,1122.1571c-4.62,9.88-9.5,19.83-11.6001,30.62
c-1.7999,8.86-1.34,18.1,0.8301,26.85c5.25,0.79,10.83,0.5901,15.63-1.9399c8.6599-4.3401,13.8199-13.6,15.5399-22.86
c1.42-8.5601,0.5701-18.1801-5.08-25.13C1801.5378,1124.9771,1795.6979,1122.6171,1789.8779,1122.1571z"/>
<path stroke="#000000" stroke-width="0.0938" d="M267.0778,698.3471c8.45-0.59,16.97-1.7,25.43-0.84c3.12,0.26,4.12,3.82,6.67,5.1
c2.61,0.22,5.16-0.72,7.77-0.5c1.77,0.83,3.24,2.18,5.01,3.04c2.95,0.69,6.01,0.17,9,0.05c5.99-0.54,12.01-0.34,18.02-0.53
c12.03-0.31,24.07-0.85,36.1-0.35c3.43,5.1801,4.08,11.57,4.22,17.63c0,5.97,0.11,12.06-1.34,17.9c-0.62,2.29-1.75,5.04-4.32,5.64
c-5.18,1.11-10.5,0.24-15.74,0.34c-12.64,0.24-25.28,0.63-37.92,0.51c-4.44-0.09-9.06,0.57-12.67,3.35c-2.47-0.01-4.95-0.33-7.41,0
c-3.18,0.8199-4.28,5.11-7.87,5.0699c-12.65,1.47-25.36-0.43-38.02-0.92c-27.03-0.85-54.07,0.19-81.11,0.38
c-27.33-0.14-54.67,0.73-81.99-0.15c-3.43-0.17-6.92,0-10.29-0.69c-0.74-1.1-1.29-2.28-1.89-3.43c-1.64-0.96-3.98-1.74-3.3-4.14
c1.28-2.85,4.94-2.26,7.5-2.37c8.39,0.55,16.66-1.2,24.93-2.32c3.13-0.4901,6.81-0.87,8.6-3.88c-1.95-1.29-4.09-2.37-6.48-2.41
c-6.37-0.33-12.53-2.43-18.94-2.32c-3.16-0.02-6.63,0.31-9.38-1.6c-0.09-0.73-0.27-2.18-0.36-2.9c1.33-0.79,2.66-1.56,4-2.3199
c-4.12-0.2-8.68,0.14-12.04-2.73c1.58-4.63,6.84-3.32,10.58-3.46c10.72-0.6,21.36-2.53,31.75-5.15
c-12.16-3.99-25.15-0.92-37.61-2.28c-1.81-1.0099-1.31-3.73,0.44-4.5c2.04-1.09,4.11-2.62,6.56-2.25
c11.72,0.41,23.36-1.6,35.07-1.3c3.41-0.42,6.39-2.49,9.86-2.66c9.01-0.77,18.06-0.09,27.08,0.16c24.32,0.34,48.6-1.39,72.92-1.8
C242.2978,699.5071,254.7278,699.5871,267.0778,698.3471z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1041.0879,779.8171c-0.34-1.45,1.29-2.7599,2.52-1.65
c3.74,1.4,2.6699,6.11,3.86,9.15c0.5499,2.66,4.01,1.22,5.95,1.33c-0.8099-3.8-1.27-7.76,0.22-11.46
c4.3501,1.92,4.6001,7.04,7.3101,10.34c5.71,0.89,11.34-0.97,16.9399-1.83c8.64-1.34,17.39-1.63,26.1101-2.14
c6.3999-0.38,12.88-0.5,19.1899,0.84c3.9301,9.68,4.99,20.41,2.97,30.68c-10.61,4.13-22.14,3.97-33.24,5.69
c-9.27,1.35-18.6,2.42-27.96,2.85c-5.01,0.36-1.52,6.21-2.4301,9.27c-0.46,2.4-3.25,1.03-4.5,0.01
c-2.2799-2.62-1.96-7.44-6.2999-7.87c-2.5,3.6-1.9501,8.15-2.77,12.26c-6.15-0.65-2.9301-9.35-8.1801-11.15
c-4.0599,3.37-0.6,8.97-1.74,13.37c-4.97-2.93-4.11-10.66-10.24-12.33c-3.03,3.88-0.75,8.78-1.27,13.19
c-5.78-1.38-6.02-8.29-9.52-12.09c-4.72,1.89-2,7.51-3.54,11.26c-6.01-0.07-3.32-9.1-8.44-9.58c-4.58,1.99-1.92,8.15-2.71,11.98
c-1.56-0.84-3.67-1.13-4.47-2.89c-1.41-2.6-1.09-6.54-4.16-7.93c-1.67-0.19-3.25,1.16-3.28,2.84c-0.22,2.92,0.27,5.86-0.06,8.79
c-4.65-1.58-4.85-6.86-7.26-10.39c-0.8,0.08-2.41,0.24-3.21,0.31c-0.34,0.53-1.01,1.57-1.34,2.09c0.22,3.15,0.75,6.38-0.2401,9.48
c-4.04-1.97-4.36-6.74-6.53-10.13c-1.29-1.84-3.52-0.38-5.15,0c0.48,3.43,0.8,6.92,0.23,10.37c-1.33-0.49-2.82-0.64-3.92-1.53
c-1.49-2.74-1.58-5.95-2.33-8.9c-1.8,0.03-3.59,0.07-5.36,0.19c-0.71,3.56,1.04,7.88-2.09,10.63c-3.46-1.94-3.37-6.17-5.22-9.23
c-1.69-0.57-4.06-0.42-4.84,1.45c-0.19,2.93,0.35,5.88-0.08,8.82c-4.84-0.62-5.01-5.91-6.86-9.34c-1.67-0.71-4.52-0.12-4.8,1.92
c-0.71,3.36,0.39,6.77,0.19,10.17c-4.81-1.5-4.66-7.13-6.7-10.88c-1.1-0.01-3.32-0.02-4.43-0.03
c-1.37,3.5099-0.39,7.23-0.6,10.8799c-4.38-0.48-4.4-5.35-6.22-8.34c-1.19-2.27-4.98-1.88-5.76,0.52
c-0.47,2.75,1.08,5.83-0.79,8.27c-4.19-0.86-3.97-5.53-5-8.75c-8.3-0.64-16.6201,0.19-24.83,1.34c-1.11,4.72-0.33,11.64-5.83,13.77
c-10.17,3.04-20.98,1.92-31.44,2.97c-12.65,1.22-25.34,0.06-38,0.69c-59.05,1.54-117.63,9.83-175.97,18.54
c-6.88,0.83-13.97,2.67-20.86,1.04c-6.52-2.59-1.99-13.05-8.9-15.1c-1.15-8.45-2.19-16.9-3.45-25.32
c1.51-0.75,3.03-1.49,4.54-2.2599c0.61-4.41-2.44-9.8,1.41-13.33c4.52-2.74,10.1-2.3,15.16-3.02c35.54-2.16,71.12-3.76,106.58-6.93
c39.81-3.23,79.03-10.95,118.4-17.37c8.94-1.43,18.06-3.11,27.13-1.93c6.08,1.03,6.16,9.53,12.03,10.95
c4.33,0.93,8.61-1.15,12.97-0.7c2.83,0.05,7.05,0.64,8.31-2.67c0.18-3.32-0.84-6.59-0.51-9.91c5.38,1.57,3.74,8.71,7.95,11.55
c1.36-0.86,2.9399-1.51,4.03-2.75c0.28-3.7-0.91-7.4,0.03-11.06c1.18,0.86,2.73,1.38,3.54,2.7c0.94,2.6-0.03,5.53,1.05,8.11
c1.31,2,5.33,2.79,6.2-0.04c1.17-3.73,0.31-7.77,1.57-11.49c3.44,2.62,3.84,7.13,5.86,10.66c1.46,2.23,4.43,0.67,5.88-0.81
c-0.32-3.86-1.31-7.73-0.38-11.58c4.74,2.39,4.1,8.3,6.65,12.2401c1.99,0.94,3.69-0.81,5.39-1.6c-0.22-3.81-1.4-7.66,0-11.39
c1.44,0.97,3.57,1.4901,4.06,3.4c0.81,2.36,0.56,5.09,1.97,7.25c0.82,1.75,3.17,0.89,4.68,1.22c1.81-4.36-0.77-8.95,0.67-13.39
c1.57,0.86,3.75,1.47,4.22,3.49c0.7,2.79,0.79,5.74,1.93,8.43c1.17,0.03,3.5,0.08,4.66,0.11c1.9901-4.24-0.38-8.8,0.83-13.17
c6.42,0.93,3.83,9.16,8,12.49c1.29-0.43,2.55-0.93,3.78-1.51c0.67-4.14-2.16-8.85,1.41-12.24c3.69,2.65,3.49,7.46,5.22,11.24
c1.11,2.42,3.81,0.6,5.59,0.12c0.24-4.05-0.98-8.12,0.16-12.11c1.12,0.55,2.3,1.04,3.34,1.79c2.09,2.81,0.59,6.75,2.43,9.69
c1.42,1.71,5.71,1.3199,5.32-1.47c0.29-3.26-1.55-6.86,0.58-9.79c2.08-0.1,4.22,1.37,4.34,3.57c0.36,2.94,0.69,6.31,3.89,7.54
c0.69-0.35,2.07-1.04,2.77-1.38c0.19-3.78-0.63-7.53-0.13-11.3c1.37,0.48,3.17,0.49,4.02,1.91c1.75,3.06,1.17,7.66,4.72,9.52
c5.4601-1.45,2.1901-8.34,3.3601-12.29c1.36,0.44,3.1799,0.34,4.0299,1.7599c1.6801,2.69,1.4701,6.12,3.12,8.84
c1.3101,1.76,3.4,0.2,5.0801-0.05C1041.6979,786.1171,1040.8579,782.9871,1041.0879,779.8171z"/>
<path stroke="#000000" stroke-width="0.0938" d="M277.0078,792.8871c1.1-3.48,0.74-8.69,4.8-10.18c3.28-0.93,4.01,3.91,7.01,3.71
c13.81,0.11,27.62-0.12,41.42-0.45c0.5-1.1,1-2.19,1.51-3.26c4.43,0.06,8.87-0.18,13.29,0.09c1.28,2.02,3.19,3.31,5.45,4.03
c2.7,5.24,2.76,11.3,2.98,17.06c0.01,6.02-0.24,12.16-1.94,17.97c-0.83,3.29-4.29,4.72-6.44,7.04c-5.07,0.32-11.35,1.92-15.25-2.35
c-13.71-0.25-27.4,0.69-41.1,0.5c-3.13-0.08-3.35,5.55-6.92,3.99c-3.44-1.95-3.41-6.58-4.76-9.89c-7.8,0.47-15.76-2.03-23.38,0.48
c-0.14,3.17,0.74,9.3101-4.1,8.98c-1.44-3.05-0.42-6.56-1.25-9.77c-1.6,0.18-3.2,0.39-4.79,0.62c-0.49,2.47-0.84,4.96-1.31,7.45
c-3.17-1.17-4-4.45-4.74-7.36c-1.75-0.02-3.5,0.02-5.24,0.13c-0.35,2.83-0.07,5.78-1.02,8.52c-0.89,0.35-1.8,0.4901-2.76,0.4
c-1.2-2.11-0.73-4.61-0.89-6.91c-1.82-1.05-3.8-1.77-5.83-2.3101c-0.69,2.96-0.37,6.11-1.47,8.97c-0.88,0.31-1.77,0.33-2.66,0.05
c-0.86-2.85-0.61-5.89-0.96-8.81c-2.05-0.03-4.17-0.13-6.13,0.58c-1.02,2.69,0.87,8.56-3.38,8.46c-1.45-2.65-0.22-5.87-1.4-8.59
c-1.92-0.84-4.05-0.62-6.05-0.28c-0.75,2.45-0.25,5.1-0.93,7.59c-4,0.38-2.96-4.46-3.53-6.98c-1.95-0.88-4.32-0.25-6.43-0.37
c-0.57,3.27,1.04,8.02-2.9,9.62c-0.91-3.1-1.18-6.33-1.56-9.52c-1.55-0.04-3.42-0.96-4.65,0.39c-1.91,2.83-1.69,6.57-3.69,9.39
c-2.54-2.62-1.41-6.4-2.45-9.56c-1.95-1.0099-4.06-0.05-6.01,0.42c-0.5,2.88,0.74,7.26-2.62,8.71c-2.97-2.15-1.01-6.24-2.27-9.18
c-1.96-0.73-4.02-0.1-5.98,0.22c-0.51,3.13,0.34,6.64-1.56,9.41c-4-1.5-2.37-6.64-3.67-9.86c-1.73-0.04-3.49-0.18-5.18,0.28
c-1.97,2.64,0.57,7.5-2.36,9.14c-3.62-1.42-2.47-6.1-2.96-9.11c-1.84-0.29-3.7-0.34-5.55-0.17c-0.98,3.02,0.31,7.12-2.43,9.29
c-3.9-1.59-1.97-6.57-2.78-9.84c-1.9,0.27-3.79,0.63-5.6,1.28c-0.28,2.77-0.47,5.56-0.79,8.34c-0.8-0.05-2.39-0.16-3.19-0.21
c-0.9-2.99-0.85-6.15-1.55-9.16c-1.49-0.33-3.2-0.3-4.33,0.88c-1.31,2.94-1.11,6.29-2.16,9.33c-4.53-0.96-3.84-6.08-3.86-9.6
c-1.73-0.06-3.47-0.08-5.2-0.06c-0.43,2.97-0.54,5.98-0.88,8.97c-0.98-0.08-2.93-0.25-3.91-0.34c-0.82-2.9-0.92-5.91-1.01-8.89
c-6.81-1.66-13.81-0.06-20.69-0.82c-10.43-0.94-20.94-1.41-31.24-3.32c-2.21,0.01-2.26-2.51-2.82-4.07
c-0.99-4.64-1.4-9.84,0.81-14.2c0.7-1.88,2.98-1.71,4.59-2.2c12.4-2.14,25.04-2.32,37.59-2.64c3.94-0.19,7.94-0.37,11.74-1.53
c0.15-3.25-0.02-6.53,0.86-9.7c4.88,1.11,4.13,6.8,4.94,10.6c1.67-0.04,3.34-0.09,5.01-0.15c0.53-3.34-0.19-6.83,0.97-10.06
c5.17,0.06,3.03,6.9,4.89,10.16c1.6-0.05,3.2-0.11,4.8-0.19c0.47-3.45,0.09-6.96,0.67-10.39c5.08,0.81,4.31,6.5,4.5,10.34
c1.74,0.11,3.49,0.18,5.24,0.24c0.78-3.53,0.49-7.24,1.77-10.66c4.28,1.73,2.54,7,3.28,10.59c2.04,0.05,4.08-0.01,6.12-0.17
c0.57-3.4901-0.04-7.15,1.23-10.51c4.34,1.4,2.81,7.03,3.52,10.51c2.01,0.1299,4.22,0.69,6.06-0.4301
c1.52-3.3199-0.76-7.55,1.96-10.4c2.84,2.68,2.63,6.68,3.03,10.26c1.93,0.22,3.86,0.31,5.8,0.26c0.52-3.54,0.59-7.15,1.58-10.6
c4.02,2.11,1.46,7.23,3.32,10.41c1.97,0.56,4.03,0.16,6.03-0.06c0.48-3.38,0.43-6.82,1.29-10.13c4.04,1.56,2.09,6.66,3.02,9.97
c2.01,0.23,4.15,1.09,6.11,0.2c2.72-2.86-1.16-8.57,3.26-10.14c0.98,3.53,1.01,7.21,1.55,10.82c2.05-0.12,4.1-0.34,6.13-0.68
c0.67-3.34,0.59-6.81,1.81-10.01c3.57,2.11,1.59,6.74,3.03,10.02c2.03,0.24,4.09,0.24,6.14,0.1c0.37-2.8,0.21-5.66,0.82-8.41
c0.27-1.18,2.13-1.64,2.64-0.31c1.14,2.52,0.26,5.52,1.14,8.17c1.92,1.01,4.18,0.89,6.19,0.18c0.58-3.44-0.88-8.42,3.37-9.94
c1.19,3.24,0.65,6.82,1.79,10.06c1.69,0.47,3.45,0.3,5.18,0.28c0.98-3.23-0.66-7.57,2.16-9.98c4.65,0.43,1.72,6.7,3.88,9.48
c1.45,0.14,2.91,0.2,4.37,0.2c1.22-3.5699-0.67-9.27,4.26-10.27c0.64,2.97,0.57,6.05,1.25,9.02c1.07,1.33,2.9,1.22,4.44,1.34
c2.84-2.99-0.64-9.75,5.04-10.27c0.61,3.33,0.85,6.72,1.24,10.09C261.2578,793.1071,269.1578,793.7771,277.0078,792.8871z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1442.0879,812.6071c13.84-2.81,27.62-6.42,41.7999-7.01
c34.7101-1.84,70.04,1.9,102.92,13.54c7.98,2.76,16.3101,4.33,24.67,5.46c4.76,0.9,9.71,1.51,14.1599,3.51
c2.2101,2.48,1.9801,6.15,2.6901,9.24c2.77,1.34,6.66,1.72,7.96,4.97c1.3301,4.08-0.87,8.73,1.4301,12.63
c1.75,2.76,4.73,4.46,6.59,7.18c-3.6,7.78-2.17,17.5,3.41,23.9901c-4.29,7.03-3.25,16.14,0.36,23.24
c-1.67,2.75-4.61,4.57-5.85,7.58c-0.79,3.6899,1,7.33,0.7999,11.05c-0.24,3.88-6.2999,3.19-6.75,6.99
c-0.5599,2.49-1.35,5.21-3.6599,6.64c-5.13,3.41-11.67,3.17-17.1001,5.9c-5.6,2.76-10.1,7.24-15.46,10.39
c-8.61,5.13-17.91,8.94-27.01,13.08c-7.53,3.43-15.6799,5.65-22.59,10.3c-2.61,1.58-3.4301,4.85-3.15,7.72
c0.4,4.65,2.61,8.86,4.3201,13.15c2.22,5.29,3.35,10.99,5.7899,16.2c2.0601,5.08,8.89,6.65,9.51,12.54
c3.54,21.64,9.8301,42.74,14.5701,64.13c-1.02,3.88-2.0701,7.86-1.5901,11.92c2.91,30.0499,6.7101,60.5599,18.3201,88.6799
c3.24,8.36,9.23,15.3301,12.2899,23.78c2.2401,6.0601,2.64,12.84,0.8301,19.0699c-1.59,4.1001-6.27,5.52-8.78,8.87
c-1.36,1.55,0.11,3.41,1.34,4.5c4.54,3.79,10.2201,5.78,15.23,8.8601c7.53,4.58,14.5801,9.9199,21.3,15.62
c7,6.24,13.73,13.6499,15.96,23.0299c1.8401,8.38-0.34,18.0901-6.9299,23.92c-3.42,3.02-6.85,6.08-9.54,9.8
c0.4501,1,0.9301,2.0199,1.4301,3.0599c-7.91,3.89-15.8401,7.72-23.75,11.6c-16.5-29.83-33.9401-59.13-51.1801-88.5399
c-9.3199,0.1799-17.83-5.14-22.8199-12.8101c-11.17-16.9399-21.2201-34.72-28.74-53.59c-6.7101-17.17-11.8-35.3101-11.7201-53.88
c0.0701-22.1801-5.08-43.97-11.0699-65.2c-4.0699-13.9801-8.9401-27.7001-13.97-41.3501c-3.37-2.2899-8.35-2.39-10.5-6.2
c-3.35-6.72,2.0299-14.23-0.8201-21.05c-2.11-4.69-7.26-6.83-11.9099-8.08c-10.13-2.51-20.63-2.49-30.9801-2.96
c-48.36-2.67-96.3999-11.55-144.96-9.82c-8.79,0.36-18.02,0.37-26.05,4.4301c-12.21,6.15-22.45,15.61-34.97,21.2
c-7.49,3.43-15.72,5.15-23.95,5.17c-5.78-11.9301-6.37-25.36-8.55-38.21c-5.88-32.83-12.7999-65.47-20-98.04
c-1.58-7.67-1.97-15.64-0.5699-23.37c9.62-2.09,19.73-1.9301,29.23,0.73c10.6,2.99,21.1,6.4,31.45,10.18
c6.2001,2.24,12.92,2.82,19.39,1.45c24.4-3.9,48.5-9.5,72.17-16.59C1358.9078,838.8471,1399.3479,821.8171,1442.0879,812.6071
M1611.2079,1267.8771c-2.84,2.54-7.3101,3.8301-7.97,8.12c2.6699-0.4399,4.9399-2.0599,7.5499-2.72
c1.78,0.23,3.54,1.67,2.2201,3.5601c-2.25,2.09-5.65,3.5299-5.4801,7.21c3.39-0.64,6.79-2.8,10.27-1.28
c-1.02,4.17-7.88,4.88-6.27,9.8c3.0801-0.3301,6.6801-4.24,9.25-0.92c-1.5,3.05-5.23,4.6901-5.4099,8.39
c2.8999-0.22,5.84-2.28,8.74-1.1901c2.0499,4.13-4.61,5.1101-5.03,8.92c2.67,0.09,5.2-0.86,7.8199-1.28
c3.2201,1.4601,0.38,4.7301-1.6899,5.7301c-1.92,0.7899-2.11,2.7699-2.26,4.58c2.71-0.35,5.2-2.26,8.01-1.6801
c2.28,1.29,2.16,5.0601,4.92,5.79c5.4199-1.12,8-6.52,11.2899-10.36c0.12-5.49,0.0601-11.3-2.62-16.23
c-2.49-4.3301-6.22-7.75-9.88-11.04C1627.5378,1277.1871,1619.8779,1271.5371,1611.2079,1267.8771z"/>
<path stroke="#000000" stroke-width="0.0938" d="M119.7678,892.2071c2.11-0.12,4.23-0.25,6.32,0.18
c7.85,1.51,15.91,2.67,23.17,6.22c11.77,5.92,21.04,16.09,33.54,20.68c9.68,3.36,20.1,2.47,30.16,3.28
c11.97,0.88,24,0.2401,35.96,1.25c8,0.95,16.06,0.47,24.09,1.1201c14,0.06,27.97,1.2,41.97,1.2599
c14.36-0.07,28.71,0.02,43.06,0.56c2.06,0.03,4.26,0.95,4.83,3.13c-1.61,2.09-4.43,2.31-6.86,2.52
c-45.99,3.14-91.96,6.67-137.96,9.65c-11.96,1.36-24.51,0.36-35.83,5.12c-10.81,4.94-19.2,13.76-29.62,19.38
c-8.78,4.91-18.68,7.74-28.67,8.66c-2.34,0.38-3.36-2.02-4.53-3.5c-11.55-0.68-23.05,0.71-34.51,1.87
c-1.96,0.31-4.63-0.32-4.81-2.68c-0.96-7.29-0.31-14.69-1.1-21.99c-0.43-3.64-0.48-7.3-0.38-10.96
c0.26-11.71-0.61-23.48,0.53-35.16c0.02-4.45,5.24-5.31,8.7-5.61c10.44-0.34,20.71-3.46,31.19-2.35
C119.2078,894.1771,119.5878,892.8671,119.7678,892.2071z"/>
<path stroke="#000000" stroke-width="0.0938" d="M480.1578,909.0971c3.53-3.8,8.69-5.78,13.86-5.37c21.07,0.19,41.5,5.83,62.1,9.59
c24.74,4.53,49.17,10.63,73.96,14.91c47.98,7.91,96.7,9.73,144.8,16.8c46.55,6.49,92.84,15.3,138.13,27.94
c26.88,7.6,53.45,16.52,78.98,27.89c3.28,1.15,4.09,4.99,4.3,8.06c0.3799,3.48-0.38,7.07,0.28,10.51c4,4.53,11.18,2.5,15.69,6.22
c1.93,1.46,1.5,4.1,1.59,6.23c-0.19,17.5601,1.06,35.41-3.09,52.65c-50.26,7.9-101.36,4.53-151.8,0.3101
c-28.98-2.4501-57.97-4.9901-87.05-6.14c-47.66-1.49-95.33,0.6499-142.95,2.5299c-29.99,1.25-59.98,2.51-89.99,3.3501
c-13.67,0.4299-27.32,1.72-41.01,1.59c-6.76-0.25-13.8-0.38-20.1-3.12c-5.52-2.35-7.77-8.52-9.23-13.88
c-1.84-7.84-2.15-16.61,1.68-23.91c2.9-5.73,9.68-7.34,15.4-8.71c15.87-3.15,32.15-3,48.27-3.27c42-0.41,84.0099-1.02,125.97-3.05
c17.65-1.0399,35.31,0.7301,52.96,0.77c6.46-0.4099,13.27,0.0601,19.29-2.74c6.04-2.72,12.06-5.92,18.78-6.53
c15.6-1.91,31.45-1.36,47.04,0.41c7.71,0.74,14.57,5.53,22.45,5.05c0.29-1.66,1.2-3.4501,0.21-5.03c-1.66-3-4.92-4.54-7.58-6.48
c-1.97-1.2-3.62-3.11-5.9901-3.45c-68.58-13.82-137.53-25.68-206.3799-38.05c-26.64-4.54-53.07-10.34-79.92-13.61
c-18.62-2.54-37.87-5.99-53.8-16.61C467.8178,931.4671,471.3678,918.3871,480.1578,909.0971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M356.4278,1014.2671c3.64-4.94,12.48-3.43,14.83,2.04
c3.39,15.36,5.96,30.91,9.06,46.35c0.99,5.4399,4.38,11.0601,1.97,16.61c-2.26,4.21-6.06,7.27-9.17,10.8101
c-3.4,3.5399-6.33,7.71-10.57,10.34c-5.5,2.55-12.65,2.29-17.43-1.7c-2.06-1.64-1.95-4.4901-2.23-6.8301
c-0.54-7.73-1.97-15.35-2.99-23.01c-0.19-3.4099-2.84-5.84-3.93-8.9099c-2.73-8.9401-10.4-15.4901-18.63-19.3601
c-13.04-5.6799-28.78-2.62-39.96,5.78c-2.37,1.61-4.43,3.99-7.37,4.54c-25.12,2.66-50.15,6.26-75.23,9.35
c-48.87,6.17-97.69,12.8199-146.66,18.12c-9.4,0.97-18.79,3.73-28.29,2.36c-2.95-0.36-6.07-2.35-6.07-5.63
c-0.35-6.6799-2.91-13.9299,0.3-20.25c2.97-4.11,8.06-5.9299,12.82-7.03c27.84-6.3199,55.95-11.46,84.13-15.99
c48.05-7.9299,96.37-14.3699,144.94-18.0599c5.98-0.52,11.99-0.51,17.98-0.08c10.68,0.89,21.57-0.18,32.08,2.36
c9.5,2.25,18.67,5.65,27.9,8.77c3.27,1.3401,4.83-3.4799,8.12-2.64c2.74-0.33,4.06,1.93,4.89,4.17c2.62-1.01,5.13-2.4099,6.92-4.62
C355.8078,1019.7471,354.6478,1016.4171,356.4278,1014.2671z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1364.3479,1084.2771c2.76-5.23,7.12-9.64,12.6-11.98
c-0.12,5.29-2.25,10.1799-5.02,14.59c-3.27,5.0701-3.72,11.6901-1.15,17.15c3.63,8.23,11.7001,13.11,16.63,20.42
c4.0601,5.88,3.64,13.76,1.42,20.26c-4.46,11.36-15.53,17.96-22.17,27.85c-1.36,2.26-3.51,4.46-3.24,7.2899
c0.4501,28.6801,1.15,57.4301,4.8,85.92c2.5599,19.23,6.52,38.38,13.35,56.58c6.76,16.9801,18.23,31.4801,26.23,47.8201
c15.39,29.41,30.28,59.0699,45.23,88.7c4.51,9.27,10.6801,17.64,14.9501,27.04c3.28,6.92,5.1599,14.54,4.8199,22.23
c-13.62-11.24-24.1799-25.61-33.83-40.26c-12.9301-19.72-24.6901-40.45-41-57.6699c-1.3,21.1699,4.1,41.9399,8.24,62.5299
c3.79,18.55,7.25,37.55,5.15,56.54c-10.05-13.77-15.52-30.1901-20.0701-46.4401c-4.08-14.75-7.4099-29.7-11.6699-44.3999
c-5.52-18.01-9.7201-36.38-14.77-54.52c-5.27-19.17-8.15-39.2001-16.79-57.29c-9.35-19.6899-22.37-37.27-34.49-55.28
c-9.39-14.12-18.62-28.4299-29.6801-41.3199c-6.24-7.13-13.0299-14-21.2699-18.79c-13.27-8.0599-29.8-7.2999-43.14-15.09
c-9.04-5.48-15.38-15.58-15.41-26.26c-0.45-13.89,8.3101-27.35,20.86-33.11c9.5801-4.49,21.12-3.96,30.5701,0.64
c14.1799,6.83,23.24,22.85,22.0199,38.51c-0.4399,7.46-1.9099,15.0399-0.21,22.45c3.52,16.5801,13.5,30.9401,25.04,43
c13.71,14.42,29.85,26.17,45.62,38.1801c7.76-27.79,7.4-57.0701,4.99-85.5901c-0.8-6.63-0.5-13.6-3.38-19.7799
c-4.8199-10.7001-13.87-19.03-17.6901-30.24c-2.3099-6.51-1.6299-14.0601,2.25-19.8301c5.0601-8.08,13.8701-12.36,21.51-17.48
C1358.5679,1099.2072,1360.4078,1091.2971,1364.3479,1084.2771 M1357.2979,1117.6371c-5.02,0.98-9.9,3.38-13.0599,7.5
c-5.9501,7.53-7.24,18.65-2.6801,27.1801c5.15,9.73,18.78,11.84,28.1,7.35c10.54-5.33,15.48-18.74,12.42-29.89
c-1.4301-5.13-5.12-9.75-10.2-11.61C1367.2479,1116.2771,1362.0879,1116.5471,1357.2979,1117.6371 M1232.4279,1142.6971
c-6.03,1.2899-12.09,3.72-16.38,8.2899c-4.49,4.7201-6.13,11.7101-4.89,18.03c1.4701,8.22,5.9301,15.98,12.4701,21.21
c7.46,5.4901,17.2,8.4901,26.4199,6.4701c7.59-1.5801,14.38-6.5601,18.1901-13.3101c5.95-10.4299,4.8099-25.1899-4.3-33.48
C1255.5178,1142.3671,1243.2379,1140.4971,1232.4279,1142.6971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M179.1478,1097.0071c-0.16-1.62,1.44-2.5399,2.84-2.71
c2.95-0.54,5.94,0.09,8.91,0.1799c10.7,0.3301,21.41,0.2201,32.11,0.3601c13.15,0.7,26.31-0.9601,39.45-0.17
c0.54,3.0599-0.62,5.85-2.04,8.49c2.62,0.5699,5.29,0.89,7.93,1.35c0.23,7.14-0.22,14.29,0.36,21.4301
c0.04,2.12,0.41,4.78-1.45,6.3099c-2.2,0.4701-4.48,0.3101-6.71,0.5701c0.57,2.75,3.19,5.47,1.64,8.33c-1,1.24-2.65,1.63-4.17,1.59
c-13.68-0.1599-27.36-0.2999-41.04-0.4199c-11.78-0.05-23.59,0.73-35.34,0.01c-4.37-1.11-1.63-6.4401-0.7-9.25
c-2.76-0.91-6.07,0.0699-8.36-2.0901c-0.38-8.21-0.22-16.48-0.08-24.6899c1.07-3.34,5.56-1.9,8.19-2.8
C182.0478,1101.2871,178.8478,1099.3372,179.1478,1097.0071 M255.9778,1116.5271c-2.83-1.0699-4-4.8199-7.02-5.1899
c-2.16,1.6499-3.92,3.7699-6.16,5.33c-1.21-1.88-2.1-3.92-3.09-5.9c-0.98,1.64-1.54,3.5701-2.81,5.04
c-4.05,0.4199-8.76,1.0699-12.18-1.67c-1.93-1.62-4.8-2.2-6.74-0.23c-3.56,3.6899-9.02,2.46-13.56,1.97
c-0.6-1.71-0.82-3.62-2.16-4.9299c-1.13,1.86-2.05,3.86-3.22,5.71c-2.38-1.41-3.98-3.6899-6.02-5.47
c-3.61-0.38-4.3,6.45-8.17,4.6599c-0.75-1.6399-1.15-3.4099-1.86-5.0299c-2.25,0.64-1.9,3.33-2.2,5.14
c0.06,3.2899-0.69,7.33,2.09,9.7899c1.2-1.75,0.85-6.39,4.01-5.13c1.74,1.53,3.17,3.41,4.98,4.89c2.54-1.46,4.56-3.65,7.1-5.1
c2.08,0.5,1.82,2.91,2.56,4.49c2.35,1.65,2.19-2.72,3.38-3.96c2.62-0.5,5.33-0.5901,8-0.4301c3.08,0.05,4.82,3.7101,8,3.39
c2.37-0.1,4-2.0699,6.05-3c3.31-0.26,6.68-0.47,9.99-0.0699c1.52,1.1499,1.69,3.38,2.61,5c1.04-1.78,1.82-3.75,3.34-5.1901
c2.58,0.5801,3.78,3.3,5.95,4.62c3.51-0.01,4.5-5.1899,8.16-4.98c0.79,1.75,1.3,3.62,1.98,5.4401c3.64-3.92,2.62-10.26,1.01-14.9
C257.5078,1111.8171,258.2778,1115.2971,255.9778,1116.5271z"/>
<path stroke="#000000" stroke-width="0.0938" d="M694.4978,1129.6671c22.13-3.39,44.25-6.89,66.34-10.54
c14.99-2.0599,32.56-0.3199,43.14,11.76c-1.69,6.92-5.97,13.0601-11.85,17.1c-9.87,6.8201-21.74,9.66-33.17,12.6901
c-18.59,4.4299-36.3,11.73-54.36,17.85c-21.4901,7.61-43.01,15.15-64.6801,22.23c-33.09,10.97-66.81,19.84-100.15,30.01
c-11.23,3.5-22.91,6.1801-34.75,5.6c-8.08-0.1499-15.98-2.25-24.07-1.99c-4.63,0.13-9.56-1.7-11.54-6.1899
c1.27-2.73,2.8-5.73,5.83-6.79c7.02-2.53,14.65,0.77,21.72-1.51c6.91-2.27,12.87-6.6,19.58-9.34c9.86-4.05,19.92-7.84,30.45-9.73
c15.2401-2.8,30.85-3.03,45.9901-6.42c19.71-4.45,38.55-11.89,57.47-18.84c17.15-6.48,34.63-12.04,51.94-18.0701
c17.01-5.83,34.05-11.5499,51.2-16.9299c-23.54-0.36-46.59,5.08-69.61,9.27c-24.3,4.51-49.11,6.4399-73.03,12.9299
c-17.74,4.73-33,16.1801-51.16,19.6c-6.8701,1.3401-13.81,2.2101-20.71,3.3101c-7.62,1.05-15.37,0.99-22.93,2.45
c-11.29,2.2001-19.81,11.49-31.32,13.04c-4.81,0.76-9.63-0.67-13.77-3.09c-0.36-6.87,5.7-11.2001,10.93-14.3401
c9.67-5.48,17.46-14.1699,28.26-17.6c16.91-5.72,34.79-7.5399,52.08-11.74
C605.8278,1143.4271,650.2278,1136.6671,694.4978,1129.6671z"/>
<path stroke="#000000" stroke-width="0.0938" d="M970.6678,1134.6471c2.89-1.95,5.79-4.1,9.27-4.87c2.99-1.1899,4.11,2.58,5.61,4.4
c-0.03,3.5-0.02,7.01-0.03,10.52c-6.96,4.83-12.66,11.1799-18.29,17.45c-28.03,30.61-58.51,58.83-87.75,88.26
c-10.98,10.87-21.55,22.6801-35.48,29.86c-20.98,11.1-43.83,18.13-65.01,28.8101c-5.06,2.8099-10.3,6.3099-16.4,5.5599
c-0.15-4.37,3.25-7.22,6.45-9.54c8.2-6.2999,17.15-11.61,24.92-18.47c1.39,0.35,2.79,0.73,4.2,1.13
c18.42-9.6899,35.95-21.49,50.59-36.37c-2.18-1.86-4.75-3.16-7.25-4.48c-1.28-3.14-0.53-7.15,2.76-8.6801
c4.91-2.7599,9.17,4.9601,13.93,2.02c2.48-1.6-0.05-3.98-0.9-5.74c-1.96-2.83,1.27-5.51,3.47-6.88
c3.2-1.48,5.94,1.4501,8.72,2.5701c2.43,1.26,4.91-0.51,6.79-1.9501c5.65-4.6799,9.91-10.75,15.33-15.6699
c14.56-14.1001,30.39-26.88,44.25-41.6901c-28.73,13.7001-57.1801,27.99-85.41,42.7001c1.67,3.1499,4.24,6.36,3.31,10.1699
c-1.56,2.01-4.3,3.25-6.81,2.5c-3.76-1.11-6.27-4.2999-9.11-6.77c-3.09,1.9701-3.46,5.9301-5.85,8.4401
c-2.83,2.1799-6.36,0.28-9.36-0.41c-15.39,7.03-30.07,15.5701-44.09,25.03c-3.73,2.52-7.79,4.66-10.91,7.95
c-2.43,2.53-2.47,6.6801-5.52,8.73c-4.71,3.53-10.28,5.62-15.29,8.66c-5.43,3.23-10.87,6.75-17.18,8
c-0.03-2.3199-0.04-4.61-0.02-6.9c3.46-1.5299,5.84-4.5399,8.81-6.7699c6.11-4.8101,12.63-9.16,18.11-14.7201
c7.89-7.8199,14.07-17.1899,22.19-24.7899c10.83-10.89,23.51-19.8,37.26-26.62c18.23-9.16,37.23-16.6801,55.59-25.5801
c29.35-13.74,58.73-27.4299,88.49-40.27C963.6878,1138.5671,967.3578,1136.9171,970.6678,1134.6471z"/>
<path stroke="#000000" stroke-width="0.0938" d="M69.3678,1193.2971c2.55-2.4301,6.09-3.67,9.6-3.37
c23.05,2.1899,46.06,5,69.15,6.8099c51.37,4.03,103.01,6.0601,153.94,14.38c5.04,0.6801,9.85,2.7201,14.96,2.89
c6.86-1.09,11.75-7.34,18.81-7.7999c4.62-0.49,9.6,1.9299,11.42,6.34c2.04,4.21,1.06,8.98-0.15,13.28
c7.92,3.6699,17.05,5.0399,25.58,2.87c5.07-1.3101,9.05-5.36,14.3-6.0801c2.5-0.2799,5.84,1.42,4.84,4.42
c-1.02,4.24-5.51,6.16-9.16,7.7c-10.08,3.79-21.11,3.4601-31.71,3.3c-6.2-0.04-13.06-2.58-18.67,1.16
c-20.3,12.6599-39.6,26.9299-60.61,38.4399c-39.16,22.3201-80.24,41.12-122.1,57.76c-8.94,3.71-18.09,6.9-27.32,9.8
c-7.92,2.3999-15.35,6.14-23.26,8.59c-8.08,2.92-16.68,3.83-25.1,5.3099c-5.6,0.55-11.8,1.5701-16.94-1.2799
c-5.57-4.36-7.95-11.9501-7.51-18.8301c0.84-6.73,6.69-11.23,12.1-14.5c14.64-8.51,31.4-12.0299,47.14-17.85
c42.37-15.41,84.33-31.99,125.44-50.51c16.82-7.53,33.54-15.45,49.16-25.27c-10.64-2.3099-21.5-3.23-32.29-4.51
c-3.66-0.3999-7.37-2.0299-11.04-1.0199c-3.36,1.47-4.01,5.62-6.66,7.89c-5.49,4.9199-13.25,5.6799-20.3,5.95
c-10.05,0.11-20.04-1.1901-30.04-2.04c-29.69-2.6599-59.38-5.36-89.07-8.0499c-7.96-0.9601-16.1-0.89-23.93-2.79
c-5.07-1.23-7.77-6.5699-8.19-11.4C61.0478,1207.097,63.5778,1198.7172,69.3678,1193.2971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1107.7579,1300.7172c3.6299-9.3201,12.1799-16.6201,22.0499-18.4701
c8.92-1.87,18.5,0.6,25.74,6.04c5,3.75,6.6801,10.64,12.26,13.77c7.72,3.9199,16.88,0.8199,24.79,4.12
c7.33,3.04,14.1899,7.77,18.74,14.38c3.41,4.5499,6.6799,10.1899,12.63,11.62c6.03,1.16,11.46-2.7001,15.61-6.61
c4.39-3.86,6.53-10.9,13.25-11.35c-1.6801,9.2599-8.4,16.45-15.36,22.2999c-10.99,8.9301-22.9,17.52-36.9,20.87
c-4.76,1.1801-9.64,1.74-14.52,2.02c0.89,2.75,1.7101,5.5601,1.72,8.51c2.28,0.95,5.0601,1.36,6.6801,3.4399
c3.08,3.9,3.87,9.03,3.64,13.88c-7.8101-0.59-11.21-9.14-18.4401-11.01c-8.5199-2.46-17.9199-0.75-25.6599,3.3401
c0.6499,1.9,1.6799,3.73,3.2999,5c7.27,6.0499,13.12,13.5399,19.48,20.5c2.13,2.38,4.7401,5.4099,3.37,8.86
c-2.6899,7.1-8.85,12.08-14.08,17.2999c-6.09,5.9601-14.66,9.15-23.16,8.38c-15.4399-0.37-28.8199-13.58-30.83-28.63
c-1.16-7.5399,1.71-15.49,7.24-20.7c6.55-6.3099,15.37-9.21,23.39-13.11c-5.72-4.9-12.78-7.75-19.73-10.38
c-11.72-4.33-23.98-6.96-35.62-11.49c-8.4-3.3101-17.61-2.98-26.48-3.21c-17.64-0.05-35.2301,1.6799-52.8701,1.58
c-32.05,0.04-64.1,0.76-96.13-0.49c-6.09-0.3101-12.48,0.1799-18.14-2.5c-0.1-4.5,4.03-7.14,8.0699-7.52
c34.87-5.35,70.03-8.5699,105.17-11.5c12.13,0.1899,23.86-3.61,35.98-3.63c12.35,0.52,24.58-1.75,36.87-2.5599
c7.1901-0.8301,15.15-0.9901,21.15-5.5701C1106.1478,1313.7072,1105.8479,1306.5171,1107.7579,1300.7172 M1127.4279,1290.5872
c-2.98,0.6-6.1,1.25-8.52,3.1899c-8.47,6.78-8.7799,21.52-0.34,28.45c5.5,4.3301,12.47,6.53,19.39,7.0801
c10.8199,1.09,20.88-8.16,22.51-18.54c0.4-7.28-4.1801-14.59-10.76-17.67
C1142.8379,1289.7971,1134.8479,1289.0171,1127.4279,1290.5872 M1172.3479,1311.5171c-9.09,3.14-15.85,12.64-14.9501,22.35
c0.4601,5.4701,4,10.23,8.4301,13.27c8.39,5.75,19.17,7.6,29.1,5.64c4.4501-0.86,9.01-2.39,12.3301-5.6
c3.9199-4.02,4.2599-10.34,2.85-15.49c-2.75-8.48-10.23-14.49-18.11-18.03
C1185.8878,1311.0371,1178.8379,1309.2671,1172.3479,1311.5171 M1081.8978,1334.2371c6.38,8.27,16.62,11.8501,25.91,15.74
c11.9,4.9801,24.09,9.25,36.58,12.4701c0.14-3.5,0.92-6.9,2.03-10.1901c4.4601,0.42,9.54,0.03,13.0901,3.3201
c-0.4401,3.22-1.25,6.37-2.0601,9.5199c5.5699,1.29,11.28,1.6901,16.9399,2.4301c0.2001-3.3099,1.1001-6.61,3.76-8.78
c-10.0299-0.76-17.62-7.99-24.1499-14.9299c-5.5601-6.0901-13.79-8.4301-21.55-10.25c-11.67-2.63-23.41-6.17-35.51-5.53
C1091.3779,1328.2371,1085.8179,1330.1771,1081.8978,1334.2371 M1136.4078,1386.6771c-6.89,1.28-13.73,5.04-17.09,11.41
c-4.1,7.87-2.63,18.3899,3.71,24.6799c5.7201,5.8,13.8,9.1801,21.9401,9.38c7.15,0.01,14.13-3.03,19.4199-7.78
c3.5-3.1599,6.01-7.59,6.14-12.38c0.67-7.5399-3.5399-14.7699-9.5499-19.0699
C1153.9679,1387.9271,1145.0079,1384.9271,1136.4078,1386.6771z"/>
<path stroke="#000000" stroke-width="0.0938" d="M584.9378,1305.2671c33.05,0.55,66.01-2.54,98.97-4.48
c5.88-0.53,10.49,4.02,13.8,8.3199c4.38,6.0801,8.02,13.1901,8.28,20.8201c-0.6,6.33-6.09,10.5-10.63,14.27
c-3.45,2.4099-6.29,5.5299-9.37,8.35c-14.3,1.38-28.7,0.62-43.05,1.13c-10.64,0.53-21.29,0.5499-31.92,1.16
c-9.75,0.6799-19.73,1.2999-28.83,5.1799c-9.25,3.91-19.32,5.08-29.23,5.98c-15.15,1.3201-30.38,1.14-45.55,2.0801
c-14.51,0.8199-29.03,1.2799-43.53,2.12c-12.99,0.71-25.88,4.36-38.94,2.8099c-5.17-0.4-8.97-4.6699-14.06-5.35
c-8.96-1.4301-17.97,0.66-26.96,0.45c-11.67-0.2699-23.31-1.36-34.99-1.0299c-16.1,0.0699-32.64,0.97-48.2-3.9801
c10.48-5.72,22.91-2.75,34.27-3.12c51.17-2.37,101.92-9.7899,152.88-14.6699c32.5-3.1901,65.15-5.17,97.83-4.78
c0.3-6-2.31-11.85-0.79-17.83c-50.9,3.8199-101.99,4.46-153,3.27c-24.99-0.76-49.96-2.4601-74.96-2.64
c-22.4,0.2699-44.89,3.7999-67.23,0.76c5.99-6.4701,15.35-5.17,23.29-5.4701c23.92-2.3999,47.84-4.88,71.78-7.08
c15.13-1.27,30-4.49,45.09-6.0699c34.29-3.1001,68.76-2.04,103.13-2.6901
C550.3678,1302.4672,567.6078,1304.8971,584.9378,1305.2671z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1592.4279,1417.9572c2.1901-9.1001,7.41-17.39,14.46-23.51
c37.77,3.11,75.0801,11.5299,110.4701,25.1c19.4199,7.37,38.4099,15.85,57.12,24.86c14.0599,7.04,27.9199,14.6801,40.4099,24.3101
c10.66,8.1599,20.42,17.98,32.92,23.35c9.9401,4.2899,20.9401-0.16,31.11,2.8099c3.4401,0.92,6.02,3.49,8.29,6.12
c-2.96,4.3201-7.52,7.4301-12.67,8.4401c-14.09,2.83-28.46-2.5-42.5299,0.5399c-8.7301,1.9501-17.3101,5.17-24.6001,10.41
c-3.64,2.65-7.08,6.0701-8.2999,10.54c-1.66,5.87-0.74,12.1,0.73,17.9199c2.71,10.54,7.25,20.5,10,31.03
c2.25,8.42,2.73,17.23,2.35,25.92c-0.26,5.6899-2.27,11.0499-4.25,16.33c28.12,34.5,50.99,73.24,68.71,114.0701
c10.88,25.25,19.6001,51.5499,24.4,78.6599c3.29,18.4401,4.24,37.3401,2.25,55.9801c-1.03,10.88-6.53,21.5199-15.61,27.7999
c-8.6799,6.05-19.3099,8.3201-29.63,9.66c-26.6,3.0599-53.4,2.14-80.12,2.26c-39.58,0-79.15,0.01-118.73,0
c-10.21-9.0801-21.87-17.3-28.4301-29.64c-8.5599-15.48-10.2899-33.72-9.22-51.09c1.8101-27.63,8.41-54.77,17.71-80.79
c14.1001-38.97,33.8401-75.9401,58.4801-109.27c4.62-6.37,11.85-10.6799,15.24-17.9299c2.83-8.8601-0.7201-17.9701-1.61-26.8401
c-1.3501-10.1799,3.1499-19.77,6.6599-29.0399c4.78-11.8501,9.12-24.8101,6.03-37.6801c-10.6899-2.4399-21.67-3.99-31.84-8.22
c-15.5601,3.62-23.2001,20.16-38.0901,25.1c-3.75,1.4399-7.7999,1.49-11.6899,2.21c-10.4,14.12-22.8,26.6001-35.08,39.0701
c-9.86,9.46-17.0801,21.52-28.16,29.73c-5.23,3.96-11.6801,6.17-18.24,6.24c14.6799-30.27,31.9399-59.26,45.46-90.11
c9.88-22.23,17.67-45.4401,22.46-69.3101c0.4701-2.85,1.91-6.25-0.61-8.5699c-8.6899-10.05-24.6699-8.5601-33.22-18.85
C1591.2379,1430.6071,1591.0378,1423.8271,1592.4279,1417.9572 M1794.0579,1500.9971c3.8,5.1801,10.42,9.54,17.0601,7.6
c5.49-1.59,8.75-6.75,11.0699-11.61c-3.05-5.23-6.35-10.4099-10.8199-14.5399c-5.01-4.8101-11.65-7.62-18.4801-8.53
C1787.5779,1482.0872,1788.1578,1493.2771,1794.0579,1500.9971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M497.3978,1438.5271c9.62-1.37,19.75-1.48,28.97,1.98
c3.11,1.25,6.27,2.87,8.39,5.55c1.94,2.4,2.28,6.39-0.14,8.6c-2.52,2.0699-6,1.58-9.03,1.71c-0.89,6.3,0.15,12.63,0.25,18.9501
c3.82,0.2999,7.71-0.38,11.48,0.4099c1.53,1.6901,1.31,4.15,1.66,6.27c0.8799,11.4301,1.77,22.87,2.42,34.3201
c-1.65,0.74-3.36,1.4-4.87,2.4399c0.28,2.37,2.91,2.28,4.64,3.0701c0.29,5.6599,3.96,10.35,8.66,13.21
c16.37,9.42,25.9,28.3099,26.27,46.9c0.72,25.0499-0.94,50.11-2.98,75.08c-2.31,28.7001-10.25,56.53-13.79,85.0601
c-2.67,19.8199-2.29,39.88-1.56,59.8199c0.74,16.83,4.26,33.35,7.43,49.84c1.01,5.7001,2.59,11.9701-0.01,17.5
c-2.27,4.1901-6.89,6.28-11.15,7.9c-9.35,3.1801-19.26,4.23-29.07,4.9c-17.02,0.91-34.2-0.15-50.93-3.48
c-6.27-1.4-13.56-4.2001-15.7-10.89c-1.81-8.39,1.79-16.65,3.02-24.87c4.2-25.72,5.16-51.9301,3.55-77.92
c-1.27-23.71-6.54-46.9199-11.48-70.0699c-7.09-33.5-9.82-67.73-11.23-101.89c-0.25-9.83,0.02-19.9301,3.47-29.25
c2.92-7.98,7.2-15.74,13.67-21.38c4.18-3.7,9.68-5.65,13.57-9.6801c1.6-2.95,2.39-6.26,2.85-9.5499
c2.09-0.9401,5.02-1.34,5.07-4.17c-1.58-0.58-3.17-1.13-4.74-1.64c0.14-11.8099,0.35-23.64,1.37-35.4099
c0.16-1.88,0.63-3.7101,1.07-5.52c3.72-0.64,7.5-0.61,11.25-0.9601c0.65-6.34,0.7-12.72,0.49-19.0699
c-2.75,0.14-5.49,0.65-8.25,0.47c-2.82-2.03-4.04-6.59-1.46-9.2899C484.8378,1442.597,490.9878,1439.4171,497.3978,1438.5271z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1184.3779,1462.3971c5.59-5.29,10.59-11.26,16.7999-15.87
c3.37,0.92,8.34,4.0699,6.6901,8.27c-2.51,3.41-6.9301,4.48-10.3101,6.79c-4.73,3.0299-8.6,7.1599-13.0699,10.5299
c-0.5,3.98,0.38,7.91,0.6799,11.87c0.2101,8.89-3.4099,17.9801-10.26,23.79c-6.26,5.41-14.77,7.78-22.9399,7.3199
c-10.3301-0.4299-19.77-5.3999-30.03-6.23c-15.0699-1.21-30.4399,3.4401-42.54,12.4701c-3.4399,2.46-6.6499,5.22-9.7899,8.0399
c5.45,6.1901,12.77,10.3,20.24,13.5601c10.84,4.65,22.27,7.71,33.7,10.48c8.37,1.91,17.6,3.54,25.73-0.1901
c3-1.25,4.12-4.5699,6.2201-6.7999c1.5599-1.62,5.1399-1.0801,5.5399,1.37c0.4401,2.12,0.51,4.41,1.75,6.2999
c4.0801,6.9901,6.8301,14.8,7.5601,22.88c0.9299,10.1801-2.89,20.89-10.73,27.6001c-6.17,5.39-14.5701,7.74-22.67,7.22
c-14.75-0.08-28.3101-14.12-26.63-29.03c0.26-6.3099,6.1801-10.5599,6.67-16.8099c0.52-2.99-1.2201-5.78-3.6001-7.42
c-5.0599-3.63-11.1499-5.34-17.0099-7.14c-12.7001-3.78-26.0601-6.22-39.3301-4.73c-10.45,1.11-21.26,1.25-31.13,5.27
c-4.16,1.9099-7.61-2.86-11.79-1.79c-5.74,0.92-10.9,3.78-16.37,5.6c-36.1,11.9701-72.72,22.3101-109.62,31.48
c-5.72,1.3201-11.32,3.4601-17.23,3.66c-1.83,0.02-4.47-0.62-4.7401-2.75c1.91-3.85,6.6801-4.1899,10.15-5.89
c18.48-8.27,37.11-16.1799,55.7-24.1599c6.95-2.8301,14.18-4.9901,20.84-8.5c-26.94,0.2999-53.87,2.5099-80.83,1.48
c-3.99-0.25-8.09,0.58-11.92-0.88c1.01-3.12,3.47-5.64,6.76-6.22c33.57-5.3701,67.17-10.8,100.96-14.75
c13.02-1.4301,25.92-3.8101,38.97-4.9501c6.85-0.79,14.01,1.04,20.56-1.76c11.67-4.66,24.17-6.36,36.4301-8.72
c7.36-1.5601,15.03-2.62,21.7001-6.3c2.58-1.2799,4.88-3.09,7.52-4.25c6.1899-2.14,12.71,1.63,18.8999-0.4099
c6.9401-2.4601,12.5-8.41,14.39-15.54c1.91-6.89,4.54-14.03,10.35-18.61c7.7001-6.62,18.3601-9.5601,28.37-7.87
c4.26,0.8199,7.6901,3.9199,11.9901,4.66C1179.8079,1465.8871,1182.3579,1464.1671,1184.3779,1462.3971 M1151.3878,1468.6571
c-11.71,2.27-21.96,14.6-18.0599,26.73c5.74,14.38,27.7,18.3,38.29,7.13c4.6899-5.26,7.47-12.41,6.84-19.49
c-0.49-5.71-4.53-10.64-9.62-13.02C1163.4379,1467.4271,1157.1378,1467.1671,1151.3878,1468.6571 M1131.3878,1564.6471
c-5.9099,1.8201-11.35,5.91-13.9199,11.64c-2.8201,6.89-2,15.48,3.08,21.14c9.75,10.7999,29.29,11.61,38.79,0.04
c9.34-9.1201,5.42-26.8-6.27-31.9901C1146.2878,1562.4371,1138.4279,1562.7771,1131.3878,1564.6471z"/>
<path stroke="#000000" stroke-width="0.0938" d="M664.7078,1456.4271c4.99-2.62,10.82-1.97,16.25-2.41
c6.47,0.0701,13.78-0.62,19.3,3.39c1.51,16.98,0.71,34.11,2.33,51.11c2.05,0.97,6.12,0.29,6,3.48
c1.22,11.27,0.06,22.6901,1.69,33.9401c-2.2,0.1599-4.39,0.3199-6.57,0.53c1.89,0.95,4.54,0.8899,5.67,2.9199
c9.79,15.23,19.61,30.4401,29.55,45.5701c0.93,1.4399,1.5,3.11,1.41,4.88c-3.21,51.0099-5.1,102.09-7.63,153.13
c-1.42,29.97-2.87,59.9299-4.33,89.8899c-0.58,8.3301-0.5,16.7101-1.43,25.01c-0.6,6.17-5.9,10.4501-11.26,12.7001
c-10.01,4.24-21.05,5.11-31.79,5.61c-13.48,0.1699-28.11-0.77-39.44-8.89c-4.76-3.1901-6.42-8.98-6.49-14.42
c-2.69-53.3099-5.19-106.63-7.77-159.9399c-1.77-34.36-3.76-68.73-5.12-103.1c0.19-5.1001,4.71-8.5901,6.87-12.9301
c7.81-12.76,16.22-25.13,24.26-37.74c1.24-1.63,3.48-1.83,5.22-2.7c-2.11-0.24-4.22-0.4401-6.31-0.64
c0.81-11.01,0.33-22.0801,1.03-33.0701c-0.03-3,3.42-3.3099,5.52-4.25C664.4078,1491.2671,662.9278,1473.7371,664.7078,1456.4271z"
/>
<path stroke="#000000" stroke-width="0.0938" d="M303.8678,1462.7971c5.88-1.84,12.12-0.89,18.17-1.01
c3.61,1.45,7.61,1.27,11.31,2.47c6.75,1.97,13.81,4.22,19.07,9.11c4.4,4.1001,5.63,10.9401,3.38,16.4401
c-1.51,3.13-4.11,5.5399-6.27,8.22c5.15,1.84,11.09,2.9301,14.84,7.27c2.4,2.72,1.35,6.59,0.52,9.75
c-0.95,3.75-3.16,7.26-6.53,9.2999c-4.65,2.9-10.37,2.6101-15.46,4.2301c3.37,4.45,7.6,8.37,9.75,13.6499
c3.56,8.76,6.14,18.12,5.78,27.6801c0.18,10.49-2.71,20.67-3.27,31.1c-1.2,12.98-5.12,25.78-3.97,38.9
c-0.12,12-0.1,24.03-1.01,36.02c0.3,5.3099,0.3,10.63,0.41,15.95c1.38,12.3301,2.23,24.7101,4.02,36.99
c3.45,24.1001,8,48.03,11.38,72.14c1.53,12.52,2.43,25.25,1.06,37.84c-0.92,9.1001-5.05,18.14-12.43,23.77
c-8.51,6.4701-20.01,7.3501-30.23,5.61c-12.51-2.21-22.28-11.5599-29.15-21.74c-10.96-15.95-17.84-34.2999-23.13-52.7999
c-6.82-25.9601-13.19-52.13-16.21-78.8401c-2.26-21.21-4.47-42.5699-3.23-63.9199c0.36-13.34,1.28-26.66,1.17-40.01
c0.1-11.11-0.34-22.4-3.57-33.1c-1.16-4.03-3.28-7.6801-4.7-11.6c-3.35-8.8601-9.95-16.14-12.59-25.3
c-1.38-5.04-1.28-10.8101,1.68-15.27c4.01-6.15,10.3-10.53,17.18-12.9c2.56-0.7799,4.93-3.35,3.56-6.12
c-5.52-2.9299-11.61-4.8199-16.81-8.39c-5.41-3.64-11.36-8.38-11.93-15.39c-0.44-4.34-0.5-10.0299,3.84-12.46
c7.24-4.09,16.07-3.1,23.93-1.79c8.95,2.01,18.04,4.1801,26.17,8.5801c2.23,1.16,4.85,1.6699,7.3,0.91
c1-3.0801,0.8-6.63,3.01-9.2201C293.9978,1464.8971,299.2878,1463.9871,303.8678,1462.7971z"/>
<path stroke="#000000" stroke-width="0.0938" d="M82.6178,1493.5271c3.73-0.89,7.61-0.21,11.4-0.13
c25.63,0.33,51.27,0.95,76.91,0.83c4.07,0.0601,8.31-0.83,12.26,0.4801c2.27,0.7699,2.43,3.37,2.88,5.36
c1.12,0.15,2.24,0.3099,3.36,0.49c4.4,15.33,6.5,31.4199,4.94,47.34c-0.61,2.75,1.77,4.2,3.32,6c0.24,2.62,0.2,5.3201-0.35,7.9301
c-0.72,2.63-3.7,4.11-3.98,6.9199c-1.42,10.8301-5.87,20.91-9.56,31.11c-4.52,11.64-7.19,23.87-9.88,36.04
c-1.32,10.27-2.18,20.65-1.53,31.01c0.86,14.88,2.98,29.65,4.88,44.42c3.84,24.5299,2.93,49.64-1.09,74.09
c-2.91,16.51-7.06,32.89-13.58,48.38c-4.27,10.25-10.14,19.87-17.7,28.0499c-4.58,4.8601-11.45,7.38-18.07,7.15
c-7.93-0.46-14.25-6.23-18.51-12.49c-11.86-17.4299-17.3-38.1699-21.44-58.5699c-4.87-21.9501-6.25-44.5801-4.84-66.99
c0.98-24.0901,4.68-48,5.23-72.11c0.58-21.1801-5.14-41.8301-11.54-61.8301c-2.67-9.3099-6.35-18.4299-7.21-28.15
c-0.36-4.12-2.91-7.8099-2.46-12.0199c0.06-2.4801,1.75-4.51,2.09-6.91c1.22-17.48,2.6-35.27,8.6-51.87
c0.74,0.0599,2.23,0.1899,2.97,0.25C80.4978,1496.6771,80.4878,1494.0271,82.6178,1493.5271z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1233.3679,1622.5571c1.76-0.6901,4.0599-1.13,5.5599,0.37
c1.59,2.13,1.04,5.2999-0.79,7.12c-3.6,3.65-8.5099,5.5499-12.6,8.5499c-15.45,10.51-31.58,19.9401-47.6,29.53
c-31.89,19.2001-63.78,38.41-96.3199,56.47c-14.4,8.13-29.3,15.55-42.5901,25.4801c-4.6,3.3099-9.71,6.1499-13.17,10.7799
c-4.46,5.78-8.16,12.54-14.74,16.24c-10.84,6.26-23.12,12.3201-29.24,23.8301c-1.58,6.73-2.18,13.72-4.56,20.28
c-2.95,8.96-7.98,17.58-15.85,23.0499c-9.18,6.37-20.33,9.97-31.5,10.12c-7.01,0.12-14.36-2.9099-21.04,0.4601
c-9.02,4.48-17.79,10.1799-24.15,18.12c-2.75,3.24-4.01,7.61-7.31,10.4199c-3.1,2.3401-7.43,1.39-10.47-0.5599
c-4.83-3.05-8.62-8.1801-9.4-13.89c-0.41-2.09,1.12-3.86,3.08-4.26c12.43-3.04,22.86-11.4,31.32-20.6901
c1.47-1.72,4.17-4.08,2.25-6.4199c-4.48-6.5601-7.27-14.5601-6.44-22.5601c0.68-7.4099,4.07-14.25,8.26-20.2799
c-3.12-1.38-5.66-3.6901-8.59-5.3501c-3.0601-1.8199-5.01-5.96-3.63-9.37c1.75-3.13,5.41-4.1699,8.41-5.6799
c9.89-4.7001,20.24-9.17,28.19-16.92c6.34-6.6,12.15-13.99,15.37-22.65c-9.25-1.6899-18.44-4.12-27.9-4.1799
c-6.97,0.09-13.96-1.0701-20.55-3.3201c-5.48-1.99-8.76-7.63-9.33-13.23c-1.21-10.79,2.78-21.98,10.3199-29.76
c10.1801-10.6799,25.09-15.9199,39.63-16.27c10.23-0.14,21.05,2.03,29.11,8.6901c6.71,5.45,10.29,14.64,8.46,23.1799
c-1.14,6.17-5.38,11-8.52,16.2301c-1.35,1.88-0.73,4.2799-0.8701,6.46c18.17-1.17,35.46-8.3101,53.75-8.4301
c7.17-0.1,14.8001,0.4701,21.4201-2.84c4.1899-1.98,5.97-6.84,10.1799-8.8099c17.8101-8.91,36.2401-16.4901,54.4801-24.4701
C1141.1879,1658.0872,1186.8179,1639.0771,1233.3679,1622.5571 M922.4678,1680.597c-8.07,1.55-16.17,4.78-21.78,11
c-5.08,5.39-9.22,12.7001-7.99,20.3601c0.2,2.22,2.18,3.63,4.15,4.2999c11.23,3.8101,23.5,4.24,35.05,1.64
c8.61-2,17.06-6.37,22.3-13.6899c2.82-3.9,4.68-9.38,2.26-13.89c-2.82-3.6801-7.23-5.6-11.3-7.51
C938.1678,1679.3171,929.9978,1679.1971,922.4678,1680.597 M977.7478,1733.6971c-6.83,1.61-10.89,8.01-17.27,10.49
c-4.8,2.0599-9.14,5.02-13.16,8.3199c-3.29,2.5701-7.82,2.74-11.04,5.39c-2.54,2.8201-4.78,6.15-5.45,9.96
c-0.72,3.6801-3.53,6.3401-5.86,9.0801c8.12-2.3401,16.66-2.39,25.04-2c10.36-0.1,20.91-0.4501,30.85-3.67
c16.06-5.1899,30.16-15.84,40.25-29.29c2.32-2.7899,4.8501-5.58,5.7001-9.22c-4.0601-0.8199-8.2001-1.0499-12.27-1.63
C1002.2478,1729.4672,989.7378,1730.847,977.7478,1733.6971 M935.4278,1790.7271c-10.75,3.54-21.91,8.6101-28.72,18.05
c-3.28,5.0699-6.22,11.02-5.45,17.24c0.86,5.4401,5.55,9.34,10.47,11.24c12.91,5.1,27.84,2.9601,39.74-3.7999
c9.99-5.4601,18.48-14.99,19.9-26.6101c0.83-5.09-0.84-11.1399-5.79-13.5099
C956.2978,1788.8771,945.3378,1788.1671,935.4278,1790.7271z"/>
<path stroke="#000000" stroke-width="0.0938" d="M1183.3179,1713.9171c2.54-2.42,6.0601-3.38,9.49-2.45
c11.48,2.7999,23.1901,4.5199,34.74,7.0499c27.47,5.8101,54.87,11.96,82.28,18.03c7.38,1.78,14.95-0.91,22.35,0.7
c9.15,1.6801,17.85,5.13,26.84,7.49c17.29,4.53,35.04,7.01,52.79,8.86c10.42,1.2001,20.9301,1.9501,31.16,4.41
c6.4,1.09,13.3199,3.01,19.65,0.64c7.5699-4.26,8.9299-14.28,16.24-18.87c15.9399-10.84,39.2899-6.87,51.88,7.37
c2.9199,3.63,3.4299,8.75,7.02,11.9401c4.5699,4.9299,11.7699,5.8999,18.1499,5.2c5.4701-0.6801,11.0701-1.34,16.1901-3.53
c2.24,1.77,4.6899,3.99,4.4399,7.17c-0.27,4.03-2.5699,8.61-6.75,9.7c-8.9299,1.51-16.99-5.35-25.9099-3.51
c-6.38,1.7201-9.1901,8.28-12.4401,13.37c-3.16,5.3301-8.95,8.64-14.96,9.64c-4.7001,0.73-9.42,1.51-13.8401,3.3301
c3.7001,6.7999,11.5601,9.63,15.8,15.99c3.99,5.6499,6.76,12.46,6.37,19.49c-0.26,6.9099-3.62,13.45-8.49,18.26
c-12.02,11.9399-31.89,15.13-46.9399,7.27c-7.4501-3.89-13.54-10.1901-17.4701-17.5901c-3.37-7.36-0.84-16.11-4.61-23.36
c-2.45-4.21-6.75-6.87-10.97-9c-8.49-4.26-17.74-6.71-26.3199-10.74c-9.8101-4.4301-19.25-9.6801-29.25-13.6899
c-18.6901-7.1901-38.0701-12.38-56.92-19.1101c-13.89-5.13-27.59-10.7799-41.67-15.35c-22.35-7.5399-45-14.11-67.4-21.48
C1203.5979,1727.2172,1189.7179,1725.1571,1183.3179,1713.9171 M1491.4979,1745.5071c-7.51,1.6801-14.5801,7.15-16.3301,14.9
c-1.6799,6.85,1.86,13.88,6.9601,18.34c5.0599,4.73,12.0699,6.4401,18.7699,7.27c8.0601,0.78,17.03-0.27,23.3601-5.78
c4.3099-3.95,7.5399-10.61,4.62-16.2699c-3.1101-5.8101-8.66-9.7401-13.87-13.5
C1508.2678,1745.6871,1499.6179,1743.2371,1491.4979,1745.5071 M1386.2979,1768.5671c16.75,9.12,33.9301,17.4299,50.8101,26.3199
c5.33,2.73,10.0299,6.77,15.8199,8.59c5.8101,1.5801,10.72-2.6,15.74-4.72c5.38-2.49,11.48-0.23,16.98-2.25
c-5.24-6.21-13.09-9.71-17.6499-16.5699c-2.12-3.12-4.29-7.04-8.51-7.35c-16.73-2.4-33.6801-1.4701-50.52-1.9301
C1401.2878,1770.847,1393.9479,1765.8871,1386.2979,1768.5671 M1476.5079,1808.6271c-6.52,1.62-13.54,4.7001-16.7301,11
c-2.98,6.54,0.1901,13.88,4.3101,19.15c6.79,8.48,16.89,14.9,27.91,15.62c6.59,0.01,13.7999-2.0699,18-7.47
c4.0399-5.3101,3.5199-12.84,0.63-18.55c-3.2401-6.77-9.42-11.36-15.28-15.71
C1490.0278,1808.7072,1483.0079,1806.6171,1476.5079,1808.6271z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 185 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 182 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" id="svg2" height="297mm" width="210mm" version="1.1">
<title id="title3885">shopping cart</title>
<g id="layer1">
<path id="path3847" style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m579.07 41.891c-0.5602 0.008-1.1368 0.0575-1.6876 0.15625-0.01 0.002-0.021-0.002-0.031 0l-55.625 9.5c-3.5377 0.60697-6.5035 3.0328-7.8125 6.375a2.529 2.529 0 0 0 0 0.0312l-25.812 66.187-251.91 6.2812c-2.897 0.0724-5.6164 1.3809-7.5 3.5625-1.8833 2.1817-2.7899 5.0829-2.4376 7.9688l13.906 115.03c0.5737 4.8261 4.561 8.6532 9.4063 9.0312l179.59 14.281 35.594 28a2.529 2.529 0 0 0 0.125 0.0937c0.038 0.0264 0.086 0.0365 0.125 0.0625 0.044 0.0291 0.081 0.0652 0.125 0.0937 6.4957 4.8485 8.1056 11.454 7.1876 15.125-0.5231 2.0918-1.3217 3.6286-3.2188 4.8125-1.8971 1.1838-5.1742 2.0406-10.781 1.7188a2.529 2.529 0 0 0 -0.063 0c-0.1801-0.006-0.3823-0.004-0.5624 0-0.03 0.00069-0.064-0.00096-0.094 0l-214.19 0.625h-0.031c-5.6288-0.0359-10.366 4.6852-10.344 10.312 0.022 5.6278 4.7779 10.331 10.406 10.25 0.011-0.00015 0.021 0.00019 0.031 0l15.656-0.0312c-5.8172 3.7083-9.7187 10.195-9.7187 17.562 0 11.459 9.3852 20.844 20.844 20.844s20.844-9.385 20.844-20.844c0-7.4072-3.9118-13.958-9.7812-17.656l176.38-0.5c-6.3545 3.5825-10.688 10.384-10.688 18.156 0 11.459 9.385 20.844 20.844 20.844s20.844-9.385 20.844-20.844c0-9.9515-7.0696-18.341-16.438-20.375 8.8575-3.1334 15.662-9.5946 19.875-19.469a2.529 2.529 0 0 0 0.1563 -0.375c3.23-12.916-2.4989-26.959-14.312-36.094a2.529 2.529 0 0 0 -0.094 -0.0937c-0.029-0.0222-0.034-0.0716-0.062-0.0937a2.529 2.529 0 0 0 -0.3438 -0.34375l-25.219-19.781 78.656-201.47 49.906-8.5c0.01-0.002 0.021 0.002 0.031 0 5.2427-0.84286 9.0768-5.7292 8.625-11.031-0.4525-5.3122-5.0811-9.4786-10.406-9.4062zm-98.563 98.125-14.5 37.188h-18.906v-36.344l33.406-0.84375zm-40.625 1.0312v36.156h-34.906v-35.281l34.906-0.875zm-42.125 1.0312v35.125h-34.906v-34.25l34.906-0.875zm-42.125 1.0625v34.062h-34.906v-33.188l34.906-0.875zm-42.125 1.0625v33h-34.906v-32.125l34.906-0.875zm-42.125 1.0312v31.969h-25.594l-3.7813-31.219 29.375-0.75zm-24.719 39.156h24.719v32.656h-20.781l-3.9375-32.656zm31.938 0h34.906v32.656h-34.906v-32.656zm42.125 0h34.906v32.656h-34.906v-32.656zm42.125 0h34.906v32.656h-34.906v-32.656zm42.125 0h34.906v32.656h-34.906v-32.656zm42.125 0h16.125l-12.75 32.656h-3.375v-32.656zm-195.62 39.844h19.906v23.438l-17.25-1.375-2.6562-22.062zm27.125 0h34.906v26.781l-34.906-2.7812v-24zm42.125 0h34.906v30.125l-34.906-2.75v-27.375zm42.125 0h34.906v33.5l-34.906-2.7812v-30.719zm42.125 0h34.906v19.875l-6.625 16.969c-0.86-0.41667-1.7975-0.6724-2.75-0.75l-25.531-2.0312v-34.062zm42.125 0h0.5312l-0.5312 1.4688v-1.4688zm-176.84 132.44c6.8111 0 12.25 5.439 12.25 12.25s-5.4389 12.219-12.25 12.219c-6.8107 0-12.25-5.4078-12.25-12.219 0-6.811 5.4393-12.25 12.25-12.25zm197.59 0c6.8109 0 12.25 5.439 12.25 12.25s-5.4391 12.219-12.25 12.219c-6.811 0-12.25-5.4078-12.25-12.219 0-6.811 5.439-12.25 12.25-12.25zm-197.59 5.8125c-3.7001 0-6.6562 2.9561-6.6562 6.6562 0 3.7002 2.9561 6.625 6.6562 6.625 3.7003 0 6.6563-2.9248 6.6563-6.625s-2.956-6.6562-6.6563-6.6562zm197.59 0c-3.7002 0-6.6562 2.9561-6.6562 6.6562 0 3.7002 2.956 6.625 6.6562 6.625 3.7001 0 6.6562-2.9248 6.6562-6.625s-2.9561-6.6562-6.6562-6.6562z"/>
</g>
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title>shopping cart</dc:title>
<dc:date>2010-05-13T14:39:42</dc:date>
<dc:description>shopping carg</dc:description>
<dc:source>http://openclipart.org/detail/60139/shopping-cart-by-voyeg3r</dc:source>
<dc:creator>
<cc:Agent>
<dc:title>voyeg3r</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>cart</rdf:li>
<rdf:li>clip art</rdf:li>
<rdf:li>clipart</rdf:li>
<rdf:li>shopping</rdf:li>
<rdf:li>supermarket</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
sodipodi:docname="disabled-man-icon.svg"
viewBox="0 0 700 800"
version="1.1"
inkscape:version="0.92.1 r15371"
width="746.66669"
height="853.33331">
<defs
id="defs8" />
<sodipodi:namedview
id="base"
bordercolor="#666666"
inkscape:pageshadow="2"
inkscape:window-y="7"
fit-margin-left="0"
pagecolor="#ffffff"
fit-margin-top="0"
inkscape:window-maximized="1"
inkscape:zoom="0.5"
inkscape:window-x="-4"
inkscape:window-height="1000"
showgrid="false"
borderopacity="1.0"
inkscape:current-layer="layer1"
inkscape:cx="477"
inkscape:cy="242"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1280"
inkscape:pageopacity="0.0"
inkscape:document-units="px" />
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(-533.54,-111.5)">
<path
id="path3005"
sodipodi:nodetypes="cssssscscccccccccccccccccccscccccsccccssscc"
style="fill:#333333;fill-rule:evenodd"
inkscape:connector-curvature="0"
d="m 810.21,273.78 c -12.232,12.232 -27.039,18.348 -44.421,18.348 -17.318,0 -32.124,-6.1159 -44.356,-18.348 -12.296,-12.296 -18.412,-27.103 -18.412,-44.421 0,-17.318 6.1159,-32.124 18.412,-44.421 12.232,-12.232 27.039,-18.348 44.356,-18.348 17.382,0 32.189,6.1159 44.421,18.348 12.232,12.296 18.348,27.103 18.348,44.421 0,17.318 -6.1159,32.124 -18.348,44.421 z m 13.133,139.76 h 105.32 l 24.785,56.974 h -125.79 l 2.897,39.657 h 182.06 l 91.545,210.52 61.803,-26.91 17.575,40.3 -114.08,49.7 -94.249,-216.57 h -225.9 l -19.056,-255.19 85.107,-6.309 z m -101.85,75.579 -4.8927,-65.536 c -24.27,11.009 -46.545,26.652 -66.824,46.931 -44.163,44.099 -66.245,97.403 -66.245,159.85 v 0.57941 l 0.0643,5.8584 c 1.4807,59.614 23.498,110.73 66.18,153.35 42.747,42.811 94.056,64.893 153.99,66.245 h 6.4378 c 62.124,-0.12875 115.17,-22.21 159.21,-66.245 21.245,-21.245 37.403,-44.614 48.412,-70.043 l -42.682,-97.983 c 0.13001,6.9817 0.2195,14.187 -0.1931,20.665 -2.6395,40.687 -18.734,75.837 -48.219,105.39 -32.446,32.382 -71.652,48.541 -117.55,48.541 -45.901,0 -85.043,-16.159 -117.42,-48.541 -32.446,-32.446 -48.67,-71.652 -48.67,-117.55 0,-45.901 16.223,-85.043 48.67,-117.42 9.3348,-9.3348 19.249,-17.382 29.742,-24.077" />
</g>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
<dc:publisher>
<cc:Agent
rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title>The Symbol of Disabled Man</dc:title>
<dc:date>2011-09-26T14:12:52</dc:date>
<dc:description>Simple clear icon with minimum nodes</dc:description>
<dc:source>https://openclipart.org/detail/162061/the-symbol-of-disabled-man-by-vlodco_zotov</dc:source>
<dc:creator>
<cc:Agent>
<dc:title>vlodco_zotov</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>disabled</rdf:li>
<rdf:li>icon</rdf:li>
<rdf:li>man</rdf:li>
<rdf:li>symbol</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 72 KiB

+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ns1="http://sozi.baierouge.fr"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
id="svg2319"
sodipodi:modified="true"
sodipodi:docname="simple_Gear.svg"
viewBox="0 0 121 121"
sodipodi:version="0.32"
version="1.0"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:version="0.48.4 r9939"
>
<title
id="title2822"
>Gear</title
>
<sodipodi:namedview
id="base"
inkscape:snap-center="true"
inkscape:showpageshadow="false"
inkscape:zoom="1.6644983"
borderopacity="1.0"
inkscape:current-layer="Capa_x0020_1"
inkscape:cx="73.944172"
inkscape:cy="40.809784"
inkscape:window-maximized="1"
showgrid="false"
inkscape:guide-bbox="true"
showguides="true"
bordercolor="#666666"
inkscape:window-x="65"
guidetolerance="10"
objecttolerance="10"
inkscape:window-y="24"
inkscape:window-width="1855"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
pagecolor="#ffffff"
gridtolerance="10000"
inkscape:document-units="px"
inkscape:window-height="1056"
/>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(-153.03 -268.95)"
>
<g
id="Capa_x0020_1"
style="fill-rule:evenodd"
transform="matrix(39.803 0 0 39.803 63.558 116.51)"
>
<path
id="path83"
style="stroke:#dededd;stroke-width:.057358;fill:#c2c1c1"
d="m74.031 0.0625l-7.625 13.376c-1.948-0.254-3.952-0.376-5.968-0.376-2.281 0-4.528 0.147-6.719 0.469l-8.469-13.062c-4.32 1.1292-8.454 2.7376-12.344 4.7498l2.656 15.187c-3.574 2.316-6.813 5.12-9.624 8.313l-14.813-4.5c-2.5493 3.609-4.7344 7.491-6.4688 11.625l11.688 9.906c-1.241 4.003-1.94 8.239-2.063 12.625l-14.218 6.187c0.35094 4.527 1.1952 8.929 2.4682 13.126l15.25-0.032c1.644 3.984 3.823 7.697 6.438 11.032l-6.938 13.972c3.091 3.17 6.508 6 10.219 8.43l11.688-9.9c3.713 1.95 7.719 3.4 11.937 4.28l3.563 15.19c1.898 0.18 3.804 0.28 5.75 0.28 2.519 0 4.999-0.17 7.437-0.47l2.656-15.19c4.199-0.94 8.162-2.45 11.844-4.47l12.406 9.35c3.641-2.54 6.999-5.46 9.999-8.72l-7.655-13.378c2.559-3.376 4.705-7.111 6.285-11.124l15.43-0.876c1.16-4.227 1.87-8.646 2.1-13.187l-14.35-5.281c-0.19-4.379-1-8.579-2.31-12.563l11.28-10.719c-1.84-4.079-4.13-7.929-6.78-11.468l-14.342 5.281c-2.863-3.143-6.136-5.869-9.75-8.125l1.812-15.531c-3.941-1.9002-8.114-3.3986-12.469-4.4065zm-13.531 52.626c4.313 0 7.812 3.499 7.812 7.812s-3.499 7.812-7.812 7.812-7.812-3.499-7.812-7.812 3.499-7.812 7.812-7.812z"
transform="matrix(.025123 0 0 .025123 2.248 3.8298)"
/>
</g
>
</g
>
<metadata
>
<rdf:RDF
>
<cc:Work
>
<dc:format
>image/svg+xml</dc:format
>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
/>
<cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
/>
<dc:publisher
>
<cc:Agent
rdf:about="http://openclipart.org/"
>
<dc:title
>Openclipart</dc:title
>
</cc:Agent
>
</dc:publisher
>
</cc:Work
>
<cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/"
>
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction"
/>
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution"
/>
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
/>
</cc:License
>
</rdf:RDF
>
</metadata
>
</svg
>

After

Width:  |  Height:  |  Size: 4.2 KiB

+60
View File
@@ -0,0 +1,60 @@
<?xml version="1.0"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 524.41 744.09" version="1.0">
<g id="layer1">
<g id="g6728" transform="matrix(4.9859 0 0 4.9859 -1552.8 -1873.1)">
<g id="g5114" transform="translate(14.508 -2.7766)">
<path id="path5112" stroke-linejoin="round" d="m335.97 451.57c-9.22-4.99-15.48-14.75-15.48-25.96 0-10.86 5.87-20.35 14.61-25.47" stroke-dashoffset="5" stroke="#000" stroke-linecap="round" stroke-width=".98361" fill="none"/>
<path id="path5107" stroke-linejoin="round" d="m365.47 400.48c8.42 5.2 14.04 14.51 14.04 25.13v0c0 10.97-6 20.56-14.9 25.64" stroke-dashoffset="5" stroke="#000" stroke-linecap="round" stroke-width=".98361" fill="none"/>
</g>
<use id="use5733" xlink:href="#g5114" transform="matrix(1.32 0 0 1.32 -116.64 -135.38)" height="1052.3622" width="744.09448" y="0" x="0"/>
<use id="use5735" xlink:href="#g5114" transform="matrix(1.6479 0 0 1.6479 -236.17 -274.12)" height="1052.3622" width="744.09448" y="0" x="0"/>
<path id="path5737" d="m365 422.36v80" stroke="#000" stroke-linecap="round" stroke-width="5" fill="none"/>
<path id="path5739" d="m380 429.86a7.5 7.5 0 1 1 -15 0 7.5 7.5 0 1 1 15 0z" transform="translate(-7.5 -7.5)" fill-rule="evenodd"/>
</g>
</g>
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title>Wireless/WiFi symbol</dc:title>
<dc:date>2008-03-08T19:15:09</dc:date>
<dc:description>Wireless symobol for creating network schmatic</dc:description>
<dc:source>http://openclipart.org/detail/15561/wireless/wifi-symbol-by-ispyisail</dc:source>
<dc:creator>
<cc:Agent>
<dc:title>ispyisail</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>access point</rdf:li>
<rdf:li>clip art</rdf:li>
<rdf:li>clipart</rdf:li>
<rdf:li>icon</rdf:li>
<rdf:li>image</rdf:li>
<rdf:li>media</rdf:li>
<rdf:li>network</rdf:li>
<rdf:li>png</rdf:li>
<rdf:li>public domain</rdf:li>
<rdf:li>router</rdf:li>
<rdf:li>svg</rdf:li>
<rdf:li>wifi</rdf:li>
<rdf:li>wireless</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

+1 -1
View File
@@ -58,7 +58,7 @@
% if reason: % if reason:
<p>${reason}</p> <p>${reason}</p>
% else: % else:
<p>Vous n'êtes pas authentifi&eacute;, ou n'avez pas les authorisations n&eacute;cessaires.</p> <p>Vous n'êtes pas authentifié, ou n'avez pas les authorisations nécessaires.</p>
% endif % endif
</body> </body>
</html> </html>
+1 -1
View File
@@ -54,7 +54,7 @@
</head> </head>
<body> <body>
<img src="/img/error404.png" width="200px" /> <img src="/img/error404.png" width="200px" />
<h1>Page non trouv&eacute;e</h1> <h1>Page non trouvée</h1>
% if reason: % if reason:
<p>${reason}</p> <p>${reason}</p>
% else: % else:
+12 -12
View File
@@ -10,7 +10,7 @@
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td>Conf&eacute;rences</td> <td style="text-align:center"> <td>Conférences</td> <td style="text-align:center">
% if len( request.user.year_events('Conference') ): % if len( request.user.year_events('Conference') ):
% for evt in request.user.year_events('Conference'): % for evt in request.user.year_events('Conference'):
% endfor % endfor
@@ -106,11 +106,11 @@ elif Type=='T':
%> %>
% if Type!='O': % if Type!='O':
<fieldset> <fieldset>
<legend class="lowshadow">Vos ${CurTitles} programm&eacute;s pour ${CurrentYear}</legend> <legend class="lowshadow">Vos ${CurTitles} programmés pour ${CurrentYear}</legend>
<% <%
Selection = filter(lambda x:(x.event_type==CurEventType and x.for_year==CurrentYear), uprofil.events) Selection = list(filter(lambda x:(x.event_type==CurEventType and x.for_year==CurrentYear), uprofil.events))
HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) ) HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) )
NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent NothingTitle = u"Vous n'avez pas sollicité d'intervention %s." % CurEvent
%> %>
${helpers.show_Interventions(Selection, "Sujet", NothingTitle )} ${helpers.show_Interventions(Selection, "Sujet", NothingTitle )}
</fieldset> </fieldset>
@@ -118,21 +118,21 @@ NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent
% if Type=='C': % if Type=='C':
<p> <p>
<strong>Proposer une conf&eacute;rence / un lighting talk</strong><br/> <strong>Proposer une conférence / un lighting talk</strong><br/>
<ul> <ul>
<li>Si vous avez une exp&eacute;rience particulière avec les logiciels libres <li>Si vous avez une expérience particulière avec les logiciels libres
que vous souhaitez partager.</li> que vous souhaitez partager.</li>
<li>Si vous êtes acteur dun des sujets actuels qui menacent ou qui <li>Si vous êtes acteur dun des sujets actuels qui menacent ou qui
promeuvent le logiciel libre.</li> promeuvent le logiciel libre.</li>
<li>Si vous voulez pr&eacute;senter un logiciel libre dont vous êtes lauteur.</li> <li>Si vous voulez présenter un logiciel libre dont vous êtes lauteur.</li>
</ul> </ul>
Nous serons heureux de vous &eacute;couter. Nous serons heureux de vous écouter.
<br> <br>
Nous souhaitons proposer des conf&eacute;rences pour un public d&eacute;butant Nous souhaitons proposer des conférences pour un public débutant
autant que pour des visiteurs avertis. Les sujets ne doivent pas autant que pour des visiteurs avertis. Les sujets ne doivent pas
forc&eacute;ment être techniques, mais aussi dordre g&eacute;n&eacute;ral avec la seule forcément être techniques, mais aussi dordre général avec la seule
contrainte de traiter de près ou de loin des logiciels libres, de la contrainte de traiter de près ou de loin des logiciels libres, de la
communaut&eacute; ou de vos propres exp&eacute;riences dutilisateur quotidien. <br> communauté ou de vos propres exp&eacute;riences dutilisateur quotidien. <br>
Le but de ces conf&eacute;rences est double : Le but de ces conf&eacute;rences est double :
<ul> <ul>
<li>donner confiance aux futurs utilisateurs de logiciels libres</li> <li>donner confiance aux futurs utilisateurs de logiciels libres</li>
@@ -205,7 +205,7 @@ NothingTitle = u"Vous n'avez pas sollicit&eacute; d'intervention %s." % CurEvent
<fieldset> <fieldset>
<legend class="lowshadow">Historique</legend> <legend class="lowshadow">Historique</legend>
<% <%
Selection = filter(lambda x:(x.event_type==CurEventType and x.for_year!=CurrentYear), uprofil.events) Selection = list(filter(lambda x:(x.event_type==CurEventType and x.for_year!=CurrentYear), uprofil.events))
HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) ) HeadHistTitle = u"L'historique de vos %s ( %d ) " % ( CurTitles, len(Selection) )
NothingTitle = u"D&eacute;sol&eacute;, Il n'y a rien dans l'historique vous concernant." NothingTitle = u"D&eacute;sol&eacute;, Il n'y a rien dans l'historique vous concernant."
%> %>
+1 -1
View File
@@ -30,7 +30,7 @@
</tbody> </tbody>
</table> </table>
<div class="center"> <div class="center">
Pour un co-voiturage le <u>${Exch.start_time.strftime("%a %d %b").decode('utf-8')}</u> Pour un co-voiturage le <u>${Exch.start_time.strftime("%a %d %b")}</u>
vers <strong>${Exch.start_time.strftime("%H:%M")}</strong> vers <strong>${Exch.start_time.strftime("%H:%M")}</strong>
</div> </div>
Temps de voyage estimé à <span id="summary"></span> Temps de voyage estimé à <span id="summary"></span>
+1 -1
View File
@@ -12,7 +12,7 @@
<dd>Un hébergement</dd> <dd>Un hébergement</dd>
% endif % endif
<dt>Quand </dt> <dt>Quand </dt>
<dd>La nuit du ${Exch.start_time.strftime('%A %d %b %Y').decode('utf-8')} jusqu'au lendemain</dd> <dd>La nuit du ${Exch.start_time.strftime('%A %d %b %Y')} jusqu'au lendemain</dd>
% if Exch.description: % if Exch.description:
<dt>Détails </dt> <dt>Détails </dt>
<dd>${Exch.description}</dd> <dd>${Exch.description}</dd>
+2 -2
View File
@@ -8,8 +8,8 @@
<dt>Catégorie</dt> <dt>Catégorie</dt>
<dd>${Exch.Category.exch_subtype}</dd> <dd>${Exch.Category.exch_subtype}</dd>
<dt>Quand </dt> <dt>Quand </dt>
<dd>de ${Exch.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${Exch.start_time.strftime('%Hh%M')} <dd>de ${Exch.start_time.strftime('%A %d %b %Y')} vers ${Exch.start_time.strftime('%Hh%M')}
à ${Exch.end_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${Exch.end_time.strftime('%Hh%M')} à ${Exch.end_time.strftime('%A %d %b %Y')} vers ${Exch.end_time.strftime('%Hh%M')}
</dd> </dd>
<dt>Détails </dt> <dt>Détails </dt>
<dd>${Exch.description}</dd> <dd>${Exch.description}</dd>
+17 -17
View File
@@ -8,11 +8,11 @@ DicExch = Exchanges.get_overview( request.user.uid )
<div class="tabbable tabs-left" id="Intendance_tab"> <div class="tabbable tabs-left" id="Intendance_tab">
<ul class="nav nav-tabs navbar" style="margin-bottom:0;background-color: #f7f7f7;"> <ul class="nav nav-tabs navbar" style="margin-bottom:0;background-color: #f7f7f7;">
<li class="active"> <a href="#ResumeInt" data-toggle="tab">Resum&eacute;</a> </li> <li class="active"> <a href="#ResumeInt" data-toggle="tab">Resumé</a> </li>
<li> <a href="#Miam" data-toggle="tab"><span style="font-size:1.8em;">&#127869;</span> Miam</a> </li> <li> <a href="#Miam" data-toggle="tab"><span style="font-size:1.8em;">&#127869;</span> Miam</a> </li>
<li> <a href="#Covoiturage" data-toggle="tab"><span style="font-size:1.8em;">&#128664;</span> Covoiturage</a> </li> <li> <a href="#Covoiturage" data-toggle="tab"><span style="font-size:1.8em;">&#128664;</span> Covoiturage</a> </li>
<li> <a href="#Hebergement" data-toggle="tab"><span style="font-size:1.8em;">&#127962;</span> H&eacute;bergement</a> </li> <li> <a href="#Hebergement" data-toggle="tab"><span style="font-size:1.8em;">&#127962;</span> Hébergement</a> </li>
<li> <a href="#Materiel" data-toggle="tab"><span style="font-size:1.8em;">&#128722;</span> Mat&eacute;riel</a> </li> <li> <a href="#Materiel" data-toggle="tab"><span style="font-size:1.8em;">&#128722;</span> Matériel</a> </li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
@@ -30,7 +30,7 @@ DicExch = Exchanges.get_overview( request.user.uid )
${tables.DoTable(Type, 'Ask', DicExch)} ${tables.DoTable(Type, 'Ask', DicExch)}
${tables.DoTable(Type, 'Proposal', DicExch)} ${tables.DoTable(Type, 'Proposal', DicExch)}
<fieldset> <fieldset>
<legend>Tous les &eacute;changes</legend> <legend>Tous les échanges</legend>
${Missing(Type, DicExch['Missing'])} ${Missing(Type, DicExch['Missing'])}
</fieldset> </fieldset>
</%def> </%def>
@@ -59,23 +59,23 @@ DicForm = {
</td> </td>
<td> <td>
<p> <p>
Compl&eacute;tez dès à pr&eacute;sent votre partie repas afin que l'on puisse faire les r&eacute;servations n&eacute;cessaires ! Complétez dès à présent votre partie repas afin que l'on puisse faire les réservations nécessaires !
</p> </p>
<u>Vendredi soir :</u> <u>Vendredi soir :</u>
<p> <p>
Certains conf&eacute;renciers viennent de très loin et seront pr&eacute;sent d&eacute;s le vendredi.<br /> Certains conférenciers viennent de très loin et seront présent dés le vendredi.<br />
Nous vous proposons de nous retrouver à proximit&eacute;, à la CASA.<br /> Nous vous proposons de nous retrouver à proximité, à la CASA.<br />
<a href="http://groupelacasa.com/la-carte-et-les-menus-1-2-75"> La carte CASA </a> <a href="http://groupelacasa.com/la-carte-et-les-menus-1-2-75"> La carte CASA </a>
le vendredi soir autour d'un verre et d'un bon repas ! le vendredi soir autour d'un verre et d'un bon repas !
</p> </p>
<u>Samedi Midi :</u> <u>Samedi Midi :</u>
<p> <p>
&Agrave; la pause du midi, nous vous proposons un repas avec le food-truck 'les frères toqu&eacute;s' qui sera pr&eacute;sent sur le parking de PolyTech<br /> &Agrave; la pause du midi, nous vous proposons un repas avec le food-truck 'les frères toqués' qui sera présent sur le parking de PolyTech<br />
</p> </p>
<u>Samedi Soir :</u> <u>Samedi Soir :</u>
<p> <p>
Pour conclure la journ&eacute;e nous avons l'habitude de nous retrouver au repas de cloture.<br /> Pour conclure la journée nous avons l'habitude de nous retrouver au repas de cloture.<br />
Nous vous proposons de nous retrouver à Antibes au restaurant Les Tonnelles<br /> Nous vous proposons de nous retrouver à Antibes au restaurant Les Tonnelles<br />
<a href="https://fr-fr.facebook.com/lestonnellesantibes/?_fb_noscript=1"> Les Tonnelles </a> <a href="https://fr-fr.facebook.com/lestonnellesantibes/?_fb_noscript=1"> Les Tonnelles </a>
</p> </p>
@@ -100,7 +100,7 @@ elif Type=='M':
<thead> <thead>
<tr> <tr>
<th colspan="5"> <th colspan="5">
Les &eacute;changes ${CurTitle} Les échanges ${CurTitle}
% if 0: % if 0:
<span style="float:right;"> <span style="float:right;">
<a data-original-title="Afficher les demandes" data-toggle="tooltip" id="${Type}_Demande"> <a data-original-title="Afficher les demandes" data-toggle="tooltip" id="${Type}_Demande">
@@ -124,7 +124,7 @@ elif Type=='M':
<tr> <tr>
<th style="width:1em;"></th> <th style="width:1em;"></th>
<th>D&eacute;tails</th> <th>Détails</th>
<th style="width:1em;"></th> <th style="width:1em;"></th>
<tr> <tr>
</thead> </thead>
@@ -132,7 +132,7 @@ elif Type=='M':
% if len(Selection)==0: % if len(Selection)==0:
<tr> <tr>
<td colspan="5" style="text-align:center;"> <td colspan="5" style="text-align:center;">
<i>Il n'y a aucun &eacute;change ${CurTitle} propos&eacute; actuellement...</i> <i>Il n'y a aucun échange ${CurTitle} proposé actuellement...</i>
</td> </td>
</tr> </tr>
% else: % else:
@@ -155,7 +155,7 @@ elif Type=='M':
<a href="/user/${item.provider.slug}"> ${item.provider.prenom} ${item.provider.nom} </a> offre <a href="/user/${item.provider.slug}"> ${item.provider.prenom} ${item.provider.nom} </a> offre
% endif % endif
% if item.exch_type=="C": % if item.exch_type=="C":
un co-voiturage le ${item.start_time.strftime('%a %d %b vers %Hh%M').decode('utf-8')} un co-voiturage le ${item.start_time.strftime('%a %d %b vers %Hh%M')}
de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a> de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a>
à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a> à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a>
% elif item.exch_type=="M": % elif item.exch_type=="M":
@@ -165,8 +165,8 @@ elif Type=='M':
% if item.description: % if item.description:
${item.description[:30]} ${item.description[:30]}
% endif % endif
de ${item.start_time.strftime('%a %d %b %Hh%M').decode('utf-8')} de ${item.start_time.strftime('%a %d %b %Hh%M')}
à ${item.end_time.strftime('%a %d %b %Hh%M').decode('utf-8')} à ${item.end_time.strftime('%a %d %b %Hh%M')}
% else: % else:
% if item.Category: % if item.Category:
<i>${item.Category.exch_subtype}</i> <i>${item.Category.exch_subtype}</i>
@@ -174,7 +174,7 @@ elif Type=='M':
% if item.description: % if item.description:
${item.description[:30]} ${item.description[:30]}
% endif % endif
${item.start_time.strftime('%a %d %b').decode('utf-8')} soir ${item.start_time.strftime('%a %d %b')} soir
% endif % endif
</p> </p>
</td> </td>
@@ -284,7 +284,7 @@ ListWrap = ["Co-voiturage",u"Hébergement","Matos"]
</div> </div>
<div class="accordion-group"> <div class="accordion-group">
<div class="accordion-heading"> <div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#AccordionCounter" href="#collapseAll">Les compteurs de l´&eacute;v&eacute;nement</a> <a class="accordion-toggle" data-toggle="collapse" data-parent="#AccordionCounter" href="#collapseAll">Les compteurs de l´év&eacute;nement</a>
</div> </div>
<div id="collapseAll" class="accordion-body collapse"> <div id="collapseAll" class="accordion-body collapse">
<div class="accordion-inner"> <div class="accordion-inner">
+4 -4
View File
@@ -97,17 +97,17 @@ elif Type=='M':
</td> </td>
<td> <td>
%if Type=='C': %if Type=='C':
${item.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.start_time.strftime('%Hh%M')} ${item.start_time.strftime('%A %d %b %Y')} vers ${item.start_time.strftime('%Hh%M')}
de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a> de <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.start.place_id}')">${item.Itin.start.display_name}</a>
à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a> à <a href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/${item.Itin.arrival.place_id}')">${item.Itin.arrival.display_name}</a>
%elif Type=='H': %elif Type=='H':
% if item.Category: % if item.Category:
<i>${item.Category.exch_subtype}</i>, <i>${item.Category.exch_subtype}</i>,
% endif % endif
La nuit du ${item.start_time.strftime('%A %d %b %Y').decode('utf-8')}<br> La nuit du ${item.start_time.strftime('%A %d %b %Y')}<br>
%elif Type=='M': %elif Type=='M':
de ${item.start_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.start_time.strftime('%Hh%M')} de ${item.start_time.strftime('%A %d %b %Y')} vers ${item.start_time.strftime('%Hh%M')}
à ${item.end_time.strftime('%A %d %b %Y').decode('utf-8')} vers ${item.end_time.strftime('%Hh%M')}<br> à ${item.end_time.strftime('%A %d %b %Y')} vers ${item.end_time.strftime('%Hh%M')}<br>
${item.Category.exch_subtype} ${item.Category.exch_subtype}
%endif %endif
%if item.description: %if item.description:
+1 -1
View File
@@ -1,6 +1,6 @@
<%inherit file="jm2l:templates/layout.mako"/> <%inherit file="jm2l:templates/layout.mako"/>
<%def name="jsAddOn()"> <%def name="jsAddOn()">
<script src="/vendor/timeline/js/timeline-src.js"></script> <script src="/vendor/timeline/js/timeline-min.js"></script>
<script> <script>
var timeline = new VMM.Timeline("timeline", '95%', '600px'); var timeline = new VMM.Timeline("timeline", '95%', '600px');
var c = {language:{ lang:"fr",api:{wikipedia:"fr"},date:{month:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],month_abbr:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","dec."],day:["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"],day_abbr:["Dim.","Lu.","Ma.","Me.","Jeu.","Vend.","Sam."]},dateformats:{year:"yyyy",month_short:"mmm",month:"mmmm yyyy",full_short:"d mmm",full:"d mmmm yyyy",time_short:"HH:MM:SS",time_no_seconds_short:"HH:MM",time_no_seconds_small_date:"HH:MM'<br/><small>'d mmmm yyyy'</small>'",full_long:"dddd',' d mmm yyyy 'à' HH:MM",full_long_small_date:"HH:MM'<br/><small>'dddd',' d mmm yyyy'</small>'"},messages:{loading_timeline:"Chargement de la frise en cours... ",return_to_title:"Retour à la page d'accueil",expand_timeline:"Elargir la frise",contract_timeline:"Réduire la frise",wikipedia:"Extrait de Wikipedia, l'encyclopédie libre",loading_content:"Chargement",loading:"Chargement",swipe_nav:"Swipe to Navigate"}}}; var c = {language:{ lang:"fr",api:{wikipedia:"fr"},date:{month:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],month_abbr:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","dec."],day:["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"],day_abbr:["Dim.","Lu.","Ma.","Me.","Jeu.","Vend.","Sam."]},dateformats:{year:"yyyy",month_short:"mmm",month:"mmmm yyyy",full_short:"d mmm",full:"d mmmm yyyy",time_short:"HH:MM:SS",time_no_seconds_short:"HH:MM",time_no_seconds_small_date:"HH:MM'<br/><small>'d mmmm yyyy'</small>'",full_long:"dddd',' d mmm yyyy 'à' HH:MM",full_long_small_date:"HH:MM'<br/><small>'dddd',' d mmm yyyy'</small>'"},messages:{loading_timeline:"Chargement de la frise en cours... ",return_to_title:"Retour à la page d'accueil",expand_timeline:"Elargir la frise",contract_timeline:"Réduire la frise",wikipedia:"Extrait de Wikipedia, l'encyclopédie libre",loading_content:"Chargement",loading:"Chargement",swipe_nav:"Swipe to Navigate"}}};
+4 -4
View File
@@ -23,12 +23,12 @@
<% <%
DicFormA = { DicFormA = {
'nom': {'PlaceHolder':u"Mon Nom", 'ContainerClass':"span6", 'next':False}, 'nom': {'PlaceHolder':u"Mon Nom", 'ContainerClass':"span6", 'next':False},
'prenom': {'PlaceHolder':u"Mon Pr&eacute;nom", 'ContainerClass':"span6", 'next':True}, 'prenom': {'PlaceHolder':u"Mon Prénom", 'ContainerClass':"span6", 'next':True},
'pseudo': {'PlaceHolder':u"Mon Pseudo", 'ContainerClass':"span6", 'next':False}, 'pseudo': {'PlaceHolder':u"Mon Pseudo", 'ContainerClass':"span6", 'next':False},
'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", 'ContainerClass':"span6", 'next':True}, 'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", 'ContainerClass':"span6", 'next':True},
'phone': {'PlaceHolder':u"0612345678", 'ContainerClass':"span6", 'next':False}, 'phone': {'PlaceHolder':u"0612345678", 'ContainerClass':"span6", 'next':False},
'website': {'PlaceHolder':u"http://ma-page-web.moi",'ContainerClass':"span6", 'next':True}, 'website': {'PlaceHolder':u"http://ma-page-web.moi",'ContainerClass':"span6", 'next':True},
'gpg_key': {'PlaceHolder':u"Ma cl&eacute; gpg", 'ContainerClass':"span6", 'next':False}, 'gpg_key': {'PlaceHolder':u"Ma clé gpg", 'ContainerClass':"span6", 'next':False},
'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org",'ContainerClass':"span6", 'next':True}, 'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org",'ContainerClass':"span6", 'next':True},
'bio': {'Ignore':True}, 'bio': {'Ignore':True},
'tiersship': {'Ignore':True}, 'tiersship': {'Ignore':True},
@@ -52,12 +52,12 @@ DicFormB = {
DicForm2 = { DicForm2 = {
'nom': {'PlaceHolder':u"Mon Nom", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"}, 'nom': {'PlaceHolder':u"Mon Nom", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'prenom': {'PlaceHolder':u"Mon Pr&eacute;nom", "FieldStyle":"width:16em;"}, 'prenom': {'PlaceHolder':u"Mon Prénom", "FieldStyle":"width:16em;"},
'pseudo': {'PlaceHolder':u"Mon Pseudo", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"}, 'pseudo': {'PlaceHolder':u"Mon Pseudo", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", "FieldStyle":"width:16em;"}, 'mail': {'PlaceHolder':u"mon.mail@fqdn.tld", "FieldStyle":"width:16em;"},
'phone': {'PlaceHolder':u"0612345678", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"}, 'phone': {'PlaceHolder':u"0612345678", "FieldStyle":"width:16em;", 'ContainerStyle':"float:left;"},
'website': {'PlaceHolder':u"http://ma-page-web.moi","FieldStyle":"width:16em;"}, 'website': {'PlaceHolder':u"http://ma-page-web.moi","FieldStyle":"width:16em;"},
'gpg_key': {'PlaceHolder':u"Ma cl&eacute; gpg", "FieldStyle":"width:90%;"}, 'gpg_key': {'PlaceHolder':u"Ma clé gpg", "FieldStyle":"width:90%;"},
'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org","FieldStyle":"width:90%;"}, 'soc_link':{'PlaceHolder':u"#jm2l sur irc.freenode.org","FieldStyle":"width:90%;"},
'bio': {'PlaceHolder':u"Ma Bilibiographie", "FieldStyle":"width:95%;min-height:150px;", "fieldset":True, "ckeditor":1 }, 'bio': {'PlaceHolder':u"Ma Bilibiographie", "FieldStyle":"width:95%;min-height:150px;", "fieldset":True, "ckeditor":1 },
'tiersship': {'Ignore':True} 'tiersship': {'Ignore':True}
+13 -13
View File
@@ -14,14 +14,14 @@ fieldset:disabled {
% else: % else:
<legend class="lowshadow"> <legend class="lowshadow">
<img style="max-height:50px;" src="/img/warn.png" alt="Attention !"> <img style="max-height:50px;" src="/img/warn.png" alt="Attention !">
Vous n'avez pas confirm&eacute; votre venue aux JM2L ${CurrentYear} Vous n'avez pas confirmé votre venue aux JM2L ${CurrentYear}
</legend> </legend>
<h4 class="lowshadow">Compl&eacute;tez et validez vite ce formulaire !</h4> <h4 class="lowshadow">Complétez et validez vite ce formulaire !</h4>
% endif % endif
<form id="ProfilForm" action="/MonSejour" method="POST"> <form id="ProfilForm" action="/MonSejour" method="POST">
<fieldset class="ComeToJM2L"> <fieldset class="ComeToJM2L">
<legend>Arriv&eacute;e</legend> <legend>Arrivée</legend>
<div class="form-inline"> <div class="form-inline">
J'arrive J'arrive
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu"> <select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
@@ -63,16 +63,16 @@ fieldset:disabled {
<ul style="list-style-type: none;"> <ul style="list-style-type: none;">
<li><label class="checkbox"> <li><label class="checkbox">
<input id="PMR" ${mytrip.IsCheck("Arrival:PMR")|n} name="Arrival:PMR" title="Assistance Personne à mobilit&eacute; r&eacute;duite (PMR)" type="checkbox"> <input id="PMR" ${mytrip.IsCheck("Arrival:PMR")|n} name="Arrival:PMR" title="Assistance Personne à mobilité réduite (PMR)" type="checkbox">
d'assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)</input></label> d'assistance : Personne à mobilité réduite (PMR)</input></label>
</li> </li>
<li><label class="checkbox"> <li><label class="checkbox">
<input id="Cov" ${mytrip.IsCheck("Arrival:Cov")|n} name="Arrival:Cov" title="Covoiturage" type="checkbox"> <input id="Cov" ${mytrip.IsCheck("Arrival:Cov")|n} name="Arrival:Cov" title="Covoiturage" type="checkbox">
d'un covoiturage, d'un h&eacute;bergement...<br>(j'ai rempli/je vais remplir la section Logistique).</input></label> d'un covoiturage, d'un hébergement...<br>(j'ai rempli/je vais remplir la section Logistique).</input></label>
</li> </li>
<li><label class="checkbox"> <li><label class="checkbox">
<input id="Bras" ${mytrip.IsCheck("Arrival:Bras")|n} name="Arrival:Bras" title="Bras" type="checkbox"> <input id="Bras" ${mytrip.IsCheck("Arrival:Bras")|n} name="Arrival:Bras" title="Bras" type="checkbox">
de bras, car je rapporte plein de mat&eacute;riel. <br>(Je transporte ma maison, mon garage ...)</input></label> de bras, car je rapporte plein de matériel. <br>(Je transporte ma maison, mon garage ...)</input></label>
</li> </li>
<li> <li>
<div class="form-inline"> <div class="form-inline">
@@ -81,7 +81,7 @@ fieldset:disabled {
Autres Autres
</input></label> </input></label>
<input type="text" style="width:20em;" name="Arrival:Comment" <input type="text" style="width:20em;" name="Arrival:Comment"
placeholder="Pr&eacute;cisions à propos de mon arriv&eacute;e…" /> placeholder="Précisions à propos de mon arrivée…" />
</div> </div>
</li> </li>
</ul> </ul>
@@ -90,7 +90,7 @@ fieldset:disabled {
</fieldset> </fieldset>
<fieldset class="ComeToJM2L"> <fieldset class="ComeToJM2L">
<legend>D&eacute;part</legend> <legend>Départ</legend>
<div class="form-inline"> <div class="form-inline">
Je repars Je repars
<select style="width:12em;" id="Departure:Place" class="formforform-field" name="Departure:Place" title="Alors, j'arrive"> <select style="width:12em;" id="Departure:Place" class="formforform-field" name="Departure:Place" title="Alors, j'arrive">
@@ -130,8 +130,8 @@ fieldset:disabled {
Je vais avoir besoin: &nbsp;&nbsp;<small style="color: #aaa;">(Cochez les cases correspondantes)</small> Je vais avoir besoin: &nbsp;&nbsp;<small style="color: #aaa;">(Cochez les cases correspondantes)</small>
<ul style="list-style-type: none;"> <ul style="list-style-type: none;">
<li><label class="checkbox"> <li><label class="checkbox">
<input id="PMR" ${mytrip.IsCheck("Departure:PMR")|n} name="Departure:PMR" title="d'Assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)" type="checkbox"> <input id="PMR" ${mytrip.IsCheck("Departure:PMR")|n} name="Departure:PMR" title="d'Assistance : Personne à mobilité réduite (PMR)" type="checkbox">
d'assistance : Personne à mobilit&eacute; r&eacute;duite (PMR)</input> d'assistance : Personne à mobilité réduite (PMR)</input>
</label> </label>
</li> </li>
<li><label class="checkbox"> <li><label class="checkbox">
@@ -141,7 +141,7 @@ fieldset:disabled {
</li> </li>
<li><label class="checkbox"> <li><label class="checkbox">
<input id="Bras" ${mytrip.IsCheck("Departure:Bras")|n} name="Departure:Bras" title="de bras" type="checkbox"> <input id="Bras" ${mytrip.IsCheck("Departure:Bras")|n} name="Departure:Bras" title="de bras" type="checkbox">
de bras, car j'ai en stock plein de mat&eacute;riel (Ma maison).</input> de bras, car j'ai en stock plein de matériel (Ma maison).</input>
</label> </label>
</li> </li>
<li> <li>
@@ -151,7 +151,7 @@ fieldset:disabled {
Autres Autres
</input></label> </input></label>
<input type="text" style="width:20em;" name="Departure:Comment" <input type="text" style="width:20em;" name="Departure:Comment"
placeholder="Pr&eacute;cisions à propos de mon d&eacute;part…" /> placeholder="Précisions à propos de mon départ…" />
</div> </div>
</li> </li>
</ul> </ul>
+2 -2
View File
@@ -111,7 +111,7 @@ if Counter==0:
vid = event.video.first() vid = event.video.first()
pres = event.presentation.first() pres = event.presentation.first()
%> %>
${event.start_time.strftime("%a %d %b").decode('utf-8')}<br> ${event.start_time.strftime("%a %d %b")}<br>
${event.start_time.strftime("%H:%M")} - ${event.end_time.strftime("%H:%M")} ${event.start_time.strftime("%H:%M")} - ${event.end_time.strftime("%H:%M")}
</td> </td>
<td style="position: relative;"> <td style="position: relative;">
@@ -132,7 +132,7 @@ if Counter==0:
</span> </span>
<br/> <br/>
avec avec
% for num, inter in enumerate(event.intervenants.all()): % for num, inter in enumerate(event.intervenants):
%if num>0: %if num>0:
, ,
%endif %endif
+2 -2
View File
@@ -24,7 +24,7 @@ from slugify import slugify
% if len(DicSallePhy)==0: % if len(DicSallePhy)==0:
<tr> <tr>
<td style="text-align:center;"> <td style="text-align:center;">
<i>Il n'y a pas de salle d&eacute;finie pour le moment.</i> <i>Il n'y a pas de salle définie pour le moment.</i>
</td> </td>
</tr> </tr>
% endif % endif
@@ -43,7 +43,7 @@ from slugify import slugify
% if SallePhy.uid: % if SallePhy.uid:
[ ${SallePhy.nb_places} places ] [ ${SallePhy.nb_places} places ]
% else: % else:
[ <a href="/PhySalles">Cr&eacute;er</a> ] [ <a href="/PhySalles">Créer</a> ]
% endif % endif
</div> </div>
+2 -2
View File
@@ -29,9 +29,9 @@
%endif %endif
<% <%
DicForm = { DicForm = {
'year_uid': {'PlaceHolder':u"Ann&eacute;e", "FieldStyle":"width:7em;", "ContainerStyle":"float:left;" }, 'year_uid': {'PlaceHolder':u"Année", "FieldStyle":"width:7em;", "ContainerStyle":"float:left;" },
'phy_salle_id': {'PlaceHolder':u"Salle Physique", "FieldStyle":"width:20em;", "ContainerStyle":"float:left;" }, 'phy_salle_id': {'PlaceHolder':u"Salle Physique", "FieldStyle":"width:20em;", "ContainerStyle":"float:left;" },
'place_type': {'PlaceHolder':u"Type d'&eacute;vènement","FieldStyle":"width:15em;" }, 'place_type': {'PlaceHolder':u"Type d'évènement","FieldStyle":"width:15em;" },
'name': {'PlaceHolder':u"Nom de la salle", "FieldStyle":"width:90%;" }, 'name': {'PlaceHolder':u"Nom de la salle", "FieldStyle":"width:90%;" },
'description': {'PlaceHolder':u"Description", "ContainerStyle":"width:95%;min-height:150px;padding-top: 12px;", "ckeditor":"1" }, 'description': {'PlaceHolder':u"Description", "ContainerStyle":"width:95%;min-height:150px;padding-top: 12px;", "ckeditor":"1" },
} }
+1 -1
View File
@@ -46,7 +46,7 @@
</td> </td>
</tr> </tr>
% endif % endif
% for item, one_dic in found.iteritems(): % for item, one_dic in found.items():
<tr> <tr>
<td> <td>
<a href="/user/${item}"> <a href="/user/${item}">
+1 -1
View File
@@ -63,7 +63,7 @@ from slugify import slugify
</a> </a>
<span style="float:right;"> <span style="float:right;">
- <a href="/user/${task.assignee.slug}">${task.assignee.pseudo or ' '.join([task.assignee.prenom, task.assignee.nom]) }</a> - <a href="/user/${task.assignee.slug}">${task.assignee.pseudo or ' '.join([task.assignee.prenom, task.assignee.nom]) }</a>
- ${task.due_date.strftime("%d %b").decode("utf-8")} - ${task.due_date.strftime("%d %b")}
</span> </span>
% endif % endif
</td> </td>
+5 -5
View File
@@ -30,7 +30,7 @@
%endif %endif
% if 'uid' in form._fields: % if 'uid' in form._fields:
<div class="borderboxtime"> <div class="borderboxtime">
${event.start_time.strftime('%d %b %Y').decode('utf-8')} - ${event.start_time.strftime('%d %b %Y')} -
${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')} ${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')}
%if event.Salle: %if event.Salle:
- <strong>Salle</strong>: ${event.Salle.name} - <strong>Salle</strong>: ${event.Salle.name}
@@ -43,7 +43,7 @@
<div class="borderbox"> <div class="borderbox">
Intervenants programmés: Intervenants programmés:
<ul> <ul>
% if event.intervenants.count()==0: % if len(event.intervenants)==0:
<i><b>Aucun</b></i> <i><b>Aucun</b></i>
% else: % else:
% for num, iterv in enumerate(event.intervenants): % for num, iterv in enumerate(event.intervenants):
@@ -160,7 +160,7 @@ DicForm = {
<td> <td>
<u>Les Intervenants:</u> <u>Les Intervenants:</u>
<ul> <ul>
% if event.intervenants.count()==0: % if len(event.intervenants)==0:
<i><b>Aucun</b></i> <i><b>Aucun</b></i>
% else: % else:
% for num, iterv in enumerate(event.intervenants): % for num, iterv in enumerate(event.intervenants):
@@ -184,10 +184,10 @@ DicForm = {
</fieldset> </fieldset>
<div class="clearfix">&nbsp;</div> <div class="clearfix">&nbsp;</div>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y').decode('utf-8')}</p> <p style="float:right;">Créé le ${event.created.strftime('%d %b %Y')}</p>
%else: %else:
<p style="float:right;">Créé le <p style="float:right;">Créé le
${datetime.now().strftime('%d %b %Y').decode('utf-8')} ${datetime.now().strftime('%d %b %Y')}
</p> </p>
% endif % endif
<br/> <br/>
+17 -17
View File
@@ -7,7 +7,7 @@ TabJs = {'select':[], 'desc':[]}
%> %>
<div class="row-fluid"> <div class="row-fluid">
% for FieldName, Field in form._fields.items(): % for FieldName, Field in form._fields.items():
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("Ignore"): % if Field.name in DicFormat and DicFormat[Field.name].get("Ignore"):
<% continue %> <% continue %>
% endif % endif
% if Field.type in ['HiddenField', 'CSRFTokenField']: % if Field.type in ['HiddenField', 'CSRFTokenField']:
@@ -27,7 +27,7 @@ TabJs = {'select':[], 'desc':[]}
</a> </a>
% endif % endif
</label> </label>
% if DicFormat.has_key(Field.name): % if Field.name in DicFormat:
<% <%
PlaceHolder = DicFormat[Field.name].get("PlaceHolder") PlaceHolder = DicFormat[Field.name].get("PlaceHolder")
Class = [False,"ckeditor"][ "ckeditor" in DicFormat[Field.name] ] Class = [False,"ckeditor"][ "ckeditor" in DicFormat[Field.name] ]
@@ -49,7 +49,7 @@ TabJs = {'select':[], 'desc':[]}
% endfor % endfor
</div> </div>
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("next")==True: % if Field.name in DicFormat and DicFormat[Field.name].get("next")==True:
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
% endif % endif
@@ -72,7 +72,7 @@ TabJs = {'select':[], 'desc':[]}
TabJs = {'select':[], 'desc':[]} TabJs = {'select':[], 'desc':[]}
%> %>
% for FieldName, Field in form._fields.items(): % for FieldName, Field in form._fields.items():
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("Ignore"): % if Field.name in DicFormat and DicFormat[Field.name].get("Ignore"):
<% continue %> <% continue %>
% endif % endif
% if Field.type in ['HiddenField', 'CSRFTokenField']: % if Field.type in ['HiddenField', 'CSRFTokenField']:
@@ -81,11 +81,11 @@ TabJs = {'select':[], 'desc':[]}
% elif Field.type=="SelectField": % elif Field.type=="SelectField":
<% TabJs['select'].append(Field.label.field_id) %> <% TabJs['select'].append(Field.label.field_id) %>
% endif % endif
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("fieldset"): % if Field.name in DicFormat and DicFormat[Field.name].get("fieldset"):
<fieldset> <fieldset>
<legend>${Field.label.text}</legend> <legend>${Field.label.text}</legend>
% else: % else:
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("ContainerStyle"): % if Field.name in DicFormat and DicFormat[Field.name].get("ContainerStyle"):
<div style="padding-right:5px;${DicFormat[Field.name].get("ContainerStyle")}"> <div style="padding-right:5px;${DicFormat[Field.name].get("ContainerStyle")}">
% else: % else:
<div style="padding-right:5px;"> <div style="padding-right:5px;">
@@ -101,11 +101,11 @@ TabJs = {'select':[], 'desc':[]}
% endif % endif
</label> </label>
% endif % endif
% if DicFormat.has_key(Field.name): % if Field.name in DicFormat:
<% <%
PlaceHolder = DicFormat[Field.name].get("PlaceHolder") PlaceHolder = DicFormat[Field.name].get("PlaceHolder")
FieldStyle = DicFormat[Field.name].get("FieldStyle") FieldStyle = DicFormat[Field.name].get("FieldStyle")
Class = [False,"ckeditor"][ "ckeditor" in DicFormat[Field.name] ] Class = [False, "ckeditor"][ "ckeditor" in DicFormat[Field.name] ]
%> %>
% if Field.type == "date": % if Field.type == "date":
${Field(placeholder=PlaceHolder or False, style=FieldStyle, class_="datepicker" )} ${Field(placeholder=PlaceHolder or False, style=FieldStyle, class_="datepicker" )}
@@ -122,7 +122,7 @@ TabJs = {'select':[], 'desc':[]}
${ error } ${ error }
</div> </div>
% endfor % endfor
% if DicFormat.has_key(Field.name) and DicFormat[Field.name].get("fieldset"): % if Field.name in DicFormat and DicFormat[Field.name].get("fieldset"):
</fieldset> </fieldset>
% else: % else:
</div> </div>
@@ -142,7 +142,7 @@ TabJs = {'select':[], 'desc':[]}
<%def name="sejour_wrapper(Places)"> <%def name="sejour_wrapper(Places)">
<div class="form-inline"> <div class="form-inline">
D&eacute;part : Départ :
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu"> <select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
% for place in Places: % for place in Places:
<option value="${place.place_id}">${place.display_name}</option> <option value="${place.place_id}">${place.display_name}</option>
@@ -151,7 +151,7 @@ TabJs = {'select':[], 'desc':[]}
</div> </div>
<br /> <br />
<div class="form-inline"> <div class="form-inline">
Arriv&eacute;e : Arrivée :
<select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu"> <select style="width:12em;" id="Arrival:Place" name="Arrival:Place" title="Lieu">
% for place in Places: % for place in Places:
<option value="${place.place_id}">${place.display_name}</option> <option value="${place.place_id}">${place.display_name}</option>
@@ -184,7 +184,7 @@ TabJs = {'select':[], 'desc':[]}
${itin_form.arrival_place(style='width:17em;')} ${itin_form.arrival_place(style='width:17em;')}
</div> </div>
<div style="padding:5px;"> <div style="padding:5px;">
<small style="color:#999">Si je n´ai pas trouv&eacute; le lieu dont j´ai besoin dans ces listes...</small> <small style="color:#999">Si je n´ai pas trouvé le lieu dont j´ai besoin dans ces listes...</small>
<br /> <br />
<small style="color:#999">Je peux </small> <small style="color:#999">Je peux </small>
<a class="btn btn-mini btn-info" role="button" href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/0');"> <a class="btn btn-mini btn-info" role="button" href="javascript:DoGetLieu('/${CurrentYear}/modal/Place/0');">
@@ -350,9 +350,9 @@ TabJs = {'select':[], 'desc':[]}
<tr> <tr>
<td style="text-align:center;" colspan="2"> <td style="text-align:center;" colspan="2">
% if NotFoundTitle: % if NotFoundTitle:
<i>${NotFoundTitle}</i> <i>${NotFoundTitle | h}</i>
% else: % else:
<i>D&eacute;sol&eacute;, Il n'y a rien dans l'historique.</i> <i>Désolé;, Il n'y a rien dans l'historique.</i>
% endif % endif
</td> </td>
</tr> </tr>
@@ -366,7 +366,7 @@ TabJs = {'select':[], 'desc':[]}
vid = event.video.first() vid = event.video.first()
pres = event.presentation.first() pres = event.presentation.first()
%> %>
${event.start_time.strftime('%d %b %Y').decode('utf-8')} ${event.start_time.strftime('%d %b %Y')}
${start.hour}:${"%.2d" % start.minute}-${end.hour}:${"%.2d" % end.minute} ${start.hour}:${"%.2d" % start.minute}-${end.hour}:${"%.2d" % end.minute}
</td> </td>
<td style="position: relative;">${event.event_type}: <td style="position: relative;">${event.event_type}:
@@ -391,9 +391,9 @@ TabJs = {'select':[], 'desc':[]}
</div> </div>
% endif % endif
<br/> <br/>
% if event.intervenants.count()>1: % if len(event.intervenants)>1:
avec avec
% for num, inter in enumerate(event.intervenants.all()): % for num, inter in enumerate(event.intervenants):
<% <%
if inter==uprofil: if inter==uprofil:
continue continue
+7 -7
View File
@@ -61,7 +61,7 @@
<div class="tabbable" id="main_tab"> <div class="tabbable" id="main_tab">
<ul class="nav nav-tabs nav-pills" style="margin-bottom: 5px;"> <ul class="nav nav-tabs nav-pills" style="margin-bottom: 5px;">
<li class="active"><a href="#Profil" id="Map_Profil" data-toggle="tab">Mon Profil</a></li> <li class="active"><a href="#Profil" id="Map_Profil" data-toggle="tab">Mon Profil</a></li>
<li><a href="#Sejour" id="Map_Sejour" data-toggle="tab">Mon S&eacute;jour</a></li> <li><a href="#Sejour" id="Map_Sejour" data-toggle="tab">Mon Séjour</a></li>
<li><a href="#Logistique" id="Map_Logistique" data-toggle="tab">Logistique</a></li> <li><a href="#Logistique" id="Map_Logistique" data-toggle="tab">Logistique</a></li>
<li><a href="#Interventions" id="Map_Interventions" data-toggle="tab">Mes Interventions</a></li> <li><a href="#Interventions" id="Map_Interventions" data-toggle="tab">Mes Interventions</a></li>
<li><a href="#Frais" id="Map_Frais" data-toggle="tab">Mes Frais</a></li> <li><a href="#Frais" id="Map_Frais" data-toggle="tab">Mes Frais</a></li>
@@ -79,8 +79,8 @@
<div class="tabbable tabs-left" id="Interventions_tab"> <div class="tabbable tabs-left" id="Interventions_tab">
<ul class="nav nav-tabs navbar" style="margin-bottom:0;"> <ul class="nav nav-tabs navbar" style="margin-bottom:0;">
<li class="active"> <a href="#ResumePart" data-toggle="tab">Resum&eacute;</a> </li> <li class="active"> <a href="#ResumePart" data-toggle="tab">Resumé</a> </li>
<li> <a href="#Conference" data-toggle="tab">Conf&eacute;rence</a> </li> <li> <a href="#Conference" data-toggle="tab">Conférence</a> </li>
<li> <a href="#Stand" data-toggle="tab">Stand</a> </li> <li> <a href="#Stand" data-toggle="tab">Stand</a> </li>
<li> <a href="#Atelier" data-toggle="tab">Atelier</a> </li> <li> <a href="#Atelier" data-toggle="tab">Atelier</a> </li>
<li> <a href="#TableRonde" data-toggle="tab">Table Ronde</a> </li> <li> <a href="#TableRonde" data-toggle="tab">Table Ronde</a> </li>
@@ -118,12 +118,12 @@
<div class="tab-pane fade" id="Frais"> <div class="tab-pane fade" id="Frais">
<fieldset> <fieldset>
<legend class="lowshadow">Une participation à mes frais ?</legend> <legend class="lowshadow">Une participation à mes frais ?</legend>
L'&eacute;quipe des JM2L participe aux <u>frais de transport</u> des intervenants !<br /><br /> L'équipe des JM2L participe aux <u>frais de transport</u> des intervenants !<br /><br />
Et bien oui, mais cette participation ne sera effective que si vous remplissez <u>toutes les conditions</u> suivantes: Et bien oui, mais cette participation ne sera effective que si vous remplissez <u>toutes les conditions</u> suivantes:
<ul style="list-style:circle;"> <ul style="list-style:circle;">
<li>Vous animez <strong>un atelier, une conf&eacute;rence ou une table ronde</strong> aux JM2L ${CurrentYear}.</li> <li>Vous animez <strong>un atelier, une conférence ou une table ronde</strong> aux JM2L ${CurrentYear}.</li>
<li>Votre fiche est renseign&eacute;e avec <strong>votre RIB</strong>.</li> <li>Votre fiche est renseignée avec <strong>votre RIB</strong>.</li>
<li>Votre fiche est renseign&eacute;e avec <strong>les preuves</strong> de vos achats.</li> <li>Votre fiche est renseignée avec <strong>les preuves</strong> de vos achats.</li>
<li>Vous <strong>présentez l'original de vos tickets</strong> à l'accueil pendant l'évènement.</li> <li>Vous <strong>présentez l'original de vos tickets</strong> à l'accueil pendant l'évènement.</li>
<li>Tous vos documents sont conformes.</li> <li>Tous vos documents sont conformes.</li>
</ul> </ul>
+17 -33
View File
@@ -3,7 +3,7 @@
<%namespace name="helpers" file="jm2l:templates/helpers.mako"/> <%namespace name="helpers" file="jm2l:templates/helpers.mako"/>
<% <%
context._kwargs['postpone_js']=[] context._kwargs['postpone_js']=[]
DisplayYear = request.session.get('year', 2018) DisplayYear = request.session.get('year', 2020)
%> %>
<head> <head>
<title>JM2L ${DisplayYear}</title> <title>JM2L ${DisplayYear}</title>
@@ -68,12 +68,12 @@ ${helpers.uploader_js()}
% if request.user and request.user.vote_logo not in [1,2,3]: % if request.user and request.user.vote_logo not in [1,2,3]:
<div class="item active"> <div class="item active">
<div class="align-center"> <div class="align-center">
<H1>JM2L 2017</H1> <H1>JM2L 2020</H1>
<h3>Choisissez ici votre logo pr&eacute;f&eacute;r&eacute; !</h3> <h3>Choisissez ici votre logo préféré !</h3>
<p>Utilisez les flèches pour choisir et voter !<br> <p>Utilisez les flèches pour choisir et voter !<br>
Vous pouvez changer à tout moment, mais vous n'aurez droit qu'a un seul choix, le vôtre ;)</p> Vous pouvez changer à tout moment, mais vous n'aurez droit qu'a un seul choix, le vôtre ;)</p>
<p>Vous souhaitez proposer le vôtre ? <br> <p>Vous souhaitez proposer le vôtre ? <br>
N'h&eacute;sitez pas à envoyer vos propositions par mail à l'&eacute;quipe !</p> N'hésitez pas à envoyer vos propositions par mail à l'équipe !</p>
</div> </div>
</div> </div>
% endif % endif
@@ -105,10 +105,10 @@ ${helpers.uploader_js()}
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
Édition&nbsp;<span class="caret"></span></a> Édition&nbsp;<span class="caret"></span></a>
<ul class="dropdown-menu pull-right" style="min-width:0"> <ul class="dropdown-menu pull-right" style="min-width:0">
% for tmpyear in range(2018, 2005, -1): % for tmpyear in range(2020, 2005, -1):
% if tmpyear==DisplayYear: % if tmpyear==DisplayYear:
<li><a style="font-weight: bold;" href="/year/${tmpyear}">${tmpyear}</a></li> <li><a style="font-weight: bold;" href="/year/${tmpyear}">${tmpyear}</a></li>
% elif tmpyear!=2014 and tmpyear!=2016: % elif tmpyear not in [2014, 2016, 2018, 2019]:
<li><a href="/year/${tmpyear}">${tmpyear}</a></li> <li><a href="/year/${tmpyear}">${tmpyear}</a></li>
% endif % endif
% endfor % endfor
@@ -128,17 +128,17 @@ ${helpers.uploader_js()}
% if request.user: % if request.user:
% if request.user.Staff: % if request.user.Staff:
<li><a href="/${DisplayYear}/Staff">Partie Staff</a></li> <li><a href="/${DisplayYear}/Staff">Partie Staff</a></li>
<li><a href="/${DisplayYear}/ListParticipant">G&eacute;rer les intervenants</a></li> <li><a href="/${DisplayYear}/ListParticipant">Gérer les intervenants</a></li>
<li><a href="/ListSalles">G&eacute;rer les salles</a></li> <li><a href="/ListSalles">Gérer les salles</a></li>
<li><a href="/entities">G&eacute;rer les entit&eacute;s</a></li> <li><a href="/entities">Gérer les entités</a></li>
<li><a href="/${DisplayYear}/ListOrga">Participations &agrave; l'orga</a></li> <li><a href="/${DisplayYear}/ListOrga">Participations &agrave; l'orga</a></li>
<li><a href="/${DisplayYear}/Staff/compta">Comptabilit&eacute;</a></li> <li><a href="/${DisplayYear}/Staff/compta">Comptabilité</a></li>
<li><a href="/ListSallesPhy">Les salles &agrave; Poly'tech</a></li> <li><a href="/ListSallesPhy">Les salles &agrave; Poly'tech</a></li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
% endif % endif
<li><a href="/MesJM2L">Mon profil</a></li> <li><a href="/MesJM2L">Mon profil</a></li>
<li><a href="/user/${request.user.slug}">Mon profil public</a></li> <li><a href="/user/${request.user.slug}">Mon profil public</a></li>
<li><a href="/sign/out">Me d&eacute;connecter</a></li> <li><a href="/sign/out">Me déconnecter</a></li>
% else: % else:
<li><a href="/participer-l-evenement#inscription">Je m'inscris</a></li> <li><a href="/participer-l-evenement#inscription">Je m'inscris</a></li>
<li><a href="/sign/login">Je m'identifie</a></li> <li><a href="/sign/login">Je m'identifie</a></li>
@@ -186,20 +186,20 @@ ${helpers.uploader_js()}
<footer class="footer"> <footer class="footer">
<div class="container"> <div class="container">
<h4>JM2L 2005-2018</h4> <h4>JM2L 2005-2020</h4>
<p> <p>
Concoct&eacute; par <a href="http://www.linux-azur.org/">Linux Azur</a> ~ Concocté par <a href="https://www.linux-azur.org/">Linux Azur</a> ~
<a href="http://creativecommons.org/licenses/by-sa/4.0/">CopyFriendly</a> <a href="http://creativecommons.org/licenses/by-sa/4.0/">CopyFriendly</a>
</p> </p>
<p> <p>
+33 6 52 42 31 37 ~ contact at jm2l.linux-azur dot org +33 6 52 42 31 37 ~ contact at jm2l.linux-azur dot org
</p> </p>
<p> <p>
Conception et construction en <a href="http://git.linux-azur.org/JM2L/jm2l/src/master">DIY</a> ~ Conception et construction en <a href="https://git.linux-azur.org/tr4ck3ur/jm2l/src/branch/feature/python-3-migration">DIY</a> ~
H&eacute;berg&eacute; par <a href="http://www.heberg-24.com/"> Heberg24 </a> Hébergé par <a href="http://www.heberg-24.com/"> Heberg24 </a>
</p> </p>
<p> <p>
Vous avez trouv&eacute; un bug ? <a href="http://git.linux-azur.org/JM2L/jm2l/issues">Reportez-le ici</a> Vous avez trouvé un bug ? <a href="https://git.linux-azur.org/tr4ck3ur/jm2l/issues/new">Reportez-le ici</a>
</p> </p>
</div> </div>
</footer> </footer>
@@ -222,22 +222,6 @@ ${jsitem | n}
HandleControls(); HandleControls();
</script> </script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//stats.style-python.fr/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', 4]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//stats.style-python.fr/piwik.php?idsite=4" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
% if request.user: % if request.user:
<script> <script>
function handlevote() { function handlevote() {
@@ -245,7 +229,7 @@ function handlevote() {
$('.carousel-vote a').attr('href', "/vote_logo/" + currentIndex ) $('.carousel-vote a').attr('href', "/vote_logo/" + currentIndex )
if (currentIndex==${request.user.vote_logo or 0}) { if (currentIndex==${request.user.vote_logo or 0}) {
$('.carousel-vote a').removeClass('btn-primary').addClass('btn-success') $('.carousel-vote a').removeClass('btn-primary').addClass('btn-success')
$('.carousel-vote a').html("<i class='icon-ok icon-white'></i> Mon pr&eacute;f&eacute;r&eacute; ! "); $('.carousel-vote a').html("<i class='icon-ok icon-white'></i> Mon préféré ! ");
} else { } else {
$('.carousel-vote a').removeClass('btn-success').addClass('btn-primary'); $('.carousel-vote a').removeClass('btn-success').addClass('btn-primary');
$('.carousel-vote a').html("<i class='icon-star icon-white'></i> Je vote pour ce logo ! "); $('.carousel-vote a').html("<i class='icon-star icon-white'></i> Je vote pour ce logo ! ");
+3 -3
View File
@@ -96,7 +96,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
% for t in sorted(User.task_assoc, key=lambda k:k.due_date): % for t in sorted(User.task_assoc, key=lambda k:k.due_date):
% if not t.closed: % if not t.closed:
<tr> <tr>
<td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td> <td>${t.due_date.strftime('%d %B %Y')}</td><td>${t.area.name}</td>
<td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a> <td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a>
% endif % endif
% endfor % endfor
@@ -107,7 +107,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
% for t in sorted(Contact.task_assoc, key=lambda k:k.due_date): % for t in sorted(Contact.task_assoc, key=lambda k:k.due_date):
% if not t.closed: % if not t.closed:
<tr> <tr>
<td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td> <td>${t.due_date.strftime('%d %B %Y')}</td><td>${t.area.name}</td>
<td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a> <td><a href="http://jm2l.linux-azur.org/2017/Staff/tasks/${t.uid}">${t.name}</a>
% endif % endif
% endfor % endfor
@@ -116,7 +116,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
Pour accéder à ton espace sur le site, il te suffit de cliquer sur le <a href="${request.route_url('bymail', hash=User.my_hash)}">lien suivant.</a> Pour accéder à ton espace sur le site, il te suffit de cliquer sur le <a href="${request.route_url('bymail', hash=User.my_hash)}">lien suivant.</a>
<br/><br/> <br/><br/>
% for t in filter(lambda k:k.uid==51, Contact.task_assoc): % for t in filter(lambda k:k.uid==51, Contact.task_assoc):
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30. Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B')} à 19h30.
% endfor % endfor
<p> <p>
Bon courage ! Bon courage !
+3 -3
View File
@@ -65,7 +65,7 @@ Voici ce qu'il y'a dans la liste des tâches qui te sont assignées:
% for t in sorted(User.task_assoc, key=lambda k:k.due_date): % for t in sorted(User.task_assoc, key=lambda k:k.due_date):
% if not t.closed: % if not t.closed:
- Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid} - Pour le ${t.due_date.strftime('%d %B %Y')} - ${t.area.name} tâche ${t.uid}
=> ${t.name} => ${t.name}
% endif % endif
@@ -75,7 +75,7 @@ Et il y'a aussi des tâches communes !
% for t in sorted(Contact.task_assoc, key=lambda k:k.due_date): % for t in sorted(Contact.task_assoc, key=lambda k:k.due_date):
% if not t.closed and t.uid!=51: % if not t.closed and t.uid!=51:
- Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid} - Pour le ${t.due_date.strftime('%d %B %Y')} - ${t.area.name} tâche ${t.uid}
=> ${t.name} => ${t.name}
% endif % endif
@@ -85,7 +85,7 @@ Pour accéder à ton espace il te suffit de cliquer sur le lien suivant :
${request.route_url('bymail', hash=User.my_hash)}. ${request.route_url('bymail', hash=User.my_hash)}.
% for t in filter(lambda k:k.uid==51, Contact.task_assoc): % for t in filter(lambda k:k.uid==51, Contact.task_assoc):
Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30. Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B')} à 19h30.
% endfor % endfor
+1 -1
View File
@@ -52,7 +52,7 @@
</div> </div>
<br/> <br/>
<hr/> <hr/>
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y').decode('utf-8')}</p> <p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y')}</p>
</div> </div>
</div> </div>
+2 -2
View File
@@ -13,7 +13,7 @@
</div> </div>
<strong>${event.event_type}</strong>: <strong>${event.event_type}</strong>:
<div class="borderboxtime"> <div class="borderboxtime">
${event.start_time.strftime('%d %b %Y').decode('utf-8')} - ${event.start_time.strftime('%d %b %Y')} -
${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')} ${event.start_time.strftime('%H:%M')} à ${event.end_time.strftime('%H:%M')}
</div> </div>
% if event.for_year==CurrentYear and request.user and (request.user.Staff or request.user in event.intervenants): % if event.for_year==CurrentYear and request.user and (request.user.Staff or request.user in event.intervenants):
@@ -116,7 +116,7 @@
</p> </p>
% endfor % endfor
<div class="clearfix">&nbsp;</div> <div class="clearfix">&nbsp;</div>
<p style="float:right;">Créé le ${event.created.strftime('%d %b %Y').decode('utf-8')}</p> <p style="float:right;">Créé le ${event.created.strftime('%d %b %Y')}</p>
<br/> <br/>
<hr/> <hr/>
</div> </div>
+1 -1
View File
@@ -103,7 +103,7 @@ ${The_entity_type.entity_subtype}
</p> </p>
% endfor % endfor
<br/><br/> <br/><br/>
<p style="float:right;">Créé le ${entity.created.strftime('%d %b %Y').decode('utf-8')}</p> <p style="float:right;">Créé le ${entity.created.strftime('%d %b %Y')}</p>
<br/> <br/>
<hr/> <hr/>
+1 -1
View File
@@ -47,7 +47,7 @@
<h4>Ses interventions :</h4> <h4>Ses interventions :</h4>
${helpers.show_Interventions(DispUser.events)} ${helpers.show_Interventions(DispUser.events)}
% endif % endif
<p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y').decode('utf-8')}</p> <p style="float:right;">Créé le ${DispUser.created.strftime('%d %b %Y')}</p>
</div> </div>
</div> </div>
+76 -76
View File
@@ -1,6 +1,6 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
import io
from pyramid.response import Response from pyramid.response import Response
import cStringIO as StringIO
from pyramid.view import view_config from pyramid.view import view_config
from .models import DBSession, Event, Salles from .models import DBSession, Event, Salles
from reportlab.pdfgen import canvas from reportlab.pdfgen import canvas
@@ -11,55 +11,56 @@ from .upload import MediaPath
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
# Create PDF container # Create PDF container
EXPIRATION_TIME = 300 # seconds EXPIRATION_TIME = 300 # seconds
WIDTH = 210 * mm WIDTH = 210 * mm
HEIGHT = 297 * mm HEIGHT = 297 * mm
ICONSIZE = 10 * mm ICONSIZE = 10 * mm
def JM2L_large_Logo(canvas, Offset=(0,0)): def JM2L_large_Logo(canvas, Offset=(0, 0)):
OffX, OffY = Offset OffX, OffY = Offset
canvas.setFont('Logo', 110) canvas.setFont('Logo', 110)
canvas.setFillColorRGB(.83,0,.33) canvas.setFillColorRGB(.83, 0, .33)
canvas.drawCentredString(WIDTH/2-OffY, HEIGHT-100-OffX, "JM2L") canvas.drawCentredString(WIDTH / 2 - OffY, HEIGHT - 100 - OffX, "JM2L")
canvas.setFont("Helvetica-Bold", 30) canvas.setFont("Helvetica-Bold", 30)
yearobject = canvas.beginText() year_object = canvas.beginText()
yearobject.setFillColorRGB(1,1,1) year_object.setFillColorRGB(1, 1, 1)
yearobject.setTextRenderMode(0) year_object.setTextRenderMode(0)
yearobject.setTextOrigin(WIDTH/2-OffY-120, HEIGHT-36-OffX) year_object.setTextOrigin(WIDTH / 2 - OffY - 120, HEIGHT - 36 - OffX)
yearobject.setWordSpace(48) year_object.setWordSpace(48)
yearobject.textLines("2 0 1 5") year_object.textLines("2 0 1 5")
yearobject.setWordSpace(1) year_object.setWordSpace(1)
canvas.drawText(yearobject) canvas.drawText(year_object)
def one_time_step(canvas, str, hour, max_size, offset): def one_time_step(canvas, str, hour, max_size, offset):
max_x, max_y = max_size max_x, max_y = max_size
off_x, off_y = offset off_x, off_y = offset
step_y = max_y/9 step_y = max_y / 9
half_step = step_y/2 half_step = step_y / 2
canvas.drawCentredString(off_x-30, max_y-step_y*hour+off_y-3, str) canvas.drawCentredString(off_x - 30, max_y - step_y * hour + off_y - 3, str)
hour_place = step_y*hour+off_y hour_place = step_y * hour + off_y
canvas.line(off_x-5, hour_place, off_x, hour_place) canvas.line(off_x - 5, hour_place, off_x, hour_place)
if hour<9: if hour < 9:
canvas.line(off_x-2, hour_place+half_step, off_x, hour_place+half_step) canvas.line(off_x - 2, hour_place + half_step, off_x, hour_place + half_step)
@view_config(route_name='stand_print', http_cache = (EXPIRATION_TIME, {'public':True})) @view_config(route_name='stand_print', http_cache=(EXPIRATION_TIME, {'public': True}))
def stand_print(request): def stand_print(request):
# Ok let's generate a print for place schedule # Ok let's generate a print for place schedule
# Register LiberationMono font # Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
# Import font #  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = StringIO.StringIO() pdf = io.BytesIO()
c = canvas.Canvas( pdf, pagesize=(HEIGHT, WIDTH) ) c = canvas.Canvas(pdf, pagesize=(HEIGHT, WIDTH))
c.translate(mm, mm) c.translate(mm, mm)
# Feed some metadata # Feed some metadata
@@ -70,43 +71,42 @@ def stand_print(request):
year = int(request.matchdict.get('year', CurrentYear)) year = int(request.matchdict.get('year', CurrentYear))
Events = DBSession.query(Event)\ Events = DBSession.query(Event) \
.filter(Event.for_year == year)\ .filter(Event.for_year == year) \
.filter(Event.event_type == "Stand") .filter(Event.event_type == "Stand")
for ev in Events: for ev in Events:
c.setFont('Logo', 50) c.setFont('Logo', 50)
c.setFillColorRGB(.5,.5,.5) c.setFillColorRGB(.5, .5, .5)
c.drawString(HEIGHT-150, 30, "JM2L") c.drawString(HEIGHT - 150, 30, "JM2L")
c.setFont('Logo', 100) c.setFont('Logo', 100)
c.setFillColorRGB(0.5,0.5,0.5) c.setFillColorRGB(0.5, 0.5, 0.5)
c.drawCentredString(HEIGHT/2, WIDTH-90, "STAND", 0) c.drawCentredString(HEIGHT / 2, WIDTH - 90, "STAND", 0)
c.setFillColorRGB(0,0,0) c.setFillColorRGB(0, 0, 0)
c.setFont('Helvetica', 42) c.setFont('Helvetica', 42)
c.drawCentredString(HEIGHT/2, WIDTH/2, ev.name, 0) c.drawCentredString(HEIGHT / 2, WIDTH / 2, ev.name, 0)
c.showPage() c.showPage()
c.save() c.save()
pdf.seek(0) pdf.seek(0)
return Response(app_iter=pdf, content_type = 'application/pdf' ) return Response(app_iter=pdf, content_type='application/pdf')
@view_config(route_name='place_print', http_cache=(EXPIRATION_TIME, {'public': True}))
@view_config(route_name='place_print', http_cache = (EXPIRATION_TIME, {'public':True}))
def place_print(request): def place_print(request):
# Ok let's generate a print for place schedule # Ok let's generate a print for place schedule
# Register LiberationMono font # Register LiberationMono font
ttfFile = "jm2l/static/fonts/LiberationMono-Regular.ttf" ttf_file = "jm2l/static/fonts/LiberationMono-Regular.ttf"
pdfmetrics.registerFont(TTFont("Liberation", ttfFile)) pdfmetrics.registerFont(TTFont("Liberation", ttf_file))
# Import font #  Import font
ttfFile_Logo = "jm2l/static/fonts/PWTinselLetters.ttf" ttf_file_logo = "jm2l/static/fonts/PWTinselLetters.ttf"
pdfmetrics.registerFont(TTFont("Logo", ttfFile_Logo)) pdfmetrics.registerFont(TTFont("Logo", ttf_file_logo))
pdf = StringIO.StringIO() pdf = io.BytesIO()
c = canvas.Canvas( pdf, pagesize=(WIDTH, HEIGHT) ) c = canvas.Canvas(pdf, pagesize=(WIDTH, HEIGHT))
c.translate(mm, mm) c.translate(mm, mm)
# Feed some metadata # Feed some metadata
@@ -118,67 +118,67 @@ def place_print(request):
year = int(request.matchdict.get('year', CurrentYear)) year = int(request.matchdict.get('year', CurrentYear))
# Initialization # Initialization
# Compute days used by all events matching the specified input year # Compute days used by all events matching the specified input year
place_used = DBSession.query(Event.salle_uid)\ place_used = DBSession.query(Event.salle_uid) \
.filter(Event.for_year == year)\ .filter(Event.for_year == year) \
.filter(Event.event_type != 'Stand')\ .filter(Event.event_type != 'Stand') \
.group_by(Event.salle_uid) .group_by(Event.salle_uid)
for place in place_used: for place in place_used:
place_uid = place[0] place_uid = place[0]
place_obj = Salles.by_id(place_uid) place_obj = Salles.by_id(place_uid)
# Logo on Top # Logo on Top
JM2L_large_Logo(c) JM2L_large_Logo(c)
max_size = (WIDTH-110, HEIGHT-300) max_size = (WIDTH - 110, HEIGHT - 300)
offset = (70, 90) offset = (70, 90)
c.setFillColorRGB(.5,.5,.5) c.setFillColorRGB(.5, .5, .5)
c.setFont('Liberation', 40) c.setFont('Liberation', 40)
c.drawCentredString(WIDTH/2, HEIGHT-190, place_obj.name, 1) c.drawCentredString(WIDTH / 2, HEIGHT - 190, place_obj.name, 1)
c.setFont('Liberation', 35) c.setFont('Liberation', 35)
c.drawCentredString(WIDTH/2, HEIGHT-145, place_obj.place_type, 0 ) c.drawCentredString(WIDTH / 2, HEIGHT - 145, place_obj.place_type, 0)
c.setFont('Helvetica', 20) c.setFont('Helvetica', 20)
c.drawCentredString(WIDTH/2, 55, place_obj.phy.name, 0) c.drawCentredString(WIDTH / 2, 55, place_obj.phy.name, 0)
# Timetable container # Timetable container
c.setLineWidth(.1) c.setLineWidth(.1)
c.setLineCap(2) c.setLineCap(2)
#c.setFillColorRGB(0,0,1) # c.setFillColorRGB(0,0,1)
c.rect(offset[0], offset[1], max_size[0], max_size[1], fill=0, stroke=1) c.rect(offset[0], offset[1], max_size[0], max_size[1], fill=0, stroke=1)
c.setLineWidth(.5) c.setLineWidth(.5)
# create time mark # create time mark
c.setFillColorRGB(0,0,0) c.setFillColorRGB(0, 0, 0)
c.setFont('Helvetica', 10) c.setFont('Helvetica', 10)
for i in range(0,10): for i in range(0, 10):
one_time_step(c, "%.2dh00" % (i+10), i, max_size, offset) one_time_step(c, "%.2dh00" % (i + 10), i, max_size, offset)
#c.setFont('Helvetica', 12) # c.setFont('Helvetica', 12)
Events = DBSession.query(Event)\ Events = DBSession.query(Event) \
.filter(Event.for_year == year)\ .filter(Event.for_year == year) \
.filter(Event.salle_uid == place_uid)\ .filter(Event.salle_uid == place_uid) \
.order_by(Event.start_time) .order_by(Event.start_time)
for ev in Events: for ev in Events:
place_time(c, ev, max_size, offset) place_time(c, ev, max_size, offset)
#c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1) # c.rect(70, 50, WIDTH-100, HEIGHT-250, fill=0, stroke=1)
c.showPage() c.showPage()
c.save() c.save()
pdf.seek(0) pdf.seek(0)
return Response(app_iter=pdf, content_type = 'application/pdf' ) return Response(app_iter=pdf, content_type='application/pdf')
def place_time(c, ev, max_size, offset): def place_time(c, ev, max_size, offset):
max_x, max_y = max_size max_x, max_y = max_size
off_x, off_y = offset off_x, off_y = offset
minute = max_y/(9*60) minute = max_y / (9 * 60)
start_pos_y = ((int( ev.start_time.strftime('%H') )-10)*60 + int( ev.start_time.strftime('%M') )) * minute start_pos_y = ((int(ev.start_time.strftime('%H')) - 10) * 60 + int(ev.start_time.strftime('%M'))) * minute
stop_pos_y = ((int( ev.end_time.strftime('%H') )-10)*60 + int( ev.end_time.strftime('%M') )) * minute stop_pos_y = ((int(ev.end_time.strftime('%H')) - 10) * 60 + int(ev.end_time.strftime('%M'))) * minute
c.setFillColorRGB(0.98,0.98,0.98) c.setFillColorRGB(0.98, 0.98, 0.98)
c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y-stop_pos_y, fill=1, stroke=1) c.rect(offset[0], max_y + off_y - start_pos_y, max_size[0], start_pos_y - stop_pos_y, fill=1, stroke=1)
c.setFillColorRGB(0,0,0) c.setFillColorRGB(0, 0, 0)
#c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0) # c.drawString(off_x+5, max_y + off_y - 15 - start_pos_y, ev.start_time.strftime('%H:%M'), 0)
c.setFont('Helvetica', 12) c.setFont('Helvetica', 12)
c.drawCentredString(WIDTH/2, max_y + off_y - 35 - start_pos_y, ev.name, 0) c.drawCentredString(WIDTH / 2, max_y + off_y - 35 - start_pos_y, ev.name, 0)
intervs = ', '.join( [x.slug for x in ev.intervenants] ) intervs = ', '.join([x.slug for x in ev.intervenants])
c.setFont('Helvetica', 10) c.setFont('Helvetica', 10)
c.drawCentredString(WIDTH/2, max_y + off_y - 55 - start_pos_y, intervs, 0) c.drawCentredString(WIDTH / 2, max_y + off_y - 55 - start_pos_y, intervs, 0)
+158 -152
View File
@@ -9,111 +9,112 @@ from os import path
import mimetypes import mimetypes
import magic import magic
import subprocess import subprocess
import cStringIO as StringIO try:
from StringIO import StringIO
except ImportError:
from io import StringIO
# Database access imports # Database access imports
from .models import User, Place, Tiers, Event, SallePhy from .models import User, Place, Tiers, Event, SallePhy
from .blenderthumbnailer import blend_extract_thumb, write_png from .blenderthumbnailer import blend_extract_thumb, write_png
from jm2l.const import CurrentYear from jm2l.const import CurrentYear
from slugify import slugify from slugify import slugify
MIN_FILE_SIZE = 1 # bytes MIN_FILE_SIZE = 1 # bytes
MAX_FILE_SIZE = 500000000 # bytes MAX_FILE_SIZE = 500000000 # bytes
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
ACCEPTED_MIMES = ['application/pdf', ACCEPTED_MIMES = ['application/pdf',
'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-template', 'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.graphics', 'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-template', 'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-template', 'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template', 'application/vnd.oasis.opendocument.spreadsheet-template',
'image/svg+xml', 'image/svg+xml',
'application/x-blender' 'application/x-blender'
] ]
ACCEPT_FILE_TYPES = IMAGE_TYPES ACCEPT_FILE_TYPES = IMAGE_TYPES
THUMBNAIL_SIZE = 80 THUMBNAIL_SIZE = 80
EXPIRATION_TIME = 300 # seconds EXPIRATION_TIME = 300 # seconds
IMAGEPATH = [ 'images' ] IMAGEPATH = ['images']
DOCPATH = [ 'document' ] DOCPATH = ['document']
THUMBNAILPATH = [ 'images', 'thumbnails' ] THUMBNAILPATH = ['images', 'thumbnails']
# change the following to POST if DELETE isn't supported by the webserver # change the following to POST if DELETE isn't supported by the webserver
DELETEMETHOD="DELETE" DELETEMETHOD = "DELETE"
mimetypes.init() mimetypes.init()
class MediaPath(): class MediaPath():
def get_all(self, media_table, linked_id, MediaType=None): def get_all(self, media_table, linked_id, MediaType=None):
filelist = list() filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None) curpath = self.get_mediapath(media_table, linked_id, None)
thumbpath = os.path.join( curpath, 'thumbnails') thumbpath = os.path.join(curpath, 'thumbnails')
if not os.path.isdir(curpath) or not os.path.isdir(thumbpath): if not os.path.isdir(curpath) or not os.path.isdir(thumbpath):
return list() return list()
for f in os.listdir(curpath): for f in os.listdir(curpath):
filename, ext = os.path.splitext( f ) filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath,f)): if os.path.isdir(os.path.join(curpath, f)):
continue continue
if f.endswith('.type'): if f.endswith('.type'):
continue continue
if f: if f:
ress_url = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20")) ress_url = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
thumb_url = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ","%20")) thumb_url = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None: if MediaType is None:
if os.path.exists(os.path.join(thumbpath, f +".jpg")): if os.path.exists(os.path.join(thumbpath, f + ".jpg")):
filelist.append((ress_url, thumb_url +".jpg")) filelist.append((ress_url, thumb_url + ".jpg"))
else: else:
filelist.append((ress_url, thumb_url)) filelist.append((ress_url, thumb_url))
elif MediaType=='Image' and len( os.path.splitext(filename)[1] )==0: elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
filelist.append((ress_url, thumb_url)) filelist.append((ress_url, thumb_url))
elif MediaType=='Other' and len( os.path.splitext(filename)[1] ): elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
filelist.append((ress_url, thumb_url)) filelist.append((ress_url, thumb_url))
return filelist return filelist
def get_list(self, media_table, linked_id, MediaType=None): def get_list(self, media_table, linked_id, MediaType=None):
filelist = list() filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None) curpath = self.get_mediapath(media_table, linked_id, None)
if not os.path.isdir(curpath): if not os.path.isdir(curpath):
return list() return list()
for f in os.listdir(curpath): for f in os.listdir(curpath):
if os.path.isdir(os.path.join(curpath,f)): if os.path.isdir(os.path.join(curpath, f)):
continue continue
if f.endswith('.type'): if f.endswith('.type'):
continue continue
if f: if f:
filename, ext = os.path.splitext( f ) filename, ext = os.path.splitext(f)
tmpurl = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ","%20")) tmpurl = '/image/%s/%d/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None: if MediaType is None:
filelist.append(tmpurl) filelist.append(tmpurl)
elif MediaType=='Image' and ext.lower() in ['.gif','.jpg','.png','.svg','.jpeg']: elif MediaType == 'Image' and ext.lower() in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl) filelist.append(tmpurl)
elif MediaType=='Other' and ext.lower() not in ['.gif','.jpg','.png','.svg','.jpeg']: elif MediaType == 'Other' and ext.lower() not in ['.gif', '.jpg', '.png', '.svg', '.jpeg']:
filelist.append(tmpurl) filelist.append(tmpurl)
return filelist return filelist
def get_thumb(self, media_table, linked_id, MediaType=None): def get_thumb(self, media_table, linked_id, MediaType=None):
filelist = list() filelist = list()
curpath = self.get_mediapath(media_table, linked_id, None) curpath = self.get_mediapath(media_table, linked_id, None)
curpath = os.path.join( curpath, 'thumbnails') curpath = os.path.join(curpath, 'thumbnails')
if not os.path.isdir(curpath): if not os.path.isdir(curpath):
return list() return list()
for f in os.listdir(curpath): for f in os.listdir(curpath):
filename, ext = os.path.splitext( f ) filename, ext = os.path.splitext(f)
if os.path.isdir(os.path.join(curpath,f)): if os.path.isdir(os.path.join(curpath, f)):
continue continue
if f.endswith('.type'): if f.endswith('.type'):
continue continue
if f: if f:
tmpurl = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ","%20")) tmpurl = '/image/%s/%d/thumbnails/%s' % (media_table, linked_id, f.replace(" ", "%20"))
if MediaType is None: if MediaType is None:
filelist.append(tmpurl) filelist.append(tmpurl)
elif MediaType=='Image' and len( os.path.splitext(filename)[1] )==0: elif MediaType == 'Image' and len(os.path.splitext(filename)[1]) == 0:
filelist.append(tmpurl) filelist.append(tmpurl)
elif MediaType=='Other' and len( os.path.splitext(filename)[1] ): elif MediaType == 'Other' and len(os.path.splitext(filename)[1]):
filelist.append(tmpurl) filelist.append(tmpurl)
return filelist return filelist
@@ -126,8 +127,8 @@ class MediaPath():
:return: Error if any :return: Error if any
""" """
if media_table in ['tiers', 'place', 'salle', 'users']: if media_table in ['tiers', 'place', 'salle', 'users']:
src = IMAGEPATH + [ media_table, from_id ] src = IMAGEPATH + [media_table, from_id]
dst = IMAGEPATH + [ media_table, to_id ] dst = IMAGEPATH + [media_table, to_id]
else: else:
raise RuntimeError("Sorry, Media '%s' not supported yet for move." % media_table) raise RuntimeError("Sorry, Media '%s' not supported yet for move." % media_table)
@@ -153,51 +154,51 @@ class MediaPath():
linked_id = str(linked_id) linked_id = str(linked_id)
if media_table in ['tiers', 'place', 'salle']: if media_table in ['tiers', 'place', 'salle']:
# Retrieve Slug # Retrieve Slug
if media_table=='tiers': if media_table == 'tiers':
slug = Tiers.by_id(linked_id).slug slug = Tiers.by_id(linked_id).slug
if media_table=='place': if media_table == 'place':
slug = Place.by_id(linked_id).slug or slugify(Place.by_id(linked_id).name) slug = Place.by_id(linked_id).slug or slugify(Place.by_id(linked_id).name)
if media_table=='salle': if media_table == 'salle':
slug = SallePhy.by_id(linked_id).slug slug = SallePhy.by_id(linked_id).slug
p = IMAGEPATH + [ media_table, slug ] p = IMAGEPATH + [media_table, slug]
elif media_table=='presse': elif media_table == 'presse':
# Use Year in linked_id # Use Year in linked_id
p = IMAGEPATH + [ media_table, linked_id ] p = IMAGEPATH + [media_table, linked_id]
elif media_table=='tasks': elif media_table == 'tasks':
# Use Current Year # Use Current Year
p = IMAGEPATH + [ str(CurrentYear), media_table, linked_id ] p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
elif media_table=='poles': elif media_table == 'poles':
# Use Current Year # Use Current Year
p = IMAGEPATH + [ str(CurrentYear), media_table, linked_id ] p = IMAGEPATH + [str(CurrentYear), media_table, linked_id]
elif media_table in ['RIB', 'Justif']: elif media_table in ['RIB', 'Justif']:
slug = User.by_id(linked_id).slug slug = User.by_id(linked_id).slug
p = IMAGEPATH + ['users', slug , media_table ] p = IMAGEPATH + ['users', slug, media_table]
elif media_table in ['users', 'badge']: elif media_table in ['users', 'badge']:
user = User.by_id(linked_id) user = User.by_id(linked_id)
if not user: if not user:
raise HTTPNotFound() raise HTTPNotFound()
else: else:
slug = user.slug slug = user.slug
p = IMAGEPATH + [media_table, slug ] p = IMAGEPATH + [media_table, slug]
elif media_table=='event': elif media_table == 'event':
ev = Event.by_id(linked_id) ev = Event.by_id(linked_id)
slug = ev.slug slug = ev.slug
year = ev.for_year year = ev.for_year
p = IMAGEPATH + ['event', str(year), slug ] p = IMAGEPATH + ['event', str(year), slug]
if name: if name:
p += [ name ] p += [name]
TargetPath = os.path.join('jm2l/upload', *p) TargetPath = os.path.join('jm2l/upload', *p)
if not os.path.isdir(os.path.dirname(TargetPath)): if not os.path.isdir(os.path.dirname(TargetPath)):
try: try:
os.makedirs(os.path.dirname(TargetPath)) os.makedirs(os.path.dirname(TargetPath))
except OSError, e: except OSError as e:
if e.errno != 17: if e.errno != 17:
raise e raise e
return os.path.join('jm2l/upload', *p) return os.path.join('jm2l/upload', *p)
def ExtMimeIcon(self, mime): def ExtMimeIcon(self, mime):
if mime=='application/pdf': if mime == 'application/pdf':
return "/img/PDF.png" return "/img/PDF.png"
def check_blend_file(self, fileobj): def check_blend_file(self, fileobj):
@@ -217,12 +218,12 @@ class MediaPath():
fileobj.seek(0) fileobj.seek(0)
# Check if the binary file is a blender file # Check if the binary file is a blender file
if ( mimetype == "application/octet-stream" or mimetype == "application/x-gzip" ) and self.check_blend_file(fileobj): if (mimetype == "application/octet-stream" or mimetype == "application/x-gzip") and self.check_blend_file(
fileobj):
return "application/x-blender", True return "application/x-blender", True
else: else:
return mimetype, False return mimetype, False
def get_mimetype(self, name): def get_mimetype(self, name):
""" This function return the mime-type based on .type file """ """ This function return the mime-type based on .type file """
try: try:
@@ -232,6 +233,7 @@ class MediaPath():
except IOError: except IOError:
return None return None
@view_defaults(route_name='media_upload') @view_defaults(route_name='media_upload')
class MediaUpload(MediaPath): class MediaUpload(MediaPath):
@@ -265,8 +267,8 @@ class MediaUpload(MediaPath):
# MonKey Patch of content type # MonKey Patch of content type
result['type'] = found_mime result['type'] = found_mime
# Reject mime type that don't match # Reject mime type that don't match
if found_mime!=result['type']: if found_mime != result['type']:
result['error'] = 'L\'extension du fichier ne correspond pas à son contenu - ' result['error'] = 'L\'extension du fichier ne correspond pas à son contenu - '
result['error'] += "( %s vs %s )" % (found_mime, result['type']) result['error'] += "( %s vs %s )" % (found_mime, result['type'])
return False return False
@@ -281,7 +283,7 @@ class MediaUpload(MediaPath):
result['error'] = 'le fichier est trop petit' result['error'] = 'le fichier est trop petit'
elif result['size'] > MAX_FILE_SIZE: elif result['size'] > MAX_FILE_SIZE:
result['error'] = 'le fichier est trop voluminueux' result['error'] = 'le fichier est trop voluminueux'
#elif not ACCEPT_FILE_TYPES.match(file['type']): # elif not ACCEPT_FILE_TYPES.match(file['type']):
# file['error'] = u'les type de fichiers acceptés sont png, jpg et gif' # file['error'] = u'les type de fichiers acceptés sont png, jpg et gif'
else: else:
return True return True
@@ -289,80 +291,82 @@ class MediaUpload(MediaPath):
return False return False
def get_file_size(self, fileobj): def get_file_size(self, fileobj):
fileobj.seek(0, 2) # Seek to the end of the file fileobj.seek(0, 2) # Seek to the end of the file
size = fileobj.tell() # Get the position of EOF size = fileobj.tell() # Get the position of EOF
fileobj.seek(0) # Reset the file position to the beginning fileobj.seek(0) # Reset the file position to the beginning
return size return size
def thumbnailurl(self,name): def thumbnailurl(self, name):
return self.request.route_url('media_view',name='thumbnails', return self.request.route_url('media_view', name='thumbnails',
media_table=self.media_table, media_table=self.media_table,
uid=self.linked_id) + '/' + name uid=self.linked_id) + '/' + name
def thumbnailpath(self,name): def thumbnailpath(self, name):
origin = self.mediapath(name) origin = self.mediapath(name)
TargetPath = os.path.join( os.path.dirname(origin), 'thumbnails', name) TargetPath = os.path.join(os.path.dirname(origin), 'thumbnails', name)
if not os.path.isdir(os.path.dirname(TargetPath)): if not os.path.isdir(os.path.dirname(TargetPath)):
os.makedirs(os.path.dirname(TargetPath)) os.makedirs(os.path.dirname(TargetPath))
return TargetPath return TargetPath
def createthumbnail(self, filename): def createthumbnail(self, filename):
image = Image.open( self.mediapath(filename) ) image = Image.open(self.mediapath(filename))
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS) image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0)) timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
timage.paste( timage.paste(
image, image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2)) (int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
TargetFileName = self.thumbnailpath(filename) TargetFileName = self.thumbnailpath(filename)
timage.save( TargetFileName ) if not TargetFileName.endswith('png'):
return self.thumbnailurl( os.path.basename(TargetFileName) ) timage = timage.convert('RGB')
timage.save(TargetFileName)
return self.thumbnailurl(os.path.basename(TargetFileName))
def pdfthumbnail(self, filename): def pdfthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename) TargetFileName = self.thumbnailpath(filename)
Command = ["convert","./%s[0]" % self.mediapath(filename),"./%s_.jpg" % TargetFileName] Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
Result = subprocess.call(Command) Result = subprocess.call(Command)
if Result==0: if Result == 0:
image = Image.open( TargetFileName+"_.jpg" ) image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open( "jm2l/static/img/PDF_Thumb_Stamp.png" ) pdf_indicator = Image.open("jm2l/static/img/PDF_Thumb_Stamp.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS) image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0)) timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail # Add thumbnail
timage.paste( timage.paste(
image, image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2)) (int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
# Stamp with PDF file type # Stamp with PDF file type
timage.paste( timage.paste(
pdf_indicator, pdf_indicator,
(timage.size[0]-30, timage.size[1]-30), (timage.size[0] - 30, timage.size[1] - 30),
pdf_indicator, pdf_indicator,
) )
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG') timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName+"_.jpg") os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") ) return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
return self.ExtMimeIcon('application/pdf') return self.ExtMimeIcon('application/pdf')
def svgthumbnail(self, filename): def svgthumbnail(self, filename):
TargetFileName = self.thumbnailpath(filename) TargetFileName = self.thumbnailpath(filename)
Command = ["convert","./%s[0]" % self.mediapath(filename),"./%s_.jpg" % TargetFileName] Command = ["convert", "./%s[0]" % self.mediapath(filename), "./%s_.jpg" % TargetFileName]
Result = subprocess.call(Command) Result = subprocess.call(Command)
if Result==0: if Result == 0:
image = Image.open( TargetFileName+"_.jpg" ) image = Image.open(TargetFileName + "_.jpg")
pdf_indicator = Image.open( "jm2l/static/img/svg-icon.png" ) pdf_indicator = Image.open("jm2l/static/img/svg-icon.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS) image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0)) timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail # Add thumbnail
timage.paste( timage.paste(
image, image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2)) (int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
# Stamp with PDF file type # Stamp with PDF file type
timage.paste( timage.paste(
pdf_indicator, pdf_indicator,
(timage.size[0]-30, timage.size[1]-30), (timage.size[0] - 30, timage.size[1] - 30),
pdf_indicator, pdf_indicator,
) )
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG') timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
os.unlink(TargetFileName+"_.jpg") os.unlink(TargetFileName + "_.jpg")
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") ) return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
return self.ExtMimeIcon('image/svg+xml') return self.ExtMimeIcon('image/svg+xml')
def docthumbnail(self, filename): def docthumbnail(self, filename):
@@ -370,29 +374,30 @@ class MediaUpload(MediaPath):
# let's take the thumbnail generated inside the document # let's take the thumbnail generated inside the document
Command = ["unzip", "-p", self.mediapath(filename), "Thumbnails/thumbnail.png"] Command = ["unzip", "-p", self.mediapath(filename), "Thumbnails/thumbnail.png"]
ThumbBytes = subprocess.check_output(Command) ThumbBytes = subprocess.check_output(Command)
image = Image.open( StringIO.StringIO(ThumbBytes) ) image = Image.open(StringIO.StringIO(ThumbBytes))
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS) image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
# Use the correct stamp # Use the correct stamp
f, ext = os.path.splitext( filename ) f, ext = os.path.splitext(filename)
istamp = [ ('Writer','odt'), istamp = [('Writer', 'odt'),
('Impress','odp'), ('Impress', 'odp'),
('Calc','ods'), ('Calc', 'ods'),
('Draw','odg')] ('Draw', 'odg')]
stampfilename = filter(lambda (x,y): ext.endswith(y), istamp) stampfilename = filter(lambda x, y: ext.endswith(y), istamp)
stamp = Image.open( "jm2l/static/img/%s-icon.png" % stampfilename[0][0]) stamp = Image.open("jm2l/static/img/%s-icon.png" % stampfilename[0][0])
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0)) timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail # Add thumbnail
timage.paste( timage.paste(
image, image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2)) (int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
# Stamp with PDF file type # Stamp with PDF file type
timage.paste( timage.paste(
stamp, stamp,
(timage.size[0]-30, timage.size[1]-30), (timage.size[0] - 30, timage.size[1] - 30),
stamp, stamp,
) )
timage.convert('RGB').save( TargetFileName+".jpg", 'JPEG') timage.convert('RGB').save(TargetFileName + ".jpg", 'JPEG')
return self.thumbnailurl( os.path.basename(TargetFileName+".jpg") ) return self.thumbnailurl(os.path.basename(TargetFileName + ".jpg"))
def blendthumbnail(self, filename): def blendthumbnail(self, filename):
blendfile = self.mediapath(filename) blendfile = self.mediapath(filename)
@@ -411,34 +416,34 @@ class MediaUpload(MediaPath):
png = write_png(buf, width, height) png = write_png(buf, width, height)
TargetFileName = self.thumbnailpath(filename) TargetFileName = self.thumbnailpath(filename)
image = Image.open(StringIO.StringIO(png)) image = Image.open(StringIO.StringIO(png))
blender_indicator = Image.open( "jm2l/static/img/Blender_Thumb_Stamp.png" ) blender_indicator = Image.open("jm2l/static/img/Blender_Thumb_Stamp.png")
image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS) image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.ANTIALIAS)
timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0)) timage = Image.new('RGBA', (THUMBNAIL_SIZE, THUMBNAIL_SIZE), (255, 255, 255, 0))
# Add thumbnail # Add thumbnail
timage.paste( timage.paste(
image, image,
((THUMBNAIL_SIZE - image.size[0]) / 2, (THUMBNAIL_SIZE - image.size[1]) / 2)) (int((THUMBNAIL_SIZE - image.size[0]) / 2), int((THUMBNAIL_SIZE - image.size[1]) / 2)))
# Stamp with Blender file type # Stamp with Blender file type
timage.paste( timage.paste(
blender_indicator, blender_indicator,
(timage.size[0]-30, timage.size[1]-30), (timage.size[0] - 30, timage.size[1] - 30),
blender_indicator, blender_indicator,
) )
timage.save( TargetFileName+".png") timage.save(TargetFileName + ".png")
return self.thumbnailurl( os.path.basename(TargetFileName+".png") ) return self.thumbnailurl(os.path.basename(TargetFileName + ".png"))
return self.ExtMimeIcon('application/x-blender') return self.ExtMimeIcon('application/x-blender')
def fileinfo(self,name): def fileinfo(self, name):
filename = self.mediapath(name) filename = self.mediapath(name)
f, ext = os.path.splitext(name) f, ext = os.path.splitext(name)
if ext!='.type' and os.path.isfile(filename): if ext != '.type' and os.path.isfile(filename):
info = {} info = {}
info['name'] = name info['name'] = name
info['size'] = os.path.getsize(filename) info['size'] = os.path.getsize(filename)
info['url'] = self.request.route_url('media_view', info['url'] = self.request.route_url('media_view',
name=name, name=name,
media_table=self.media_table, media_table=self.media_table,
uid=self.linked_id) uid=self.linked_id)
mime = self.get_mimetype(name) mime = self.get_mimetype(name)
if IMAGE_TYPES.match(mime): if IMAGE_TYPES.match(mime):
@@ -448,8 +453,8 @@ class MediaUpload(MediaPath):
thumbext = ".jpg" thumbext = ".jpg"
if mime == "application/x-blender": if mime == "application/x-blender":
thumbext = ".png" thumbext = ".png"
if os.path.exists( thumb + thumbext ): if os.path.exists(thumb + thumbext):
info['thumbnailUrl'] = self.thumbnailurl(name)+thumbext info['thumbnailUrl'] = self.thumbnailurl(name) + thumbext
else: else:
info['thumbnailUrl'] = self.ExtMimeIcon(mime) info['thumbnailUrl'] = self.ExtMimeIcon(mime)
else: else:
@@ -457,10 +462,10 @@ class MediaUpload(MediaPath):
if not self.display_only: if not self.display_only:
info['deleteType'] = DELETEMETHOD info['deleteType'] = DELETEMETHOD
info['deleteUrl'] = self.request.route_url('media_upload', info['deleteUrl'] = self.request.route_url('media_upload',
sep='', sep='',
name='', name='',
media_table=self.media_table, media_table=self.media_table,
uid=self.linked_id) + '/' + name uid=self.linked_id) + '/' + name
if DELETEMETHOD != 'DELETE': if DELETEMETHOD != 'DELETE':
info['deleteUrl'] += '&_method=DELETE' info['deleteUrl'] += '&_method=DELETE'
return info return info
@@ -488,7 +493,7 @@ class MediaUpload(MediaPath):
n = self.fileinfo(f) n = self.fileinfo(f)
if n: if n:
filelist.append(n) filelist.append(n)
return { "files":filelist } return {"files": filelist}
@view_config(request_method='DELETE', xhr=True, accept="application/json", renderer='json') @view_config(request_method='DELETE', xhr=True, accept="application/json", renderer='json')
def delete(self): def delete(self):
@@ -506,7 +511,7 @@ class MediaUpload(MediaPath):
except OSError: except OSError:
pass pass
try: try:
os.remove(self.thumbnailpath(filename+".jpg")) os.remove(self.thumbnailpath(filename + ".jpg"))
except IOError: except IOError:
pass pass
except OSError: except OSError:
@@ -523,71 +528,72 @@ class MediaUpload(MediaPath):
return self.delete() return self.delete()
results = [] results = []
for name, fieldStorage in self.request.POST.items(): for name, fieldStorage in self.request.POST.items():
if isinstance(fieldStorage,unicode): # if isinstance(fieldStorage, unicode):
continue # continue
result = {} result = {}
result['name'] = os.path.basename(fieldStorage.filename) result['name'] = os.path.basename(fieldStorage.filename)
result['type'] = fieldStorage.type result['type'] = fieldStorage.type
result['size'] = self.get_file_size(fieldStorage.file) result['size'] = self.get_file_size(fieldStorage.file)
if self.validate(result, fieldStorage.file): if self.validate(result, fieldStorage.file):
filename, file_extension = os.path.splitext( result['name'] ) filename, file_extension = os.path.splitext(result['name'])
local_filename = slugify( filename ) + file_extension local_filename = slugify(filename) + file_extension
# Keep mime-type in .type file # Keep mime-type in .type file
with open( self.mediapath( local_filename ) + '.type', 'w') as f: with open(self.mediapath(local_filename) + '.type', 'w') as f:
f.write(result['type']) f.write(result['type'])
# Store uploaded file # Store uploaded file
fieldStorage.file.seek(0) fieldStorage.file.seek(0)
with open( self.mediapath( local_filename ), 'wb') as f: with open(self.mediapath(local_filename), 'wb') as f:
shutil.copyfileobj( fieldStorage.file , f) shutil.copyfileobj(fieldStorage.file, f)
if re.match(IMAGE_TYPES, result['type']): if re.match(IMAGE_TYPES, result['type']):
result['thumbnailUrl'] = self.createthumbnail(local_filename) result['thumbnailUrl'] = self.createthumbnail(local_filename)
elif result['type']=='application/pdf': elif result['type'] == 'application/pdf':
result['thumbnailUrl'] = self.pdfthumbnail(local_filename) result['thumbnailUrl'] = self.pdfthumbnail(local_filename)
elif result['type']=='image/svg+xml': elif result['type'] == 'image/svg+xml':
result['thumbnailUrl'] = self.svgthumbnail(local_filename) result['thumbnailUrl'] = self.svgthumbnail(local_filename)
elif result['type'].startswith('application/vnd'): elif result['type'].startswith('application/vnd'):
result['thumbnailUrl'] = self.docthumbnail(local_filename) result['thumbnailUrl'] = self.docthumbnail(local_filename)
elif result['type']=='application/x-blender': elif result['type'] == 'application/x-blender':
result['thumbnailUrl'] = self.blendthumbnail(local_filename) result['thumbnailUrl'] = self.blendthumbnail(local_filename)
else: else:
result['thumbnailUrl'] = self.ExtMimeIcon(result['type']) result['thumbnailUrl'] = self.ExtMimeIcon(result['type'])
result['deleteType'] = DELETEMETHOD result['deleteType'] = DELETEMETHOD
result['deleteUrl'] = self.request.route_url('media_upload', result['deleteUrl'] = self.request.route_url('media_upload',
sep='', sep='',
name='', name='',
media_table=self.media_table, media_table=self.media_table,
uid=self.linked_id) + '/' + local_filename uid=self.linked_id) + '/' + local_filename
result['url'] = self.request.route_url('media_view', result['url'] = self.request.route_url('media_view',
media_table=self.media_table, media_table=self.media_table,
uid=self.linked_id, uid=self.linked_id,
name=local_filename) name=local_filename)
if DELETEMETHOD != 'DELETE': if DELETEMETHOD != 'DELETE':
result['deleteUrl'] += '&_method=DELETE' result['deleteUrl'] += '&_method=DELETE'
results.append(result) results.append(result)
return {"files":results} return {"files": results}
@view_defaults(route_name='media_view') @view_defaults(route_name='media_view')
class MediaView(MediaPath): class MediaView(MediaPath):
def __init__(self,request): def __init__(self, request):
self.request = request self.request = request
self.media_table = self.request.matchdict.get('media_table') self.media_table = self.request.matchdict.get('media_table')
self.linked_id = self.request.matchdict.get('uid') self.linked_id = self.request.matchdict.get('uid')
def mediapath(self,name): def mediapath(self, name):
return self.get_mediapath(self.media_table, self.linked_id, name) return self.get_mediapath(self.media_table, self.linked_id, name)
@view_config(request_method='GET', http_cache = (EXPIRATION_TIME, {'public':True})) @view_config(request_method='GET', http_cache=(EXPIRATION_TIME, {'public': True}))
def get(self): def get(self):
name = self.request.matchdict.get('name') name = self.request.matchdict.get('name')
self.request.response.content_type = self.get_mimetype(name) self.request.response.content_type = self.get_mimetype(name)
try: try:
self.request.response.body_file = open( self.mediapath(name), 'rb', 10000) self.request.response.body_file = open(self.mediapath(name), 'rb', 10000)
except IOError: except IOError:
raise NotFound raise NotFound
return self.request.response return self.request.response
+783 -702
View File
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -11,6 +11,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f:
## Do not forget to run for lxml dependencies ## Do not forget to run for lxml dependencies
## apt-get install libxml2-dev libxslt1-dev ## apt-get install libxml2-dev libxslt1-dev
requires = [ requires = [
'pyramid', 'pyramid',
'pyramid_chameleon', 'pyramid_chameleon',
@@ -28,15 +29,19 @@ requires = [
'python-magic', 'python-magic',
'Pillow', 'Pillow',
'pyramid_exclog', 'pyramid_exclog',
'repoze.sendmail==4.1', 'repoze.sendmail',
'pyramid_mailer', 'pyramid_mailer',
'apscheduler', 'apscheduler',
'qrcode', 'qrcode',
'reportlab', 'reportlab',
'passlib', 'passlib',
'argon2_cffi' 'argon2_cffi',
'paginate',
'markupsafe',
'webhelpers2',
'email_validator',
'pyramid-scheduler'
] ]
setup(name='JM2L', setup(name='JM2L',
version='0.1', version='0.1',
description='JM2L', description='JM2L',
+6 -9
View File
@@ -1,9 +1,6 @@
APP_CONFIG = "prod.ini" import sys
sys.path.append("/srv/.venv_jm2l/lib/python3.7/site-packages")
#Setup logging ini_path = "/srv/jm2l.linux-azur.org/jm2l/production.ini"
import logging.config from pyramid.paster import get_app, setup_logging
logging.config.fileConfig(APP_CONFIG) setup_logging(ini_path)
application = get_app(ini_path, 'main')
#Load the application
from paste.deploy import loadapp
application = loadapp('config:%s' % APP_CONFIG)