Refactored dashboard icons and menu registration

This commit is contained in:
Marc Aymerich 2015-05-07 14:09:37 +00:00
parent 524b1ce15f
commit 17974d41fa
79 changed files with 2515 additions and 317 deletions

15
TODO.md
View file

@ -376,3 +376,18 @@ TODO mount the filesystem with "nosuid" option
# orchestrate async stdout stderr (inspired on pangea managemengt commands) # orchestrate async stdout stderr (inspired on pangea managemengt commands)
# orchestra-beat support for uwsgi cron # orchestra-beat support for uwsgi cron
# message.log if 1: return changeform
# generate nginx certs on project dir rather than nginx
# Register icons
# send_message doesn't log task
make django admin taskstate uncollapse fucking traceback, ( if exists ?)
# receive tass stuck at RECEIVED
# monitor tasks in started and backend already in success?
# custom message on admin save

View file

@ -1,32 +1,25 @@
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from fluent_dashboard import dashboard from fluent_dashboard import dashboard
from fluent_dashboard.modules import CmsAppIconList from fluent_dashboard.modules import CmsAppIconList
from orchestra.core import services from orchestra.core import services, accounts, administration
class AppDefaultIconList(CmsAppIconList):
def __init__(self, *args, **kwargs):
self.icons = kwargs.pop('icons')
super(AppDefaultIconList, self).__init__(*args, **kwargs)
def get_icon_for_model(self, app_name, model_name, default=None):
icon = self.icons.get('.'.join((app_name, model_name)))
return super(AppDefaultIconList, self).get_icon_for_model(app_name, model_name, default=icon)
class OrchestraIndexDashboard(dashboard.FluentIndexDashboard): class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
_registry = {} def process_registered_view(self, module, view_name, options):
@classmethod
def register_link(cls, module, view_name, title):
registered = cls._registry.get(module, [])
registered.append((view_name, title))
cls._registry[module] = registered
def get_application_modules(self):
modules = super(OrchestraIndexDashboard, self).get_application_modules()
models = []
for model, options in services.get().items():
if options.get('menu', True):
models.append("%s.%s" % (model.__module__, model._meta.object_name))
for module in modules:
registered = self._registry.get(module.title, None)
if registered:
for view_name, title in registered:
# This values are shit, but it is how fluent dashboard will look for the icon
app_name, name = view_name.split('_')[:-1] app_name, name = view_name.split('_')[:-1]
module.icons['.'.join((app_name, name))] = options.get('icon')
url = reverse('admin:' + view_name) url = reverse('admin:' + view_name)
add_url = '/'.join(url.split('/')[:-2]) add_url = '/'.join(url.split('/')[:-2])
module.children.append({ module.children.append({
@ -35,11 +28,34 @@ class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
'app_name': app_name, 'app_name': app_name,
'change_url': url, 'change_url': url,
'name': name, 'name': name,
'title': title }], 'title': options.get('verbose_name')}],
'name': app_name, 'name': app_name,
'title': title, 'title': options.get('verbose_name'),
'url': add_url, 'url': add_url,
}) })
service_icon_list = CmsAppIconList('Services', models=models, collapsible=True)
modules.append(service_icon_list) def get_application_modules(self):
from fluent_dashboard import appsettings
modules = []
# Honor settings override, hacky. I Know
if appsettings.FLUENT_DASHBOARD_APP_GROUPS[0][0] != _('CMS'):
modules = super(OrchestraIndexDashboard, self).get_application_modules()
for register in (accounts, administration, services):
title = register.verbose_name
models = []
icons = {}
views = []
for model, options in register.get().items():
if isinstance(model, str):
views.append((model, options))
elif options.get('dashboard', True):
opts = model._meta
label = "%s.%s" % (model.__module__, opts.object_name)
models.append(label)
label = '.'.join((opts.app_label, opts.model_name))
icons[label] = options.get('icon')
module = AppDefaultIconList(title, models=models, icons=icons, collapsible=True)
for view_name, options in views:
self.process_registered_view(module, view_name, options)
modules.append(module)
return modules return modules

View file

@ -27,80 +27,37 @@ def api_link(context):
return reverse('api-root') return reverse('api-root')
def process_registered_models(register): from copy import copy
childrens = [] def process_registry(register):
for model, options in register.get().items(): def get_item(model, options):
if options.get('menu', True): if isinstance(model, str):
url = reverse('admin:'+model)
else:
opts = model._meta opts = model._meta
url = reverse('admin:{}_{}_changelist'.format( url = reverse('admin:{}_{}_changelist'.format(
opts.app_label, opts.model_name)) opts.app_label, opts.model_name))
name = capfirst(options.get('verbose_name_plural')) name = capfirst(options.get('verbose_name_plural'))
childrens.append(items.MenuItem(name, url)) return items.MenuItem(name, url)
return childrens
childrens = {}
def get_services(): for model, options in register.get().items():
childrens = process_registered_models(services) if options.get('menu', True):
return sorted(childrens, key=lambda i: i.title) parent = options.get('parent')
if parent:
parent_item = childrens.get(parent)
def get_accounts(): if parent_item:
childrens=[] if not parent_item.children:
if isinstalled('orchestra.contrib.payments'): parent_item.children.append(copy(parent_item))
url = reverse('admin:payments_transactionprocess_changelist') else:
childrens.append(items.MenuItem(_("Transaction processes"), url)) parent_item = get_item(parent, register[parent])
if isinstalled('orchestra.contrib.issues'): parent_item.children = []
url = reverse('admin:issues_ticket_changelist') parent_item.children.append(get_item(model, options))
childrens.append(items.MenuItem(_("Tickets"), url)) childrens[parent] = parent_item
childrens.extend(process_registered_models(accounts)) elif model not in childrens:
return sorted(childrens, key=lambda i: i.title) childrens[model] = get_item(model, options)
else:
childrens[model].children.insert(0, get_item(model, options))
def get_administration_items(): return sorted(childrens.values(), key=lambda i: i.title)
childrens = []
if isinstalled('orchestra.contrib.settings'):
url = reverse('admin:settings_setting_change')
childrens.append(items.MenuItem(_("Settings"), url))
if isinstalled('orchestra.contrib.services'):
url = reverse('admin:services_service_changelist')
childrens.append(items.MenuItem(_("Services"), url))
url = reverse('admin:plans_plan_changelist')
childrens.append(items.MenuItem(_("Plans"), url))
if isinstalled('orchestra.contrib.orchestration'):
route = reverse('admin:orchestration_route_changelist')
backendlog = reverse('admin:orchestration_backendlog_changelist')
server = reverse('admin:orchestration_server_changelist')
childrens.append(items.MenuItem(_("Orchestration"), route, children=[
items.MenuItem(_("Routes"), route),
items.MenuItem(_("Backend logs"), backendlog),
items.MenuItem(_("Servers"), server),
]))
if isinstalled('orchestra.contrib.resources'):
resource = reverse('admin:resources_resource_changelist')
data = reverse('admin:resources_resourcedata_changelist')
monitor = reverse('admin:resources_monitordata_changelist')
childrens.append(items.MenuItem(_("Resources"), resource, children=[
items.MenuItem(_("Resources"), resource),
items.MenuItem(_("Data"), data),
items.MenuItem(_("Monitoring"), monitor),
]))
if isinstalled('orchestra.contrib.miscellaneous'):
url = reverse('admin:miscellaneous_miscservice_changelist')
childrens.append(items.MenuItem(_("Miscellaneous"), url))
if isinstalled('orchestra.contrib.issues'):
url = reverse('admin:issues_queue_changelist')
childrens.append(items.MenuItem(_("Ticket queues"), url))
if isinstalled('djcelery'):
task = reverse('admin:djcelery_taskstate_changelist')
periodic = reverse('admin:djcelery_periodictask_changelist')
worker = reverse('admin:djcelery_workerstate_changelist')
childrens.append(items.MenuItem(_("Tasks"), task, children=[
items.MenuItem(_("Logs"), task),
items.MenuItem(_("Periodic tasks"), periodic),
items.MenuItem(_("Workers"), worker),
]))
childrens.extend(process_registered_models(administration))
return childrens
class OrchestraMenu(Menu): class OrchestraMenu(Menu):
@ -122,16 +79,16 @@ class OrchestraMenu(Menu):
# items.Bookmarks(), # items.Bookmarks(),
items.MenuItem( items.MenuItem(
_("Services"), _("Services"),
children=get_services() children=process_registry(services)
), ),
items.MenuItem( items.MenuItem(
_("Accounts"), _("Accounts"),
reverse('admin:accounts_account_changelist'), reverse('admin:accounts_account_changelist'),
children=get_accounts() children=process_registry(accounts)
), ),
items.MenuItem( items.MenuItem(
_("Administration"), _("Administration"),
children=get_administration_items() children=process_registry(administration)
), ),
items.MenuItem("API", api_link(context)), items.MenuItem("API", api_link(context)),
] ]

View file

@ -233,75 +233,6 @@ ADMIN_TOOLS_MENU = 'orchestra.admin.menu.OrchestraMenu'
# Fluent dashboard # Fluent dashboard
ADMIN_TOOLS_INDEX_DASHBOARD = 'orchestra.admin.dashboard.OrchestraIndexDashboard' ADMIN_TOOLS_INDEX_DASHBOARD = 'orchestra.admin.dashboard.OrchestraIndexDashboard'
FLUENT_DASHBOARD_ICON_THEME = '../orchestra/icons' FLUENT_DASHBOARD_ICON_THEME = '../orchestra/icons'
FLUENT_DASHBOARD_APP_GROUPS = (
# Services group is generated by orchestra.admin.dashboard
('Accounts', {
'models': (
'orchestra.contrib.accounts.models.Account',
'orchestra.contrib.contacts.models.Contact',
'orchestra.contrib.orders.models.Order',
'orchestra.contrib.plans.models.ContractedPlan',
'orchestra.contrib.bills.models.Bill',
'orchestra.contrib.payments.models.Transaction',
'orchestra.contrib.issues.models.Ticket',
),
'collapsible': True,
}),
('Administration', {
'models': (
'djcelery.models.TaskState',
'orchestra.contrib.orchestration.models.Route',
'orchestra.contrib.orchestration.models.BackendLog',
'orchestra.contrib.orchestration.models.Server',
'orchestra.contrib.resources.models.Resource',
'orchestra.contrib.resources.models.ResourceData',
'orchestra.contrib.services.models.Service',
'orchestra.contrib.plans.models.Plan',
'orchestra.contrib.miscellaneous.models.MiscService',
),
'collapsible': True,
}),
)
FLUENT_DASHBOARD_APP_ICONS = {
# Services
'webs/web': 'web.png',
'mail/address': 'X-office-address-book.png',
'mailboxes/mailbox': 'email.png',
'mailboxes/address': 'X-office-address-book.png',
'lists/list': 'email-alter.png',
'domains/domain': 'domain.png',
'multitenance/tenant': 'apps.png',
'webapps/webapp': 'Applications-other.png',
'websites/website': 'Applications-internet.png',
'databases/database': 'database.png',
'databases/databaseuser': 'postgresql.png',
'vps/vps': 'TuxBox.png',
'miscellaneous/miscellaneous': 'applications-other.png',
'saas/saas': 'saas.png',
'systemusers/systemuser': 'roleplaying.png',
# Accounts
'accounts/account': 'Face-monkey.png',
'contacts/contact': 'contact_book.png',
'orders/order': 'basket.png',
'plans/contractedplan': 'ContractedPack.png',
'services/service': 'price.png',
'bills/bill': 'invoice.png',
'payments/paymentsource': 'card_in_use.png',
'payments/transaction': 'transaction.png',
'payments/transactionprocess': 'transactionprocess.png',
'issues/ticket': 'Ticket_star.png',
'miscellaneous/miscservice': 'Misc-Misc-Box-icon.png',
# Administration
'settings/setting': 'preferences.png',
'djcelery/taskstate': 'taskstate.png',
'orchestration/server': 'vps.png',
'orchestration/route': 'hal.png',
'orchestration/backendlog': 'scriptlog.png',
'resources/resource': "gauge.png",
'resources/resourcedata': "monitor.png",
'plans/plan': 'Pack.png',
}
# Django-celery # Django-celery

View file

@ -12,7 +12,7 @@ class AccountConfig(AppConfig):
def ready(self): def ready(self):
from .management import create_initial_superuser from .management import create_initial_superuser
from .models import Account from .models import Account
services.register(Account, menu=False) services.register(Account, menu=False, dashboard=False)
accounts.register(Account) accounts.register(Account, icon='Face-monkey.png')
post_migrate.connect(create_initial_superuser, post_migrate.connect(create_initial_superuser,
dispatch_uid="orchestra.contrib.accounts.management.createsuperuser") dispatch_uid="orchestra.contrib.accounts.management.createsuperuser")

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.bills.apps.BillsConfig'

View file

@ -0,0 +1,12 @@
from django.apps import AppConfig
from orchestra.core import accounts
class BillsConfig(AppConfig):
name = 'orchestra.contrib.bills'
verbose_name = 'Bills'
def ready(self):
from .models import Bill
accounts.register(Bill, icon='invoice.png')

View file

@ -13,7 +13,7 @@ from django.utils.translation import ugettext_lazy as _
from orchestra.contrib.accounts.models import Account from orchestra.contrib.accounts.models import Account
from orchestra.contrib.contacts.models import Contact from orchestra.contrib.contacts.models import Contact
from orchestra.core import accounts, validators from orchestra.core import validators
from orchestra.utils.html import html_to_pdf from orchestra.utils.html import html_to_pdf
from . import settings from . import settings
@ -351,6 +351,3 @@ class BillSubline(models.Model):
# if self.line.bill.is_open: # if self.line.bill.is_open:
# self.line.bill.total = self.line.bill.get_total() # self.line.bill.total = self.line.bill.get_total()
# self.line.bill.save(update_fields=['total']) # self.line.bill.save(update_fields=['total'])
accounts.register(Bill)

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.contacts.apps.ContactsConfig'

View file

@ -0,0 +1,12 @@
from django.apps import AppConfig
from orchestra.core import accounts
class ContactsConfig(AppConfig):
name = 'orchestra.contrib.contacts'
verbose_name = 'Contacts'
def ready(self):
from .models import Contact
accounts.register(Contact, icon='contact_book.png')

View file

@ -3,7 +3,7 @@ from django.core.validators import RegexValidator
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import accounts, validators from orchestra.core import validators
from orchestra.models.fields import MultiSelectField from orchestra.models.fields import MultiSelectField
from . import settings from . import settings
@ -78,6 +78,3 @@ class Contact(models.Model):
errors['zipcode'] = error errors['zipcode'] = error
if errors: if errors:
raise ValidationError(errors) raise ValidationError(errors)
accounts.register(Contact)

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.databases.apps.DatabasesConfig'

View file

@ -0,0 +1,14 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
from orchestra.core import services
class DatabasesConfig(AppConfig):
name = 'orchestra.contrib.databases'
verbose_name = 'Databases'
def ready(self):
from .models import Database, DatabaseUser
services.register(Database, icon='database.png')
services.register(DatabaseUser, icon='postgresql.png', verbose_name_plural=_("Database users"))

View file

@ -3,7 +3,7 @@ import hashlib
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import validators, services from orchestra.core import validators
from . import settings from . import settings
@ -76,7 +76,3 @@ class DatabaseUser(models.Model):
self.password = '*%s' % hexdigest.upper() self.password = '*%s' % hexdigest.upper()
else: else:
raise TypeError("Database type '%s' not supported" % self.type) raise TypeError("Database type '%s' not supported" % self.type)
services.register(Database)
services.register(DatabaseUser, verbose_name_plural=_("Database users"))

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.domains.apps.DomainsConfig'

View file

@ -11,8 +11,8 @@ from orchestra.contrib.accounts.admin import AccountAdminMixin
from orchestra.utils import apps from orchestra.utils import apps
from .actions import view_zone from .actions import view_zone
from .forms import RecordInlineFormSet, BatchDomainCreationAdminForm
from .filters import TopDomainListFilter from .filters import TopDomainListFilter
from .forms import RecordInlineFormSet, BatchDomainCreationAdminForm
from .models import Domain, Record from .models import Domain, Record
@ -21,11 +21,6 @@ class RecordInline(admin.TabularInline):
formset = RecordInlineFormSet formset = RecordInlineFormSet
verbose_name_plural = _("Extra records") verbose_name_plural = _("Extra records")
# class Media:
# css = {
# 'all': ('orchestra/css/hide-inline-id.css',)
# }
#
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
""" Make value input widget bigger """ """ Make value input widget bigger """
if db_field.name == 'value': if db_field.name == 'value':
@ -73,9 +68,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
change_view_actions = [view_zone] change_view_actions = [view_zone]
def structured_name(self, domain): def structured_name(self, domain):
if not domain.is_top: if domain.is_top:
return ' '*4 + domain.name
return domain.name return domain.name
return ' '*4 + domain.name
structured_name.short_description = _("name") structured_name.short_description = _("name")
structured_name.allow_tags = True structured_name.allow_tags = True
structured_name.admin_order_field = 'structured_name' structured_name.admin_order_field = 'structured_name'

View file

@ -0,0 +1,12 @@
from django.apps import AppConfig
from orchestra.core import services
class DomainsConfig(AppConfig):
name = 'orchestra.contrib.domains'
verbose_name = 'Domains'
def ready(self):
from .models import Domain
services.register(Domain, icon='domain.png')

View file

@ -2,7 +2,6 @@ from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.core import services
from orchestra.core.validators import validate_ipv4_address, validate_ipv6_address, validate_ascii from orchestra.core.validators import validate_ipv4_address, validate_ipv6_address, validate_ascii
from orchestra.utils.python import AttrDict from orchestra.utils.python import AttrDict
@ -271,6 +270,3 @@ class Record(models.Model):
def get_ttl(self): def get_ttl(self):
return self.ttl or settings.DOMAINS_DEFAULT_TTL return self.ttl or settings.DOMAINS_DEFAULT_TTL
services.register(Domain)

View file

@ -1 +1 @@
REQUIRED_APPS = ['slices'] default_app_config = 'orchestra.contrib.issues.apps.IssuesConfig'

View file

@ -0,0 +1,13 @@
from django.apps import AppConfig
from orchestra.core import accounts, administration
class IssuesConfig(AppConfig):
name = 'orchestra.contrib.issues'
verbose_name = "Issues"
def ready(self):
from .models import Queue, Ticket
accounts.register(Ticket, icon='Ticket_star.png')
administration.register(Queue, dashboard=False)

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.lists.apps.ListsConfig'

View file

@ -0,0 +1,12 @@
from django.apps import AppConfig
from orchestra.core import services
class ListsConfig(AppConfig):
name = 'orchestra.contrib.lists'
verbose_name = 'Lists'
def ready(self):
from .models import List
services.register(List, icon='email-alter.png')

View file

@ -2,7 +2,6 @@ from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import services
from orchestra.core.validators import validate_name from orchestra.core.validators import validate_name
from . import settings from . import settings
@ -70,6 +69,3 @@ class List(models.Model):
'name': self.name 'name': self.name
} }
return settings.LISTS_LIST_URL % context return settings.LISTS_LIST_URL % context
services.register(List)

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.mailboxes.apps.MailboxesConfig'

View file

@ -0,0 +1,13 @@
from django.apps import AppConfig
from orchestra.core import services
class MailboxesConfig(AppConfig):
name = 'orchestra.contrib.mailboxes'
verbose_name = 'Mailboxes'
def ready(self):
from .models import Mailbox, Address
services.register(Mailbox, icon='email.png')
services.register(Address, icon='X-office-address-book.png')

View file

@ -6,8 +6,6 @@ from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import services
from . import validators, settings from . import validators, settings
@ -152,7 +150,3 @@ class Autoresponse(models.Model):
def __str__(self): def __str__(self):
return self.address return self.address
services.register(Mailbox)
services.register(Address)

View file

@ -9,4 +9,4 @@ class MailerConfig(AppConfig):
def ready(self): def ready(self):
from .models import Message from .models import Message
administration.register(Message) administration.register(Message, icon='Mail-send.png')

View file

@ -43,7 +43,7 @@ class Message(models.Model):
# Max tries # Max tries
if self.retries >= len(settings.MAILER_DEFERE_SECONDS): if self.retries >= len(settings.MAILER_DEFERE_SECONDS):
self.state = self.FAILED self.state = self.FAILED
self.save(update_fields=('state', 'retries')) self.save(update_fields=('state', 'retries', 'last_retry'))
def sent(self): def sent(self):
self.state = self.SENT self.state = self.SENT

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.miscellaneous.apps.MiscellaneousConfig'

View file

@ -0,0 +1,15 @@
from django.apps import AppConfig
from orchestra.core import services, administration
from orchestra.core.translations import ModelTranslation
class MiscellaneousConfig(AppConfig):
name = 'orchestra.contrib.miscellaneous'
verbose_name = 'Miscellaneous'
def ready(self):
from .models import MiscService, Miscellaneous
services.register(Miscellaneous, icon='applications-other.png')
administration.register(MiscService, icon='Misc-Misc-Box-icon.png')
ModelTranslation.register(MiscService, ('verbose_name',))

View file

@ -2,8 +2,6 @@ from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import services
from orchestra.core.translations import ModelTranslation
from orchestra.core.validators import validate_name from orchestra.core.validators import validate_name
from orchestra.models.fields import NullableCharField from orchestra.models.fields import NullableCharField
@ -69,8 +67,3 @@ class Miscellaneous(models.Model):
if self.identifier: if self.identifier:
self.identifier = self.identifier.strip() self.identifier = self.identifier.strip()
self.description = self.description.strip() self.description = self.description.strip()
services.register(Miscellaneous)
ModelTranslation.register(MiscService, ('verbose_name',))

View file

@ -3,6 +3,9 @@ import copy
from .backends import ServiceBackend, ServiceController, replace from .backends import ServiceBackend, ServiceController, replace
default_app_config = 'orchestra.contrib.orchestration.apps.OrchestrationConfig'
class Operation(): class Operation():
DELETE = 'delete' DELETE = 'delete'
SAVE = 'save' SAVE = 'save'
@ -30,10 +33,10 @@ class Operation():
self.routes = routes self.routes = routes
@classmethod @classmethod
def execute(cls, operations, async=False): def execute(cls, operations, serialize=False, async=False):
from . import manager from . import manager
scripts, block = manager.generate(operations) scripts, oserialize = manager.generate(operations)
return manager.execute(scripts, block=block, async=async) return manager.execute(scripts, serialize=(serialize or oserialize), async=async)
@classmethod @classmethod
def execute_action(cls, instance, action): def execute_action(cls, instance, action):

View file

@ -0,0 +1,14 @@
from django.apps import AppConfig
from orchestra.core import administration
class OrchestrationConfig(AppConfig):
name = 'orchestra.contrib.orchestration'
verbose_name = "Orchestration"
def ready(self):
from .models import Server, Route, BackendLog
administration.register(BackendLog, icon='scriptlog.png')
administration.register(Server, parent=BackendLog, icon='vps.png')
administration.register(Route, parent=BackendLog, icon='hal.png')

View file

@ -45,7 +45,7 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
actions = [] actions = []
default_route_match = 'True' default_route_match = 'True'
# Force the backend manager to block in multiple backend executions executing them synchronously # Force the backend manager to block in multiple backend executions executing them synchronously
block = False serialize = False
doc_settings = None doc_settings = None
# By default backend will not run if actions do not generate insctructions, # By default backend will not run if actions do not generate insctructions,
# If your backend uses prepare() or commit() only then you should set force_empty_action_execution = True # If your backend uses prepare() or commit() only then you should set force_empty_action_execution = True

View file

@ -71,7 +71,7 @@ class Command(BaseCommand):
else: else:
for instance in queryset: for instance in queryset:
manager.collect(instance, action, operations=operations, route_cache=route_cache) manager.collect(instance, action, operations=operations, route_cache=route_cache)
scripts, block = manager.generate(operations) scripts, serialize = manager.generate(operations)
servers = [] servers = []
# Print scripts # Print scripts
for key, value in scripts.items(): for key, value in scripts.items():
@ -96,7 +96,7 @@ class Command(BaseCommand):
return return
break break
if not dry: if not dry:
logs = manager.execute(scripts, block=block) logs = manager.execute(scripts, serialize=serialize)
for log in logs: for log in logs:
self.stdout.write(log.stdout) self.stdout.write(log.stdout)
self.stderr.write(log.stderr) self.stderr.write(log.stderr)

View file

@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
router = import_class(settings.ORCHESTRATION_ROUTER) router = import_class(settings.ORCHESTRATION_ROUTER)
def as_task(execute, log, operations): def keep_log(execute, log, operations):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
""" send report """ """ send report """
# Remember that threads have their oun connection poll # Remember that threads have their oun connection poll
@ -30,14 +30,14 @@ def as_task(execute, log, operations):
if log.state != log.SUCCESS: if log.state != log.SUCCESS:
send_report(execute, args, log) send_report(execute, args, log)
except Exception as e: except Exception as e:
subject = 'EXCEPTION executing backend(s) %s %s' % (str(args), str(kwargs)) trace = traceback.format_exc()
message = traceback.format_exc()
logger.error(subject)
logger.error(message)
mail_admins(subject, message)
log.state = BackendLog.EXCEPTION log.state = BackendLog.EXCEPTION
log.stderr = traceback.format_exc() log.stderr = trace
log.save(update_fields=('state', 'stderr')) log.save()
subject = 'EXCEPTION executing backend(s) %s %s' % (str(args), str(kwargs))
logger.error(subject)
logger.error(trace)
mail_admins(subject, trace)
# We don't propagate the exception further to avoid transaction rollback # We don't propagate the exception further to avoid transaction rollback
finally: finally:
# Store and log the operation # Store and log the operation
@ -56,7 +56,7 @@ def as_task(execute, log, operations):
def generate(operations): def generate(operations):
scripts = OrderedDict() scripts = OrderedDict()
cache = {} cache = {}
block = False serialize = False
# Generate scripts per route+backend # Generate scripts per route+backend
for operation in operations: for operation in operations:
logger.debug("Queued %s" % str(operation)) logger.debug("Queued %s" % str(operation))
@ -86,18 +86,18 @@ def generate(operations):
pre_action.send(**kwargs) pre_action.send(**kwargs)
method(operation.instance) method(operation.instance)
post_action.send(**kwargs) post_action.send(**kwargs)
if backend.block: if backend.serialize:
block = True serialize = True
for value in scripts.values(): for value in scripts.values():
backend, operations = value backend, operations = value
backend.set_tail() backend.set_tail()
pre_commit.send(sender=backend.__class__, backend=backend) pre_commit.send(sender=backend.__class__, backend=backend)
backend.commit() backend.commit()
post_commit.send(sender=backend.__class__, backend=backend) post_commit.send(sender=backend.__class__, backend=backend)
return scripts, block return scripts, serialize
def execute(scripts, block=False, async=False): def execute(scripts, serialize=False, async=False):
""" executes the operations on the servers """ """ executes the operations on the servers """
if settings.ORCHESTRATION_DISABLE_EXECUTION: if settings.ORCHESTRATION_DISABLE_EXECUTION:
logger.info('Orchestration execution is dissabled by ORCHESTRATION_DISABLE_EXECUTION settings.') logger.info('Orchestration execution is dissabled by ORCHESTRATION_DISABLE_EXECUTION settings.')
@ -110,21 +110,22 @@ def execute(scripts, block=False, async=False):
route, __ = key route, __ = key
backend, operations = value backend, operations = value
args = (route.host,) args = (route.host,)
async = not serialize and (async or route.async)
kwargs = { kwargs = {
'async': async or route.async 'async': async,
} }
log = backend.create_log(*args, **kwargs) log = backend.create_log(*args, **kwargs)
kwargs['log'] = log kwargs['log'] = log
task = as_task(backend.execute, log, operations) task = keep_log(backend.execute, log, operations)
logger.debug('%s is going to be executed on %s' % (backend, route.host)) logger.debug('%s is going to be executed on %s' % (backend, route.host))
if block: if serialize:
# Execute one backend at a time, no need for threads # Execute one backend at a time, no need for threads
task(*args, **kwargs) task(*args, **kwargs)
else: else:
task = close_connection(task) task = close_connection(task)
thread = threading.Thread(target=task, args=args, kwargs=kwargs) thread = threading.Thread(target=task, args=args, kwargs=kwargs)
thread.start() thread.start()
if not route.async: if not async:
threads_to_join.append(thread) threads_to_join.append(thread)
logs.append(log) logs.append(log)
[ thread.join() for thread in threads_to_join ] [ thread.join() for thread in threads_to_join ]

View file

@ -97,14 +97,14 @@ class OperationsMiddleware(object):
operations = self.get_pending_operations() operations = self.get_pending_operations()
if operations: if operations:
try: try:
scripts, block = manager.generate(operations) scripts, serialize = manager.generate(operations)
except Exception as exception: except Exception as exception:
self.leave_transaction_management(exception) self.leave_transaction_management(exception)
raise raise
# We commit transaction just before executing operations # We commit transaction just before executing operations
# because here is when IntegrityError show up # because here is when IntegrityError show up
self.leave_transaction_management() self.leave_transaction_management()
logs = manager.execute(scripts, block=block) logs = manager.execute(scripts, serialize=serialize)
if logs and resolve(request.path).app_name == 'admin': if logs and resolve(request.path).app_name == 'admin':
message_user(request, logs) message_user(request, logs)
return response return response

View file

@ -10,6 +10,6 @@ class OrdersConfig(AppConfig):
def ready(self): def ready(self):
from .models import Order from .models import Order
accounts.register(Order) accounts.register(Order, icon='basket.png')
if database_ready(): if database_ready():
from . import signals from . import signals

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.payments.apps.PaymentsConfig'

View file

@ -0,0 +1,14 @@
from django.apps import AppConfig
from orchestra.core import accounts
class PaymentsConfig(AppConfig):
name = 'orchestra.contrib.payments'
verbose_name = "Payments"
def ready(self):
from .models import PaymentSource, Transaction, TransactionProcess
accounts.register(PaymentSource, dashboard=False)
accounts.register(Transaction, icon='transaction.png')
accounts.register(TransactionProcess, icon='transactionprocess.png', dashboard=False)

View file

@ -4,7 +4,6 @@ from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from jsonfield import JSONField from jsonfield import JSONField
from orchestra.core import accounts
from orchestra.models.queryset import group_by from orchestra.models.queryset import group_by
from . import settings from . import settings
@ -200,7 +199,3 @@ class TransactionProcess(models.Model):
for transaction in self.transactions.processing(): for transaction in self.transactions.processing():
transaction.mark_as_secured() transaction.mark_as_secured()
self.save(update_fields=['state']) self.save(update_fields=['state'])
accounts.register(PaymentSource)
accounts.register(Transaction)

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.plans.apps.PlansConfig'

View file

@ -0,0 +1,15 @@
from django.apps import AppConfig
from orchestra.core import administration, accounts
from orchestra.core.translations import ModelTranslation
class PlansConfig(AppConfig):
name = 'orchestra.contrib.plans'
verbose_name = 'Plans'
def ready(self):
from .models import Plan, ContractedPlan
accounts.register(ContractedPlan, icon='ContractedPack.png')
administration.register(Plan, icon='Pack.png')
ModelTranslation.register(Plan, ('verbose_name',))

View file

@ -5,7 +5,6 @@ from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import services, accounts from orchestra.core import services, accounts
from orchestra.core.translations import ModelTranslation
from orchestra.core.validators import validate_name from orchestra.core.validators import validate_name
from orchestra.models import queryset from orchestra.models import queryset
@ -100,9 +99,3 @@ class Rate(models.Model):
for name, method in cls.RATE_METHODS.items(): for name, method in cls.RATE_METHODS.items():
choices.append((name, method.verbose_name)) choices.append((name, method.verbose_name))
return choices return choices
accounts.register(ContractedPlan)
services.register(ContractedPlan, menu=False)
ModelTranslation.register(Plan, ('verbose_name',))

View file

@ -1,6 +1,7 @@
from django import db from django import db
from django.apps import AppConfig from django.apps import AppConfig
from orchestra.core import administration
from orchestra.utils.db import database_ready from orchestra.utils.db import database_ready
@ -16,6 +17,10 @@ class ResourcesConfig(AppConfig):
except db.utils.OperationalError: except db.utils.OperationalError:
# Not ready afterall # Not ready afterall
pass pass
from .models import Resource, ResourceData, MonitorData
administration.register(Resource, icon='gauge.png')
administration.register(ResourceData, parent=Resource, icon='monitor.png')
administration.register(MonitorData, parent=Resource, dashboard=False)
def reload_relations(self): def reload_relations(self):
from .admin import insert_resource_inlines from .admin import insert_resource_inlines

View file

@ -72,7 +72,7 @@ class ServiceMonitor(ServiceBackend):
MonitorData.objects.create(monitor=name, object_id=object_id, MonitorData.objects.create(monitor=name, object_id=object_id,
content_type=ct, value=value, created_at=self.current_date) content_type=ct, value=value, created_at=self.current_date)
def execute(self, server, async=False): def execute(self, *args, **kwargs):
log = super(ServiceMonitor, self).execute(server, async=async) log = super(ServiceMonitor, self).execute(*args, **kwargs)
self.store(log) self.store(log)
return log return log

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('resources', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CrontabSchedule',
fields=[
('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')),
('minute', models.CharField(max_length=64, verbose_name='minute', default='*')),
('hour', models.CharField(max_length=64, verbose_name='hour', default='*')),
('day_of_week', models.CharField(max_length=64, verbose_name='day of week', default='*')),
('day_of_month', models.CharField(max_length=64, verbose_name='day of month', default='*')),
('month_of_year', models.CharField(max_length=64, verbose_name='month of year', default='*')),
],
options={
'verbose_name': 'crontab',
'ordering': ('month_of_year', 'day_of_month', 'day_of_week', 'hour', 'minute'),
'verbose_name_plural': 'crontabs',
},
),
]

View file

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('resources', '0002_auto_20150502_1429'),
]
operations = [
]

View file

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('resources', '0003_auto_20150502_1433'),
]
operations = [
]

View file

@ -148,9 +148,8 @@ class Resource(models.Model):
def monitor(self, async=True): def monitor(self, async=True):
if async: if async:
print(tasks.monitor.delay) return tasks.monitor.apply_async(self.pk)
return tasks.monitor.delay(self.pk, async=async) return tasks.monitor(self.pk)
return tasks.monitor(self.pk, async=async)
class ResourceData(models.Model): class ResourceData(models.Model):

View file

@ -7,7 +7,7 @@ from .backends import ServiceMonitor
@task(name='resources.Monitor') @task(name='resources.Monitor')
def monitor(resource_id, ids=None, async=True): def monitor(resource_id, ids=None):
with LockFile('/dev/shm/resources.monitor-%i.lock' % resource_id, expire=60*60): with LockFile('/dev/shm/resources.monitor-%i.lock' % resource_id, expire=60*60):
from .models import ResourceData, Resource from .models import ResourceData, Resource
resource = Resource.objects.get(pk=resource_id) resource = Resource.objects.get(pk=resource_id)
@ -29,9 +29,7 @@ def monitor(resource_id, ids=None, async=True):
for obj in model.objects.filter(**kwargs): for obj in model.objects.filter(**kwargs):
op = Operation(backend, obj, Operation.MONITOR) op = Operation(backend, obj, Operation.MONITOR)
monitorings.append(op) monitorings.append(op)
# TODO async=True only when running with celery logs += Operation.execute(monitorings, async=False)
# monitor.request.id
logs += Operation.execute(monitorings, async=async)
kwargs = {'id__in': ids} if ids else {} kwargs = {'id__in': ids} if ids else {}
# Update used resources and trigger resource exceeded and revovery # Update used resources and trigger resource exceeded and revovery

View file

@ -10,6 +10,4 @@ class SaaSConfig(AppConfig):
def ready(self): def ready(self):
from . import signals from . import signals
from .models import SaaS from .models import SaaS
services.register(SaaS) services.register(SaaS, icon='saas.png')

View file

@ -12,7 +12,7 @@ class GitLabSaaSBackend(ServiceController):
verbose_name = _("GitLab SaaS") verbose_name = _("GitLab SaaS")
model = 'saas.SaaS' model = 'saas.SaaS'
default_route_match = "saas.service == 'gitlab'" default_route_match = "saas.service == 'gitlab'"
block = True serialize = True
actions = ('save', 'delete', 'validate_creation') actions = ('save', 'delete', 'validate_creation')
doc_settings = (settings, doc_settings = (settings,
('SAAS_GITLAB_DOMAIN', 'SAAS_GITLAB_ROOT_PASSWORD'), ('SAAS_GITLAB_DOMAIN', 'SAAS_GITLAB_ROOT_PASSWORD'),

View file

@ -18,7 +18,7 @@ class PhpListSaaSBackend(ServiceController):
verbose_name = _("phpList SaaS") verbose_name = _("phpList SaaS")
model = 'saas.SaaS' model = 'saas.SaaS'
default_route_match = "saas.service == 'phplist'" default_route_match = "saas.service == 'phplist'"
block = True serialize = True
def _save(self, saas, server): def _save(self, saas, server):
admin_link = 'http://%s/admin/' % saas.get_site_domain() admin_link = 'http://%s/admin/' % saas.get_site_domain()

View file

@ -1,6 +1,14 @@
from django.apps import AppConfig from django.apps import AppConfig
from orchestra.core import administration, accounts
from orchestra.core.translations import ModelTranslation
class ServicesConfig(AppConfig): class ServicesConfig(AppConfig):
name = 'orchestra.contrib.services' name = 'orchestra.contrib.services'
verbose_name = 'Services' verbose_name = 'Services'
def ready(self):
from .models import Service
administration.register(Service, icon='price.png')
ModelTranslation.register(Service, ('description',))

View file

@ -8,7 +8,6 @@ from django.utils.module_loading import autodiscover_modules
from django.utils.translation import string_concat, ugettext_lazy as _ from django.utils.translation import string_concat, ugettext_lazy as _
from orchestra.core import caches, validators from orchestra.core import caches, validators
from orchestra.core.translations import ModelTranslation
from orchestra.utils.python import import_class from orchestra.utils.python import import_class
from . import settings from . import settings
@ -244,6 +243,3 @@ class Service(models.Model):
for instance in queryset: for instance in queryset:
updates += order_model.update_orders(instance, service=self, commit=commit) updates += order_model.update_orders(instance, service=self, commit=commit)
return updates return updates
ModelTranslation.register(Service, ('description',))

View file

@ -103,7 +103,5 @@ class SettingFileView(generic.TemplateView):
return context return context
admin.site.register_url(r'^settings/setting/view/$', SettingFileView.as_view(), 'settings_setting_view') admin.site.register_url(r'^settings/setting/view/$', SettingFileView.as_view(), 'settings_setting_view')
admin.site.register_url(r'^settings/setting/$', SettingView.as_view(), 'settings_setting_change') admin.site.register_url(r'^settings/setting/$', SettingView.as_view(), 'settings_setting_change')
OrchestraIndexDashboard.register_link('Administration', 'settings_setting_change', _("Settings"))

View file

@ -1,13 +1,21 @@
from django.apps import AppConfig from django.apps import AppConfig
from django.core.checks import register, Error from django.core.checks import register, Error
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import ngettext, ugettext_lazy as _
from orchestra.core import administration
from . import Setting from . import Setting
class SettingsConfig(AppConfig): class SettingsConfig(AppConfig):
name = 'orchestra.contrib.settings' name = 'orchestra.contrib.settings'
verbose_name = 'Settings' verbose_name = 'Settings'
def ready(self):
administration.register_view('settings_setting_change', verbose_name=_("Settings"),
icon='Multimedia-volume-control.png')
@register() @register()
def check_settings(app_configs, **kwargs): def check_settings(app_configs, **kwargs):
""" perfroms all the validation """ """ perfroms all the validation """

View file

@ -12,7 +12,7 @@ class SystemUsersConfig(AppConfig):
def ready(self): def ready(self):
from .models import SystemUser from .models import SystemUser
services.register(SystemUser) services.register(SystemUser, icon='roleplaying.png')
if 'migrate' in sys.argv and 'accounts' not in sys.argv: if 'migrate' in sys.argv and 'accounts' not in sys.argv:
post_migrate.connect(self.create_initial_systemuser, post_migrate.connect(self.create_initial_systemuser,
dispatch_uid="orchestra.contrib.systemusers.apps.create_initial_systemuser") dispatch_uid="orchestra.contrib.systemusers.apps.create_initial_systemuser")

View file

@ -2,3 +2,6 @@ import sys
from . import settings from . import settings
from .decorators import task, periodic_task, keep_state, apply_async from .decorators import task, periodic_task, keep_state, apply_async
default_app_config = 'orchestra.contrib.tasks.apps.TasksConfig'

View file

@ -0,0 +1,14 @@
from django.apps import AppConfig
from orchestra.core import administration
class TasksConfig(AppConfig):
name = 'orchestra.contrib.tasks'
verbose_name = "Tasks"
def ready(self):
from djcelery.models import PeriodicTask, TaskState, WorkerState
administration.register(TaskState, icon='Edit-check-sheet.png')
administration.register(PeriodicTask, parent=TaskState, icon='Appointment.png')
administration.register(WorkerState, parent=TaskState, dashboard=False)

View file

@ -6,6 +6,7 @@ from threading import Thread
from celery import shared_task as celery_shared_task from celery import shared_task as celery_shared_task
from celery import states from celery import states
from celery.decorators import periodic_task as celery_periodic_task from celery.decorators import periodic_task as celery_periodic_task
from django.core.mail import mail_admins
from django.utils import timezone from django.utils import timezone
from orchestra.utils.db import close_connection from orchestra.utils.db import close_connection
@ -26,11 +27,15 @@ def keep_state(fn):
result = fn(*args, **kwargs) result = fn(*args, **kwargs)
except Exception as exc: except Exception as exc:
state.state = states.FAILURE state.state = states.FAILURE
state.traceback = traceback.format_exc() state.traceback = trace
state.runtime = (timezone.now()-now).total_seconds() state.runtime = (timezone.now()-now).total_seconds()
state.save() state.save()
subject = 'EXCEPTION executing task %s(args=%s, kwargs=%s)' % (name, str(args), str(kwargs))
trace = traceback.format_exc()
logger.error(subject)
logger.error(trace)
mail_admins(subject, trace)
return return
# TODO send email
else: else:
state.state = states.SUCCESS state.state = states.SUCCESS
state.result = str(result) state.result = str(result)

View file

@ -1,2 +1,15 @@
# create crontab entries for defines periodic tasks from django.core.management.base import BaseCommand, CommandError
from djcelery.app import app
from djcelery.schedulers import DatabaseScheduler
class Command(BaseCommand):
help = 'Runs Orchestra method.'
def handle(self, *args, **options):
dbschedule = DatabaseScheduler(app=app)
self.stdout.write('\033[1m%i periodic tasks have been syncronized:\033[0m' % len(dbschedule.schedule))
size = max([len(name) for name in dbschedule.schedule])+1
for name, task in dbschedule.schedule.items():
spaces = ' '*(size-len(name))
self.stdout.write(' %s%s%s' % (name, spaces, task.schedule))

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.vps.apps.VPSConfig'

View file

@ -0,0 +1,12 @@
from django.apps import AppConfig
from orchestra.core import services
class VPSConfig(AppConfig):
name = 'orchestra.contrib.vps'
verbose_name = 'VPS'
def ready(self):
from .models import VPS
services.register(VPS, icon='TuxBox.png')

View file

@ -1,8 +1,7 @@
from django.contrib.auth.hashers import make_password
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.hashers import make_password
from orchestra.core import services
from orchestra.core.validators import validate_hostname from orchestra.core.validators import validate_hostname
from . import settings from . import settings
@ -32,6 +31,3 @@ class VPS(models.Model):
def get_username(self): def get_username(self):
return self.hostname return self.hostname
services.register(VPS)

View file

@ -10,4 +10,4 @@ class WebAppsConfig(AppConfig):
def ready(self): def ready(self):
from . import signals from . import signals
from .models import WebApp from .models import WebApp
services.register(WebApp) services.register(WebApp, icon='Applications-other.png')

View file

@ -0,0 +1 @@
default_app_config = 'orchestra.contrib.websites.apps.WebsitesConfig'

View file

@ -1,17 +1,20 @@
from django.apps import AppConfig from django.apps import AppConfig
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from orchestra.core import services
from orchestra.utils.db import database_ready from orchestra.utils.db import database_ready
class WebsiteConfig(AppConfig): class WebsitesConfig(AppConfig):
name = 'orchestra.contrib.websites' name = 'orchestra.contrib.websites'
def ready(self): def ready(self):
if database_ready(): if database_ready():
from django.contrib.contenttypes.models import ContentType # from django.contrib.contenttypes.models import ContentType
from .models import Content # from .models import Content, Website
qset = Content.content_type.field.get_limit_choices_to() # qset = Content.content_type.field.get_limit_choices_to()
for ct in ContentType.objects.filter(qset): # for ct in ContentType.objects.filter(qset):
relation = GenericRelation('websites.Content') # relation = GenericRelation('websites.Content')
ct.model_class().add_to_class('content_set', relation) # ct.model_class().add_to_class('content_set', relation)
from .models import Website
services.register(Website, icon='Applications-internet.png')

View file

@ -5,7 +5,7 @@ from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core import validators, services from orchestra.core import validators
from orchestra.utils.functional import cached from orchestra.utils.functional import cached
from . import settings from . import settings
@ -152,6 +152,3 @@ class Content(models.Model):
domain = self.website.domains.first() domain = self.website.domains.first()
if domain: if domain:
return '%s://%s%s' % (self.website.get_protocol(), domain, self.path) return '%s://%s%s' % (self.website.get_protocol(), domain, self.path)
services.register(Website)

View file

@ -1,9 +1,12 @@
from django.utils.translation import string_concat
from ..utils.python import AttrDict from ..utils.python import AttrDict
class Register(object): class Register(object):
def __init__(self): def __init__(self, verbose_name=None):
self._registry = {} self._registry = {}
self.verbose_name = verbose_name
def __contains__(self, key): def __contains__(self, key):
return key in self._registry return key in self._registry
@ -13,13 +16,21 @@ class Register(object):
def register(self, model, **kwargs): def register(self, model, **kwargs):
if model in self._registry: if model in self._registry:
raise KeyError("%s already registered" % str(model)) raise KeyError("%s already registered" % model)
plural = kwargs.get('verbose_name_plural', model._meta.verbose_name_plural) if 'verbose_name' not in kwargs:
self._registry[model] = AttrDict(**{ kwargs['verbose_name'] = model._meta.verbose_name
'verbose_name': kwargs.get('verbose_name', model._meta.verbose_name), if 'verbose_name_plural' not in kwargs:
'verbose_name_plural': plural, kwargs['verbose_name_plural'] = model._meta.verbose_name_plural
'menu': kwargs.get('menu', True), self._registry[model] = AttrDict(**kwargs)
})
def register_view(self, view_name, **kwargs):
if view_name in self._registry:
raise KeyError("%s already registered" % view_name)
if 'verbose_name' not in kwargs:
raise KeyError("%s verbose_name is required for views" % view_name)
if 'verbose_name_plural' not in kwargs:
kwargs['verbose_name_plural'] = string_concat(kwargs['verbose_name'], 's')
self._registry[view_name] = AttrDict(**kwargs)
def get(self, *args): def get(self, *args):
if args: if args:
@ -27,7 +38,7 @@ class Register(object):
return self._registry return self._registry
services = Register() services = Register(verbose_name='Services')
# TODO rename to something else # TODO rename to something else
accounts = Register() accounts = Register(verbose_name='Accounts')
administration = Register() administration = Register(verbose_name='Administration')

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,413 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="90.000000"
inkscape:export-xdpi="90.000000"
inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Appointment.png"
width="48px"
height="48px"
id="svg11300"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Appointment.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs3">
<linearGradient
inkscape:collect="always"
id="linearGradient5204">
<stop
style="stop-color:#c4a000;stop-opacity:1;"
offset="0"
id="stop5206" />
<stop
style="stop-color:#c4a000;stop-opacity:0;"
offset="1"
id="stop5208" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient5196">
<stop
style="stop-color:#c4a000;stop-opacity:1;"
offset="0"
id="stop5198" />
<stop
style="stop-color:#c4a000;stop-opacity:0;"
offset="1"
id="stop5200" />
</linearGradient>
<linearGradient
id="linearGradient12512">
<stop
style="stop-color:#ffffff;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop12513" />
<stop
style="stop-color:#fff520;stop-opacity:0.89108908;"
offset="0.50000000"
id="stop12517" />
<stop
style="stop-color:#fff300;stop-opacity:0.0000000;"
offset="1.0000000"
id="stop12514" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient12512"
id="radialGradient278"
gradientUnits="userSpaceOnUse"
cx="55.000000"
cy="125.00000"
fx="55.000000"
fy="125.00000"
r="14.375000" />
<linearGradient
id="linearGradient10653">
<stop
style="stop-color:#f3f4ff;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop10655" />
<stop
style="stop-color:#9193af;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop10657" />
</linearGradient>
<linearGradient
id="linearGradient42174">
<stop
style="stop-color:#a0a0a0;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop42176" />
<stop
style="stop-color:#ffffff;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop42178" />
</linearGradient>
<linearGradient
id="linearGradient2145">
<stop
style="stop-color:#fffffd;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop2147" />
<stop
style="stop-color:#cbcbc9;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop2149" />
</linearGradient>
<linearGradient
id="linearGradient37935">
<stop
id="stop37937"
offset="0.0000000"
style="stop-color:#9497b3;stop-opacity:1.0000000;" />
<stop
id="stop37939"
offset="1.0000000"
style="stop-color:#4c4059;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient2152">
<stop
id="stop2154"
offset="0.0000000"
style="stop-color:#9aa29a;stop-opacity:1.0000000;" />
<stop
id="stop2156"
offset="1.0000000"
style="stop-color:#b5beb5;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3816">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3818" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3820" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3816"
id="radialGradient3822"
cx="31.112698"
cy="19.008621"
fx="31.112698"
fy="19.008621"
r="8.6620579"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2152"
id="linearGradient4307"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(3.123841,0.000000,0.000000,0.969691,-31.88758,-19.59492)"
x1="8.9156475"
y1="37.197018"
x2="9.8855033"
y2="52.090678" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10653"
id="radialGradient4309"
gradientUnits="userSpaceOnUse"
cx="11.329200"
cy="10.583970"
fx="11.329200"
fy="10.583970"
r="15.532059" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2145"
id="radialGradient4311"
gradientUnits="userSpaceOnUse"
cx="11.901996"
cy="10.045444"
fx="11.901996"
fy="10.045444"
r="29.292715" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient42174"
id="linearGradient4313"
gradientUnits="userSpaceOnUse"
x1="6.3422160"
y1="7.7893324"
x2="22.218424"
y2="25.884274" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5196"
id="radialGradient5202"
cx="23.375"
cy="10.972863"
fx="23.375"
fy="10.972863"
r="3.3478092"
gradientTransform="matrix(3.630420,1.654030e-15,-1.608743e-15,3.742066,-61.48607,-29.18618)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5204"
id="linearGradient5210"
x1="19.667364"
y1="4.2570662"
x2="20.329933"
y2="5.2845874"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient37935"
id="radialGradient5212"
gradientUnits="userSpaceOnUse"
cx="8.7468252"
cy="6.8283234"
fx="8.7468252"
fy="6.8283234"
r="29.889715" />
</defs>
<sodipodi:namedview
stroke="#c4a000"
fill="#babdb6"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.25490196"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="27.543713"
inkscape:cy="25.106052"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:showpageshadow="false"
inkscape:window-width="833"
inkscape:window-height="772"
inkscape:window-x="1266"
inkscape:window-y="144"
inkscape:window-maximized="0" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:source>http://jimmac.musichall.cz</dc:source>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
<dc:title>New Appointment</dc:title>
<dc:subject>
<rdf:Bag>
<rdf:li>appointment</rdf:li>
<rdf:li>new</rdf:li>
<rdf:li>meeting</rdf:li>
<rdf:li>rvsp</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z"
sodipodi:ry="8.6620579"
sodipodi:rx="8.6620579"
sodipodi:cy="19.008621"
sodipodi:cx="31.112698"
id="path4318"
style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc"
transform="matrix(2.563158,0.000000,0.000000,1.219602,-55.98414,14.04144)" />
<path
sodipodi:nodetypes="cccc"
id="path14341"
d="M 18.587591,1.403729 L 4.226755,18.096665 L 5.4854717,19.339844 L 18.587591,1.403729 z "
style="color:#000000;fill:url(#linearGradient4307);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
<path
sodipodi:nodetypes="cccc"
id="path18921"
d="M 18.467176,1.3138035 L 5.6605716,19.072612 L 7.4900985,20.687913 L 18.467176,1.3138035 z "
style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
<path
transform="matrix(1.431529,0.000000,0.000000,1.431529,0.569459,-1.654618)"
d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
sodipodi:ry="14.910714"
sodipodi:rx="14.910714"
sodipodi:cy="16.910715"
sodipodi:cx="16.25"
id="path27786"
style="fill:url(#radialGradient5212);fill-opacity:1;fill-rule:evenodd;stroke:#605773;stroke-width:0.69855404;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:type="arc" />
<path
transform="matrix(1.163838,0.000000,0.000000,1.163838,4.824801,2.777556)"
d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
sodipodi:ry="14.910714"
sodipodi:rx="14.910714"
sodipodi:cy="16.910715"
sodipodi:cx="16.25"
id="path35549"
style="fill:url(#radialGradient4311);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4313);stroke-width:0.71139598;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="opacity:1;color:#000000;fill:url(#radialGradient5202);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5210);stroke-width:0.56498736;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
id="path4120"
sodipodi:cx="23.375"
sodipodi:cy="11.875"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
d="M 16.679382,6.6387137 A 8.5,8.5 0 0 1 23.332691,3.3751053 L 23.375,11.875 z"
transform="matrix(1.769951,0.000000,0.000000,1.769951,-17.02424,1.610741)"
sodipodi:start="3.8052902"
sodipodi:end="4.7074114" />
<path
transform="matrix(2.073295,0.000000,0.000000,2.073295,-7.310224,-13.13682)"
d="M 16.40625 17.28125 A 1.21875 1.21875 0 1 1 13.96875,17.28125 A 1.21875 1.21875 0 1 1 16.40625 17.28125 z"
sodipodi:ry="1.21875"
sodipodi:rx="1.21875"
sodipodi:cy="17.28125"
sodipodi:cx="15.1875"
id="path34778"
style="fill:#f3f3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.48232403;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="arc" />
<path
id="path35559"
d="M 22.176614,20.718014 L 13.155702,13.140282"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
id="path35561"
d="M 19.408614,29.776506 L 22.368655,25.283228"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:nodetypes="cc" />
<path
transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,-12.40939)"
d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
sodipodi:ry="0.61871845"
sodipodi:rx="0.61871845"
sodipodi:cy="7.6932044"
sodipodi:cx="16.705399"
id="path35563"
style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
sodipodi:type="arc" />
<path
transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,14.80922)"
d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
sodipodi:ry="0.61871845"
sodipodi:rx="0.61871845"
sodipodi:cy="7.6932044"
sodipodi:cx="16.705399"
id="path35565"
style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
sodipodi:type="arc" />
<path
transform="matrix(2.749493,0.000000,0.000000,2.749493,-35.91004,1.199890)"
d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
sodipodi:ry="0.61871845"
sodipodi:rx="0.61871845"
sodipodi:cy="7.6932044"
sodipodi:cx="16.705399"
id="path35567"
style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
sodipodi:type="arc" />
<path
transform="matrix(2.749493,0.000000,0.000000,2.749493,-8.691448,1.199890)"
d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
sodipodi:ry="0.61871845"
sodipodi:rx="0.61871845"
sodipodi:cy="7.6932044"
sodipodi:cx="16.705399"
id="path35569"
style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient4309);stroke-width:0.73656511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
id="path10651"
sodipodi:cx="16.25"
sodipodi:cy="16.910715"
sodipodi:rx="14.910714"
sodipodi:ry="14.910714"
d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
transform="matrix(1.357654,0.000000,0.000000,1.357654,1.769896,-0.493735)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="48px"
width="48px"
id="svg2"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Edit-check-sheet.svg"
inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Edit-check-sheet.png"
inkscape:export-xdpi="503.74228"
inkscape:export-ydpi="503.74228">
<metadata
id="metadata112">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview110"
showgrid="false"
inkscape:zoom="4.9166667"
inkscape:cx="24"
inkscape:cy="24"
inkscape:window-x="945"
inkscape:window-y="165"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<linearGradient
id="i"
y2="-.2"
gradientUnits="userSpaceOnUse"
y1="12.17"
x2="25.69"
x1="25.68">
<stop
stop-color="#fff"
offset="0"
id="stop7" />
<stop
stop-opacity="0"
stop-color="#fff"
offset="1"
id="stop9" />
</linearGradient>
<linearGradient
id="e"
x1="25.4"
xlink:href="#b"
gradientUnits="userSpaceOnUse"
y1="3.82"
gradientTransform="matrix(1 0 0 .884-.63.84)"
x2="25.46"
y2="9.32" />
<linearGradient
id="h"
x1="33.4"
xlink:href="#i"
gradientUnits="userSpaceOnUse"
x2="34.2"
y1="36.92"
y2="38.1" />
<linearGradient
id="f"
xlink:href="#b"
gradientUnits="userSpaceOnUse"
y1="3.82"
gradientTransform="matrix(.539 0 0 .512 10.8-.58)"
x2="0"
y2="6.48" />
<linearGradient
id="g"
x1="26.1"
xlink:href="#i"
gradientUnits="userSpaceOnUse"
x2="30.81"
y1="26.7"
y2="42" />
<linearGradient
id="j"
y2="37.77"
gradientUnits="userSpaceOnUse"
y1="40.46"
x2="33.66"
x1="36">
<stop
stop-color="#7c7c7c"
offset="0"
id="stop16" />
<stop
stop-color="#b8b8b8"
offset="1"
id="stop18" />
</linearGradient>
<linearGradient
id="b">
<stop
stop-color="#97978a"
offset="0"
id="stop21" />
<stop
stop-color="#c2c2b9"
offset=".5"
id="stop23" />
<stop
stop-color="#7d7d6f"
offset="1"
id="stop25" />
</linearGradient>
<linearGradient
id="n"
y2="37.88"
gradientUnits="userSpaceOnUse"
y1="10.45"
x2="33.86"
x1="6.11">
<stop
stop-color="#c68827"
offset="0"
id="stop28" />
<stop
stop-color="#89601f"
offset="1"
id="stop30" />
</linearGradient>
<linearGradient
id="k"
y2="42.1"
gradientUnits="userSpaceOnUse"
y1="39.2"
x2="39.1"
x1="36.81">
<stop
offset="0"
id="stop33" />
<stop
stop-opacity="0"
offset="1"
id="stop35" />
</linearGradient>
<linearGradient
id="m"
y2="39.5"
gradientUnits="userSpaceOnUse"
y1="18.99"
gradientTransform="matrix(1.066 0 0 .988-1.56.07)"
x2="35.79"
x1="22.31">
<stop
stop-color="#f0f0ef"
offset="0"
id="stop38" />
<stop
stop-color="#e8e8e8"
offset=".6"
id="stop40" />
<stop
stop-color="#fff"
offset=".83"
id="stop42" />
<stop
stop-color="#d8d8d3"
offset="1"
id="stop44" />
</linearGradient>
<linearGradient
id="l"
x1="25.4"
xlink:href="#b"
gradientUnits="userSpaceOnUse"
y1="3.82"
gradientTransform="matrix(1.053 0 0 1-1.79 0)"
x2="25.46"
y2="9.32" />
<radialGradient
id="d"
gradientUnits="userSpaceOnUse"
cy="45.3"
cx="24.65"
gradientTransform="matrix(1 0 0 .111 0 40.3)"
r="21">
<stop
stop-color="#646459"
offset="0"
id="stop48" />
<stop
stop-opacity="0"
stop-color="#646459"
offset="1"
id="stop50" />
</radialGradient>
</defs>
<path
fill="url(#d)"
d="m45.66 45.27a21.01 2.323 0 1 1 -42.02 0 21.01 2.323 0 1 1 42.02 0"
transform="matrix(.913 0 0 1.179 1.92-8.11)"
id="path52" />
<rect
rx="1.39"
height="41"
width="39"
stroke="#714c16"
y="4.5"
x="4.46"
fill="url(#n)"
id="rect54" />
<rect
rx=".57"
height="35.98"
width="30.95"
stroke="#888a85"
y="6.53"
x="8.53"
fill="url(#m)"
id="rect56" />
<rect
rx="1"
height="4"
width="12"
x="18"
fill="#5c5c5c"
id="rect58" />
<rect
id="a"
opacity=".4"
rx="1"
height="3.7"
width="3.7"
stroke="#2e3436"
y="14.4"
x="11.7"
stroke-width=".8"
fill="none" />
<use
y="6.48"
xlink:href="#a"
id="use61" />
<rect
opacity=".5"
rx="1"
height="5"
width="5"
stroke="#2e3436"
y="34.37"
x="11.64"
stroke-width=".8"
fill="none"
id="rect63" />
<use
y="12.96"
xlink:href="#a"
id="use65" />
<g
fill="none"
id="g67">
<path
stroke="url(#g)"
d="m9.52 7.47h29v34h-29z"
id="path69" />
<rect
rx=".5"
height="39.1"
width="37.1"
stroke="#c68827"
y="5.43"
x="5.44"
id="rect71" />
</g>
<rect
opacity=".11"
rx="1.39"
height="7"
width="18.95"
stroke="#000"
y="4.47"
x="14.79"
id="rect73" />
<rect
rx="1.39"
height="7"
width="18.95"
stroke="#5c5c5c"
y="3.5"
x="14.53"
fill="url(#l)"
id="rect75" />
<rect
rx=".33"
height="3.58"
width="9.7"
y="1.21"
x="19.1"
fill="url(#f)"
id="rect77" />
<rect
rx="1"
height="6.19"
width="18.1"
y="3.94"
x="14.95"
fill="url(#e)"
id="rect79" />
<path
opacity=".5"
d="m39 36.3l0.04 5.81-8.5-0.04 8.46-5.77"
fill="url(#k)"
id="path81" />
<path
stroke="#868a84"
d="m30.1 42.1c1.79 0.16 8.99-4.37 9.48-8.39-1.56 2.42-4.96 1.97-9.1 2.13 0 0 0.39 5.76-0.42 6.26z"
fill="url(#j)"
id="path83" />
<g
fill="none"
id="g85">
<path
opacity=".32"
stroke="url(#i)"
d="m19.47 1.47v0.03h-0.03v2.88c0 0.001 0.03 0.03 0.03 0.03v0.03h-3.59c-0.04 0-0.1 0.02-0.13 0.03-0.14 0.06-0.27 0.2-0.31 0.34-0.001 0.04 0 0.11 0 0.16v4.22c0 0.03 0.02 0.09 0.03 0.12 0.001 0.02 0.02 0.07 0.03 0.09 0 0.001 0.03 0.03 0.03 0.03 0.02 0.03 0.07 0.07 0.09 0.09 0.02 0.001 0.05 0.02 0.07 0.03 0.001 0.001 0.04 0.03 0.06 0.03 0.03 0.001 0.09 0.03 0.13 0.03h16.22c0.04-0.001 0.1-0.02 0.13-0.03 0.02-0.001 0.05-0.02 0.06-0.03 0.02-0.001 0.05-0.02 0.07-0.03l0.09-0.09c0-0.001 0.03-0.03 0.03-0.03 0.001-0.02 0.02-0.07 0.03-0.09 0.001-0.03 0.03-0.09 0.03-0.12v-4.22c0-0.04 0.001-0.12 0-0.16-0.04-0.14-0.17-0.29-0.31-0.34-0.03-0.001-0.09-0.03-0.13-0.03h-3.59v-0.03l0.03-0.03v-2.88h-0.03v-0.03h-9.03s-0.03 0-0.03 0z"
id="path87" />
<path
opacity=".37"
stroke="url(#h)"
d="m31.51 40.69c1.37-0.69 4.53-2.6 5.83-4.48-1.79 0.37-2.99 0.58-5.73 0.69 0 0 0.09 3-0.1 3.79z"
id="path89" />
</g>
<g
opacity=".17"
id="g91">
<path
d="m19.76 15h16.34v2h-16.34z"
id="path93" />
<path
d="m19.76 19h15.56v2h-15.56z"
id="path95" />
<path
d="m19.76 23h14v2h-14z"
id="path97" />
<path
d="m19.76 27h16.34v2h-16.34z"
id="path99" />
<path
d="m19.76 31h10.12v2h-10.12z"
id="path101" />
</g>
<path
id="c"
d="m18.57 28.81c3.909-6.26 4.744-6.495 9.012-11.93 1.32-1.47 5.119-5.149 6.888-4.447 1.351 0.537-0.8798 2.34-1.53 3.17-5.72 7.3-9.097 12.28-14.4 19.89-0.817 1.172-2.128 1.514-3.407 1.241-1.3-0.28-2.07-2.68-2.5-3.82-0.6404-1.7-2.255-3.821-2.254-5.641 0.0004468-1.47 0.7726-2.205 2.074-2.305 1.675-0.1285 2.298 2.19 2.789 3.557 0.93 2.58 1.13 3.81 3.33 0.29z"
transform="matrix(.292 0 0 .293 8.7 7.4)"
fill="#4e9a06" />
<use
y="6.46"
xlink:href="#c"
id="use104" />
<use
y="12.92"
xlink:href="#c"
id="use106" />
<use
xlink:href="#c"
transform="matrix(2.076 0 0 2.076 -13.72 1.792)"
stroke="#555753"
stroke-width=".3"
id="use108" />
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,999 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="Mail-send.svg"
inkscape:version="0.48.3.1 r9886"
sodipodi:version="0.32"
id="svg5816"
height="48px"
width="48px"
version="1.1"
inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/Mail-send.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs3">
<linearGradient
inkscape:collect="always"
id="linearGradient5476">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5478" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop5480" />
</linearGradient>
<linearGradient
id="linearGradient5464">
<stop
style="stop-color:#729fcf;stop-opacity:1;"
offset="0"
id="stop5466" />
<stop
style="stop-color:#afc9e4;stop-opacity:1;"
offset="1"
id="stop5468" />
</linearGradient>
<linearGradient
id="linearGradient2624">
<stop
id="stop2626"
offset="0"
style="stop-color:#dfe0df;stop-opacity:1;" />
<stop
style="stop-color:#a6b0a6;stop-opacity:1;"
offset="0.23809524"
id="stop2630" />
<stop
id="stop2628"
offset="1.0000000"
style="stop-color:#b5beb5;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2573">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2575" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2577" />
</linearGradient>
<linearGradient
id="linearGradient2274">
<stop
style="stop-color:#000000;stop-opacity:0.12871288;"
offset="0.0000000"
id="stop2276" />
<stop
style="stop-color:#000000;stop-opacity:0.0000000;"
offset="1.0000000"
id="stop2278" />
</linearGradient>
<linearGradient
id="linearGradient9749">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop9751" />
<stop
style="stop-color:#ededed;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop9753" />
</linearGradient>
<linearGradient
id="linearGradient15107">
<stop
style="stop-color:#ffffff;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop15109" />
<stop
style="stop-color:#e2e2e2;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop15111" />
</linearGradient>
<linearGradient
id="linearGradient10691"
inkscape:collect="always">
<stop
id="stop10693"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop10695"
offset="1"
style="stop-color:#000000;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient4274">
<stop
id="stop4276"
offset="0.0000000"
style="stop-color:#ffffff;stop-opacity:0.25490198;" />
<stop
id="stop4278"
offset="1.0000000"
style="stop-color:#ffffff;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2187">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2189" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2191" />
</linearGradient>
<linearGradient
id="linearGradient6901"
inkscape:collect="always">
<stop
id="stop6903"
offset="0"
style="stop-color:#3465a4;stop-opacity:1;" />
<stop
id="stop6905"
offset="1"
style="stop-color:#3465a4;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient6925"
inkscape:collect="always">
<stop
id="stop6927"
offset="0"
style="stop-color:#204a87;stop-opacity:1;" />
<stop
id="stop6929"
offset="1"
style="stop-color:#204a87;stop-opacity:0;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6901"
id="linearGradient2562"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,1,-1,0,37.07553,-5.879343)"
x1="15.193591"
y1="15.028743"
x2="12.252101"
y2="30.55784" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6925"
id="linearGradient2564"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,1,-1,0,37.07553,-5.879343)"
x1="10.791593"
y1="23.332331"
x2="10.112462"
y2="27.145725" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2187"
id="linearGradient2566"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.412791e-16,0.914114,-0.914114,-1.412791e-16,39.78243,-9.748047)"
x1="41.093174"
y1="16.612858"
x2="16.588747"
y2="29.698416" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4274"
id="linearGradient2365"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,1,-1,0,37.07553,-5.879343)"
x1="26.577936"
y1="7.7850504"
x2="38.129341"
y2="12.765438" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10691"
id="radialGradient1481"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(1.902215,0.525703)"
cx="6.7027131"
cy="73.615714"
fx="6.7027131"
fy="73.615714"
r="7.2284161" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient1483"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.357669,0,0,1.505846,2.84291,-2.266018)"
x1="11.572842"
y1="4.7461626"
x2="18.475286"
y2="26.022910" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2624"
id="linearGradient1487"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.454781,0,0,0.762004,2.88175,0.337386)"
x1="9.1643066"
y1="38.070892"
x2="9.8855038"
y2="52.090679" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2274"
id="radialGradient1491"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.629929,0.459373,-0.147675,0.248512,16.51724,9.053737)"
cx="27.741131"
cy="38.711506"
fx="27.741131"
fy="38.711506"
r="17.977943" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient1493"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.276531,0,0,-1.406115,24.24763,33.3374)"
x1="11.74217"
y1="11.48487"
x2="13.846983"
y2="11.981981" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient1497"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.296015,0,0,-1.43692,3.746576,33.20516)"
x1="11.74217"
y1="11.48487"
x2="13.846983"
y2="11.981981" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient1501"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.570607,0,0,-1.231511,2.973436,33.33485)"
x1="10.027"
y1="20.219761"
x2="17.178024"
y2="-7.5274644" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient9749"
id="linearGradient1503"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.370928,0,0,-1.46456,2.525057,33.71269)"
x1="11.841544"
y1="4.2507305"
x2="40.024059"
y2="7.4121075" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2573"
id="linearGradient1505"
gradientUnits="userSpaceOnUse"
x1="17.397203"
y1="33.357376"
x2="22.17771"
y2="31.026741" />
<radialGradient
r="13.565360"
fy="19.836468"
fx="16.214741"
cy="19.836468"
cx="16.214741"
gradientTransform="matrix(1,0,0,0.681917,-1.105561e-15,8.233773)"
gradientUnits="userSpaceOnUse"
id="radialGradient1381"
xlink:href="#linearGradient4344"
inkscape:collect="always" />
<linearGradient
y2="35.803486"
x2="30.935921"
y1="29.553486"
x1="30.935921"
gradientTransform="translate(-12.41789,-7)"
gradientUnits="userSpaceOnUse"
id="linearGradient1372"
xlink:href="#linearGradient3824"
inkscape:collect="always" />
<linearGradient
y2="36.217758"
x2="22.626925"
y1="35.817974"
x1="20.661695"
gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,-7.07212,-9.82492)"
gradientUnits="userSpaceOnUse"
id="linearGradient1369"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<linearGradient
y2="35.739632"
x2="21.408455"
y1="36.390400"
x1="22.686766"
gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,41.80576,-11.11866)"
gradientUnits="userSpaceOnUse"
id="linearGradient1366"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<linearGradient
y2="35.739632"
x2="21.408455"
y1="36.390400"
x1="22.686766"
gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,41.80576,-11.11866)"
gradientUnits="userSpaceOnUse"
id="linearGradient4374"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<linearGradient
y2="36.217758"
x2="22.626925"
y1="35.817974"
x1="20.661695"
gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,-7.072120,-9.824920)"
gradientUnits="userSpaceOnUse"
id="linearGradient4372"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(-0.977685,0.210075,0.210075,0.977685,55.1096,-3.945209)"
y2="35.739632"
x2="21.408455"
y1="36.390400"
x1="22.686766"
gradientUnits="userSpaceOnUse"
id="linearGradient4366"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(0.983375,0.181588,-0.181588,0.983375,6.231716,-2.651466)"
gradientUnits="userSpaceOnUse"
y2="36.217758"
x2="22.626925"
y1="35.817974"
x1="20.661695"
id="linearGradient4362"
xlink:href="#linearGradient4356"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.681917,0.000000,8.233773)"
r="13.565360"
fy="19.836468"
fx="16.214741"
cy="19.836468"
cx="16.214741"
id="radialGradient4350"
xlink:href="#linearGradient4344"
inkscape:collect="always" />
<radialGradient
r="8.6620579"
fy="19.008621"
fx="31.112698"
cy="19.008621"
cx="31.112698"
gradientUnits="userSpaceOnUse"
id="radialGradient4336"
xlink:href="#linearGradient3816"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(-13.12500,-7.000000)"
y2="35.803486"
x2="30.935921"
y1="29.553486"
x1="30.935921"
gradientUnits="userSpaceOnUse"
id="linearGradient4332"
xlink:href="#linearGradient3824"
inkscape:collect="always" />
<radialGradient
r="8.6620579"
fy="19.008621"
fx="31.112698"
cy="19.008621"
cx="31.112698"
gradientUnits="userSpaceOnUse"
id="radialGradient4330"
xlink:href="#linearGradient3816"
inkscape:collect="always" />
<radialGradient
r="9.1620579"
fy="17.064077"
fx="29.344931"
cy="17.064077"
cx="29.344931"
gradientTransform="matrix(0.787998,3.877637e-16,-3.877637e-16,0.787998,6.221198,3.617627)"
gradientUnits="userSpaceOnUse"
id="radialGradient4328"
xlink:href="#linearGradient4338"
inkscape:collect="always" />
<linearGradient
y2="35.803486"
x2="30.935921"
y1="29.553486"
x1="30.935921"
gradientTransform="translate(-12.41789,-7.000000)"
gradientUnits="userSpaceOnUse"
id="linearGradient4326"
xlink:href="#linearGradient3824"
inkscape:collect="always" />
<radialGradient
r="8.6620579"
fy="19.008621"
fx="31.112698"
cy="19.008621"
cx="31.112698"
gradientUnits="userSpaceOnUse"
id="radialGradient4179"
xlink:href="#linearGradient3816"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(0.707108,0.000000)"
y2="35.803486"
x2="30.935921"
y1="29.553486"
x1="30.935921"
gradientUnits="userSpaceOnUse"
id="linearGradient4175"
xlink:href="#linearGradient3824"
inkscape:collect="always" />
<radialGradient
gradientTransform="matrix(0.787998,3.877637e-16,-3.877637e-16,0.787998,6.221198,3.617627)"
r="9.1620579"
fy="17.064077"
fx="29.344931"
cy="17.064077"
cx="29.344931"
gradientUnits="userSpaceOnUse"
id="radialGradient4171"
xlink:href="#linearGradient3800"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.297564,2.881172e-16,-1.96472e-16,0.884831,-8.358505,4.940469)"
r="13.565360"
fy="27.203083"
fx="28.089741"
cy="27.203083"
cx="28.089741"
id="radialGradient4169"
xlink:href="#linearGradient4163"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="35.803486"
x2="30.935921"
y1="29.553486"
x1="30.935921"
id="linearGradient3830"
xlink:href="#linearGradient3824"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
r="8.6620579"
fy="19.008621"
fx="31.112698"
cy="19.008621"
cx="31.112698"
id="radialGradient3822"
xlink:href="#linearGradient3816"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
r="9.1620579"
fy="17.064077"
fx="29.344931"
cy="17.064077"
cx="29.344931"
id="radialGradient3806"
xlink:href="#linearGradient3800"
inkscape:collect="always" />
<linearGradient
id="linearGradient3800">
<stop
id="stop3802"
offset="0.0000000"
style="stop-color:#f4d9b1;stop-opacity:1.0000000;" />
<stop
id="stop3804"
offset="1.0000000"
style="stop-color:#df9725;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient3816"
inkscape:collect="always">
<stop
id="stop3818"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop3820"
offset="1"
style="stop-color:#000000;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient3824">
<stop
id="stop3826"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop3828"
offset="1.0000000"
style="stop-color:#c9c9c9;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient4163">
<stop
id="stop4165"
offset="0.0000000"
style="stop-color:#3b74bc;stop-opacity:1.0000000;" />
<stop
id="stop4167"
offset="1.0000000"
style="stop-color:#2d5990;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient4338">
<stop
style="stop-color:#e9b15e;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop4340" />
<stop
style="stop-color:#966416;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop4342" />
</linearGradient>
<linearGradient
id="linearGradient4344">
<stop
id="stop4346"
offset="0"
style="stop-color:#727e0a;stop-opacity:1;" />
<stop
id="stop4348"
offset="1.0000000"
style="stop-color:#5b6508;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient4356"
inkscape:collect="always">
<stop
id="stop4358"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop4360"
offset="1"
style="stop-color:#000000;stop-opacity:0;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5464"
id="linearGradient5472"
gradientUnits="userSpaceOnUse"
x1="21.587093"
y1="23.499001"
x2="21.587093"
y2="2.8163671"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5476"
id="linearGradient5482"
x1="25.950134"
y1="2.8703361"
x2="29.477814"
y2="46.06208"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5476"
id="linearGradient5486"
gradientUnits="userSpaceOnUse"
x1="25.950134"
y1="2.8703361"
x2="29.477814"
y2="46.06208"
gradientTransform="matrix(-0.901805,0.210818,-0.211618,-0.898788,63.54132,37.87423)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient5506"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.357669,0,0,1.505846,2.84291,-2.266018)"
x1="11.572842"
y1="4.7461626"
x2="18.475286"
y2="26.022910" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2624"
id="linearGradient5508"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.454781,0,0,0.762004,2.88175,0.337386)"
x1="9.1643066"
y1="38.070892"
x2="9.8855038"
y2="52.090679" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2274"
id="radialGradient5510"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.629929,0.459373,-0.147675,0.248512,16.51724,9.053737)"
cx="27.741131"
cy="38.711506"
fx="27.741131"
fy="38.711506"
r="17.977943" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient5512"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.296015,0,0,-1.43692,3.746576,33.20516)"
x1="11.74217"
y1="11.48487"
x2="13.846983"
y2="11.981981" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient15107"
id="linearGradient5514"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.570607,0,0,-1.231511,2.973436,33.33485)"
x1="10.027"
y1="20.219761"
x2="17.178024"
y2="-7.5274644" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient9749"
id="linearGradient5516"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.370928,0,0,-1.46456,2.525057,33.71269)"
x1="11.841544"
y1="4.2507305"
x2="40.024059"
y2="7.4121075" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2573"
id="linearGradient5518"
gradientUnits="userSpaceOnUse"
x1="17.397203"
y1="33.357376"
x2="22.17771"
y2="31.026741" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5476"
id="linearGradient5528"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.901805,0.210818,-0.211618,-0.898788,63.54132,37.87423)"
x1="25.950134"
y1="2.8703361"
x2="29.477814"
y2="46.06208" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5464"
id="linearGradient5530"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)"
x1="21.587093"
y1="23.499001"
x2="21.587093"
y2="2.8163671" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5476"
id="linearGradient5532"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)"
x1="25.950134"
y1="2.8703361"
x2="29.477814"
y2="46.06208" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5464"
id="linearGradient3297"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)"
x1="21.587093"
y1="23.499001"
x2="21.587093"
y2="2.8163671" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5476"
id="linearGradient3299"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.106909,-0.258404,0.259748,1.101665,-19.66697,12.19788)"
x1="25.950134"
y1="2.8703361"
x2="29.477814"
y2="46.06208" />
</defs>
<sodipodi:namedview
inkscape:window-y="27"
inkscape:window-x="0"
inkscape:window-height="1024"
inkscape:window-width="1920"
inkscape:document-units="px"
inkscape:grid-bbox="true"
showgrid="false"
inkscape:current-layer="layer1"
inkscape:cy="-14.347029"
inkscape:cx="38.533427"
inkscape:zoom="1.4142136"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="0.16862745"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:grid-points="true"
gridtolerance="2"
inkscape:object-bbox="false"
inkscape:object-points="false"
objecttolerance="2.8"
guidetolerance="2"
showguides="true"
inkscape:guide-bbox="true"
inkscape:showpageshadow="false"
inkscape:object-paths="false"
inkscape:has_abs_tolerance="false"
inkscape:window-maximized="1">
<inkscape:grid
id="GridFromPre046Settings"
type="xygrid"
originx="0px"
originy="0px"
spacingx="1px"
spacingy="1px"
color="#3f3fff"
empcolor="#3f3fff"
opacity="0.15"
empopacity="0.38"
empspacing="2" />
</sodipodi:namedview>
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Send and Receive Mail</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>Andreas Nilsson, Garrett LeSage</dc:title>
</cc:Agent>
</dc:contributor>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
<dc:subject>
<rdf:Bag>
<rdf:li>mail</rdf:li>
<rdf:li>e-mail</rdf:li>
<rdf:li>send</rdf:li>
<rdf:li>receive</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
inkscape:label="Layer 1"
id="layer1">
<path
sodipodi:type="arc"
style="opacity:0.3;color:#000000;fill:url(#radialGradient1481);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;visibility:visible;display:inline;overflow:visible"
id="path10699"
sodipodi:cx="12.75"
sodipodi:cy="38.700001"
sodipodi:rx="13.75"
sodipodi:ry="3.8"
d="m 26.5,38.700001 a 13.75,3.8 0 1 1 -27.5,0 13.75,3.8 0 1 1 27.5,0 z"
transform="matrix(1.66707,0,0,1.5930485,5.3581929,-22.843871)"
inkscape:r_cx="true"
inkscape:r_cy="true" />
<g
id="g2570"
transform="matrix(0.7571799,0,0,0.75599508,14.45706,-1.0815005)"
inkscape:r_cx="true"
inkscape:r_cy="true">
<path
id="path12723"
d="m 6.3437483,15.454879 0,25.987281 37.3593247,0 -0.06316,-25.887713 c -1.3e-5,-0.0057 3.78e-4,-0.02709 0,-0.03319 -7.39e-4,-0.0065 0.0011,-0.02633 0,-0.03319 -0.0015,-0.0072 -0.02977,-0.02558 -0.03158,-0.03319 l -37.2645847,0 z"
style="fill:url(#linearGradient1483);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.37973988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccccc"
id="path1634"
d="M 20.490674,29.058712 7.09471,40.0307 l 13.908842,-9.604306 9.018158,0 12.419047,9.482193 -11.863425,-10.849875 -10.086658,0 z"
style="fill:url(#linearGradient1487);fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
id="path15103"
d="m 7.5310575,16.733861 c -0.00667,0.01319 0.00537,0.01943 0,0.03125 -0.00236,0.0056 -0.029093,0.02604 -0.031121,0.03125 -0.0017,0.0049 0.00136,0.02674 0,0.03125 -0.00102,0.0041 6.829e-4,0.02747 0,0.03125 l 0.031121,23.217159 34.7933665,0 -0.06224,-23.092168 c -6.84e-4,-0.0037 0.001,-0.02721 0,-0.03125 -0.0146,-0.04755 -0.04166,-0.130713 -0.09336,-0.218735 l -34.6377615,0 z"
style="fill:none;stroke:#ffffff;stroke-width:1.37974012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
id="path2563"
d="M 23.329298,32.996721 C 20.937189,32.550375 7.9003872,18.771125 6.5966059,16.372022 6.5816495,16.343448 6.5559705,16.288608 6.5446896,16.2636 l 34.5131134,0 c -0.277079,2.502804 -7.524227,16.505746 -9.561279,16.733121 -0.0082,4.68e-4 -0.02128,0 -0.02927,0 l -8.020859,0 c -0.03363,0 -0.07755,0.0074 -0.117094,0 z"
style="fill:url(#radialGradient1491);fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
id="path1613"
d="M 20.77475,31.085394 C 18.407309,30.694257 7.945269,18.619435 7.1185841,16.517089 7.109327,16.49205 7.094677,16.443993 7.088438,16.422079 l 35.542207,0 c -0.823616,2.19322 -11.29845,14.464065 -13.445143,14.663315 -0.0085,4.09e-4 -0.02191,0 -0.03015,0 l -8.260021,0 c -0.03463,0 -0.08145,0.0065 -0.120584,0 z"
style="fill:url(#linearGradient1497);fill-opacity:1;fill-rule:evenodd;stroke:#989898;stroke-width:1.18189096;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
id="path18153"
d="M 20.625174,30.490479 C 18.519211,29.999928 7.7224803,17.987711 7.0314243,16.466377 c -0.00254,-0.006 0.00218,-0.02669 0,-0.03231 -0.00545,-0.01576 -0.029096,-0.0523 -0.03125,-0.06463 2.87e-5,-0.0033 -4.061e-4,-0.02938 0,-0.03231 0.00117,-0.0021 0.029695,0.0017 0.03125,0 l 0.09375,-0.09694 35.4687497,0 c -0.0027,0.02433 -0.02268,0.06687 -0.03125,0.09694 -0.0075,0.0236 -0.02057,0.07023 -0.03125,0.09694 -0.922098,2.180937 -11.507988,13.766449 -13.34375,14.056416 -0.01493,0.0016 -0.04885,0 -0.0625,0 l -8.375,0 c -0.03029,-0.0017 -0.08975,0.0082 -0.125,0 z"
style="fill:url(#linearGradient1501);fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
id="path1616"
d="M 20.875174,30.051141 C 18.427215,29.501671 8.7040003,18.433898 7.5314243,16.451725 l 34.5937497,0 c -1.490188,2.333171 -11.046672,13.411791 -13.15625,13.599416 -0.0087,4.02e-4 -0.02278,0 -0.03125,0 l -7.90625,0 c -0.02639,0 -0.06488,0.0036 -0.09375,0 -0.01979,-0.0031 -0.04165,0.0047 -0.0625,0 z"
style="fill:none;stroke:url(#linearGradient1503);stroke-width:1.18189073;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccccc"
id="path1636"
d="m 20.959511,30.447113 -11.941499,8.270856 2.219433,0.0061 9.998125,-6.86894 8.821908,-1.422838 -9.097967,0.01482 z"
style="fill:url(#linearGradient1505);fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
</g>
<g
inkscape:r_cy="true"
inkscape:r_cx="true"
transform="matrix(0.7571799,0,0,0.75599508,4.1230464,8.5143759)"
id="g5488">
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#linearGradient5506);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.37973988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 6.3437483,15.454879 0,25.987281 37.3593247,0 -0.06316,-25.887713 c -1.3e-5,-0.0057 3.78e-4,-0.02709 0,-0.03319 -7.39e-4,-0.0065 0.0011,-0.02633 0,-0.03319 -0.0015,-0.0072 -0.02977,-0.02558 -0.03158,-0.03319 l -37.2645847,0 z"
id="path5490"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#linearGradient5508);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="M 20.490674,29.058712 7.09471,40.0307 l 13.908842,-9.604306 9.018158,0 12.419047,9.482193 -11.863425,-10.849875 -10.086658,0 z"
id="path5492"
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:none;stroke:#ffffff;stroke-width:1.37974012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 7.5310575,16.733861 c -0.00667,0.01319 0.00537,0.01943 0,0.03125 -0.00236,0.0056 -0.029093,0.02604 -0.031121,0.03125 -0.0017,0.0049 0.00136,0.02674 0,0.03125 -0.00102,0.0041 6.829e-4,0.02747 0,0.03125 l 0.031121,23.217159 34.7933665,0 -0.06224,-23.092168 c -6.84e-4,-0.0037 0.001,-0.02721 0,-0.03125 -0.0146,-0.04755 -0.04166,-0.130713 -0.09336,-0.218735 l -34.6377615,0 z"
id="path5494"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#radialGradient5510);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="M 23.329298,32.996721 C 20.937189,32.550375 7.9003872,18.771125 6.5966059,16.372022 6.5816495,16.343448 6.5559705,16.288608 6.5446896,16.2636 l 34.5131134,0 c -0.277079,2.502804 -7.524227,16.505746 -9.561279,16.733121 -0.0082,4.68e-4 -0.02128,0 -0.02927,0 l -8.020859,0 c -0.03363,0 -0.07755,0.0074 -0.117094,0 z"
id="path5496"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#linearGradient5512);fill-opacity:1;fill-rule:evenodd;stroke:#989898;stroke-width:1.18189096;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
d="M 20.77475,31.085394 C 18.407309,30.694257 7.945269,18.619435 7.1185841,16.517089 7.109327,16.49205 7.094677,16.443993 7.088438,16.422079 l 35.542207,0 c -0.823616,2.19322 -11.29845,14.464065 -13.445143,14.663315 -0.0085,4.09e-4 -0.02191,0 -0.03015,0 l -8.260021,0 c -0.03463,0 -0.08145,0.0065 -0.120584,0 z"
id="path5498"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#linearGradient5514);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="M 20.625174,30.490479 C 18.519211,29.999928 7.7224803,17.987711 7.0314243,16.466377 c -0.00254,-0.006 0.00218,-0.02669 0,-0.03231 -0.00545,-0.01576 -0.029096,-0.0523 -0.03125,-0.06463 2.87e-5,-0.0033 -4.061e-4,-0.02938 0,-0.03231 0.00117,-0.0021 0.029695,0.0017 0.03125,0 l 0.09375,-0.09694 35.4687497,0 c -0.0027,0.02433 -0.02268,0.06687 -0.03125,0.09694 -0.0075,0.0236 -0.02057,0.07023 -0.03125,0.09694 -0.922098,2.180937 -11.507988,13.766449 -13.34375,14.056416 -0.01493,0.0016 -0.04885,0 -0.0625,0 l -8.375,0 c -0.03029,-0.0017 -0.08975,0.0082 -0.125,0 z"
id="path5500"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:none;stroke:url(#linearGradient5516);stroke-width:1.18189073;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
d="M 20.875174,30.051141 C 18.427215,29.501671 8.7040003,18.433898 7.5314243,16.451725 l 34.5937497,0 c -1.490188,2.333171 -11.046672,13.411791 -13.15625,13.599416 -0.0087,4.02e-4 -0.02278,0 -0.03125,0 l -7.90625,0 c -0.02639,0 -0.06488,0.0036 -0.09375,0 -0.01979,-0.0031 -0.04165,0.0047 -0.0625,0 z"
id="path5502"
inkscape:connector-curvature="0" />
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="fill:url(#linearGradient5518);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 20.959511,30.447113 -11.941499,8.270856 2.219433,0.0061 9.998125,-6.86894 8.821908,-1.422838 -9.097967,0.01482 z"
id="path5504"
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0" />
</g>
<g
id="g5524"
inkscape:r_cx="true"
inkscape:r_cy="true"
transform="matrix(1.0358731,0.12915398,-0.12915398,1.0358731,3.4793879,-8.4319748)">
<path
sodipodi:nodetypes="cccccccc"
inkscape:r_cy="true"
inkscape:r_cx="true"
id="path4587"
d="M 1.349542,35.242012 7.245074,40.036876 20.092052,24.392047 24.022407,27.588624 30.349935,5.1150928 10.266168,16.400607 14.19652,19.597183 z"
style="color:#000000;fill:url(#linearGradient3297);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999911;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
<path
style="opacity:0.57142861;color:#000000;fill:none;stroke:url(#linearGradient3299);stroke-width:0.99999946;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
d="m 2.982173,35.037884 4.072772,3.399631 12.855565,-15.699276 3.510841,2.868302 4.811841,-17.6344247 -16.088989,8.4894697 3.680552,2.931418 z"
id="path5474"
inkscape:r_cx="true"
inkscape:r_cy="true"
sodipodi:nodetypes="cccccccc"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,242 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48px"
height="48px"
id="svg1717"
sodipodi:version="0.32"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="Multimedia-volume-control.svg"
version="1.1"
inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Multimedia-volume-control.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs1719">
<linearGradient
inkscape:collect="always"
id="linearGradient2335">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2337" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2339" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2327">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2329" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2331" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3574">
<stop
style="stop-color:#3465a4;stop-opacity:1;"
offset="0"
id="stop3576" />
<stop
style="stop-color:#3465a4;stop-opacity:0;"
offset="1"
id="stop3578" />
</linearGradient>
<linearGradient
id="linearGradient3566">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop3568" />
<stop
style="stop-color:#a6ae9d;stop-opacity:1;"
offset="1"
id="stop3570" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3558">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3560" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3562" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3558"
id="radialGradient3564"
cx="22.571428"
cy="30.857143"
fx="22.571428"
fy="30.857143"
r="15.571428"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.651376,3.763482e-15,10.75754)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3566"
id="linearGradient3572"
x1="19.544102"
y1="22.640625"
x2="36.0625"
y2="22.640625"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.184060,0.000000,0.000000,1.184060,-5.942398,-5.052390)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3574"
id="linearGradient3580"
x1="22.031542"
y1="22.78162"
x2="20.71196"
y2="4.7503953"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.184060,0.000000,0.000000,1.184060,-5.942398,-5.052390)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2327"
id="linearGradient2333"
x1="17.525631"
y1="20.396902"
x2="33.474358"
y2="15.271904"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.184060,0.000000,0.000000,1.184060,-5.942398,-4.319792)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2335"
id="linearGradient2341"
x1="23.9375"
y1="18.725033"
x2="23.9375"
y2="16.847691"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.184060,0.000000,0.000000,1.184060,-5.942398,-4.319792)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.12156863"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="35.22146"
inkscape:cy="15.407751"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:showpageshadow="false"
fill="#3465a4"
stroke="#888a85"
inkscape:window-width="737"
inkscape:window-height="669"
inkscape:window-x="697"
inkscape:window-y="181"
inkscape:window-maximized="0" />
<metadata
id="metadata1722">
<rdf:RDF>
<cc:Work
rdf:about="">
<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/by-sa/2.0/" />
<dc:title>Volume Control</dc:title>
<dc:subject>
<rdf:Bag>
<rdf:li>multimedia</rdf:li>
<rdf:li>sound</rdf:li>
<rdf:li>volume</rdf:li>
<rdf:li>knob</rdf:li>
<rdf:li>control</rdf:li>
<rdf:li>mixer</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:creator>
<dc:source>http://jimmac.musichall.cz</dc:source>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="opacity:1;color:#000000;fill:url(#linearGradient3580);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:1 1 ;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M 3.5532403,33.393643 C -5.5596849,21.573975 6.9131063,9.4946328 20.952673,9.8329353 C 34.99224,10.171238 45.099036,15.118916 47.467155,27.805271 C 47.467155,27.805271 39.728479,27.086378 39.728479,27.086378 C 39.728479,19.305413 32.804297,15.24578 21.121824,15.24578 C 9.107311,15.24578 -2.6269476,18.34756 3.5532403,33.393643 z "
id="path2664"
sodipodi:nodetypes="cscczc" />
<path
sodipodi:type="arc"
style="opacity:0.47368421;color:#000000;fill:url(#radialGradient3564);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
id="path3556"
sodipodi:cx="22.571428"
sodipodi:cy="30.857143"
sodipodi:rx="15.571428"
sodipodi:ry="10.142858"
d="M 38.142857 30.857143 A 15.571428 10.142858 0 1 1 7,30.857143 A 15.571428 10.142858 0 1 1 38.142857 30.857143 z"
transform="matrix(1.408115,0.000000,0.000000,1.408115,-10.54085,-16.32385)" />
<path
style="opacity:1;color:#000000;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:1 1 ;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M 39.390175,28.439589 C 39.390175,28.439589 38.882722,30.638557 38.290692,31.399738 L 46.832838,37.235461 C 47.847746,34.021585 47.509443,29.7928 47.509443,29.7928 L 39.390175,28.439589 z "
id="path3539"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:1;color:#000000;fill:url(#linearGradient3572);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M 20.883958,6.1221749 C 13.55429,6.1221749 7.6002852,10.219577 7.6002852,15.261641 C 7.6002852,16.855622 5.2321652,23.956925 5.2321652,26.732222 C 5.2321652,32.609278 12.155451,37.388761 20.698949,37.388762 C 29.242446,37.388762 36.165734,32.609276 36.165733,26.732222 C 36.165733,24.022217 34.13063,15.261641 34.13063,15.261641 L 33.982622,8.1572805 L 29.690405,8.5272993 C 27.34265,7.0620706 24.305772,6.1221749 20.883958,6.1221749 z "
id="path3541"
sodipodi:nodetypes="csssssccc" />
<path
style="opacity:0.73684208;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2341);stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
d="M 20.698949,6.6031993 C 14.047951,6.6031993 8.636338,10.051187 8.636338,14.299592 C 8.636338,18.547995 14.047951,21.995982 20.698949,21.995982 C 27.349947,21.995982 32.761559,18.547995 32.76156,14.299592 C 32.76156,13.51384 32.401598,12.793721 32.058525,12.079479 L 33.316588,8.8233143 L 29.653403,9.3043386 C 27.444179,7.6893945 24.31762,6.6031994 20.698949,6.6031993 z "
id="path3545" />
<path
sodipodi:nodetypes="csssssccc"
id="path1452"
d="M 20.87031,7.2748571 C 14.081079,7.2748571 8.5660815,11.070145 8.5660815,15.740442 C 8.5660815,17.216895 6.3725701,23.794597 6.3725701,26.365264 C 6.3725701,31.808986 12.785381,36.236064 20.698941,36.236065 C 28.6125,36.236065 35.025314,31.808986 35.025312,26.365264 C 35.025312,23.855076 33.140264,15.740442 33.140264,15.740442 L 33.003169,9.1599082 L 29.02743,9.5026438 C 26.852782,8.1454517 24.039823,7.2748571 20.87031,7.2748571 z "
style="opacity:0.47368421;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2333);stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB