diff --git a/accounts/templates/login.html b/accounts/templates/login.html index c3ca001..c55a07a 100644 --- a/accounts/templates/login.html +++ b/accounts/templates/login.html @@ -17,7 +17,7 @@

{% trans "Sign In" %}

- + diff --git a/computes/templates/overview.html b/computes/templates/overview.html index 34e68c5..88f6f2f 100644 --- a/computes/templates/overview.html +++ b/computes/templates/overview.html @@ -11,6 +11,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -20,6 +23,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/computes/urls.py b/computes/urls.py index 58a0497..352b156 100644 --- a/computes/urls.py +++ b/computes/urls.py @@ -1,9 +1,26 @@ from django.conf.urls import url -from . import views +from storages.views import storages, storage +from networks.views import networks, network +from secrets.views import secrets +from create.views import create_instance +from interfaces.views import interfaces, interface +from computes.views import overview, compute_graph, computes +from instances.views import instances +from nwfilters.views import nwfilter, nwfilters urlpatterns = [ - url(r'^$', views.computes, name='computes'), - url(r'^overview/(?P[0-9]+)/$', views.overview, name='overview'), - url(r'^statistics/(?P[0-9]+)/$', - views.compute_graph, name='compute_graph'), + url(r'^/', computes, name='computes'), + url(r'^(?P[0-9]+)/$', overview, name='overview'), + url(r'^(?P[0-9]+)/statistics$', compute_graph, name='compute_graph'), + url(r'^(?P[0-9]+)/instances/$', instances, name='instances'), + url(r'^(?P[0-9]+)/storages/$', storages, name='storages'), + url(r'^(?P[0-9]+)/storage/(?P[\w\-\.\/]+)/$', storage, name='storage'), + url(r'^(?P[0-9]+)/networks/$', networks, name='networks'), + url(r'^(?P[0-9]+)/network/(?P[\w\-\.]+)/$', network, name='network'), + url(r'^(?P[0-9]+)/interfaces/$', interfaces, name='interfaces'), + url(r'^(?P[0-9]+)/interface/(?P[\w\-\.\:]+)/$', interface, name='interface'), + url(r'^(?P[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), + url(r'^(?P[0-9]+)/nwfilter/(?P[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), + url(r'^(?P[0-9]+)/secrets/$', secrets, name='secrets'), + url(r'^(?P[0-9]+)/create/$', create_instance, name='create_instance'), ] diff --git a/create/forms.py b/create/forms.py index 0f208ce..d1e5bf0 100644 --- a/create/forms.py +++ b/create/forms.py @@ -38,6 +38,7 @@ class NewVMForm(forms.Form): disk = forms.IntegerField(required=False) memory = forms.IntegerField(error_messages={'required': _('No RAM size has been entered')}) networks = forms.CharField(error_messages={'required': _('No Network pool has been choice')}) + nwfilter = forms.CharField(required=False) storage = forms.CharField(max_length=20, required=False) template = forms.CharField(required=False) images = forms.CharField(required=False) diff --git a/create/templates/create_instance.html b/create/templates/create_instance.html index 88b5fbe..8b741f2 100644 --- a/create/templates/create_instance.html +++ b/create/templates/create_instance.html @@ -107,6 +107,17 @@ {% endfor %} + +
    + +
    + +
    @@ -226,6 +237,17 @@
    +
    + +
    + +
    +
    @@ -379,6 +401,17 @@
    +
    + +
    + +
    +
    diff --git a/create/views.py b/create/views.py index 0c39a1d..2cacdc4 100644 --- a/create/views.py +++ b/create/views.py @@ -28,7 +28,6 @@ def create_instance(request, compute_id): storages = [] networks = [] meta_prealloc = False - #computes = Compute.objects.all() compute = get_object_or_404(Compute, pk=compute_id) flavors = Flavor.objects.filter().order_by('id') @@ -40,6 +39,7 @@ def create_instance(request, compute_id): storages = sorted(conn.get_storages(only_actives=True)) networks = sorted(conn.get_networks()) + nwfilters = conn.get_nwfilters() instances = conn.get_instances() videos = conn.get_video() cache_modes = sorted(conn.get_cache_modes().items()) @@ -139,11 +139,11 @@ def create_instance(request, compute_id): try: conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'], uuid, volumes, data['cache_mode'], data['networks'], data['virtio'], - data["listener_addr"], None, data["video"], data["console_pass"], + data["listener_addr"], data["nwfilter"], data["video"], data["console_pass"], data['mac']) create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid) create_instance.save() - messages.success(request,"Instance is created.") + messages.success(request, _("Instance is created.")) return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']])) except libvirtError as lib_err: if data['hdd_size'] or volumes[clone_path]: diff --git a/instances/templates/add_instance_network_block.html b/instances/templates/add_instance_network_block.html index 990c524..9d65601 100644 --- a/instances/templates/add_instance_network_block.html +++ b/instances/templates/add_instance_network_block.html @@ -33,12 +33,24 @@
    +
    + +
    + +
    + + diff --git a/instances/templates/allinstances.html b/instances/templates/allinstances.html new file mode 100644 index 0000000..0a00e85 --- /dev/null +++ b/instances/templates/allinstances.html @@ -0,0 +1,184 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "Instances" %}{% endblock %} +{% block style %} + +{% endblock %} +{% block content %} + +
    +
    + {% if request.user.is_superuser %} + {% include 'create_inst_block.html' %} + {% endif %} + {% if all_host_vms or all_user_vms %} + + {% endif %} +

    {% trans "Instances" %}

    +
    +
    + + + {% include 'errors_block.html' %} + +
    +
    +
    + {% if request.user.is_superuser %} + {% if not all_host_vms %} +
    +
    + + {% trans "Warning:" %} {% trans "You don't have any Instance" %} +
    +
    + {% else %} + {% ifequal view_style "nongrouped" %} + {% include 'allinstances_index_nongrouped.html' %} + {% endifequal %} + {% ifequal view_style "grouped" %} + {% include 'allinstances_index_grouped.html' %} + {% endifequal %} + {% endif %} + {% else %} + {% if not all_user_vms %} +
    +
    + + {% trans "Warning:" %} {% trans "You don't have any Instance" %} +
    +
    + {% else %} + + + + + + + + + + + + {% for inst, vm in all_user_vms.items %} + + + + + + + + {% endfor %} + +
    NameStatusVCPUMemoryActions
    {{ vm.name }}
    {{ vm.title }}
    {% ifequal vm.status 1 %} + {% trans "Active" %} + {% endifequal %} + {% ifequal vm.status 5 %} + {% trans "Off" %} + {% endifequal %} + {% ifequal vm.status 3 %} + {% trans "Suspend" %} + {% endifequal %} + {{ vm.vcpu }}{{ vm.memory }} {% trans "MB" %}
    {% csrf_token %} + + + {% ifequal vm.status 5 %} + {% if inst.instance.is_template %} + + {% else %} + + {% endif %} + + + + {% endifequal %} + {% ifequal vm.status 3 %} + + + + + {% endifequal %} + {% ifequal vm.status 1 %} + + + + + + + {% endifequal %} +
    +
    + {% endif %} + {% endif %} +
    +
    +
    +{% endblock %} +{% block script %} + + + + +{% if request.user.is_superuser %} + +{% endif %} +{% endblock %} diff --git a/instances/templates/instances_grouped.html b/instances/templates/allinstances_index_grouped.html similarity index 100% rename from instances/templates/instances_grouped.html rename to instances/templates/allinstances_index_grouped.html diff --git a/instances/templates/instances_nongrouped.html b/instances/templates/allinstances_index_nongrouped.html similarity index 100% rename from instances/templates/instances_nongrouped.html rename to instances/templates/allinstances_index_nongrouped.html diff --git a/instances/templates/instance.html b/instances/templates/instance.html index 9b34878..2628fe2 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -833,39 +833,63 @@ {% if request.user.is_superuser %}

    - {% trans "Assign network device to bridge" %} - {% include 'add_instance_network_block.html' %} + {% trans "Assign network device to bridge" %} + {% include 'add_instance_network_block.html' %}

    -
    {% csrf_token %} -

    {% trans "Network devices" %}

    +

    {% trans "Network devices" %}

    +
    + {% csrf_token %} {% for network in networks %} -
    - -
    - +
    +
    +
    -
    - +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    -
    - + +
    {% endfor %} - {% ifequal status 5 %} - - {% else %} - - {% endifequal %} + + + +
    +
    {% endif %} {% if request.user.is_superuser or request.user.userattributes.can_clone_instances %} @@ -1237,7 +1261,7 @@ - @@ -170,15 +185,15 @@ {% if request.user.is_superuser %} {% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/instances/urls.py b/instances/urls.py index 93ac0c4..1054ed1 100644 --- a/instances/urls.py +++ b/instances/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from . import views urlpatterns = [ + url(r'^$', views.allinstances, name='allinstances'), url(r'^(?P[0-9]+)/(?P[\w\-\.]+)/$', views.instance, name='instance'), url(r'^statistics/(?P[0-9]+)/(?P[\w\-\.]+)/$', views.inst_graph, name='inst_graph'), url(r'^status/(?P[0-9]+)/(?P[\w\-\.]+)/$', views.inst_status, name='inst_status'), diff --git a/instances/views.py b/instances/views.py index ec6adbc..375d63c 100644 --- a/instances/views.py +++ b/instances/views.py @@ -26,175 +26,72 @@ from logs.views import addlogmsg from django.conf import settings from django.contrib import messages - @login_required def index(request): """ :param request: :return: """ - - return HttpResponseRedirect(reverse('instances')) + return HttpResponseRedirect(reverse('allinstances')) @login_required -def instances(request): +def allinstances(request): + """ + INSTANCES LIST FOR ALL HOSTS + :param request: + :return: + """ + all_host_vms = {} + error_messages = [] + computes = Compute.objects.all().order_by("name") + + if not request.user.is_superuser: + all_user_vms = get_user_instances(request) + else: + for comp in computes: + try: + all_host_vms.update(get_host_instances(request,comp)) + except libvirtError as lib_err: + error_messages.append(lib_err) + + if request.method == 'POST': + try: + instances_actions(request) + except libvirtError as lib_err: + error_messages.append(lib_err) + addlogmsg(request.user.username, instance.name, lib_err.message) + + view_style = settings.VIEW_INSTANCES_LIST_STYLE + + return render(request, 'allinstances.html', locals()) + + +@login_required +def instances(request, compute_id): """ :param request: :return: """ error_messages = [] - all_host_vms = {} - all_user_vms = {} - computes = Compute.objects.all().order_by("name") + compute = get_object_or_404(Compute, pk=compute_id) - def get_userinstances_info(instance): - info = {} - uis = UserInstance.objects.filter(instance=instance) - info['count'] = uis.count() - if info['count'] > 0: - info['first_user'] = uis[0] - else: - info['first_user'] = None - return info - - def refresh_instance_database(comp, vm, info): - instances = Instance.objects.filter(name=vm) - if instances.count() > 1: - for i in instances: - user_instances_count = UserInstance.objects.filter(instance=i).count() - if user_instances_count == 0: - addlogmsg(request.user.username, i.name, _("Deleting due to multiple records.")) - i.delete() - - try: - check_uuid = Instance.objects.get(compute_id=comp["id"], name=vm) - if check_uuid.uuid != info['uuid']: - check_uuid.save() - - all_host_vms[comp["id"], - comp["name"], - comp["status"], - comp["cpu"], - comp["mem_size"], - comp["mem_perc"]][vm]['is_template'] = check_uuid.is_template - all_host_vms[comp["id"], - comp["name"], - comp["status"], - comp["cpu"], - comp["mem_size"], - comp["mem_perc"]][vm]['userinstances'] = get_userinstances_info(check_uuid) - except Instance.DoesNotExist: - check_uuid = Instance(compute_id=comp["id"], name=vm, uuid=info['uuid']) - check_uuid.save() - if not request.user.is_superuser: - user_instances = UserInstance.objects.filter(user_id=request.user.id) - for usr_inst in user_instances: - if connection_manager.host_is_up(usr_inst.instance.compute.type, - usr_inst.instance.compute.hostname): - conn = wvmHostDetails(usr_inst.instance.compute, - usr_inst.instance.compute.login, - usr_inst.instance.compute.password, - usr_inst.instance.compute.type) - all_user_vms[usr_inst] = conn.get_user_instances(usr_inst.instance.name) - all_user_vms[usr_inst].update({'compute_id': usr_inst.instance.compute.id}) + all_user_vms = get_user_instances(request) else: - for comp in computes: - status = connection_manager.host_is_up(comp.type, comp.hostname) - if status: - try: - conn = wvmHostDetails(comp, comp.login, comp.password, comp.type) - comp_node_info = conn.get_node_info() - comp_mem = conn.get_memory_usage() - comp_instances = conn.get_host_instances(True) - - if comp_instances: - comp_info= { - "id": comp.id, - "name": comp.name, - "status": status, - "cpu": comp_node_info[3], - "mem_size": comp_node_info[2], - "mem_perc": comp_mem['percent'] - } - all_host_vms[comp_info["id"], comp_info["name"], comp_info["status"], comp_info["cpu"], - comp_info["mem_size"], comp_info["mem_perc"]] = comp_instances - for vm, info in comp_instances.items(): - refresh_instance_database(comp_info, vm, info) - - conn.close() - except libvirtError as lib_err: - error_messages.append(lib_err) + try: + all_host_vms = get_host_instances(request, compute) + except libvirtError as lib_err: + error_messages.append(lib_err) if request.method == 'POST': - name = request.POST.get('name', '') - compute_id = request.POST.get('compute_id', '') - instance = Instance.objects.get(compute_id=compute_id, name=name) try: - conn = wvmInstances(instance.compute.hostname, - instance.compute.login, - instance.compute.password, - instance.compute.type) - if 'poweron' in request.POST: - msg = _("Power On") - addlogmsg(request.user.username, instance.name, msg) - conn.start(name) - return HttpResponseRedirect(request.get_full_path()) - - if 'poweroff' in request.POST: - msg = _("Power Off") - addlogmsg(request.user.username, instance.name, msg) - conn.shutdown(name) - return HttpResponseRedirect(request.get_full_path()) - - if 'powercycle' in request.POST: - msg = _("Power Cycle") - conn.force_shutdown(name) - conn.start(name) - addlogmsg(request.user.username, instance.name, msg) - return HttpResponseRedirect(request.get_full_path()) - - if 'getvvfile' in request.POST: - msg = _("Send console.vv file") - addlogmsg(request.user.username, instance.name, msg) - response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None, charset='utf-8') - response.writelines('[virt-viewer]\n') - response.writelines('type=' + conn.graphics_type(name) + '\n') - response.writelines('host=' + conn.graphics_listen(name) + '\n') - response.writelines('port=' + conn.graphics_port(name) + '\n') - response.writelines('title=' + conn.domain_name(name) + '\n') - response.writelines('password=' + conn.graphics_passwd(name) + '\n') - response.writelines('enable-usbredir=1\n') - response.writelines('disable-effects=all\n') - response.writelines('secure-attention=ctrl+alt+ins\n') - response.writelines('release-cursor=ctrl+alt\n') - response.writelines('fullscreen=1\n') - response.writelines('delete-this-file=1\n') - response['Content-Disposition'] = 'attachment; filename="console.vv"' - return response - - if request.user.is_superuser: - - if 'suspend' in request.POST: - msg = _("Suspend") - addlogmsg(request.user.username, instance.name, msg) - conn.suspend(name) - return HttpResponseRedirect(request.get_full_path()) - - if 'resume' in request.POST: - msg = _("Resume") - addlogmsg(request.user.username, instance.name, msg) - conn.resume(name) - return HttpResponseRedirect(request.get_full_path()) - + instances_actions(request) except libvirtError as lib_err: error_messages.append(lib_err) addlogmsg(request.user.username, instance.name, lib_err.message) - view_style = settings.VIEW_INSTANCES_LIST_STYLE - return render(request, 'instances.html', locals()) @@ -206,7 +103,7 @@ def instance(request, compute_id, vname): """ error_messages = [] - #messages = [] + # messages = [] compute = get_object_or_404(Compute, pk=compute_id) computes = Compute.objects.all().order_by('name') computes_count = computes.count() @@ -217,8 +114,8 @@ def instance(request, compute_id, vname): console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES try: userinstance = UserInstance.objects.get(instance__compute_id=compute_id, - instance__name=vname, - user__id=request.user.id) + instance__name=vname, + user__id=request.user.id) except UserInstance.DoesNotExist: userinstance = None @@ -231,15 +128,15 @@ def instance(request, compute_id, vname): return 0 size_str = size_str.encode('ascii', 'ignore').upper().translate(None, " B") if 'K' == size_str[-1]: - return long(float(size_str[:-1]))<<10 + return long(float(size_str[:-1])) << 10 elif 'M' == size_str[-1]: - return long(float(size_str[:-1]))<<20 + return long(float(size_str[:-1])) << 20 elif 'G' == size_str[-1]: - return long(float(size_str[:-1]))<<30 + return long(float(size_str[:-1])) << 30 elif 'T' == size_str[-1]: - return long(float(size_str[:-1]))<<40 + return long(float(size_str[:-1])) << 40 elif 'P' == size_str[-1]: - return long(float(size_str[:-1]))<<50 + return long(float(size_str[:-1])) << 50 else: return long(float(size_str)) @@ -268,16 +165,16 @@ def instance(request, compute_id, vname): if connection_manager.host_is_up(usr_inst.instance.compute.type, usr_inst.instance.compute.hostname): conn = wvmInstance(usr_inst.instance.compute, - usr_inst.instance.compute.login, - usr_inst.instance.compute.password, - usr_inst.instance.compute.type, - usr_inst.instance.name) + usr_inst.instance.compute.login, + usr_inst.instance.compute.password, + usr_inst.instance.compute.type, + usr_inst.instance.name) cpu += int(conn.get_vcpu()) memory += int(conn.get_memory()) for disk in conn.get_disk_device(): if disk['size']: - disk_size += int(disk['size'])>>30 - + disk_size += int(disk['size']) >> 30 + if ua.max_instances > 0 and instance > ua.max_instances: msg = "instance" if settings.QUOTA_DEBUG: @@ -301,7 +198,7 @@ def instance(request, compute_id, vname): dev_base = "vd" else: dev_base = "sd" - existing_devs = [ disk['dev'] for disk in disks ] + existing_devs = [disk['dev'] for disk in disks] for l in string.lowercase: dev = dev_base + l if dev not in existing_devs: @@ -348,6 +245,7 @@ def instance(request, compute_id, vname): vname) compute_networks = sorted(conn.get_networks()) compute_interfaces = sorted(conn.get_ifaces()) + compute_nwfilters = conn.get_nwfilters() status = conn.get_status() autostart = conn.get_autostart() vcpu = conn.get_vcpu() @@ -364,6 +262,7 @@ def instance(request, compute_id, vname): else: media_iso = [] networks = conn.get_net_device() + vcpu_range = conn.get_max_cpus() memory_range = [256, 512, 768, 1024, 2048, 4096, 6144, 8192, 16384] if memory not in memory_range: @@ -377,7 +276,7 @@ def instance(request, compute_id, vname): console_port = conn.get_console_port() console_keymap = conn.get_console_keymap() console_listen_address = conn.get_console_listen_addr() - snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k:k['date']) + snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k: k['date']) inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE) has_managed_save_image = conn.get_managed_save_image() console_passwd = conn.get_console_passwd() @@ -387,6 +286,7 @@ def instance(request, compute_id, vname): cache_modes = sorted(conn.get_cache_modes().items()) default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT + default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER formats = conn.get_image_formats() busses = conn.get_busses() @@ -450,7 +350,8 @@ def instance(request, compute_id, vname): instance.delete() try: - del_userinstance = UserInstance.objects.filter(instance__compute_id=compute_id, instance__name=vname) + del_userinstance = UserInstance.objects.filter(instance__compute_id=compute_id, + instance__name=vname) del_userinstance.delete() except UserInstance.DoesNotExist: pass @@ -458,7 +359,7 @@ def instance(request, compute_id, vname): msg = _("Destroy") addlogmsg(request.user.username, instance_name, msg) - return HttpResponseRedirect(reverse('instances')) + return HttpResponseRedirect(reverse('allinstances')) if 'rootpasswd' in request.POST: passwd = request.POST.get('passwd', '') @@ -504,7 +405,8 @@ def instance(request, compute_id, vname): msg = _("Please shutdown down your instance and then try again") error_messages.append(msg) - if 'resize' in request.POST and (request.user.is_superuser or request.user.is_staff or userinstance.is_change): + if 'resize' in request.POST and ( + request.user.is_superuser or request.user.is_staff or userinstance.is_change): new_vcpu = request.POST.get('vcpu', '') new_cur_vcpu = request.POST.get('cur_vcpu', '') new_memory = request.POST.get('memory', '') @@ -518,13 +420,13 @@ def instance(request, compute_id, vname): disks_new = [] for disk in disks: input_disk_size = filesizefstr(request.POST.get('disk_size_' + disk['dev'], '')) - if input_disk_size > disk['size']+(64<<20): + if input_disk_size > disk['size'] + (64 << 20): disk['size_new'] = input_disk_size - disks_new.append(disk) - disk_sum = sum([disk['size']>>30 for disk in disks_new]) - disk_new_sum = sum([disk['size_new']>>30 for disk in disks_new]) - quota_msg = check_user_quota(0, int(new_vcpu)-vcpu, int(new_memory)-memory, disk_new_sum-disk_sum) - if not request.user.is_superuser and quota_msg: + disks_new.append(disk) + disk_sum = sum([disk['size'] >> 30 for disk in disks_new]) + disk_new_sum = sum([disk['size_new'] >> 30 for disk in disks_new]) + quota_msg = check_user_quota(0, int(new_vcpu) - vcpu, int(new_memory) - memory, disk_new_sum - disk_sum) + if not request.user.is_superuser and quota_msg: msg = _("User %s quota reached, cannot resize '%s'!" % (quota_msg, instance.name)) error_messages.append(msg) else: @@ -539,19 +441,19 @@ def instance(request, compute_id, vname): if 'addvolume' in request.POST and (request.user.is_superuser or userinstance.is_change): connCreate = wvmCreate(compute.hostname, - compute.login, - compute.password, - compute.type) + compute.login, + compute.password, + compute.type) storage = request.POST.get('storage', '') name = request.POST.get('name', '') - format = request.POST.get('format', '') + format = request.POST.get('format', default_format) size = request.POST.get('size', 0) meta_prealloc = request.POST.get('meta_prealloc', False) - bus = request.POST.get('bus', '') - cache = request.POST.get('cache', '') + bus = request.POST.get('bus', default_bus) + cache = request.POST.get('cache', default_cache) target = get_new_disk_dev(disks, bus) - - path = connCreate.create_volume(storage, name, size, format, meta_prealloc) + + path = connCreate.create_volume(storage, name, size, format, meta_prealloc, default_owner) conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus) msg = _('Attach new disk') addlogmsg(request.user.username, instance.name, msg) @@ -667,7 +569,7 @@ def instance(request, compute_id, vname): msg = _("Set VNC type") addlogmsg(request.user.username, instance.name, msg) return HttpResponseRedirect(request.get_full_path() + '#vncsettings') - + if 'set_console_listen_address' in request.POST: console_type = request.POST.get('console_listen_address', '') conn.set_console_listen_addr(console_type) @@ -689,6 +591,7 @@ def instance(request, compute_id, vname): return HttpResponseRedirect(reverse('instance', args=[new_compute.id, vname])) if 'change_network' in request.POST: + msg = _("Change network") network_data = {} for post in request.POST: @@ -700,31 +603,43 @@ def instance(request, compute_id, vname): network_data[post] = request.POST.get(post, '') conn.change_network(network_data) - msg = _("Edit network") addlogmsg(request.user.username, instance.name, msg) msg = _("Network Devices are changed. Please reboot instance to activate.") - messages.success(request, msg) + if conn.get_status() != 5: messages.success(request, msg) return HttpResponseRedirect(request.get_full_path() + '#network') if 'add_network' in request.POST: + msg = _("Add network") mac = request.POST.get('add-net-mac') + nwfilter = request.POST.get('add-net-nwfilter') (source, source_type) = get_network_tuple(request.POST.get('add-net-network')) - conn.add_network(mac, source, source_type) - msg = _("Edit network") + conn.add_network(mac, source, source_type, nwfilter=nwfilter) + addlogmsg(request.user.username, instance.name, msg) - msg = _("Network Devices are changed. Please reboot instance to activate.") - messages.success(request, msg) + msg = _("Network Device is added. Please reboot instance to activate.") + if conn.get_status() != 5: messages.success(request, msg) + return HttpResponseRedirect(request.get_full_path() + '#network') - + + if 'delete_network' in request.POST: + msg = _("Delete network") + mac_address = request.POST.get('delete_network', '') + + conn.delete_network(mac_address) + addlogmsg(request.user.username, instance.name, msg) + msg = _("Network Device is deleted. Please reboot instance to activate.") + if conn.get_status() != 5: messages.success(request, msg) + return HttpResponseRedirect(request.get_full_path() + '#network') + if 'add_owner' in request.POST: user_id = int(request.POST.get('user_id', '')) - + if settings.ALLOW_INSTANCE_MULTIPLE_OWNER: check_inst = UserInstance.objects.filter(instance=instance, user_id=user_id) else: check_inst = UserInstance.objects.filter(instance=instance) - + if check_inst: msg = _("Owner already added") error_messages.append(msg) @@ -743,19 +658,18 @@ def instance(request, compute_id, vname): addlogmsg(request.user.username, instance.name, msg) return HttpResponseRedirect(request.get_full_path() + '#users') - if request.user.is_superuser or request.user.userattributes.can_clone_instances: if 'clone' in request.POST: clone_data = {} clone_data['name'] = request.POST.get('name', '') - disk_sum = sum([disk['size']>>30 for disk in disks]) + disk_sum = sum([disk['size'] >> 30 for disk in disks]) quota_msg = check_user_quota(1, vcpu, memory, disk_sum) check_instance = Instance.objects.filter(name=clone_data['name']) - + for post in request.POST: clone_data[post] = request.POST.get(post, '').strip() - + if clone_instance_auto_name and not clone_data['name']: auto_vname = clone_free_names[0] clone_data['name'] = auto_vname @@ -764,7 +678,7 @@ def instance(request, compute_id, vname): disk_dev = "disk-{}".format(disk['dev']) disk_name = get_clone_disk_name(disk, vname, auto_vname) clone_data[disk_dev] = disk_name - + if not request.user.is_superuser and quota_msg: msg = _("User %s quota reached, cannot create '%s'!" % (quota_msg, clone_data['name'])) error_messages.append(msg) @@ -774,14 +688,16 @@ def instance(request, compute_id, vname): elif not re.match(r'^[a-zA-Z0-9-]+$', clone_data['name']): msg = _("Instance name '%s' contains invalid characters!" % clone_data['name']) error_messages.append(msg) - elif not re.match(r'^([0-9A-F]{2})(\:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'], re.IGNORECASE): + elif not re.match(r'^([0-9A-F]{2})(\:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'], + re.IGNORECASE): msg = _("Instance mac '%s' invalid format!" % clone_data['clone-net-mac-0']) error_messages.append(msg) else: new_uuid = conn.clone_instance(clone_data) new_instance = Instance(compute_id=compute_id, name=clone_data['name'], uuid=new_uuid) new_instance.save() - userinstance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, is_delete=True) + userinstance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, + is_delete=True) userinstance.save() msg = _("Clone of '%s'" % instance.name) @@ -789,18 +705,19 @@ def instance(request, compute_id, vname): if settings.CLONE_INSTANCE_AUTO_MIGRATE: new_compute = Compute.objects.order_by('?').first() migrate_instance(new_compute, new_instance, xml_del=True, offline=True) - return HttpResponseRedirect(reverse('instance', args=[new_instance.compute.id, new_instance.name])) + return HttpResponseRedirect( + reverse('instance', args=[new_instance.compute.id, new_instance.name])) if 'change_options' in request.POST: instance.is_template = request.POST.get('is_template', False) instance.save() - + options = {} for post in request.POST: if post in ['title', 'description']: options[post] = request.POST.get(post, '') conn.set_options(options) - + msg = _("Edit options") addlogmsg(request.user.username, instance.name, msg) return HttpResponseRedirect(request.get_full_path() + '#options') @@ -839,6 +756,154 @@ def inst_status(request, compute_id, vname): return response +def get_host_instances(request,comp): + + def refresh_instance_database(comp, inst_name, info): + def get_userinstances_info(instance): + info = {} + uis = UserInstance.objects.filter(instance=instance) + info['count'] = uis.count() + if info['count'] > 0: + info['first_user'] = uis[0] + else: + info['first_user'] = None + return info + + instances = Instance.objects.filter(name=inst_name) + if instances.count() > 1: + for i in instances: + user_instances_count = UserInstance.objects.filter(instance=i).count() + if user_instances_count == 0: + addlogmsg(request.user.username, i.name, _("Deleting due to multiple records.")) + i.delete() + + try: + inst_on_db = Instance.objects.get(compute_id=comp["id"], name=inst_name) + if inst_on_db.uuid != info['uuid']: + inst_on_db.save() + + all_host_vms[comp["id"], + comp["name"], + comp["status"], + comp["cpu"], + comp["mem_size"], + comp["mem_perc"]][inst_name]['is_template'] = inst_on_db.is_template + all_host_vms[comp["id"], + comp["name"], + comp["status"], + comp["cpu"], + comp["mem_size"], + comp["mem_perc"]][inst_name]['userinstances'] = get_userinstances_info(inst_on_db) + except Instance.DoesNotExist: + inst_on_db = Instance(compute_id=comp["id"], name=inst_name, uuid=info['uuid']) + inst_on_db.save() + + all_host_vms = {} + status = connection_manager.host_is_up(comp.type, comp.hostname) + + if status: + + conn = wvmHostDetails(comp, comp.login, comp.password, comp.type) + comp_node_info = conn.get_node_info() + comp_mem = conn.get_memory_usage() + comp_instances = conn.get_host_instances(True) + + if comp_instances: + comp_info = { + "id": comp.id, + "name": comp.name, + "status": status, + "cpu": comp_node_info[3], + "mem_size": comp_node_info[2], + "mem_perc": comp_mem['percent'] + } + all_host_vms[comp_info["id"], comp_info["name"], comp_info["status"], comp_info["cpu"], + comp_info["mem_size"], comp_info["mem_perc"]] = comp_instances + for vm, info in comp_instances.items(): + refresh_instance_database(comp_info, vm, info) + + conn.close() + + return all_host_vms + +def get_user_instances(request): + all_user_vms = {} + user_instances = UserInstance.objects.filter(user_id=request.user.id) + for usr_inst in user_instances: + if connection_manager.host_is_up(usr_inst.instance.compute.type, + usr_inst.instance.compute.hostname): + conn = wvmHostDetails(usr_inst.instance.compute, + usr_inst.instance.compute.login, + usr_inst.instance.compute.password, + usr_inst.instance.compute.type) + all_user_vms[usr_inst] = conn.get_user_instances(usr_inst.instance.name) + all_user_vms[usr_inst].update({'compute_id': usr_inst.instance.compute.id}) + return all_user_vms + + +def instances_actions(request): + name = request.POST.get('name', '') + compute_id = request.POST.get('compute_id', '') + instance = Instance.objects.get(compute_id=compute_id, name=name) + + conn = wvmInstances(instance.compute.hostname, + instance.compute.login, + instance.compute.password, + instance.compute.type) + if 'poweron' in request.POST: + msg = _("Power On") + addlogmsg(request.user.username, instance.name, msg) + conn.start(name) + return HttpResponseRedirect(request.get_full_path()) + + if 'poweroff' in request.POST: + msg = _("Power Off") + addlogmsg(request.user.username, instance.name, msg) + conn.shutdown(name) + return HttpResponseRedirect(request.get_full_path()) + + if 'powercycle' in request.POST: + msg = _("Power Cycle") + conn.force_shutdown(name) + conn.start(name) + addlogmsg(request.user.username, instance.name, msg) + return HttpResponseRedirect(request.get_full_path()) + + if 'getvvfile' in request.POST: + msg = _("Send console.vv file") + addlogmsg(request.user.username, instance.name, msg) + response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None, + charset='utf-8') + response.writelines('[virt-viewer]\n') + response.writelines('type=' + conn.graphics_type(name) + '\n') + response.writelines('host=' + conn.graphics_listen(name) + '\n') + response.writelines('port=' + conn.graphics_port(name) + '\n') + response.writelines('title=' + conn.domain_name(name) + '\n') + response.writelines('password=' + conn.graphics_passwd(name) + '\n') + response.writelines('enable-usbredir=1\n') + response.writelines('disable-effects=all\n') + response.writelines('secure-attention=ctrl+alt+ins\n') + response.writelines('release-cursor=ctrl+alt\n') + response.writelines('fullscreen=1\n') + response.writelines('delete-this-file=1\n') + response['Content-Disposition'] = 'attachment; filename="console.vv"' + return response + + if request.user.is_superuser: + + if 'suspend' in request.POST: + msg = _("Suspend") + addlogmsg(request.user.username, instance.name, msg) + conn.suspend(name) + return HttpResponseRedirect(request.get_full_path()) + + if 'resume' in request.POST: + msg = _("Resume") + addlogmsg(request.user.username, instance.name, msg) + conn.resume(name) + return HttpResponseRedirect(request.get_full_path()) + + @login_required def inst_graph(request, compute_id, vname): """ diff --git a/interfaces/templates/interface.html b/interfaces/templates/interface.html index c55750d..5c5c2b5 100644 --- a/interfaces/templates/interface.html +++ b/interfaces/templates/interface.html @@ -10,6 +10,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -19,6 +22,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/interfaces/templates/interfaces.html b/interfaces/templates/interfaces.html index 42d4456..8305b88 100644 --- a/interfaces/templates/interfaces.html +++ b/interfaces/templates/interfaces.html @@ -12,6 +12,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -21,6 +24,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/networks/templates/network.html b/networks/templates/network.html index 7d922b1..6fa0c2e 100644 --- a/networks/templates/network.html +++ b/networks/templates/network.html @@ -10,6 +10,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -19,6 +22,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/networks/templates/networks.html b/networks/templates/networks.html index 36322e2..b57f7c6 100644 --- a/networks/templates/networks.html +++ b/networks/templates/networks.html @@ -11,6 +11,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -20,6 +23,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/nwfilters/__init__.py b/nwfilters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nwfilters/admin.py b/nwfilters/admin.py new file mode 100644 index 0000000..13be29d --- /dev/null +++ b/nwfilters/admin.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.contrib import admin + +# Register your models here. diff --git a/nwfilters/apps.py b/nwfilters/apps.py new file mode 100644 index 0000000..11475c5 --- /dev/null +++ b/nwfilters/apps.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class NwfiltersConfig(AppConfig): + name = 'nwfilters' diff --git a/nwfilters/migrations/__init__.py b/nwfilters/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nwfilters/models.py b/nwfilters/models.py new file mode 100644 index 0000000..1dfab76 --- /dev/null +++ b/nwfilters/models.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models + +# Create your models here. diff --git a/nwfilters/templates/create_nwfilter_block.html b/nwfilters/templates/create_nwfilter_block.html new file mode 100644 index 0000000..01056ab --- /dev/null +++ b/nwfilters/templates/create_nwfilter_block.html @@ -0,0 +1,32 @@ +{% load i18n %} +{% if request.user.is_superuser %} + + + + + + +{% endif %} diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html new file mode 100644 index 0000000..377190d --- /dev/null +++ b/nwfilters/templates/nwfilter.html @@ -0,0 +1,223 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {% trans "NWFilter:" %} {{ name }}

    + +
    +
    + + + {% include 'errors_block.html' %} + {% include 'messages_block.html' %} + +
    +
    +

    {% trans "UUID:" %}

    +

    {% trans "Name:" %}

    +
    + +
    +

    {{ uuid }}

    +

    {{ name }}

    +
    + +
    +
    +

    {% trans "XML:" %}

    +
    {% csrf_token %} +
    + + +
    + +
    +
    +
    +

    {% trans "Filter References:" %}

    +
    {% csrf_token %} +
    + + + + +
    +
    + +
    +
    +
    + + + + + + + + + + {% for ref in refs %} + + + + + + {% endfor %} + +
    #{% trans "Reference" %}{% trans "Action" %}
    {{ forloop.counter }}{{ ref }} +
    {% csrf_token %} + + +
    +
    +
    +
    +
    +

    {% trans "Rules:" %}

    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + {% for rule in rules %} + + + + + + + + + + {% endfor %} + +
    {% trans "Rule" %}{% trans "ActionType" %}{% trans "Direction" %}{% trans "Priority" %}{% trans "Statematch" %}{% trans "Directives" %}{% trans "Action" %}
    {{ forloop.counter }}{{ rule.action }}{{ rule.direction }}{{ rule.priority }}{{ rule.statematch }}{{ rule.directives }} +
    {% csrf_token %} + + + + +
    +
    +
    +
    + + +{% endblock %} + +{% block script %} + + + + + +{% endblock %} diff --git a/nwfilters/templates/nwfilters.html b/nwfilters/templates/nwfilters.html new file mode 100644 index 0000000..dba8377 --- /dev/null +++ b/nwfilters/templates/nwfilters.html @@ -0,0 +1,171 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {{ compute.name }}

    + +
    +
    + + +{% include 'errors_block.html' %} +{% include 'messages_block.html' %} + +
    +
    +
    +
    + +
    + + +
    + {% if nwfilters %} +
    + + + + + + + + + + + {% for nwfilter in nwfilters %} + + + + + + + + + {% endfor %} + +
    #{% trans "UUID" %}{% trans "Name" %}{% trans "Action" %}
    {{ forloop.counter }}{{ nwfilter.uuid }}{{ nwfilter.name }} + + + + + + +
    {% csrf_token %} + + +
    +
    +
    + {% else %} +
    +
    + + {% trans "Warning:" %} {% trans "Hypervisor doesn't have any NWFilters" %} +
    +
    + {% endif %} +
    +
    +{% endblock %} + +{% block script %} + + + + + + + +{% endblock %} diff --git a/nwfilters/tests.py b/nwfilters/tests.py new file mode 100644 index 0000000..5982e6b --- /dev/null +++ b/nwfilters/tests.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.test import TestCase + +# Create your tests here. diff --git a/nwfilters/views.py b/nwfilters/views.py new file mode 100644 index 0000000..c0dd8d8 --- /dev/null +++ b/nwfilters/views.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.shortcuts import render +from django.http import HttpResponseRedirect +from django.shortcuts import render, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse +from django.contrib.auth.decorators import login_required +from computes.models import Compute +from vrtManager import util +from vrtManager.nwfilters import wvmNWFilters, wvmNWFilter +from vrtManager.instance import wvmInstances, wvmInstance +from libvirt import libvirtError +from logs.views import addlogmsg + + +@login_required +def nwfilters(request, compute_id): + """ + :param request: + :return: + """ + + if not request.user.is_superuser: + return HttpResponseRedirect(reverse('index')) + + error_messages = [] + nwfilters_all = [] + compute = get_object_or_404(Compute, pk=compute_id) + + try: + conn = wvmNWFilters(compute.hostname, + compute.login, + compute.password, + compute.type) + + if request.method == 'POST': + if 'create_nwfilter' in request.POST: + xml = request.POST.get('nwfilter_xml', '') + if xml: + try: + util.etree.fromstring(xml) + name = util.get_xml_path(xml, '/filter/@name') + uuid = util.get_xml_path(xml, '/filter/uuid') + except util.etree.ParseError: + name = None + + for nwf in nwfilters: + if name == nwf.name(): + error_msg = _("A network filter with this name already exists") + raise Exception(error_msg) + if uuid == nwf.UUIDString(): + error_msg = _("A network filter with this uuid already exists") + raise Exception(error_msg) + else: + try: + msg = _("Creating NWFilter: %s" % name) + conn.create_nwfilter(xml) + addlogmsg(request.user.username, compute.hostname, msg) + except libvirtError as lib_err: + error_messages.append(lib_err.message) + addlogmsg(request.user.username, compute.hostname, lib_err.message) + + if 'del_nwfilter' in request.POST: + name = request.POST.get('nwfiltername','') + msg = _("Deleting NWFilter: %s" % name) + in_use = False + nwfilter = conn.get_nwfilter(name) + + is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type) + instances = is_conn.get_instances() + for inst in instances: + # if in_use: break + i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst) + dom_filterrefs = i_conn.get_filterrefs() + + if name in dom_filterrefs: + in_use = True + msg = _("NWFilter is in use by %s. Cannot be deleted." % inst) + error_messages.append(msg) + addlogmsg(request.user.username, compute.hostname, msg) + i_conn.close() + break + + is_conn.close() + if nwfilter and not in_use: + nwfilter.undefine() + addlogmsg(request.user.username, compute.hostname, msg) + + if 'cln_nwfilter' in request.POST: + + name = request.POST.get('nwfiltername','') + cln_name = request.POST.get('cln_name', name + '-clone') + + conn.clone_nwfilter(name,cln_name) + msg = _("Cloning NWFilter %s as %s" % (name, cln_name)) + addlogmsg(request.user.username, compute.hostname, msg) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf)) + + conn.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + addlogmsg(request.user.username, compute.hostname, lib_err) + except Exception as err: + error_messages.append(err) + addlogmsg(request.user.username, compute.hostname, err) + + return render(request, 'nwfilters.html', {'error_messages': error_messages, + 'nwfilters': nwfilters_all, + 'compute': compute}) + + +@login_required +def nwfilter(request, compute_id, nwfltr): + + error_messages = [] + nwfilters_all = [] + compute = get_object_or_404(Compute, pk=compute_id) + + try: + nwfilter = wvmNWFilter(compute.hostname, + compute.login, + compute.password, + compute.type, + nwfltr) + conn = wvmNWFilters(compute.hostname, + compute.login, + compute.password, + compute.type) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf)) + + uuid = nwfilter.get_uuid() + name = nwfilter.get_name() + xml = nwfilter.get_xml() + rules = nwfilter.get_rules() + refs = nwfilter.get_filter_refs() + + if request.method == 'POST': + + if 'edit_nwfilter' in request.POST: + new_xml = request.POST.get('edit_xml', '') + + if new_xml: + nwfilter.delete() + try: + conn.create_nwfilter(new_xml) + except libvirtError as lib_err: + conn.create_nwfilter(xml) + raise libvirtError(lib_err) + + if 'del_nwfilter_rule' in request.POST: + action = request.POST.get('action', '') + direction = request.POST.get('direction', '') + priority = request.POST.get('priority', '') + + new_xml = nwfilter.delete_rule(action, direction, priority) + nwfilter.delete() + try: + conn.create_nwfilter(new_xml) + except libvirtError as lib_err: + conn.create_nwfilter(xml) + raise libvirtError(lib_err) + + if 'del_nwfilter_ref' in request.POST: + ref_name = request.POST.get('ref') + new_xml = nwfilter.delete_ref(ref_name) + nwfilter.delete() + try: + conn.create_nwfilter(new_xml) + except libvirtError as lib_err: + conn.create_nwfilter(xml) + raise libvirtError(lib_err) + + if 'add_nwfilter_rule' in request.POST: + rule_xml = request.POST.get('nwfilterrule_xml', '') + if not rule_xml: + return HttpResponseRedirect(request.get_full_path()) + new_xml = nwfilter.add_rule(rule_xml) + nwfilter.delete() + try: + conn.create_nwfilter(new_xml) + except libvirtError as lib_err: + conn.create_nwfilter(xml) + raise libvirtError(lib_err) + + if 'add_nwfilter_ref' in request.POST: + ref_name = request.POST.get('nwfilters_select', '') + if not ref_name: + return HttpResponseRedirect(request.get_full_path()) + new_xml = nwfilter.add_ref(ref_name) + nwfilter.delete() + try: + conn.create_nwfilter(new_xml) + except libvirtError as lib_err: + conn.create_nwfilter(xml) + raise libvirtError(lib_err) + + return HttpResponseRedirect(request.get_full_path()) + conn.close() + nwfilter.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + except Exception as error_msg: + error_messages.append(error_msg) + + return render(request, 'nwfilter.html', locals()) \ No newline at end of file diff --git a/secrets/templates/secrets.html b/secrets/templates/secrets.html index 8286bfb..7f781ce 100644 --- a/secrets/templates/secrets.html +++ b/secrets/templates/secrets.html @@ -15,6 +15,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -24,6 +27,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/static/css/font-awesome.min.css b/static/css/font-awesome.min.css old mode 100644 new mode 100755 index 24fcc04..540440c --- a/static/css/font-awesome.min.css +++ b/static/css/font-awesome.min.css @@ -1,4 +1,4 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/static/fonts/FontAwesome.otf b/static/fonts/FontAwesome.otf old mode 100644 new mode 100755 index f7936cc..401ec0f Binary files a/static/fonts/FontAwesome.otf and b/static/fonts/FontAwesome.otf differ diff --git a/static/fonts/fontawesome-webfont.eot b/static/fonts/fontawesome-webfont.eot old mode 100644 new mode 100755 index 33b2bb8..e9f60ca Binary files a/static/fonts/fontawesome-webfont.eot and b/static/fonts/fontawesome-webfont.eot differ diff --git a/static/fonts/fontawesome-webfont.svg b/static/fonts/fontawesome-webfont.svg old mode 100644 new mode 100755 index 1ee89d4..855c845 --- a/static/fonts/fontawesome-webfont.svg +++ b/static/fonts/fontawesome-webfont.svg @@ -1,565 +1,2671 @@ - - + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/fonts/fontawesome-webfont.ttf b/static/fonts/fontawesome-webfont.ttf old mode 100644 new mode 100755 index ed9372f..35acda2 Binary files a/static/fonts/fontawesome-webfont.ttf and b/static/fonts/fontawesome-webfont.ttf differ diff --git a/static/fonts/fontawesome-webfont.woff b/static/fonts/fontawesome-webfont.woff old mode 100644 new mode 100755 index 8b280b9..400014a Binary files a/static/fonts/fontawesome-webfont.woff and b/static/fonts/fontawesome-webfont.woff differ diff --git a/static/fonts/fontawesome-webfont.woff2 b/static/fonts/fontawesome-webfont.woff2 old mode 100644 new mode 100755 index 3311d58..4d13fc6 Binary files a/static/fonts/fontawesome-webfont.woff2 and b/static/fonts/fontawesome-webfont.woff2 differ diff --git a/storages/templates/storage.html b/storages/templates/storage.html index ecc9adc..17ed99c 100644 --- a/storages/templates/storage.html +++ b/storages/templates/storage.html @@ -16,6 +16,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -25,6 +28,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/templates/storages.html b/storages/templates/storages.html index 21bca90..7529842 100644 --- a/storages/templates/storages.html +++ b/storages/templates/storages.html @@ -11,6 +11,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • @@ -20,6 +23,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/views.py b/storages/views.py index f18cad6..d2214aa 100644 --- a/storages/views.py +++ b/storages/views.py @@ -155,7 +155,7 @@ def storage(request, compute_id, pool): meta_prealloc = True try: conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc) - messages.success("Image file {} is created successfully".format(data['name']+".img")) + messages.success(request, _("Image file {} is created successfully".format(data['name']+".img"))) return HttpResponseRedirect(request.get_full_path()) except libvirtError as lib_err: error_messages.append(lib_err) @@ -167,7 +167,7 @@ def storage(request, compute_id, pool): try: vol = conn.get_volume(volname) vol.delete(0) - messages.success(request,_('Volume: {} is deleted.'.format(volname))) + messages.success(request, _('Volume: {} is deleted.'.format(volname))) return HttpResponseRedirect(request.get_full_path()) except libvirtError as lib_err: error_messages.append(lib_err.message) @@ -197,8 +197,7 @@ def storage(request, compute_id, pool): format = None try: conn.clone_volume(data['image'], data['name'], format, meta_prealloc) - messages.success(request, _("{} image cloned as {} successfully".format(data['image'], - data['name'] + ".img"))) + messages.success(request, _("{} image cloned as {} successfully".format(data['image'], data['name'] + ".img"))) return HttpResponseRedirect(request.get_full_path()) except libvirtError as lib_err: error_messages.append(lib_err) diff --git a/templates/navbar.html b/templates/navbar.html index 6b69be4..1a1263b 100644 --- a/templates/navbar.html +++ b/templates/navbar.html @@ -15,7 +15,7 @@