diff --git a/.gitignore b/.gitignore index e300831e4..9f5ded8b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,23 @@ -*.py[cod] -.idea -test.py .DS_Store -db.sqlite3 -# C extensions -*.so - -# Packages -*.egg -*.egg-info +*.pyc +*.pyo +*.swp +.env +env +env* dist build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 -__pycache__ - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage +*.egg +*.egg-info +_mailinglist +dump.rdb .tox -nosetests.xml - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject -.settings +.cache/ +.idea/ +db.sqlite3 +config.py +migrations/ *.log -logs/* -keys/* -jumpserver.conf -nohup.out -tmp/* +host_rsa_key +*.bat +tags diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..bec3a35ee --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +system diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..2e9631c6a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM jumpserver/base-env-alpine:latest +MAINTAINER Jumpserver Team + +#RUN apk add --update python gcc python-dev py-pip musl-dev linux-headers \ +# libffi-dev openssl-dev jpeg-dev redis && rm -rf /var/cache/apk/* +COPY . /opt/jumpserver +WORKDIR /opt/jumpserver + +RUN cp config_example.py config.py +#RUN pip install -r requirements.txt -i https://pypi.doubanio.com/simple +RUN rm -f db.sqlite3 && cd utils && sh make_migrations.sh && sh init_db.sh +EXPOSE 8080 +CMD redis-server utils/redis.conf && python run_server.py diff --git a/Dockerfile-base-env-alpine b/Dockerfile-base-env-alpine new file mode 100644 index 000000000..7fb4f8a7e --- /dev/null +++ b/Dockerfile-base-env-alpine @@ -0,0 +1,9 @@ +FROM alpine:3.4 +MAINTAINER Jumpserver Team + +RUN apk add --update python gcc python-dev py-pip musl-dev linux-headers \ + libffi-dev openssl-dev jpeg-dev freetype-dev redis && rm -rf /var/cache/apk/* +COPY ./requirements.txt /tmp +WORKDIR /tmp + +RUN pip install -r requirements.txt -i https://pypi.doubanio.com/simple \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..e69de29bb diff --git a/README.md b/README.md new file mode 100644 index 000000000..9ec85a624 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ + // Jumpserver // + + + ~ Jumpserver是什么? + + Jumpserver是一款开源的跳板机(堡垒机)产品, 主要使用Python,Django开发 + 他实现了跳板机(堡垒机)的主要功能,删减、优化了传统堡垒机,致力于为互联网 + 运维提供服务 + + ~ 版本依赖 + + * Python 2.7 + + * Django 1.10 + + + ~ 快速开始 + + ``` + pip install -r requirements.txt # Install pip module + + yum -y install `cat rpm_requirements.txt` # Install rpm package + + cp config_example.py config.py # Prepaire config from example config + + cd apps && python manage.py makemigrations # Make migrations for django + + python manage.py migrate # Migrate ORM to database + + python manage.py loaddata init # Init some data + + python manage.py loaddata fake # Generake some fake data + + yum -y install redis && service redis start # Or install redis docker + + python manage.py runserver 0.0.0.0:80 # Run it + + ``` + + ~ 文档 + + * [项目结构描述](https://code.jumpserver.org/jumpserver/jumpserver/blob/master/docs/project_structure.md) + * [Python代码规范](https://code.jumpserver.org/jumpserver/jumpserver/blob/master/docs/python_style_guide.md) + * [API设计规范](https://code.jumpserver.org/jumpserver/jumpserver/blob/master/docs/api_style_guide.md) + * [表结构](https://code.jumpserver.org/Jumpserver/jumpserver/wikis/table-structure) + diff --git a/apps/__init__.py b/apps/__init__.py new file mode 100644 index 000000000..f93d0bec7 --- /dev/null +++ b/apps/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + + +if __name__ == '__main__': + pass diff --git a/apps/applications/__init__.py b/apps/applications/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/applications/admin.py b/apps/applications/admin.py new file mode 100644 index 000000000..8c38f3f3d --- /dev/null +++ b/apps/applications/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/applications/api.py b/apps/applications/api.py new file mode 100644 index 000000000..d30f9667c --- /dev/null +++ b/apps/applications/api.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# + +from collections import OrderedDict +from django.core.cache import cache +from django.conf import settings +from django.utils import timezone +import copy +from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView +from rest_framework import viewsets +from rest_framework.views import APIView, Response +from rest_framework.permissions import AllowAny +from django.shortcuts import get_object_or_404 +from rest_framework.decorators import api_view + +from .models import Terminal, TerminalHeatbeat +from .serializers import TerminalSerializer, TerminalHeatbeatSerializer +from .hands import IsSuperUserOrAppUser, IsAppUser, User, ProxyLog +from common.utils import get_object_or_none + + +class TerminalRegisterView(ListCreateAPIView): + queryset = Terminal.objects.all() + serializer_class = TerminalSerializer + permission_classes = (AllowAny,) + + def create(self, request, *args, **kwargs): + name = request.data.get('name', '') + remote_addr = request.META.get('X-Real-IP') or \ + request.META.get('REMOTE_ADDR') + serializer = self.serializer_class( + data={'name': name, 'remote_addr': remote_addr}) + + if get_object_or_none(Terminal, name=name): + return Response({'msg': 'Already register, Need ' + 'administrator active it'}, status=200) + + if serializer.is_valid(): + terminal = serializer.save() + app_user, access_key = terminal.create_related_app_user() + data = OrderedDict() + data['terminal'] = copy.deepcopy(serializer.data) + data['user'] = app_user.to_json() + data['access_key_id'] = access_key.id + data['access_key_secret'] = access_key.secret + return Response(data, status=201) + else: + data = {'msg': 'Not valid', 'detail': ';'.join(serializer.errors)} + return Response(data, status=400) + + def list(self, request, *args, **kwargs): + return Response('', status=404) + + +class TerminalViewSet(viewsets.ModelViewSet): + queryset = Terminal.objects.all() + serializer_class = TerminalSerializer + permission_classes = (IsSuperUserOrAppUser,) + + def create(self, request, *args, **kwargs): + return Response({'msg': 'Use register view except that'}, status=404) + + # def destroy(self, request, *args, **kwargs): + # instance = self.get_object() + # if instance.user is not None: + # instance.user.delete() + # return super(TerminalViewSet, self).destroy(request, *args, **kwargs) + +tasks = OrderedDict() +# tasks = {1: [{'name': 'kill_proxy', 'proxy_log_id': 23}]} + + +class TerminalHeatbeatViewSet(viewsets.ModelViewSet): + queryset = TerminalHeatbeat.objects.all() + serializer_class = TerminalHeatbeatSerializer + permission_classes = (IsAppUser,) + + def create(self, request, *args, **kwargs): + terminal = request.user.terminal + TerminalHeatbeat.objects.create(terminal=terminal) + task = tasks.get(terminal.name) + tasks[terminal.name] = [] + return Response({'msg': 'Success', + 'tasks': task}, + status=201) + + +class TerminateConnectionView(APIView): + def post(self, request, *args, **kwargs): + if isinstance(request.data, dict): + data = [request.data] + else: + data = request.data + for d in data: + proxy_log_id = d.get('proxy_log_id') + proxy_log = get_object_or_404(ProxyLog, id=proxy_log_id) + terminal_id = proxy_log.terminal + proxy_log.is_finished = True + proxy_log.date_finished = timezone.now() + proxy_log.save() + if terminal_id in tasks: + tasks[terminal_id].append({'name': 'kill_proxy', + 'proxy_log_id': proxy_log_id}) + else: + tasks[terminal_id] = [{'name': 'kill_proxy', + 'proxy_log_id': proxy_log_id}] + + print(tasks) + return Response({'msg': 'get it'}) diff --git a/apps/applications/apps.py b/apps/applications/apps.py new file mode 100644 index 000000000..3c22ddedc --- /dev/null +++ b/apps/applications/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class ApplicationsConfig(AppConfig): + name = 'applications' diff --git a/apps/applications/forms.py b/apps/applications/forms.py new file mode 100644 index 000000000..7ca7bea77 --- /dev/null +++ b/apps/applications/forms.py @@ -0,0 +1,19 @@ +# ~*~ coding: utf-8 ~*~ +# + +from django import forms +from django.utils.translation import ungettext_lazy as _ + +from .models import Terminal + + +class TerminalForm(forms.ModelForm): + class Meta: + model = Terminal + fields = ['name', 'remote_addr', 'type', 'url', 'comment'] + help_texts = { + 'url': 'Example: ssh://192.168.1.1:22 or http://jms.jumpserver.org, that user login' + } + widgets = { + 'name': forms.TextInput(attrs={'readonly': 'readonly'}) + } \ No newline at end of file diff --git a/apps/applications/hands.py b/apps/applications/hands.py new file mode 100644 index 000000000..cf5b643da --- /dev/null +++ b/apps/applications/hands.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# + +from users.models import User +from users.permissions import IsSuperUserOrAppUser, IsAppUser +from audits.models import ProxyLog \ No newline at end of file diff --git a/apps/applications/migrations/__init__.py b/apps/applications/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/applications/models.py b/apps/applications/models.py new file mode 100644 index 000000000..29adecdae --- /dev/null +++ b/apps/applications/models.py @@ -0,0 +1,62 @@ +from __future__ import unicode_literals + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from users.models import User + + +class Terminal(models.Model): + TYPE_CHOICES = ( + ('SSH', 'SSH Terminal'), + ('Web', 'Web Terminal') + ) + name = models.CharField(max_length=30, unique=True, verbose_name=_('Name')) + remote_addr = models.GenericIPAddressField(verbose_name=_('Remote address'), blank=True, null=True) + type = models.CharField(choices=TYPE_CHOICES, max_length=3, blank=True, verbose_name=_('Terminal type')) + user = models.OneToOneField(User, related_name='terminal', verbose_name='Application user', + null=True, on_delete=models.CASCADE) + url = models.CharField(max_length=100, blank=True, verbose_name=_('URL to login')) + is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted') + date_created = models.DateTimeField(auto_now_add=True) + comment = models.TextField(blank=True, verbose_name=_('Comment')) + + @property + def is_active(self): + if self.user and self.user.is_active: + return True + return False + + @is_active.setter + def is_active(self, active): + if self.user: + self.user.is_active = active + self.user.save() + + def create_related_app_user(self): + user, access_key = User.create_app_user(name=self.name, comment=self.comment) + self.user = user + self.save() + return user, access_key + + def delete(self, using=None, keep_parents=False): + if self.user: + self.user.delete() + return super(Terminal, self).delete(using=using, keep_parents=keep_parents) + + def __unicode__(self): + active = 'Active' if self.user and self.user.is_active else 'Disabled' + return '%s: %s' % (self.name, active) + + __str__ = __unicode__ + + class Meta: + ordering = ('is_accepted',) + + +class TerminalHeatbeat(models.Model): + terminal = models.ForeignKey(Terminal, on_delete=models.CASCADE) + date_created = models.DateTimeField(auto_now_add=True) + + class Meta: + db_table = 'terminal_heatbeat' diff --git a/apps/applications/serializers.py b/apps/applications/serializers.py new file mode 100644 index 000000000..56f05e67c --- /dev/null +++ b/apps/applications/serializers.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# + +from django.utils import timezone +from rest_framework import serializers + +from .models import Terminal, TerminalHeatbeat +from .hands import ProxyLog + + +class TerminalSerializer(serializers.ModelSerializer): + proxy_online = serializers.SerializerMethodField() + is_alive = serializers.SerializerMethodField() + + class Meta: + model = Terminal + fields = ['id', 'name', 'remote_addr', 'type', 'url', 'comment', + 'is_accepted', 'is_active', 'get_type_display', + 'proxy_online', 'is_alive'] + + @staticmethod + def get_proxy_online(obj): + return ProxyLog.objects.filter(terminal=obj.name, is_finished=False).count() + + @staticmethod + def get_is_alive(obj): + log = obj.terminalheatbeat_set.last() + if log and timezone.now() - log.date_created < timezone.timedelta(seconds=600): + return True + else: + return False + + +class TerminalHeatbeatSerializer(serializers.ModelSerializer): + date_start = serializers.DateTimeField + class Meta: + model = TerminalHeatbeat + + +if __name__ == '__main__': + pass diff --git a/apps/applications/tasks.py b/apps/applications/tasks.py new file mode 100644 index 000000000..69a80f243 --- /dev/null +++ b/apps/applications/tasks.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + + diff --git a/apps/applications/templates/applications/terminal_detail.html b/apps/applications/templates/applications/terminal_detail.html new file mode 100644 index 000000000..dee320c08 --- /dev/null +++ b/apps/applications/templates/applications/terminal_detail.html @@ -0,0 +1,77 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ terminal.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ terminal.name }}
{% trans 'Remote addr' %}:{{ terminal.remote_addr }}
{% trans 'Terminal url' %}:{{ terminal.url }}
{% trans 'Terminal type' %}:{{ terminal.get_type_display }}
{% trans 'Date created' %}:{{ terminal.date_created }}
{% trans 'Comment' %}:{{ asset.comment }}
+
+
+
+
+
+
+
+
+{% endblock %} + diff --git a/apps/applications/templates/applications/terminal_list.html b/apps/applications/templates/applications/terminal_list.html new file mode 100644 index 000000000..33a04c009 --- /dev/null +++ b/apps/applications/templates/applications/terminal_list.html @@ -0,0 +1,138 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block custom_head_css_js %} +{{ block.super }} + + +{% endblock %} +{% block table_search %}{% endblock %} +{% block table_container %} +{##} + + + + + + + + + + + + + + + +
+
+ +
+
{% trans 'Name' %}{% trans 'IP' %}{% trans 'Type' %}{% trans 'proxy online' %}{% trans 'Active' %}{% trans 'Alive' %}{% trans 'Action' %}
+{% include 'applications/terminal_modal_accept.html' %} + +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/applications/templates/applications/terminal_modal_accept.html b/apps/applications/templates/applications/terminal_modal_accept.html new file mode 100644 index 000000000..1a9cc384e --- /dev/null +++ b/apps/applications/templates/applications/terminal_modal_accept.html @@ -0,0 +1,19 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}modal_terminal_accept{% endblock %} +{% block modal_class %}modal-lg{% endblock %} +{% block modal_title%}{% trans "Accept terminal registration" %}{% endblock %} +{% block modal_body %} +{% load bootstrap %} +
+ {% csrf_token %} + + {{ form.name|bootstrap_horizontal }} + {{ form.remote_addr|bootstrap_horizontal }} + {{ form.type|bootstrap_horizontal }} + {{ form.url|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
+ +{% endblock %} +{% block modal_confirm_id %}btn_terminal_accept{% endblock %} \ No newline at end of file diff --git a/apps/applications/templates/applications/terminal_modal_test.html b/apps/applications/templates/applications/terminal_modal_test.html new file mode 100644 index 000000000..862e39f62 --- /dev/null +++ b/apps/applications/templates/applications/terminal_modal_test.html @@ -0,0 +1,5 @@ +
+ {% csrf_token %} + {{ form }} + +
\ No newline at end of file diff --git a/apps/applications/templates/applications/terminal_update.html b/apps/applications/templates/applications/terminal_update.html new file mode 100644 index 000000000..718ceda94 --- /dev/null +++ b/apps/applications/templates/applications/terminal_update.html @@ -0,0 +1,72 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+
+
+ {% csrf_token %} +

{% trans 'Info' %}

+ {{ form.name|bootstrap_horizontal }} + {{ form.remote_addr|bootstrap_horizontal }} + {{ form.type|bootstrap_horizontal }} + {{ form.url|bootstrap_horizontal }} + +
+

{% trans 'Other' %}

+ {{ form.comment|bootstrap_horizontal }} +
+
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/applications/tests.py b/apps/applications/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/applications/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/applications/urls/__init__.py b/apps/applications/urls/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/applications/urls/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/applications/urls/api_urls.py b/apps/applications/urls/api_urls.py new file mode 100644 index 000000000..ed0e42c32 --- /dev/null +++ b/apps/applications/urls/api_urls.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from django.conf.urls import url +from rest_framework import routers + +from .. import api + +app_name = 'applications' + +router = routers.DefaultRouter() +router.register(r'v1/terminal/heatbeat', api.TerminalHeatbeatViewSet, 'terminal-heatbeat') +router.register(r'v1/terminal', api.TerminalViewSet, 'terminal') + +urlpatterns = [ + url(r'^v1/terminal/register/$', api.TerminalRegisterView.as_view(), + name='terminal-register'), + url(r'^v1/terminate/connection/$', api.TerminateConnectionView.as_view(), + name='terminate-connection') + # url(r'^v1/terminal/heatbeat/$', api.TestHeatbeat.as_view()) +] + +urlpatterns += router.urls diff --git a/apps/applications/urls/views_urls.py b/apps/applications/urls/views_urls.py new file mode 100644 index 000000000..717234aa3 --- /dev/null +++ b/apps/applications/urls/views_urls.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from django.conf.urls import url + +from .. import views + +app_name = 'applications' + +urlpatterns = [ + url(r'^terminal$', views.TerminalListView.as_view(), name='terminal-list'), + url(r'^terminal/(?P\d+)/$', views.TerminalDetailView.as_view(), + name='terminal-detail'), + url(r'^terminal/(?P\d+)/update$', views.TerminalUpdateView.as_view(), + name='terminal-update'), + url(r'^terminal/(?P\d+)/modal/accept$', views.TerminalModelAccept.as_view(), + name='terminal-modal-accept'), +] diff --git a/apps/applications/views.py b/apps/applications/views.py new file mode 100644 index 000000000..dcf1f182c --- /dev/null +++ b/apps/applications/views.py @@ -0,0 +1,90 @@ +# ~*~ coding: utf-8 ~*~ +# + +from django.views.generic import ListView, UpdateView, DeleteView, DetailView +from django.views.generic.edit import BaseUpdateView +from django.utils.translation import ugettext as _ +from django.urls import reverse_lazy + +from .models import Terminal +from users.utils import AdminUserRequiredMixin +from common.mixins import JSONResponseMixin +from .forms import TerminalForm + + +class TerminalListView(ListView): + model = Terminal + template_name = 'applications/terminal_list.html' + form_class = TerminalForm + + def get_context_data(self, **kwargs): + context = super(TerminalListView, self).get_context_data(**kwargs) + context.update({ + 'app': _('Terminal'), + 'action': _('Terminal list'), + 'form': self.form_class() + }) + return context + + +class TerminalUpdateView(UpdateView): + model = Terminal + form_class = TerminalForm + template_name = 'applications/terminal_update.html' + success_url = reverse_lazy('applications:applications-list') + + def get_context_data(self, **kwargs): + context = super(TerminalUpdateView, self).get_context_data(**kwargs) + context.update({'app': _('Applications'), 'action': _('Update terminal')}) + return context + + +class TerminalDetailView(DetailView): + model = Terminal + template_name = 'applications/terminal_detail.html' + context_object_name = 'terminal' + + def get_context_data(self, **kwargs): + context = super(TerminalDetailView, self).get_context_data(**kwargs) + context.update({ + 'app': _('Applications'), + 'action': _('Terminal detail') + }) + return context + + +class TerminalDeleteView(DeleteView): + model = Terminal + template_name = 'assets/delete_confirm.html' + success_url = reverse_lazy('applications:applications-list') + + +class TerminalModelAccept(AdminUserRequiredMixin, JSONResponseMixin, UpdateView): + model = Terminal + form_class = TerminalForm + template_name = 'applications/terminal_modal_test.html' + + def post(self, request, *args, **kwargs): + print(request.POST) + return super(TerminalModelAccept, self).post(request, *args, **kwargs) + + def form_valid(self, form): + terminal = form.save() + terminal.is_accepted = True + terminal.is_active = True + terminal.save() + data = { + 'success': True, + 'msg': 'success' + } + return self.render_json_response(data) + + def form_invalid(self, form): + print('form.data') + data = { + 'success': False, + 'msg': str(form.errors), + } + return self.render_json_response(data) + + diff --git a/apps/assets/__init__.py b/apps/assets/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/assets/api.py b/apps/assets/api.py new file mode 100644 index 000000000..0d427b91f --- /dev/null +++ b/apps/assets/api.py @@ -0,0 +1,162 @@ +# ~*~ coding: utf-8 ~*~ + +from rest_framework import viewsets, generics, mixins + +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework_bulk import BulkModelViewSet, BulkDestroyAPIView +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin, ListBulkCreateUpdateDestroyAPIView +from django.shortcuts import get_object_or_404 + +from common.mixins import IDInFilterMixin +from common.utils import get_object_or_none, signer +from .hands import IsSuperUser, IsAppUser +from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser, Tag +from . import serializers + + +class AssetViewSet(IDInFilterMixin, BulkModelViewSet): + """API endpoint that allows Asset to be viewed or edited.""" + queryset = Asset.objects.all() + serializer_class = serializers.AssetSerializer + permission_classes = (IsSuperUser,) + + def get_queryset(self): + queryset = super(AssetViewSet, self).get_queryset() + idc_id = self.request.query_params.get('idc_id', '') + tags_id = self.request.query_params.get('tag_id', '') + system_users_id = self.request.query_params.get('system_user_id', '') + asset_group_id = self.request.query_params.get('asset_group_id', '') + admin_user_id = self.request.query_params.get('admin_user_id', '') + if idc_id: + queryset = queryset.filter(idc__id=idc_id) + if tags_id: + queryset = queryset.filter(tags__id=tags_id) + if system_users_id: + queryset = queryset.filter(system_users__id=system_users_id) + if admin_user_id: + queryset = queryset.filter(admin_user__id=admin_user_id) + if asset_group_id: + queryset = queryset.filter(groups__id=asset_group_id) + return queryset + + +class AssetGroupViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupSerializer + permission_classes = (IsSuperUser,) + + +class AssetUpdateGroupApi(generics.RetrieveUpdateAPIView): + queryset = Asset.objects.all() + serializer_class = serializers.AssetUpdateGroupSerializer + permission_classes = (IsSuperUser,) + + +## update the asset group, and add or delete the asset to the group +class AssetGroupUpdateApi(generics.RetrieveUpdateAPIView): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupUpdateSerializer + permission_classes = (IsSuperUser,) + + +## update the asset group, and add or delete the system_user to the group +class AssetGroupUpdateSystemUserApi(generics.RetrieveUpdateAPIView): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupUpdateSystemUserSerializer + permission_classes = (IsSuperUser,) + + +## update the IDC, and add or delete the assets to the IDC +class IDCupdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = IDC.objects.all() + serializer_class = serializers.IDCUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + + +class IDCViewSet(IDInFilterMixin, BulkModelViewSet): + """API endpoint that allows IDC to be viewed or edited.""" + queryset = IDC.objects.all() + serializer_class = serializers.IDCSerializer + permission_classes = (IsSuperUser,) + + +class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = AdminUser.objects.all() + serializer_class = serializers.AdminUserSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserUpdateApi(generics.RetrieveUpdateAPIView): + queryset = Asset.objects.all() + serializer_class = serializers.AssetUpdateSystemUserSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserUpdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserUpdateAssetGroupApi(generics.RetrieveUpdateAPIView): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserUpdateAssetGroupSerializer + permission_classes = (IsSuperUser,) + + +# class IDCAssetsApi(generics.ListAPIView): +# model = IDC +# serializer_class = serializers.AssetSerializer +# +# def get(self, request, *args, **kwargs): +# filter_kwargs = {self.lookup_field: self.kwargs[self.lookup_field]} +# self.object = get_object_or_404(self.model, **filter_kwargs) +# return super(IDCAssetsApi, self).get(request, *args, **kwargs) +# +# def get_queryset(self): +# return self.object.assets.all() + + +class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): + queryset = Asset.objects.all() + serializer_class = serializers.AssetSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserAuthInfoApi(generics.RetrieveAPIView): + queryset = SystemUser.objects.all() + permission_classes = (IsAppUser,) + + def retrieve(self, request, *args, **kwargs): + system_user = self.get_object() + data = { + 'id': system_user.id, + 'name': system_user.name, + 'username': system_user.username, + 'password': system_user.password, + 'private_key': system_user.private_key, + 'auth_method': system_user.auth_method, + } + return Response(data) + + +class TagViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = Tag.objects.all() + serializer_class = serializers.TagSerializer + permission_classes = (IsSuperUser,) + + +## update the IDC, and add or delete the assets to the IDC +class TagUpdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = Tag.objects.all() + serializer_class = serializers.TagUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + diff --git a/apps/assets/apps.py b/apps/assets/apps.py new file mode 100644 index 000000000..89c61e1db --- /dev/null +++ b/apps/assets/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class AssetsConfig(AppConfig): + name = 'assets' diff --git a/apps/assets/forms.py b/apps/assets/forms.py new file mode 100644 index 000000000..c8f846f15 --- /dev/null +++ b/apps/assets/forms.py @@ -0,0 +1,307 @@ +# coding:utf-8 +from django import forms +from django.utils.translation import gettext_lazy as _ + +from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag +from common.utils import validate_ssh_private_key, ssh_pubkey_gen + + +class AssetCreateForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + instance = kwargs.get('instance', None) + if instance: + initial = kwargs.get('initial', {}) + initial['tags'] = [t.pk for t in kwargs['instance'].tags.all()] + super(AssetCreateForm, self).__init__(*args, **kwargs) + + def _save_m2m(self): + super(AssetCreateForm, self)._save_m2m() + tags = self.cleaned_data['tags'] + self.instance.tags.clear() + self.instance.tags.add(*tuple(tags)) + + # def clean(self): + # clean_data = super(AssetCreateForm, self).clean() + # ip = clean_data.get('ip') + # port = clean_data.get('port') + # query = Asset.objects.filter(ip=ip, port=port) + # if query: + # raise forms.ValidationError('this asset has exists.') + + class Meta: + model = Asset + tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all()) + fields = [ + 'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups', + 'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', + 'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags', + ] + widgets = { + 'groups': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset groups')}), + 'tags': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset tags')}), + 'system_users': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset system users')}), + 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}), + } + help_texts = { + 'hostname': '* required', + 'ip': '* required', + 'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'), + 'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'), + 'tags': '最多5个标签,单个标签最长8个汉字,按回车确认' + } + + +class AssetGroupForm(forms.ModelForm): + # See AdminUserForm comment same it + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + + def __init__(self, *args, **kwargs): + if kwargs.get('instance', None): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(AssetGroupForm, self).__init__(*args, **kwargs) + + def _save_m2m(self): + super(AssetGroupForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + + class Meta: + model = AssetGroup + fields = [ + "name", "comment","system_users", + ] + widgets = { + 'name' : forms.TextInput(attrs={}), + 'system_users': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}), + + } + help_texts = { + 'name': '* required', + } + + +class IDCForm(forms.ModelForm): + # See AdminUserForm comment same it + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + + def __init__(self, *args, **kwargs): + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(IDCForm, self).__init__(*args, **kwargs) + + def _save_m2m(self): + super(IDCForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + + class Meta: + model = IDC + fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'intranet', 'extranet','comment'] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'intranet': forms.Textarea( + attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}), + 'extranet': forms.Textarea( + attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'}) + } + + +class AdminUserForm(forms.ModelForm): + # Admin user assets define, let user select, save it in form not in view + assets = forms.ModelMultipleChoiceField( + queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + # Form field name can not start with `_`, so redefine it, + password = forms.CharField( + widget=forms.PasswordInput, max_length=100, + min_length=8, strip=True, required=False, + help_text=_('If also set private key, use that first'), + ) + # Need use upload private key file except paste private key content + private_key_file = forms.FileField(required=False) + + def __init__(self, *args, **kwargs): + # When update a admin user instance, initial it + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(AdminUserForm, self).__init__(*args, **kwargs) + + def _save_m2m(self): + # Save assets relation with admin user + super(AdminUserForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + + def save(self, commit=True): + # Because we define custom field, so we need rewrite :method: `save` + admin_user = super(AdminUserForm, self).save(commit=commit) + password = self.cleaned_data['password'] + private_key = self.cleaned_data['private_key_file'] + + if password: + admin_user.password = password + if private_key: + public_key = ssh_pubkey_gen(private_key) + admin_user.private_key = private_key + admin_user.public_key = public_key + admin_user.save() + return admin_user + + def clean_private_key_file(self): + private_key_file = self.cleaned_data['private_key_file'] + if private_key_file: + private_key = private_key_file.read() + if not validate_ssh_private_key(private_key): + raise forms.ValidationError(_('Invalid private key')) + return private_key + return private_key_file + + def clean(self): + password = self.cleaned_data['password'] + private_key_file = self.cleaned_data.get('private_key_file', '') + + if not self.instance and not (password or private_key_file): + raise forms.ValidationError( + _('Password and private key file must be input one')) + + class Meta: + model = AdminUser + fields = ['name', 'username', 'password', 'private_key_file', 'comment'] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'username': forms.TextInput(attrs={'placeholder': _('Username')}), + } + help_texts = { + 'name': '* required', + 'username': '* required', + } + + +class SystemUserForm(forms.ModelForm): + # Admin user assets define, let user select, save it in form not in view + auto_generate_key = forms.BooleanField(initial=True, required=False) + # Form field name can not start with `_`, so redefine it, + password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True) + # Need use upload private key file except paste private key content + private_key_file = forms.FileField(required=False) + + def __init__(self, *args, **kwargs): + # When update a admin user instance, initial it + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + initial['asset_groups'] = kwargs['instance'].asset_groups.all() + super(SystemUserForm, self).__init__(*args, **kwargs) + + def save(self, commit=True): + # Because we define custom field, so we need rewrite :method: `save` + system_user = super(SystemUserForm, self).save(commit=commit) + password = self.cleaned_data['password'] + private_key_file = self.cleaned_data['private_key_file'] + + if system_user.auth_method == 'P': + if password: + system_user.password = password + print(password) + # Todo: Validate private key file, and generate public key + # Todo: Auto generate private key and public key + if private_key_file: + system_user.private_key = private_key_file.read().strip() + system_user.save() + return self.instance + + # Todo: check valid + # def clean_private_key_file(self): + # if not self.cleaned_data['auto_generate_key']: + # if not self.cleaned_data['private_key_file']: + # raise forms.ValidationError(_('Private key required')) + + # def clean_password(self): + # if self.cleaned_data['auth_method'] == 'P': + # if not self.cleaned_data['password']: + # raise forms.ValidationError(_('Password required')) + # return self.cleaned_data['password'] + + # def clean(self): + # password = self.cleaned_data['password'] + # private_key_file = self.cleaned_data.get('private_key_file', '') + # + # if not (password or private_key_file): + # raise forms.ValidationError(_('Password and private key file must be input one')) + + class Meta: + model = SystemUser + fields = [ + 'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'auth_method', + 'auto_push', 'sudo', 'comment', 'shell', 'home', 'uid', + ] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'username': forms.TextInput(attrs={'placeholder': _('Username')}), + } + help_texts = { + 'name': '* required', + 'username': '* required', + 'auto_push': 'Auto push system user to asset', + } + + +class AssetTagForm(forms.ModelForm): + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + + def __init__(self, *args, **kwargs): + if kwargs.get('instance', None): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].asset_set.all() + super(AssetTagForm, self).__init__(*args, **kwargs) + + def _save_m2m(self): + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + super(AssetTagForm, self)._save_m2m() + + class Meta: + model = Tag + fields = [ + "name", + ] + widgets = { + 'name' : forms.TextInput(attrs={}), + + } + help_texts = { + 'name': '* required', + } + + +class FileForm(forms.Form): + file = forms.FileField() diff --git a/apps/assets/hands.py b/apps/assets/hands.py new file mode 100644 index 000000000..633a995f6 --- /dev/null +++ b/apps/assets/hands.py @@ -0,0 +1,16 @@ +""" + jumpserver.__app__.hands.py + ~~~~~~~~~~~~~~~~~ + + This app depends other apps api, function .. should be import or write mack here. + + Other module of this app shouldn't connect with other app. + + :copyright: (c) 2014-2016 by Jumpserver Team. + :license: GPL v2, see LICENSE for more details. +""" + + +from users.utils import AdminUserRequiredMixin +from users.permissions import IsAppUser, IsSuperUser +from users.models import User, UserGroup diff --git a/apps/assets/migrations/__init__.py b/apps/assets/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/assets/models/__init__.py b/apps/assets/models/__init__.py new file mode 100644 index 000000000..5ee3050c4 --- /dev/null +++ b/apps/assets/models/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from .idc import * +from .user import * +from .group import * +from .asset import * diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py new file mode 100644 index 000000000..da1ee37d6 --- /dev/null +++ b/apps/assets/models/asset.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals + +from django.db import models +import logging +from django.utils.translation import ugettext_lazy as _ + +from . import IDC, AssetGroup, AdminUser, SystemUser + +__all__ = ['Asset', 'Tag'] +logger = logging.getLogger(__name__) + + +def get_default_idc(): + return IDC.initial() + + +class Asset(models.Model): + STATUS_CHOICES = ( + ('In use', _('In use')), + ('Out of use', _('Out of use')), + ) + TYPE_CHOICES = ( + ('Server', _('Server')), + ('VM', _('VM')), + ('Switch', _('Switch')), + ('Router', _('Router')), + ('Firewall', _('Firewall')), + ('Storage', _("Storage")), + ) + ENV_CHOICES = ( + ('Prod', 'Production'), + ('Dev', 'Development'), + ('Test', 'Testing'), + ) + + ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True) + other_ip = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('Other IP')) + remote_card_ip = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Remote card IP')) + hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname')) + port = models.IntegerField(default=22, verbose_name=_('Port')) + groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets', verbose_name=_('Asset groups')) + admin_user = models.ForeignKey(AdminUser, null=True, blank=True, related_name='assets', + on_delete=models.SET_NULL, verbose_name=_("Admin user")) + system_users = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User")) + idc = models.ForeignKey(IDC, blank=True, null=True, related_name='assets', + on_delete=models.SET_NULL, verbose_name=_('IDC'),) + mac_address = models.CharField(max_length=20, null=True, blank=True, verbose_name=_("Mac address")) + brand = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Brand')) + cpu = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('CPU')) + memory = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Memory')) + disk = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk')) + os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS')) + cabinet_no = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Cabinet number')) + cabinet_pos = models.IntegerField(null=True, blank=True, verbose_name=_('Cabinet position')) + number = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Asset number')) + status = models.CharField(choices=STATUS_CHOICES, max_length=8, null=True, blank=True, + default='In use', verbose_name=_('Asset status')) + type = models.CharField(choices=TYPE_CHOICES, max_length=16, blank=True, null=True, + default='Server', verbose_name=_('Asset type'),) + env = models.CharField(choices=ENV_CHOICES, max_length=8, blank=True, null=True, + default='Prod', verbose_name=_('Asset environment'),) + sn = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Serial number')) + created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) + is_active = models.BooleanField(default=True, verbose_name=_('Is active')) + date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date added')) + comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) + tags = models.ManyToManyField('Tag', related_name='assets', blank=True, verbose_name=_('Tags')) + + def __unicode__(self): + return '%(ip)s:%(port)s' % {'ip': self.ip, 'port': self.port} + + __str__ = __unicode__ + + @property + def is_valid(self): + warning = '' + if not self.is_active: + warning += ' inactive' + else: + return True, '' + return False, warning + + def to_json(self): + pass + + class Meta: + unique_together = ('ip', 'port') + + @classmethod + def generate_fake(cls, count=100): + from random import seed, choice + import forgery_py + from django.db import IntegrityError + + seed() + for i in range(count): + asset = cls(ip='%s.%s.%s.%s' % (i, i, i, i), + hostname=forgery_py.internet.user_name(True), + admin_user=choice(AdminUser.objects.all()), + idc=choice(IDC.objects.all()), + port=22, + created_by='Fake') + try: + asset.save() + asset.system_users = [choice(SystemUser.objects.all()) for i in range(3)] + asset.groups = [choice(AssetGroup.objects.all()) for i in range(3)] + logger.debug('Generate fake asset : %s' % asset.ip) + except IntegrityError: + print('Error continue') + continue + + +class Tag(models.Model): + name = models.CharField(max_length=64, unique=True, verbose_name=_('Name')) + created_time = models.DateTimeField(auto_now_add=True, verbose_name=_('Create time')) + created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) + + def __unicode__(self): + return self.name + + __str__ = __unicode__ + + class Meta: + db_table = 'tag' diff --git a/apps/assets/models/group.py b/apps/assets/models/group.py new file mode 100644 index 000000000..dfae079f4 --- /dev/null +++ b/apps/assets/models/group.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals + +from django.db import models +import logging +from django.utils.translation import ugettext_lazy as _ + +from . import SystemUser + +__all__ = ['AssetGroup'] +logger = logging.getLogger(__name__) + + +class AssetGroup(models.Model): + name = models.CharField(max_length=64, unique=True, verbose_name=_('Name')) + system_users = models.ManyToManyField(SystemUser, related_name='asset_groups', blank=True) + created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) + date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date added')) + comment = models.TextField(blank=True, verbose_name=_('Comment')) + + def __unicode__(self): + return self.name + + class Meta: + ordering = ['name'] + + @classmethod + def initial(cls): + asset_group = cls(name=_('Default'), comment=_('Default asset group')) + asset_group.save() + + @classmethod + def generate_fake(cls, count=100): + from random import seed + import forgery_py + from django.db import IntegrityError + + seed() + for i in range(count): + group = cls(name=forgery_py.name.full_name(), + comment=forgery_py.lorem_ipsum.sentence(), + created_by='Fake') + try: + group.save() + logger.debug('Generate fake asset group: %s' % group.name) + except IntegrityError: + print('Error continue') + continue diff --git a/apps/assets/models/idc.py b/apps/assets/models/idc.py new file mode 100644 index 000000000..18ccc642d --- /dev/null +++ b/apps/assets/models/idc.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals + +from django.db import models +import logging +from django.utils.translation import ugettext_lazy as _ + + +__all__ = ['IDC'] +logger = logging.getLogger(__name__) + + +class IDC(models.Model): + name = models.CharField(max_length=32, verbose_name=_('Name')) + bandwidth = models.CharField(max_length=32, blank=True, verbose_name=_('Bandwidth')) + contact = models.CharField(max_length=16, blank=True, verbose_name=_('Contact')) + phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone')) + address = models.CharField(max_length=128, blank=True, verbose_name=_("Address")) + intranet = models.TextField(blank=True, verbose_name=_('Intranet')) + extranet = models.TextField(blank=True, verbose_name=_('Extranet')) + date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date added')) + operator = models.CharField(max_length=32, blank=True, verbose_name=_('Operator')) + created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) + comment = models.TextField(blank=True, verbose_name=_('Comment')) + + def __unicode__(self): + return self.name + + @classmethod + def initial(cls): + return cls.objects.get_or_create(name=_('Default'), created_by=_('System'), comment=_('Default IDC'))[0] + + class Meta: + ordering = ['name'] + + @classmethod + def generate_fake(cls, count=100): + from random import seed, choice + import forgery_py + from django.db import IntegrityError + + seed() + for i in range(count): + idc = cls(name=forgery_py.name.full_name(), + bandwidth='200M', + contact=forgery_py.name.full_name(), + phone=forgery_py.address.phone(), + address=forgery_py.address.city() + forgery_py.address.street_address(), + operator=choice(['北京联通', '北京电信', 'BGP全网通']), + comment=forgery_py.lorem_ipsum.sentence(), + created_by='Fake') + try: + idc.save() + logger.debug('Generate fake asset group: %s' % idc.name) + except IntegrityError: + print('Error continue') + continue + diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py new file mode 100644 index 000000000..5440d3910 --- /dev/null +++ b/apps/assets/models/user.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals + +from django.db import models +import logging +from django.utils.translation import ugettext_lazy as _ +from django.core.exceptions import ValidationError + +from common.utils import signer, validate_ssh_private_key + +__all__ = ['AdminUser', 'SystemUser', 'private_key_validator'] +logger = logging.getLogger(__name__) + + +def private_key_validator(value): + if not validate_ssh_private_key(value): + raise ValidationError( + _('%(value)s is not an even number'), + params={'value': value}, + ) + + +class AdminUser(models.Model): + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) + username = models.CharField(max_length=16, verbose_name=_('Username')) + _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) + _private_key = models.CharField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), + validators=[private_key_validator,]) + _public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key')) + comment = models.TextField(blank=True, verbose_name=_('Comment')) + date_created = models.DateTimeField(auto_now_add=True, null=True) + created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by')) + + def __unicode__(self): + return self.name + + __str__ = __unicode__ + + @property + def password(self): + return signer.unsign(self._password) + + @password.setter + def password(self, password_raw): + self._password = signer.sign(password_raw) + + @property + def private_key(self): + return signer.unsign(self._private_key) + + @private_key.setter + def private_key(self, private_key_raw): + self._private_key = signer.sign(private_key_raw) + + @property + def public_key(self): + return signer.unsign(self._public_key) + + @public_key.setter + def public_key(self, public_key_raw): + self._public_key = signer.sign(public_key_raw) + + @property + def assets_amount(self): + return self.assets.count() + + class Meta: + ordering = ['name'] + + @classmethod + def generate_fake(cls, count=100): + from random import seed + import forgery_py + from django.db import IntegrityError + + seed() + for i in range(count): + obj = cls(name=forgery_py.name.full_name(), + username=forgery_py.internet.user_name(), + password=forgery_py.lorem_ipsum.word(), + comment=forgery_py.lorem_ipsum.sentence(), + created_by='Fake') + try: + obj.save() + logger.debug('Generate fake asset group: %s' % obj.name) + except IntegrityError: + print('Error continue') + continue + + +class SystemUser(models.Model): + PROTOCOL_CHOICES = ( + ('ssh', 'ssh'), + ) + AUTH_METHOD_CHOICES = ( + ('P', 'Password'), + ('K', 'Public key'), + ) + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) + username = models.CharField(max_length=16, verbose_name=_('Username')) + _password = models.CharField(max_length=256, blank=True, verbose_name=_('Password')) + protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol')) + _private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key')) + _public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key')) + auth_method = models.CharField(choices=AUTH_METHOD_CHOICES, default='K', + max_length=1, verbose_name=_('Auth method')) + auto_push = models.BooleanField(default=True, verbose_name=_('Auto push')) + auto_update = models.BooleanField(default=True, verbose_name=_('Auto update pass/key')) + sudo = models.TextField(max_length=4096, default='/user/bin/whoami', verbose_name=_('Sudo')) + shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell')) + home = models.CharField(max_length=64, blank=True, verbose_name=_('Home')) + uid = models.IntegerField(null=True, blank=True, verbose_name=_('Uid')) + date_created = models.DateTimeField(auto_now_add=True) + created_by = models.CharField(max_length=32, blank=True, verbose_name=_('Created by')) + comment = models.TextField(max_length=128, blank=True, verbose_name=_('Comment')) + + def __unicode__(self): + return self.name + + @property + def password(self): + return signer.unsign(self._password) + + @password.setter + def password(self, password_raw): + self._password = signer.sign(password_raw) + + @property + def private_key(self): + return signer.unsign(self._private_key) + + @private_key.setter + def private_key(self, private_key_raw): + self._private_key = signer.sign(private_key_raw) + + @property + def public_key(self): + return signer.unsign(self._public_key) + + @public_key.setter + def public_key(self, public_key_raw): + self._public_key = signer.sign(public_key_raw) + + def get_assets_inherit_from_asset_groups(self): + assets = set() + asset_groups = self.asset_groups.all() + for asset_group in asset_groups: + for asset in asset_group.assets.all(): + setattr(asset, 'is_inherit_from_asset_groups', True) + setattr(asset, 'inherit_from_asset_groups', + getattr(asset, b'inherit_from_asset_groups', set()).add(asset_group)) + assets.add(asset) + return assets + + def get_assets(self): + assets = set(self.assets.all()) | self.get_assets_inherit_from_asset_groups() + return list(assets) + + @property + def assets_amount(self): + return self.assets.count() + + @property + def asset_group_amount(self): + return self.asset_groups.count() + + def to_json(self): + return { + 'id': self.id, + 'name': self.name, + 'username': self.username, + 'protocol': self.protocol, + 'auth_method': self.auth_method, + 'auto_push': self.auto_push, + } + + class Meta: + ordering = ['name'] + + @classmethod + def generate_fake(cls, count=100): + from random import seed + import forgery_py + from django.db import IntegrityError + + seed() + for i in range(count): + obj = cls(name=forgery_py.name.full_name(), + username=forgery_py.internet.user_name(), + password=forgery_py.lorem_ipsum.word(), + comment=forgery_py.lorem_ipsum.sentence(), + created_by='Fake') + try: + obj.save() + logger.debug('Generate fake asset group: %s' % obj.name) + except IntegrityError: + print('Error continue') + continue + diff --git a/apps/assets/models/utils.py b/apps/assets/models/utils.py new file mode 100644 index 000000000..ed2727cdb --- /dev/null +++ b/apps/assets/models/utils.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +from . import IDC, SystemUser, AdminUser, AssetGroup, Asset, Tag + +__all__ = ['initial', 'generate_fake'] + + +def initial(): + for cls in [IDC, SystemUser, AdminUser, AssetGroup, Asset, Tag]: + if hasattr(cls, 'initial'): + cls.initial() + + +def generate_fake(): + for cls in [IDC, SystemUser, AdminUser, AssetGroup, Asset, Tag]: + if hasattr(cls, 'generate_fake'): + cls.generate_fake() + + +if __name__ == '__main__': + pass diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py new file mode 100644 index 000000000..a9c9c41a8 --- /dev/null +++ b/apps/assets/serializers.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +from django.utils.translation import ugettext_lazy as _ +from rest_framework import viewsets, serializers,generics +from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser, Tag +from common.mixins import IDInFilterMixin +from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin + + +class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = AssetGroup + list_serializer_class = BulkListSerializer + fields = ['id', 'name', 'comment', 'assets_amount', 'assets'] + + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() + + +class AssetUpdateGroupSerializer(serializers.ModelSerializer): + groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) + + class Meta: + model = Asset + fields = ['id', 'groups'] + + +class AssetUpdateSystemUserSerializer(serializers.ModelSerializer): + system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) + + class Meta: + model = Asset + fields = ['id', 'system_users'] + + +class AssetGroupUpdateSerializer(serializers.ModelSerializer): + """update the asset group, and add or delete the asset to the group""" + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = AssetGroup + fields = ['id', 'assets'] + + +class AssetGroupUpdateSystemUserSerializer(serializers.ModelSerializer): + system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) + + class Meta: + model = AssetGroup + fields = ['id', 'system_users'] + + +class IDCUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = IDC + fields = ['id', 'assets'] + + +class TagSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = Tag + list_serializer_class = BulkListSerializer + fields = '__all__' + + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() + + +class AdminUserSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = AdminUser + fields = '__all__' + + def get_field_names(self, declared_fields, info): + fields = super(AdminUserSerializer, self).get_field_names(declared_fields, info) + fields.append('assets_amount') + return fields + + +class SystemUserSerializer(serializers.ModelSerializer): + class Meta: + model = SystemUser + exclude = ('_password', '_private_key', '_public_key') + + def get_field_names(self, declared_fields, info): + fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) + fields.extend(['assets_amount']) + return fields + + +class AssetSystemUserSerializer(serializers.ModelSerializer): + class Meta: + model = SystemUser + fields = ('id', 'name', 'username', 'protocol', 'auth_method', 'comment') + + +class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = SystemUser + fields = ['id', 'assets'] + + +class SystemUserUpdateAssetGroupSerializer(serializers.ModelSerializer): + asset_groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) + + class Meta: + model = SystemUser + fields = ['id', 'asset_groups'] + + +class SystemUserSimpleSerializer(serializers.ModelSerializer): + class Meta: + model = SystemUser + fields = ('id', 'name', 'username') + + +class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): + # system_users = SystemUserSerializer(many=True, read_only=True) + # admin_user = AdminUserSerializer(many=False, read_only=True) + hardware = serializers.SerializerMethodField() + + class Meta(object): + model = Asset + list_serializer_class = BulkListSerializer + fields = '__all__' + + @staticmethod + def get_hardware(obj): + if obj.cpu: + return '%s %s %s' % (obj.cpu, obj.memory, obj.disk) + else: + return '' + + def get_field_names(self, declared_fields, info): + fields = super(AssetSerializer, self).get_field_names(declared_fields, info) + fields.extend(['get_type_display', 'get_env_display']) + return fields + + +class AssetGrantedSerializer(serializers.ModelSerializer): + system_users_granted = AssetSystemUserSerializer(many=True, read_only=True) + is_inherited = serializers.SerializerMethodField() + system_users_join = serializers.SerializerMethodField() + + class Meta(object): + model = Asset + fields = ("id", "hostname", "ip", "port", "system_users_granted", "is_inherited", + "is_active", "system_users_join", "comment") + + @staticmethod + def get_is_inherited(obj): + if getattr(obj, 'inherited', ''): + return True + else: + return False + + @staticmethod + def get_system_users_join(obj): + return ', '.join([system_user.username for system_user in obj.system_users_granted]) + + +class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = IDC + fields = '__all__' + + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() + + def get_field_names(self, declared_fields, info): + fields = super(IDCSerializer, self).get_field_names(declared_fields, info) + fields.append('assets_amount') + return fields + + +class TagUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = Tag + fields = ['id', 'assets'] \ No newline at end of file diff --git a/apps/assets/templates/assets/_asset_bulk_update_modal.html b/apps/assets/templates/assets/_asset_bulk_update_modal.html new file mode 100644 index 000000000..9ff3d2973 --- /dev/null +++ b/apps/assets/templates/assets/_asset_bulk_update_modal.html @@ -0,0 +1,82 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}asset_bulk_update_modal{% endblock %} +{% block modal_class %}modal-lg{% endblock %} +{% block modal_title%}{% trans "Update Asset" %}{% endblock %} +{% block modal_body %} +{% load bootstrap %} +

{% trans "Hint: only change the field you want to update." %}

+ +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+
+ + +
+ +
+ +

+ 最多5个标签,单个标签最长8个汉字,按回车确认 +

+
+ +
+ +
+{% endblock %} +{% block modal_confirm_id %}btn_asset_bulk_update{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/_asset_group_bulk_update_modal.html b/apps/assets/templates/assets/_asset_group_bulk_update_modal.html new file mode 100644 index 000000000..80967da34 --- /dev/null +++ b/apps/assets/templates/assets/_asset_group_bulk_update_modal.html @@ -0,0 +1,42 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}asset_group_bulk_update_modal{% endblock %} +{% block modal_class %}modal-lg{% endblock %} +{% block modal_title%}{% trans "Update Asset Group" %}{% endblock %} +{% block modal_body %} +{% load bootstrap %} +

{% trans "Hint: only change the field you want to update." %}

+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+
+ +
+
+
+ +
+{% endblock %} +{% block modal_confirm_id %}btn_asset_group_bulk_update{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/_asset_import_modal.html b/apps/assets/templates/assets/_asset_import_modal.html new file mode 100644 index 000000000..72d13f7a8 --- /dev/null +++ b/apps/assets/templates/assets/_asset_import_modal.html @@ -0,0 +1,27 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}asset_import_modal{% endblock %} +{% block modal_title%}{% trans "Import asset" %}{% endblock %} +{% block modal_body %} +

{% trans "Download template or use export excel format" %}

+
+ {% csrf_token %} +
+ + {% trans 'Download' %} +
+
+ + +
+
+

+

+

+

+

+

+

+

+{% endblock %} +{% block modal_confirm_id %}btn_asset_import{% endblock %} diff --git a/apps/assets/templates/assets/admin_user_create_update.html b/apps/assets/templates/assets/admin_user_create_update.html new file mode 100644 index 000000000..2849a51c5 --- /dev/null +++ b/apps/assets/templates/assets/admin_user_create_update.html @@ -0,0 +1,63 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{% trans 'Create admin user' %}
+ +
+
+ {% if form.non_field_errors %} +
+ {{ form.non_field_errors }} +
+ {% endif %} +
+ {% csrf_token %} + {{ form.name|bootstrap_horizontal }} + {{ form.username|bootstrap_horizontal }} + {{ form.password|bootstrap_horizontal }} + {{ form.private_key_file|bootstrap_horizontal }} + {{ form.assets|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} + +
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html new file mode 100644 index 000000000..2d4cd53ef --- /dev/null +++ b/apps/assets/templates/assets/admin_user_detail.html @@ -0,0 +1,440 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ admin_user.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ admin_user.name }}
{% trans 'Username' %}:{{ admin_user.username }}
{% trans 'Date created' %}:{{ admin_user.date_created }}
{% trans 'Created by' %}:{{ asset_group.created_by }}
{% trans 'Comment' %}:{{ admin_user.comment }}
+
+
+ +
+
+ {% trans 'Asset list of ' %} {{ admin_user.name }} {{ paginator.count }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + +{# {% for asset in page_obj %}#} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# {% endfor %}#} + +
{% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Alive' %}{% trans 'Action' %}
{{ asset.hostname }}{{ asset.ip }}{{ asset.port }}Alive
+{#
#} +{# {% include '_pagination.html' %}#} +{#
#} +
+
+
+
+
+
+ {% trans 'Quick update' %} +
+
+ + + + + + + + + + + + + + + + + +
{% trans 'Get install script' %}: + + + +
{% trans 'Retest asset connectivity' %}: + + + +
{% trans 'Reset private key' %}: + + + +
+
+
+ +
+
+ {% trans 'Replace asset admin user with this' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+ {% trans 'Replace asset admin user with this admin user' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html new file mode 100644 index 000000000..73539ff5e --- /dev/null +++ b/apps/assets/templates/assets/admin_user_list.html @@ -0,0 +1,137 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %} +{% endblock %} +{% block table_container %} + + + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Username' %}{% trans 'Asset num' %}{% trans 'Lost connection' %}{% trans 'Comment' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + + + diff --git a/apps/assets/templates/assets/asset_create.html b/apps/assets/templates/assets/asset_create.html new file mode 100644 index 000000000..1a4aa38d5 --- /dev/null +++ b/apps/assets/templates/assets/asset_create.html @@ -0,0 +1,51 @@ +{% extends '_base_create_update.html' %} +{% load static %} +{% load bootstrap %} +{% load i18n %} + +{% block form %} +
+ {% csrf_token %} +

{% trans 'Basic' %}

+ {{ form.hostname|bootstrap_horizontal }} + {{ form.ip|bootstrap_horizontal }} + {{ form.port|bootstrap_horizontal }} + {{ form.type|bootstrap_horizontal }} + +
+

{% trans 'Group' %}

+ {{ form.idc|bootstrap_horizontal }} + {{ form.groups|bootstrap_horizontal }} + +
+

{% trans 'Asset user' %}

+ {{ form.admin_user|bootstrap_horizontal }} + {{ form.system_users|bootstrap_horizontal }} + +
+

{% trans 'Other' %}

+ {{ form.tags|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} + +
+
+
+ + +
+
+
+{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html new file mode 100644 index 000000000..f52c50dc0 --- /dev/null +++ b/apps/assets/templates/assets/asset_detail.html @@ -0,0 +1,426 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ asset.hostname }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + {% if asset.admin_user %} + + {% else %} + + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Hostname' %}:{{ asset.hostname }}
{% trans 'IP' %}:{{ asset.ip }}
{% trans 'Admin user' %}:{{ asset.admin_user.name }}None
{% trans 'Other IP' %}:{{ asset.other_ip }}
{% trans 'Remote card IP' %}:{{ asset.remote_card_ip }}
{% trans 'Port' %}:{{ asset.port }}
{% trans 'Mac address' %}:{{ asset.mac_addr }}
{% trans 'CPU' %}:{{ asset.cpu }}
{% trans 'Memory' %}:{{ asset.memory }}
{% trans 'Disk' %}:{{ asset.disk }}
{% trans 'OS' %}:{{ asset.os }}
{% trans 'Asset status' %}:{{ asset.status }}
{% trans 'Is active' %}:{{ asset.is_active }}
{% trans 'Asset type' %}:{{ asset.type }}
{% trans 'Asset environment' %}:{{ asset.env }}
{% trans 'Serial number' %}:{{ asset.sn }}
{% trans 'Asset number' %}:{{ asset.number }}
{% trans 'Created by' %}:{{ asset.created_by }}
{% trans 'Date joined' %}:{{ asset.date_joined|date:"Y-m-j H:i:s" }}
{% trans 'Comment' %}:{{ asset.comment }}
+
+
+
+
+
+
+ {% trans 'Quick modify' %} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Active' %}: +
+
+ + +
+
+
{% trans 'Rrefresh hardware' %}: + + + +
{% trans 'Test admin user' %}: + + + +
{% trans 'Test system users' %}: + + + +
{% trans 'Repush system users' %}: + + + +
+
+
+ +
+
+ {% trans 'Asset groups' %} +
+
+ + + + + + + + + + + + {% for asset_group in asset_groups %} + + + + + {% endfor %} + +
+ +
+ +
{{ asset_group.name }} + +
+
+
+
+
+ {% trans 'System users' %} +
+
+ + + + + + + + + + + {% for system_user in system_users %} + + + + + {% endfor %} + +
+ +
+ +
{{ system_user.name }} + +
+
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_group_create.html b/apps/assets/templates/assets/asset_group_create.html new file mode 100644 index 000000000..f2dbfd3ee --- /dev/null +++ b/apps/assets/templates/assets/asset_group_create.html @@ -0,0 +1,124 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+ +
+
+
+
+
+
+ {% csrf_token %} +

资产组信息

+ {{ form.name|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
+

用户选择的资产

+
+ +
+
+

+ {% for asset in assets_on_list %} + + {% endfor %} +

+
+
+
+
+

资产用户

+ {{ form.system_users|bootstrap_horizontal }} +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_group_detail.html b/apps/assets/templates/assets/asset_group_detail.html new file mode 100644 index 000000000..2dc09ab41 --- /dev/null +++ b/apps/assets/templates/assets/asset_group_detail.html @@ -0,0 +1,395 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'Asset list of ' %} {{ asset_group.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + +{# {% for asset in assets %}#} +{# #} +{# #} +{# #} +{# #} +{# {% if asset.is_active %}#} +{# #} +{# {% else %}#} +{# #} +{# {% endif %}#} +{# #} +{# #} +{# {% endfor %}#} + +
{% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Type' %}{% trans 'Alive' %}{% trans 'Action' %}
{{ asset.hostname }}{{ asset.ip }}{{ asset.port }}#} +{# {% trans "Delete" %}#} +{# {% trans "Update" %}#} +{#
+
+
+
+
+
+
+ {% trans 'Add asset to this group' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+ {% trans 'Associate system user' %} +
+
+ + + + + + + + + + + {% for system_user in system_users %} + + + + + {% endfor %} + +
+ +
+ +
{{ system_user.name }} + +
+
+
+ +
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_group_list.html b/apps/assets/templates/assets/asset_group_list.html new file mode 100644 index 000000000..cfa893c31 --- /dev/null +++ b/apps/assets/templates/assets/asset_group_list.html @@ -0,0 +1,183 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %} +{% endblock %} +{% block table_container %} + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Asset' %}{% trans 'Comment' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+{% include 'assets/_asset_group_bulk_update_modal.html' %} +{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html new file mode 100644 index 000000000..d12462cab --- /dev/null +++ b/apps/assets/templates/assets/asset_list.html @@ -0,0 +1,363 @@ +{% extends '_base_list.html' %} +{% load i18n %} +{% load static %} +{% block custom_head_css_js %} + + + + +{% endblock %} +{% block content_left_head %}{% endblock %} + +{% block table_search %} + +{% endblock %} + +{% block tags_list %} + +{% endblock %} + +{% block table_container %} + + + + + + + + + + + + + + + + + + +
{% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Type' %}{% trans 'Env' %}{% trans 'Hardware' %}{% trans 'Valid' %}{% trans 'Alive' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+{% include 'assets/_asset_import_modal.html' %} +{% include 'assets/_asset_bulk_update_modal.html' %} +{% endblock %} + +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_modal_list.html b/apps/assets/templates/assets/asset_modal_list.html new file mode 100644 index 000000000..c24452c0e --- /dev/null +++ b/apps/assets/templates/assets/asset_modal_list.html @@ -0,0 +1,133 @@ + + + + + + + + diff --git a/apps/assets/templates/assets/asset_modal_update.html b/apps/assets/templates/assets/asset_modal_update.html new file mode 100644 index 000000000..c7d9ec205 --- /dev/null +++ b/apps/assets/templates/assets/asset_modal_update.html @@ -0,0 +1,212 @@ +{% extends '_base_create_update.html' %} +{% load static %} +{% load bootstrap %} +{% load i18n %} + +{% block form %} + + +
+
+
+ +
+
+ {% for asset in assets_on_list %} + + {% endfor %} +

+ {% for asset in assets_on_list %} + + {% endfor %} +

+
+
+
+
+
+ + + + + +
+
+ {% csrf_token %} + + +
+
+ + +
+
+
+ + +{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_tag_create.html b/apps/assets/templates/assets/asset_tag_create.html new file mode 100644 index 000000000..f82a86dfe --- /dev/null +++ b/apps/assets/templates/assets/asset_tag_create.html @@ -0,0 +1,124 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+ +
+
+
+
+
+
+ {% csrf_token %} +

基本信息

+ {{ form.name|bootstrap_horizontal }} +
+ +
+
+

+ {% for asset in assets_on_list %} + + {% endfor %} +

+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_tag_detail.html b/apps/assets/templates/assets/asset_tag_detail.html new file mode 100644 index 000000000..a479034fc --- /dev/null +++ b/apps/assets/templates/assets/asset_tag_detail.html @@ -0,0 +1,277 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ asset_tag.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + +
{% trans 'Tag Name' %}:{{ asset_tag.name }}
{% trans 'Created by' %}:{{ asset_tag.created_by }}
{% trans 'Date created' %}:{{ asset_tag.created_time|date:"Y-m-d H:i:s" }}
+
+
+ +
+
+ {% trans 'Asset list of ' %} {{ asset_tag.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + +
{% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Type' %}{% trans 'Valid' %}{% trans 'Action' %}
+
+
+
+
+
+
+ {% trans 'Add asset to this tag' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_tags_list.html b/apps/assets/templates/assets/asset_tags_list.html new file mode 100644 index 000000000..21df7e19b --- /dev/null +++ b/apps/assets/templates/assets/asset_tags_list.html @@ -0,0 +1,125 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block custom_head_css_js %} + + +{% endblock %} +{#{% block content_left_head %}#} +{# {% trans "Create tag" %}#} +{#{% endblock %}#} +{#{% block table_head %}#} +{# #} +{# #} +{# #} +{# {% trans 'Tag Name' %}#} +{# {% trans 'Asset num' %}#} +{# #} +{#{% endblock %}#} +{#{% block table_body %}#} +{# {% for asset_tag in asset_tags_list %}#} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# {{ asset_tag.name }}#} +{# #} +{# #} +{# {{ asset_tag.asset_set.count }}#} +{# #} +{# {% trans 'Update' %}#} +{# {% trans 'Delete' %}#} +{# #} +{# #} +{# {% endfor %}#} +{#{% endblock %}#} +{#{% block content_bottom_left %}#} +{# #} +{#{% endblock %}#} +{% block table_search %}{% endblock %} +{% block table_container %} + + + + + + + + + + + + +
{% trans 'TagName' %}{% trans 'Asset num' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+ +{% endblock %} + +{% block custom_foot_js %} + + + +{% endblock %} diff --git a/apps/assets/templates/assets/asset_update.html b/apps/assets/templates/assets/asset_update.html new file mode 100644 index 000000000..fb46c79d0 --- /dev/null +++ b/apps/assets/templates/assets/asset_update.html @@ -0,0 +1,79 @@ +{% extends '_base_create_update.html' %} +{% load static %} +{% load bootstrap %} +{% load i18n %} + +{% block custom_head_css_js_create %} + + +{% endblock %} + +{% block form %} +
+ {% csrf_token %} +

{% trans 'Basic' %}

+ {{ form.hostname|bootstrap_horizontal }} + {{ form.ip|bootstrap_horizontal }} + {{ form.port|bootstrap_horizontal }} + {{ form.type|bootstrap_horizontal }} + +
+

{% trans 'Group' %}

+ {{ form.idc|bootstrap_horizontal }} + {{ form.groups|bootstrap_horizontal }} + +
+

{% trans 'Asset user' %}

+ {{ form.admin_user|bootstrap_horizontal }} + {{ form.system_users|bootstrap_horizontal }} + +
+

{% trans 'Hardware' %}

+ {{ form.sn|bootstrap_horizontal }} + {{ form.brand|bootstrap_horizontal }} + {{ form.cpu|bootstrap_horizontal }} + {{ form.memory|bootstrap_horizontal }} + {{ form.disk|bootstrap_horizontal }} + {{ form.mac_address|bootstrap_horizontal }} + +
+

{% trans 'Configuration' %}

+ {{ form.number|bootstrap_horizontal }} + {{ form.other_ip|bootstrap_horizontal }} + {{ form.remote_card_ip|bootstrap_horizontal }} + {{ form.os|bootstrap_horizontal }} + +
+

{% trans 'Location' %}

+ {{ form.cabinet_no|bootstrap_horizontal }} + {{ form.cabinet_pos|bootstrap_horizontal }} + +
+

{% trans 'Other' %}

+ {{ form.status|bootstrap_horizontal }} + {{ form.env|bootstrap_horizontal }} + {{ form.tags|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} + +
+
+
+ + +
+
+ +
+{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/delete_confirm.html b/apps/assets/templates/assets/delete_confirm.html new file mode 100644 index 000000000..94f017ca2 --- /dev/null +++ b/apps/assets/templates/assets/delete_confirm.html @@ -0,0 +1,15 @@ +{% load i18n %} + + + + + {% trans 'Confirm delete' %} + + +
+ {% csrf_token %} +

{% trans 'Are you sure delete' %} {{ object.name }} ?

+ +
+ + \ No newline at end of file diff --git a/apps/assets/templates/assets/idc_assets.html b/apps/assets/templates/assets/idc_assets.html new file mode 100644 index 000000000..3c21728bb --- /dev/null +++ b/apps/assets/templates/assets/idc_assets.html @@ -0,0 +1,366 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'IDC assets' %} {{ idc.name }} +
+ + + + + + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ + {% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Type' %}{% trans 'Valid' %}
+ +
+
+ +
+ +
+
+
+ +
+
+
+
+
+
+ {% trans 'Attach assets to IDC ' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+{% include 'assets/_asset_bulk_update_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/assets/templates/assets/idc_create_update.html b/apps/assets/templates/assets/idc_create_update.html new file mode 100644 index 000000000..67c7f4c55 --- /dev/null +++ b/apps/assets/templates/assets/idc_create_update.html @@ -0,0 +1,73 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+ +
+
+
+
+
+
+ {% csrf_token %} +

基本信息

+ {{ form.name|bootstrap_horizontal }} + {{ form.address|bootstrap_horizontal }} + {{ form.contact|bootstrap_horizontal }} + {{ form.phone|bootstrap_horizontal }} + +
+

IP段

+ {{ form.operator|bootstrap_horizontal }} + {{ form.intranet|bootstrap_horizontal }} + {{ form.extranet|bootstrap_horizontal }} + +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ +{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/idc_detail.html b/apps/assets/templates/assets/idc_detail.html new file mode 100644 index 000000000..58082a4e0 --- /dev/null +++ b/apps/assets/templates/assets/idc_detail.html @@ -0,0 +1,156 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ idc.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ idc.name }}
{% trans 'Bandwidth' %}:{{ idc.bandwidth }}
{% trans 'Contact' %}:{{ idc.contact }}
{% trans 'Phone' %}:{{ idc.phone }}
{% trans 'Address' %}:{{ idc.address }}
{% trans 'Intranet' %}:{{ idc.Intranet }}
{% trans 'Extranet' %}:{{ idc.extranet }}
{% trans 'Operator' %}:{{ idc.operator }}
{% trans 'Date created' %}:{{ system_user.date_created }}
{% trans 'Created by' %}:{{ asset_group.created_by }}
{% trans 'Comment' %}:{{ system_user.comment }}
+
+
+
+
+
+
+
+
+ +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/idc_list.html b/apps/assets/templates/assets/idc_list.html new file mode 100644 index 000000000..8663e5009 --- /dev/null +++ b/apps/assets/templates/assets/idc_list.html @@ -0,0 +1,128 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block custom_head_css_js %} + + +{% endblock %} +{% block table_search %}{% endblock %} +{% block table_container %} + + + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Asset num' %}{% trans 'Contact' %}{% trans 'Phone' %}{% trans 'Operator' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + + + diff --git a/apps/assets/templates/assets/system_user_asset.html b/apps/assets/templates/assets/system_user_asset.html new file mode 100644 index 000000000..21814879e --- /dev/null +++ b/apps/assets/templates/assets/system_user_asset.html @@ -0,0 +1,371 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'Assets attached of ' %} {{ system_user.name }} {{ paginator.count }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + +{# {% for asset in page_obj %}#} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# {% endfor %}#} + +
{% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Reachable' %}{% trans 'Action' %}
{{ asset.hostname }}{{ asset.ip }}{{ asset.port }}#} +{# #} +{# #} +{# #} +{#
+{#
#} +{# {% include '_pagination.html' %}#} +{#
#} +
+
+
+
+
+
+ {% trans 'Attach to assets ' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+ {% trans 'Attach to asset groups' %} +
+
+ + + + + + + + + + + + {% for asset_group in asset_groups %} + + + + + {% endfor %} + +
+ +
+ +
{{ asset_group.name }} + +
+
+
+
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/system_user_asset_group.html b/apps/assets/templates/assets/system_user_asset_group.html new file mode 100644 index 000000000..13a21770e --- /dev/null +++ b/apps/assets/templates/assets/system_user_asset_group.html @@ -0,0 +1,134 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'Asset list of ' %} {{ admin_user.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + {% for asset_group in page_obj %} + + + + + + + {% endfor %} + +
{% trans 'Name' %}{% trans 'Asset num' %}{% trans 'Unavailable num' %}{% trans 'Comment' %}
{{ asset_group.name }}{{ asset_group_group.assets.count }}{{ asset_group_group.assets.count }}{{ asset_group.comment|truncatewords:4 }}
+
+ {% include '_pagination.html' %} +
+
+
+
+
+
+
+ {% trans 'Add asset group to this system user' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/system_user_create_update.html b/apps/assets/templates/assets/system_user_create_update.html new file mode 100644 index 000000000..f07109f91 --- /dev/null +++ b/apps/assets/templates/assets/system_user_create_update.html @@ -0,0 +1,123 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{% trans 'Create system user' %}
+ +
+
+ {% if form.no_field_errors %} +
+ {{ form.non_field_errors }} +
+ {% endif %} +
+ {% csrf_token %} +

{% trans 'Basic' %}

+ {{ form.name|bootstrap_horizontal }} + {{ form.username|bootstrap_horizontal }} + {{ form.protocol|bootstrap_horizontal }} +

{% trans 'Auth' %}

+ {{ form.auth_method|bootstrap_horizontal }} + +
+
+ +
+ {{ form.auto_generate_key}} +
+
+
+ {{ form.private_key_file|bootstrap_horizontal }} +
+
+
+ +
+ {{ form.auto_push}} +
+
+

{% trans 'Other' %}

+ {{ form.sudo|bootstrap_horizontal }} + {{ form.home|bootstrap_horizontal }} + {{ form.shell|bootstrap_horizontal }} + {{ form.uid|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html new file mode 100644 index 000000000..342cfbb55 --- /dev/null +++ b/apps/assets/templates/assets/system_user_detail.html @@ -0,0 +1,185 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ system_user.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% if system_user.shell %} + + + + + {% endif %} + {% if system_user.home %} + + + + + {% endif %} + {% if system_user.uid %} + + + + + {% endif %} + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ system_user.name }}
{% trans 'Username' %}:{{ system_user.username }}
{% trans 'Protocol' %}:{{ system_user.protocol }}
{% trans 'Auto push' %}:{{ system_user.protocol }}
{% trans 'Auto update' %}:{{ system_user.auto_update }}
{% trans 'As default' %}:{{ system_user.protocol }}
{% trans 'Sudo' %}:{{ system_user.sudo }}
{% trans 'Shell' %}:{{ system_user.shell }}
{% trans 'Home' %}:{{ system_user.home }}
{% trans 'Uid' %}:{{ system_user.uid }}
{% trans 'Date created' %}:{{ system_user.date_created }}
{% trans 'Created by' %}:{{ asset_group.created_by }}
{% trans 'Comment' %}:{{ system_user.comment }}
+
+
+
+ +
+
+
+ {% trans 'Quick update' %} +
+
+ + + + + + + + + + + + + + + + + +
{% trans 'Get mannual install script' %}: + + + +
{% trans 'Retest asset connectivity' %}: + + + +
{% trans 'Reset private key' %}: + + + +
+
+
+
+
+
+
+
+
+ + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html new file mode 100644 index 000000000..51b6456b4 --- /dev/null +++ b/apps/assets/templates/assets/system_user_list.html @@ -0,0 +1,138 @@ +{% extends '_base_list.html' %} +{% load i18n %} + +{% block table_search %} +{% endblock %} + +{% block table_container %} + + + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Username' %}{% trans 'Asset' %}{% trans 'Unreachable' %}{% trans 'Comment' %}{% trans 'Action' %}
+
+
+ +
+ +
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + + + diff --git a/apps/assets/templatetags/asset_tags.py b/apps/assets/templatetags/asset_tags.py new file mode 100644 index 000000000..829ab2a80 --- /dev/null +++ b/apps/assets/templatetags/asset_tags.py @@ -0,0 +1,6 @@ + +from django import template +from django.utils import timezone +from django.conf import settings +register = template.Library() + diff --git a/apps/assets/tests.py b/apps/assets/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/assets/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/assets/urls/__init__.py b/apps/assets/urls/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/assets/urls/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py new file mode 100644 index 000000000..42839bdfa --- /dev/null +++ b/apps/assets/urls/api_urls.py @@ -0,0 +1,53 @@ +# coding:utf-8 +from django.conf.urls import url +from .. import api +from rest_framework import routers +from rest_framework_bulk.routes import BulkRouter + +app_name = 'assets' + + +router = BulkRouter() +router.register(r'v1/asset-groups', api.AssetGroupViewSet, 'asset-group') +router.register(r'v1/assets', api.AssetViewSet, 'asset') +router.register(r'v1/idc', api.IDCViewSet, 'idc') +router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user') +router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user') +router.register(r'v1/tags', api.TagViewSet, 'asset-tag') + +urlpatterns = [ + url(r'^v1/assets_bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), + # url(r'^v1/idc/(?P[0-9]+)/assets/$', api.IDCAssetsApi.as_view(), name='api-idc-assets'), + url(r'^v1/system-user/(?P[0-9]+)/auth-info/', api.SystemUserAuthInfoApi.as_view(), + name='system-user-auth-info'), + url(r'^v1/assets/(?P\d+)/groups/$', + api.AssetUpdateGroupApi.as_view(), name='asset-update-group'), + + url(r'^v1/assets/(?P\d+)/system-users/$', + api.SystemUserUpdateApi.as_view(), name='asset-update-system-users'), + + # update the system users, which add and delete the asset to the system user + url(r'^v1/system_user/(?P\d+)/assets/$', + api.SystemUserUpdateAssetsApi.as_view(), name='systemuser-update-assets'), + + url(r'^v1/system_user/(?P\d+)/groups/$', + api.SystemUserUpdateAssetGroupApi.as_view(), name='systemuser-update-assetgroups'), + + # update the asset group, which add or delete the asset to the group + url(r'^v1/groups/(?P\d+)/assets/$', + api.AssetGroupUpdateApi.as_view(), name='asset-groups-update'), + + # update the asset group, and add or delete the system_user to the group + url(r'^v1/groups/(?P\d+)/system-users/$', + api.AssetGroupUpdateSystemUserApi.as_view(), name='asset-groups-update-systemusers'), + + # update the IDC, and add or delete the assets to the IDC + url(r'^v1/idc/(?P\d+)/assets/$', + api.IDCupdateAssetsApi.as_view(), name='idc-update-assets'), + + url(r'v1/tag/(?P\d+)/assets/$', + api.TagUpdateAssetsApi.as_view(), name='tag-update-assets'), +] + +urlpatterns += router.urls + diff --git a/apps/assets/urls/views_urls.py b/apps/assets/urls/views_urls.py new file mode 100644 index 000000000..a2b4537a3 --- /dev/null +++ b/apps/assets/urls/views_urls.py @@ -0,0 +1,60 @@ +# coding:utf-8 +from django.conf.urls import url +from .. import views + +app_name = 'assets' + +urlpatterns = [ + # Resource asset url + url(r'^$', views.AssetListView.as_view(), name='asset-index'), + url(r'^asset/$', views.AssetListView.as_view(), name='asset-list'), + url(r'^asset/create/$', views.AssetCreateView.as_view(), name='asset-create'), + url(r'^asset/export/$', views.AssetExportView.as_view(), name='asset-export'), + url(r'^asset/import/$', views.BulkImportAssetView.as_view(), name='asset-import'), + url(r'^asset/(?P[0-9]+)/$', views.AssetDetailView.as_view(), name='asset-detail'), + url(r'^asset/(?P[0-9]+)/update/$', views.AssetUpdateView.as_view(), name='asset-update'), + url(r'^asset/(?P[0-9]+)/delete/$', views.AssetDeleteView.as_view(), name='asset-delete'), + url(r'^asset-modal$', views.AssetModalListView.as_view(), name='asset-modal-list'), + url(r'^asset-modal-update$', views.AssetModalCreateView.as_view(), name='asset-modal-update'), + + # Resource asset group url + url(r'^asset-group/$', views.AssetGroupListView.as_view(), name='asset-group-list'), + url(r'^asset-group/create/$', views.AssetGroupCreateView.as_view(), name='asset-group-create'), + url(r'^asset-group/(?P[0-9]+)/$', views.AssetGroupDetailView.as_view(), name='asset-group-detail'), + url(r'^asset-group/(?P[0-9]+)/update/$', views.AssetGroupUpdateView.as_view(), name='asset-group-update'), + url(r'^asset-group/(?P[0-9]+)/delete/$', views.AssetGroupDeleteView.as_view(), name='asset-group-delete'), + + url(r'^tags/$', views.TagsListView.as_view(), name='asset-tag-list'), + url(r'^asset-by-tag/(?P[0-9]+)/$', views.TagView.as_view(), name='asset-tags'), + url(r'^tags/create/$', views.AssetTagCreateView.as_view(), name='asset-tag-create'), + url(r'^asset-tag/(?P[0-9]+)/$', views.AssetTagDetailView.as_view(), name='asset-tag-detail'), + url(r'^asset-tag/(?P[0-9]+)/update/$', views.AssetTagUpdateView.as_view(), name='asset-tag-update'), + url(r'^asset-tag/(?P[0-9]+)/delete/$', views.AssetTagDeleteView.as_view(), name='asset-tag-delete'), + + # Resource idc url + url(r'^idc/$', views.IDCListView.as_view(), name='idc-list'), + url(r'^idc/create/$', views.IDCCreateView.as_view(), name='idc-create'), + url(r'^idc/(?P[0-9]+)/$', views.IDCDetailView.as_view(), name='idc-detail'), + url(r'^idc/(?P[0-9]+)/update/', views.IDCUpdateView.as_view(), name='idc-update'), + url(r'^idc/(?P[0-9]+)/delete/$', views.IDCDeleteView.as_view(), name='idc-delete'), + url(r'^idc/(?P[0-9]+)/assets/$', views.IDCAssetsView.as_view(), name='idc-assets'), + + # Resource admin user url + url(r'^admin-user/$', views.AdminUserListView.as_view(), name='admin-user-list'), + url(r'^admin-user/create/$', views.AdminUserCreateView.as_view(), name='admin-user-create'), + url(r'^admin-user/(?P[0-9]+)/$', views.AdminUserDetailView.as_view(), name='admin-user-detail'), + url(r'^admin-user/(?P[0-9]+)/update/$', views.AdminUserUpdateView.as_view(), name='admin-user-update'), + url(r'^admin-user/(?P[0-9]+)/delete/$', views.AdminUserDeleteView.as_view(), name='admin-user-delete'), + + # Resource system user url + url(r'^system-user/$', views.SystemUserListView.as_view(), name='system-user-list'), + url(r'^system-user/create/$', views.SystemUserCreateView.as_view(), name='system-user-create'), + url(r'^system-user/(?P[0-9]+)/$', views.SystemUserDetailView.as_view(), name='system-user-detail'), + url(r'^system-user/(?P[0-9]+)/update/$', views.SystemUserUpdateView.as_view(), name='system-user-update'), + url(r'^system-user/(?P[0-9]+)/delete/$', views.SystemUserDeleteView.as_view(), name='system-user-delete'), + url(r'^system-user/(?P[0-9]+)/asset/$', views.SystemUserAssetView.as_view(), name='system-user-asset'), + # url(r'^system-user/(?P[0-9]+)/asset-group$', views.SystemUserAssetGroupView.as_view(), + # name='system-user-asset-group'), + +] + diff --git a/apps/assets/utils.py b/apps/assets/utils.py new file mode 100644 index 000000000..e6269e3b1 --- /dev/null +++ b/apps/assets/utils.py @@ -0,0 +1,38 @@ +# ~*~ coding: utf-8 ~*~ +# +from rest_framework import serializers +from models import Tag +from django.views.generic.edit import CreateView + +class CreateAssetTagsMiXin(CreateView): + def get_form_kwargs(self): + tags_list = self.request.POST.getlist('tags') + kwargs = { + 'initial': self.get_initial(), + 'prefix': self.get_prefix(), + } + if self.request.method in ('POST', 'PUT'): + post_data = self.request.POST.copy() + if post_data.has_key('tags'): + post_data.pop('tags') + for t in tags_list: + try: + oTag = Tag.objects.get(pk=int(t)) + except (Tag.DoesNotExist, UnicodeEncodeError): + oTag = Tag(name=t, created_by=self.request.user.username or 'Admin') + oTag.save() + post_data.update({'tags':oTag.pk}) + else: + post_data.update({'tags':int(t)}) + kwargs.update({ + 'data': post_data, + 'files': self.request.FILES, + }) + return kwargs + +class UpdateAssetTagsMiXin(CreateAssetTagsMiXin): + def get_form_kwargs(self): + kwargs = super(UpdateAssetTagsMiXin, self).get_form_kwargs() + if hasattr(self, 'object'): + kwargs.update({'instance': self.object}) + return kwargs \ No newline at end of file diff --git a/apps/assets/views.py b/apps/assets/views.py new file mode 100644 index 000000000..df9a4b1e2 --- /dev/null +++ b/apps/assets/views.py @@ -0,0 +1,855 @@ +# coding:utf-8 +from __future__ import absolute_import, unicode_literals +import json +import uuid + +from openpyxl import Workbook +from openpyxl.writer.excel import save_virtual_workbook +from openpyxl import load_workbook +from django.utils.translation import ugettext as _ +from django.conf import settings +from django.db.models import Q +from django.db import IntegrityError +from django.views.generic import TemplateView, ListView, View +from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView +from django.urls import reverse_lazy +from django.contrib.messages.views import SuccessMessageMixin +from django.views.generic.detail import DetailView, SingleObjectMixin +from django.shortcuts import get_object_or_404, reverse, redirect +from django.http import HttpResponse, JsonResponse, HttpResponseRedirect +from django.views.decorators.csrf import csrf_protect, csrf_exempt +from django.utils.decorators import method_decorator +from django.core.cache import cache +from django.utils import timezone + +from common.mixins import JSONResponseMixin +from common.utils import get_object_or_none +from .utils import CreateAssetTagsMiXin, UpdateAssetTagsMiXin +from . import forms +from .models import Asset, AssetGroup, AdminUser, IDC, SystemUser, Tag +from .hands import AdminUserRequiredMixin + + +class AssetListView(AdminUserRequiredMixin, TemplateView): + template_name = 'assets/asset_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': 'Assets', + 'action': 'asset list', + 'groups': AssetGroup.objects.all(), + 'system_users': SystemUser.objects.all(), + 'tag_list': [(i.id, i.name, i.assets.all().count())for i in Tag.objects.all().order_by('name')], + 'tags': Tag.objects.all().order_by('name') + } + kwargs.update(context) + return super(AssetListView, self).get_context_data(**kwargs) + + +class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView): + model = Asset + tag_type = 'asset' + form_class = forms.AssetCreateForm + template_name = 'assets/asset_create.html' + success_url = reverse_lazy('assets:asset-list') + + def form_valid(self, form): + asset = form.save() + asset.created_by = self.request.user.username or 'Admin' + asset.save() + return super(AssetCreateView, self).form_valid(form) + + def form_invalid(self, form): + if form.errors.get('__all__'): + form.errors['all'] = form.errors.get('__all__') + return super(AssetCreateView, self).form_invalid(form) + + def get_context_data(self, **kwargs): + context = { + 'app': 'Assets', + 'action': 'Create asset', + } + kwargs.update(context) + return super(AssetCreateView, self).get_context_data(**kwargs) + + +class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListView): + model = Asset + form_class = forms.AssetCreateForm + template_name = 'assets/asset_modal_update.html' + success_url = reverse_lazy('assets:asset-list') + + def get_queryset(self): + self.queryset = super(AssetModalCreateView,self).get_queryset() + self.s = self.request.GET.get('plain_id_lists') + if "," in str(self.s): + self.plain_id_lists = [int(x) for x in self.s.split(',')] + else: + self.plain_id_lists = [self.s] + return self.queryset + + def get_context_data(self, **kwargs): + asset_on_list = Asset.objects.filter(id__in = self.plain_id_lists) + context = { + 'app': 'Assets', + 'action': 'Bulk Update asset', + 'assets_on_list': asset_on_list, + 'assets_count': len(asset_on_list), + 'plain_id_lists':self.s, + } + kwargs.update(context) + return super(AssetModalCreateView, self).get_context_data(**kwargs) + + +class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView): + model = Asset + form_class = forms.AssetCreateForm + template_name = 'assets/asset_update.html' + success_url = reverse_lazy('assets:asset-list') + new_form = '' + assets_ids = '' + + def post(self, request, *args, **kwargs): + default_keys = [ + 'csrfmiddlewaretoken', + 'assets_ids', + 'ip', + 'number', + 'hostname', + 'system_users', + 'admin_user', + ] + self.assets_ids = self.request.POST.getlist('assets_ids') + self.new_form = self.request.POST.copy() + for i in default_keys: + if self.new_form.has_key(i): + self.new_form.pop(i) + + return super(AssetUpdateView, self).post(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = { + 'app': 'Assets', + 'action': 'Update asset', + } + kwargs.update(context) + return super(AssetUpdateView, self).get_context_data(**kwargs) + + def form_invalid(self, form): + print(form.errors) + return super(AssetUpdateView, self).form_invalid(form) + + # def form_valid(self, form): + # asset = form.save(commit=False) + # + # def prn_obj_key(obj_form): + # return obj_form.clean().keys() + # + # for i in prn_obj_key(form): + # if i not in self.new_form.keys(): + # print i + + #delattr(asset, '"%s" % i') + #del asset.i + asset.save() + asset.id = 27 + # asset.created_by = self.request.user.username or 'Admin' + asset.save() + asset.id = 28 + asset.save() + return super(AssetUpdateView, self).form_valid(form) + + +class AssetDeleteView(DeleteView): + model = Asset + template_name = 'assets/delete_confirm.html' + success_url = reverse_lazy('assets:asset-list') + + +class AssetDetailView(DetailView): + model = Asset + context_object_name = 'asset' + template_name = 'assets/asset_detail.html' + + def get_context_data(self, **kwargs): + asset_groups = self.object.groups.all() + system_users = self.object.system_users.all() + context = { + 'app': 'Assets', + 'action': 'Asset detail', + 'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all() + if asset_group not in asset_groups], + 'asset_groups': asset_groups, + 'system_users_remain': [system_user for system_user in SystemUser.objects.all() + if system_user not in system_users], + 'system_users': system_users, + } + kwargs.update(context) + return super(AssetDetailView, self).get_context_data(**kwargs) + + +class AssetModalListView(AdminUserRequiredMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + model = Asset + context_object_name = 'asset_modal_list' + template_name = 'assets/asset_modal_list.html' + + def get_context_data(self, **kwargs): + group_id = self.request.GET.get('group_id') + tag_id = self.request.GET.get('tag_id') + plain_id_lists = self.request.GET.get('plain_id_lists') + self.s = self.request.GET.get('plain_id_lists') + if "," in str(self.s): + self.plain_id_lists = [int(x) for x in self.s.split(',')] + else: + self.plain_id_lists = [self.s] + + if plain_id_lists: + if "," in str(self.s): + plain_id_lists = [int(x) for x in self.s.split(',')] + else: + plain_id_lists = [int(self.s)] + context = { + 'all_assets' :plain_id_lists + } + kwargs.update(context) + if group_id: + group = AssetGroup.objects.get(id=group_id) + context = { + 'all_assets': [x.id for x in group.assets.all()] + } + kwargs.update(context) + if tag_id: + tag = Tag.objects.get(id=tag_id) + context = { + 'all_assets': [x.id for x in tag.asset_set.all()] + } + kwargs.update(context) + return super(AssetModalListView, self).get_context_data(**kwargs) + + +class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): + model = AssetGroup + form_class = forms.AssetGroupForm + template_name = 'assets/asset_group_create.html' + success_url = reverse_lazy('assets:asset-group-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Create asset group'), + 'assets_count': 0, + } + kwargs.update(context) + return super(AssetGroupCreateView, self).get_context_data(**kwargs) + + def form_valid(self, form): + asset_group = form.save() + assets_id_list = self.request.POST.getlist('assets', []) + assets = [get_object_or_404(Asset, id=int(asset_id)) + for asset_id in assets_id_list] + asset_group.created_by = self.request.user.username or 'Admin' + asset_group.assets.add(*tuple(assets)) + asset_group.save() + return super(AssetGroupCreateView, self).form_valid(form) + + +class AssetGroupListView(AdminUserRequiredMixin, TemplateView): + template_name = 'assets/asset_group_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Asset group list'), + 'assets': Asset.objects.all(), + 'system_users': SystemUser.objects.all(), + 'keyword': self.request.GET.get('keyword', '') + } + kwargs.update(context) + return super(AssetGroupListView, self).get_context_data(**kwargs) + + +class AssetGroupDetailView(AdminUserRequiredMixin, DetailView): + model = AssetGroup + template_name = 'assets/asset_group_detail.html' + context_object_name = 'asset_group' + + def get_context_data(self, **kwargs): + assets_remain = Asset.objects.exclude(id__in=self.object.assets.all()) + system_users = self.object.system_users.all() + system_users_remain = SystemUser.objects.exclude(id__in=system_users) + context = { + 'app': _('Assets'), + 'action': _('Asset group detail'), + 'assets_remain': assets_remain, + 'assets': [asset for asset in Asset.objects.all() + if asset not in assets_remain], + 'system_users': system_users, + 'system_users_remain': system_users_remain, + } + kwargs.update(context) + return super(AssetGroupDetailView, self).get_context_data(**kwargs) + + +class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView): + model = AssetGroup + form_class = forms.AssetGroupForm + template_name = 'assets/asset_group_create.html' + success_url = reverse_lazy('assets:asset-group-list') + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AssetGroup.objects.all()) + return super(AssetGroupUpdateView, self).get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + assets_all = self.object.assets.all() + context = { + 'app': _('Assets'), + 'action': _('Create asset group'), + 'assets_on_list': assets_all, + 'assets_count': len(assets_all), + 'group_id':self.object.id, + } + kwargs.update(context) + return super(AssetGroupUpdateView, self).get_context_data(**kwargs) + + +class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView): + template_name = 'assets/delete_confirm.html' + model = AssetGroup + success_url = reverse_lazy('assets:asset-group-list') + + +class IDCListView(AdminUserRequiredMixin, TemplateView): + template_name = 'assets/idc_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('IDC list'), + # 'keyword': self.request.GET.get('keyword', '') + } + kwargs.update(context) + return super(IDCListView, self).get_context_data(**kwargs) + + +class IDCCreateView(AdminUserRequiredMixin, CreateView): + model = IDC + form_class = forms.IDCForm + template_name = 'assets/idc_create_update.html' + success_url = reverse_lazy('assets:idc-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('assets'), + 'action': _('Create IDC'), + } + kwargs.update(context) + return super(IDCCreateView, self).get_context_data(**kwargs) + + def form_valid(self, form): + idc = form.save(commit=False) + idc.created_by = self.request.user.username or 'System' + idc.save() + return super(IDCCreateView, self).form_valid(form) + + +class IDCUpdateView(AdminUserRequiredMixin, UpdateView): + model = IDC + form_class = forms.IDCForm + template_name = 'assets/idc_create_update.html' + context_object_name = 'idc' + success_url = reverse_lazy('assets:idc-list') + + def form_valid(self, form): + idc = form.save(commit=False) + idc.save() + return super(IDCUpdateView, self).form_valid(form) + + def get_context_data(self, **kwargs): + context = { + 'app': _('assets'), + 'action': _('Update IDC'), + } + kwargs.update(context) + return super(IDCUpdateView, self).get_context_data(**kwargs) + + +class IDCDetailView(AdminUserRequiredMixin, DetailView): + model = IDC + template_name = 'assets/idc_detail.html' + context_object_name = 'idc' + + +class IDCAssetsView(AdminUserRequiredMixin, DetailView): + model = IDC + template_name = 'assets/idc_assets.html' + context_object_name = 'idc' + + def get_context_data(self, **kwargs): + assets_remain = Asset.objects.exclude(id__in=self.object.assets.all()) + + context = { + 'app': _('Assets'), + 'action': _('Asset detail'), + 'groups': AssetGroup.objects.all(), + 'system_users': SystemUser.objects.all(), + 'tags': Tag.objects.all(), + 'assets_remain': assets_remain, + 'assets': [asset for asset in Asset.objects.all() if asset not in assets_remain], + } + kwargs.update(context) + return super(IDCAssetsView, self).get_context_data(**kwargs) + + +class IDCDeleteView(AdminUserRequiredMixin, DeleteView): + model = IDC + template_name = 'assets/delete_confirm.html' + success_url = reverse_lazy('assets:idc-list') + + +class AdminUserListView(AdminUserRequiredMixin, TemplateView): + model = AdminUser + template_name = 'assets/admin_user_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Admin user list'), + } + kwargs.update(context) + return super(AdminUserListView, self).get_context_data(**kwargs) + + +class AdminUserCreateView(AdminUserRequiredMixin, + SuccessMessageMixin, + CreateView): + model = AdminUser + form_class = forms.AdminUserForm + template_name = 'assets/admin_user_create_update.html' + success_url = reverse_lazy('assets:admin-user-list') + + def get_context_data(self, **kwargs): + context = { + 'app': 'assets', + 'action': 'Create admin user' + } + kwargs.update(context) + return super(AdminUserCreateView, self).get_context_data(**kwargs) + + def get_success_message(self, cleaned_data): + success_message = _( + 'Create admin user %s successfully.' % ( + reverse_lazy('assets:admin-user-detail', + kwargs={'pk': self.object.pk}), + self.object.name, + )) + return success_message + + def form_invalid(self, form): + return super(AdminUserCreateView, self).form_invalid(form) + + +class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView): + model = AdminUser + form_class = forms.AdminUserForm + template_name = 'assets/admin_user_create_update.html' + + def get_context_data(self, **kwargs): + context = { + 'app': 'assets', + 'action': 'Update admin user' + } + kwargs.update(context) + return super(AdminUserUpdateView, self).get_context_data(**kwargs) + + def get_success_url(self): + success_url = reverse_lazy('assets:admin-user-detail', + kwargs={'pk': self.object.pk}) + return success_url + + +class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + template_name = 'assets/admin_user_detail.html' + context_object_name = 'admin_user' + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AdminUser.objects.all()) + return super(AdminUserDetailView, self).get(request, *args, **kwargs) + + # Todo: queryset default order by connectivity, need ops support + def get_queryset(self): + return self.object.assets.all() + + # def get_asset_groups(self): + # return self.object.asset_groups.all() + + def get_context_data(self, **kwargs): + asset_groups = AssetGroup.objects.all() + assets = self.get_queryset() + context = { + 'app': 'assets', + 'action': 'Admin user detail', + 'assets_remain': [asset for asset in Asset.objects.all() if asset not in assets], + 'asset_groups': asset_groups, + # 'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all() + # if asset_group not in asset_groups] + } + kwargs.update(context) + return super(AdminUserDetailView, self).get_context_data(**kwargs) + + +class AdminUserDeleteView(AdminUserRequiredMixin, DeleteView): + model = AdminUser + template_name = 'assets/delete_confirm.html' + success_url = reverse_lazy('assets:admin-user-list') + + +class SystemUserListView(AdminUserRequiredMixin, TemplateView): + template_name = 'assets/system_user_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('System user list'), + } + kwargs.update(context) + return super(SystemUserListView, self).get_context_data(**kwargs) + + +class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): + model = SystemUser + form_class = forms.SystemUserForm + template_name = 'assets/system_user_create_update.html' + success_url = reverse_lazy('assets:system-user-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Create system user'), + } + kwargs.update(context) + return super(SystemUserCreateView, self).get_context_data(**kwargs) + + def form_invalid(self, form): + print(form.errors) + return super(SystemUserCreateView, self).form_invalid(form) + + def get_success_message(self, cleaned_data): + success_message = _('Create system user %s successfully.' % + ( + reverse_lazy('assets:system-user-detail', kwargs={'pk': self.object.pk}), + self.object.name, + )) + + return success_message + + +class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): + model = SystemUser + form_class = forms.SystemUserForm + template_name = 'assets/system_user_create_update.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Update system user') + } + kwargs.update(context) + return super(SystemUserUpdateView, self).get_context_data(**kwargs) + + def get_success_url(self): + success_url = reverse_lazy('assets:system-user-detail', kwargs={'pk': self.object.pk}) + return success_url + + +class SystemUserDetailView(AdminUserRequiredMixin, DetailView): + template_name = 'assets/system_user_detail.html' + context_object_name = 'system_user' + model = SystemUser + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('System user detail') + } + kwargs.update(context) + return super(SystemUserDetailView, self).get_context_data(**kwargs) + + +class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView): + model = SystemUser + template_name = 'assets/delete_confirm.html' + success_url = reverse_lazy('assets:system-user-list') + + +class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + template_name = 'assets/system_user_asset.html' + context_object_name = 'system_user' + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=SystemUser.objects.all()) + return super(SystemUserAssetView, self).get(request, *args, **kwargs) + + def get_asset_groups(self): + return self.object.asset_groups.all() + + # Todo: queryset default order by connectivity, need ops support + def get_queryset(self): + return list(self.object.get_assets()) + + def get_context_data(self, **kwargs): + asset_groups = self.get_asset_groups() + assets = self.get_queryset() + context = { + 'app': 'assets', + 'action': 'System user asset', + 'assets_remain': [asset for asset in Asset.objects.all() if asset not in assets], + 'asset_groups': asset_groups, + 'asset_groups_remain': [asset_group for asset_group in AssetGroup.objects.all() + if asset_group not in asset_groups] + } + kwargs.update(context) + return super(SystemUserAssetView, self).get_context_data(**kwargs) + + +class TagView(ListView): + context_object_name = 'asset_list' + template_name = 'assets/asset_list.html' + + def get_queryset(self): + asset_list = Asset.objects.filter(tags=self.kwargs['tag_id']) + return asset_list + + def get_context_data(self, **kwargs): + kwargs['app'] = 'Assets' + kwargs['action']='asset list' + kwargs['tag_list'] = [(i.id,i.name,i.asset_set.all().count() )for i in Tag.objects.all().order_by('name')] + kwargs['tag_id'] = self.kwargs['tag_id'] + return super(TagView, self).get_context_data(**kwargs) + + +class TagsListView(AdminUserRequiredMixin, ListView): + model = Tag + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + context_object_name = 'asset_tags_list' + template_name = 'assets/asset_tags_list.html' + ordering = '-id' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Tag'), + 'action': _('Asset Tags list'), + 'keyword': self.request.GET.get('keyword', '') + } + kwargs.update(context) + return super(TagsListView, self).get_context_data(**kwargs) + + +class AssetTagCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView): + model = Tag + form_class = forms.AssetTagForm + template_name = 'assets/asset_tag_create.html' + success_url = reverse_lazy('assets:asset-tag-list') + #ordering = '-id' + + # Todo: Asset group create template select assets so hard, need be resolve next + + def get_context_data(self, **kwargs): + context = { + 'app': _('Tag'), + 'action': _('Asset Tags list'), + 'assets_count': 0, + } + kwargs.update(context) + return super(AssetTagCreateView, self).get_context_data(**kwargs) + + def form_valid(self, form): + asset_tag = form.save() + assets_id_list = self.request.POST.getlist('assets', []) + assets = [get_object_or_404(Asset, id=int(asset_id)) for asset_id in assets_id_list] + asset_tag.created_by = self.request.user.username or 'Admin' + asset_tag.assets.add(*tuple(assets)) + asset_tag.save() + return super(AssetTagCreateView, self).form_valid(form) + + +class AssetTagDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView): + template_name = 'assets/asset_tag_detail.html' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=Tag.objects.all()) + return super(AssetTagDetailView, self).get(request, *args, **kwargs) + + def get_queryset(self): + return self.object.assets.all() + + def get_context_data(self, **kwargs): + assets_remain = Asset.objects.exclude(id__in=self.object.assets.all()) + context = { + 'app': _('Tag'), + 'action': _('Asset Tags detail'), + 'asset_tag': self.object, + 'assets_remain': assets_remain, + 'assets': [asset for asset in Asset.objects.all() if asset not in assets_remain] + } + kwargs.update(context) + return super(AssetTagDetailView, self).get_context_data(**kwargs) + + +class AssetTagUpdateView(AdminUserRequiredMixin, UpdateView): + model = Tag + form_class = forms.AssetTagForm + template_name = 'assets/asset_tag_create.html' + success_url = reverse_lazy('assets:asset-tag-list') + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=Tag.objects.all()) + return super(AssetTagUpdateView, self).get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + assets_all = self.object.assets.all() + context = { + 'app': _('Tag'), + 'action': _('Asset Tags detail'), + 'assets_count': len(assets_all), + 'assets_on_list': assets_all, + 'tag_id':self.object.id, + } + kwargs.update(context) + return super(AssetTagUpdateView, self).get_context_data(**kwargs) + + +class AssetTagDeleteView(AdminUserRequiredMixin, DeleteView): + template_name = 'assets/delete_confirm.html' + model = Tag + success_url = reverse_lazy('assets:asset-tag-list') + + +@method_decorator(csrf_exempt, name='dispatch') +class AssetExportView(View): + + @staticmethod + def get_asset_attr(asset, attr): + if attr in ['admin_user', 'idc']: + return getattr(asset, attr).name + elif attr in ['status', 'type', 'env']: + return getattr(asset, 'get_{}_display'.format(attr))() + else: + return getattr(asset, attr) + + def get(self, request, *args, **kwargs): + spm = request.GET.get('spm', '') + assets_id = cache.get(spm) + if not assets_id and not isinstance(assets_id, list): + return HttpResponse('May be expired', status=404) + + assets = Asset.objects.filter(id__in=assets_id) + wb = Workbook() + ws = wb.active + ws.title = 'Asset' + header = ['hostname', 'ip', 'port', 'admin_user', 'idc', 'cpu', 'memory', 'disk', + 'mac_address', 'other_ip', 'remote_card_ip', 'os', 'cabinet_no', + 'cabinet_pos', 'number', 'status', 'type', 'env', 'sn', 'comment'] + ws.append(header) + + for asset in assets: + ws.append([self.get_asset_attr(asset, attr) for attr in header]) + + filename = 'assets-{}.xlsx'.format(timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S')) + response = HttpResponse(save_virtual_workbook(wb), content_type='applications/vnd.ms-excel') + response['Content-Disposition'] = 'attachment; filename="%s"' % filename + return response + + def post(self, request, *args, **kwargs): + try: + assets_id = json.loads(request.body).get('assets_id', []) + print(assets_id) + except ValueError: + return HttpResponse('Json object not valid', status=400) + spm = uuid.uuid4().get_hex() + cache.set(spm, assets_id, 300) + url = reverse_lazy('assets:asset-export') + '?spm=%s' % spm + return JsonResponse({'redirect': url}) + + +class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): + form_class = forms.FileForm + + def form_valid(self, form): + try: + wb = load_workbook(form.cleaned_data['file']) + ws = wb.get_active_sheet() + except Exception as e: + print(e) + data = {'valid': False, 'msg': 'Not a valid Excel file'} + return self.render_json_response(data) + + rows = ws.rows + header_all = ['hostname', 'ip', 'port', 'admin_user', 'idc', 'cpu', 'memory', 'disk', + 'mac_address', 'other_ip', 'remote_card_ip', 'os', 'cabinet_no', + 'cabinet_pos', 'number', 'status', 'type', 'env', 'sn', 'comment'] + header_min = ['hostname', 'ip', 'port', 'admin_user', 'comment'] + header = [col.value for col in next(rows)] + if not set(header).issubset(set(header_all)) and not set(header).issuperset(set(header_min)): + data = {'valid': False, 'msg': 'Must be same format as template or export file'} + return self.render_json_response(data) + + created = [] + updated = [] + failed = [] + for row in rows: + asset_dict = dict(zip(header, [col.value for col in row])) + if asset_dict.get('admin_user', None): + admin_user = get_object_or_none(AdminUser, name=asset_dict['admin_user']) + asset_dict['admin_user'] = admin_user + + if asset_dict.get('idc'): + idc = get_object_or_none(IDC, name=asset_dict['idc']) + asset_dict['idc'] = idc + + if asset_dict.get('type'): + asset_display_type_map = dict(zip(dict(Asset.TYPE_CHOICES).values(), dict(Asset.TYPE_CHOICES).keys())) + asset_type = asset_display_type_map.get(asset_dict['type'], 'Server') + asset_dict['type'] = asset_type + + if asset_dict.get('status'): + asset_display_status_map = dict(zip(dict(Asset.STATUS_CHOICES).values(), + dict(Asset.STATUS_CHOICES).keys())) + asset_status = asset_display_status_map.get(asset_dict['status'], 'In use') + asset_dict['status'] = asset_status + + if asset_dict.get('env'): + asset_display_env_map = dict(zip(dict(Asset.ENV_CHOICES).values(), + dict(Asset.ENV_CHOICES).keys())) + asset_env = asset_display_env_map.get(asset_dict['env'], 'Prod') + asset_dict['env'] = asset_env + + try: + Asset.objects.create(**asset_dict) + created.append(asset_dict['ip']) + except IntegrityError as e: + asset = Asset.objects.filter(ip=asset_dict['ip'], port=asset_dict['port']) + if not asset: + failed.append(asset_dict['ip']) + continue + asset.update(**asset_dict) + updated.append(asset_dict['ip']) + except TypeError as e: + print(e) + failed.append(asset_dict['ip']) + + data = { + 'created': created, + 'created_info': 'Created {}'.format(len(created)), + 'updated': updated, + 'updated_info': 'Updated {}'.format(len(updated)), + 'failed': failed, + 'failed_info': 'Failed {}'.format(len(failed)), + 'valid': True, + 'msg': 'Created: {}. Updated: {}, Error: {}'.format(len(created), len(updated), len(failed)) + } + return self.render_json_response(data) diff --git a/apps/audits/__init__.py b/apps/audits/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/audits/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/audits/api.py b/apps/audits/api.py new file mode 100644 index 000000000..302fc3a69 --- /dev/null +++ b/apps/audits/api.py @@ -0,0 +1,97 @@ +# ~*~ coding: utf-8 ~*~ +# + + +from __future__ import absolute_import, unicode_literals + +from rest_framework import generics, viewsets +from rest_framework_bulk import BulkModelViewSet + +from audits.backends import command_store, record_store +from audits.backends.command.serializers import CommandLogSerializer +from audits.backends.record.serializers import RecordSerializer +from . import models, serializers +from .hands import IsSuperUserOrAppUser, IsAppUser + + +class ProxyLogReceiveView(generics.CreateAPIView): + queryset = models.ProxyLog.objects.all() + serializer_class = serializers.ProxyLogSerializer + permission_classes = (IsAppUser,) + + def get_serializer(self, *args, **kwargs): + kwargs['data']['terminal'] = self.request.user.terminal.name + return super(ProxyLogReceiveView, self).get_serializer(*args, **kwargs) + + +class ProxyLogViewSet(viewsets.ModelViewSet): + """User proxy to backend server need call this api. + + params: { + "username": "", + "name": "", + "hostname": "", + "ip": "", + "terminal": "", + "login_type": "", + "system_user": "", + "was_failed": "", + "date_start": "" + } + + """ + + queryset = models.ProxyLog.objects.all() + serializer_class = serializers.ProxyLogSerializer + permission_classes = (IsSuperUserOrAppUser,) + + +class CommandLogViewSet(BulkModelViewSet): + """接受app发送来的command log, 格式如下 + { + "proxy_log_id": 23, + "user": "admin", + "asset": "localhost", + "system_user": "web", + "command_no": 1, + "command": "whoami", + "output": "d2hvbWFp", # base64.b64encode(s) + "timestamp": 1485238673.0 + } + + """ + queryset = command_store.all() + serializer_class = CommandLogSerializer + permission_classes = (IsSuperUserOrAppUser,) + + +class RecordLogViewSet(BulkModelViewSet): + """接受app发送来的record log, 格式如下 + { + "proxy_log_id": 23, + "output": "d2hvbWFp", # base64.b64encode(s) + "timestamp": 1485238673.0 + } + """ + + serializer_class = RecordSerializer + permission_classes = (IsSuperUserOrAppUser,) + + def get_queryset(self): + filter_kwargs = {} + proxy_log_id = self.request.query_params.get('proxy_log_id') + data_from_ts = self.request.query_params.get('date_from_ts') + if proxy_log_id: + filter_kwargs['proxy_log_id'] = proxy_log_id + if data_from_ts: + filter_kwargs['date_from_ts'] = data_from_ts + if filter_kwargs: + return record_store.filter(**filter_kwargs) + else: + return record_store.all() + + + + + + diff --git a/apps/audits/apps.py b/apps/audits/apps.py new file mode 100644 index 000000000..d376c1e65 --- /dev/null +++ b/apps/audits/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class AuditsConfig(AppConfig): + name = 'audits' diff --git a/apps/audits/backends/__init__.py b/apps/audits/backends/__init__.py new file mode 100644 index 000000000..5a2a38ec7 --- /dev/null +++ b/apps/audits/backends/__init__.py @@ -0,0 +1,10 @@ +from importlib import import_module +from django.conf import settings + +command_engine = import_module(settings.COMMAND_STORE_BACKEND) +command_store = command_engine.CommandStore() +record_engine = import_module(settings.RECORD_STORE_BACKEND) +record_store = record_engine.RecordStore() +from .command.serializers import CommandLogSerializer + + diff --git a/apps/audits/backends/command/__init__.py b/apps/audits/backends/command/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/audits/backends/command/base.py b/apps/audits/backends/command/base.py new file mode 100644 index 000000000..54279f133 --- /dev/null +++ b/apps/audits/backends/command/base.py @@ -0,0 +1,19 @@ +# coding: utf-8 +import abc + + +class CommandBase(object): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def save(self, proxy_log_id, user, asset, system_user, + command_no, command, output, timestamp): + pass + + @abc.abstractmethod + def filter(self, date_from_ts=None, date_to_ts=None, user='', + asset='', system_user='', command='', proxy_log_id=0): + pass + + + diff --git a/apps/audits/backends/command/db.py b/apps/audits/backends/command/db.py new file mode 100644 index 000000000..26441e41f --- /dev/null +++ b/apps/audits/backends/command/db.py @@ -0,0 +1,45 @@ +# ~*~ coding: utf-8 ~*~ + +from .base import CommandBase +from audits.models import CommandLog + + +class CommandStore(CommandBase): + model = CommandLog + queryset = [] + + def save(self, proxy_log_id, user, asset, system_user, + command_no, command, output, timestamp): + self.model.objects.create( + proxy_log_id=proxy_log_id, user=user, asset=asset, + system_user=system_user, command_no=command_no, + command=command, output=output, timestamp=timestamp + ) + + def filter(self, date_from_ts=None, date_to_ts=None, user='', + asset='', system_user='', command='', proxy_log_id=0): + filter_kwargs = {} + + if date_from_ts: + filter_kwargs['timestamp__gte'] = date_from_ts + if date_to_ts: + filter_kwargs['timestamp__lte'] = date_to_ts + if user: + filter_kwargs['user'] = user + if asset: + filter_kwargs['asset'] = asset + if system_user: + filter_kwargs['system_user'] = system_user + if command: + filter_kwargs['command__icontains'] = command + if proxy_log_id: + filter_kwargs['proxy_log_id'] = proxy_log_id + + if filter_kwargs: + self.queryset = self.model.objects.filter(**filter_kwargs) + return self.queryset + + def all(self): + """返回所有数据""" + return self.model.objects.iterator() + diff --git a/apps/audits/backends/command/serializers.py b/apps/audits/backends/command/serializers.py new file mode 100644 index 000000000..32da6bcea --- /dev/null +++ b/apps/audits/backends/command/serializers.py @@ -0,0 +1,21 @@ +# ~*~ coding: utf-8 ~*~ +import base64 +from rest_framework import serializers +from audits.models import CommandLog +from audits.backends import command_store + + +class CommandLogSerializer(serializers.ModelSerializer): + """使用这个类作为基础Command Log Serializer类, 用来序列化""" + + class Meta: + model = CommandLog + fields = '__all__' + + def create(self, validated_data): + try: + output = validated_data['output'] + validated_data['output'] = base64.b64decode(output) + except IndexError: + pass + return command_store.save(**dict(validated_data)) diff --git a/apps/audits/backends/record/__init__.py b/apps/audits/backends/record/__init__.py new file mode 100644 index 000000000..3e0d2fd0f --- /dev/null +++ b/apps/audits/backends/record/__init__.py @@ -0,0 +1,2 @@ +# ~*~ coding: utf-8 ~*~ + diff --git a/apps/audits/backends/record/base.py b/apps/audits/backends/record/base.py new file mode 100644 index 000000000..e96b8b131 --- /dev/null +++ b/apps/audits/backends/record/base.py @@ -0,0 +1,14 @@ +# coding: utf-8 +import abc + + +class RecordBase(object): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def save(self, proxy_log_id, output, timestamp): + pass + + @abc.abstractmethod + def filter(self, date_from_ts=None, proxy_log_id=None): + pass diff --git a/apps/audits/backends/record/db.py b/apps/audits/backends/record/db.py new file mode 100644 index 000000000..e55211f65 --- /dev/null +++ b/apps/audits/backends/record/db.py @@ -0,0 +1,31 @@ +# ~*~ coding: utf-8 ~*~ + +from .base import RecordBase +from audits.models import RecordLog + + +class RecordStore(RecordBase): + model = RecordLog + queryset = [] + + def save(self, proxy_log_id, output, timestamp): + return self.model.objects.create( + proxy_log_id=proxy_log_id, output=output, timestamp=timestamp + ) + + def filter(self, date_from_ts=None, proxy_log_id=''): + filter_kwargs = {} + + if date_from_ts: + filter_kwargs['timestamp__gte'] = date_from_ts + if proxy_log_id: + filter_kwargs['proxy_log_id'] = proxy_log_id + + if filter_kwargs: + self.queryset = self.model.objects.filter(**filter_kwargs) + return self.queryset + + def all(self): + """返回所有数据""" + return self.model.objects.all() + diff --git a/apps/audits/backends/record/serializers.py b/apps/audits/backends/record/serializers.py new file mode 100644 index 000000000..30a5867e1 --- /dev/null +++ b/apps/audits/backends/record/serializers.py @@ -0,0 +1,20 @@ +# ~*~ coding: utf-8 ~*~ +import base64 +from rest_framework import serializers +from audits.models import RecordLog +from audits.backends import record_store + + +class RecordSerializer(serializers.ModelSerializer): + """使用这个类作为基础Command Log Serializer类, 用来序列化""" + class Meta: + model = RecordLog + fields = '__all__' + + def create(self, validated_data): + try: + output = validated_data['output'] + validated_data['output'] = base64.b64decode(output) + except IndexError: + pass + return record_store.save(**dict(validated_data)) diff --git a/apps/audits/hands.py b/apps/audits/hands.py new file mode 100644 index 000000000..13986a2c8 --- /dev/null +++ b/apps/audits/hands.py @@ -0,0 +1,8 @@ +# ~*~ coding: utf-8 ~*~ +# + +from users.utils import AdminUserRequiredMixin +from users.models import User +from assets.models import Asset, SystemUser +from users.permissions import IsSuperUserOrAppUser, IsAppUser +from applications.models import Terminal diff --git a/apps/audits/migrations/__init__.py b/apps/audits/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/audits/models.py b/apps/audits/models.py new file mode 100644 index 000000000..25790f8a0 --- /dev/null +++ b/apps/audits/models.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals +import base64 + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + + +class LoginLog(models.Model): + LOGIN_TYPE_CHOICE = ( + ('W', 'Web'), + ('ST', 'SSH Terminal'), + ('WT', 'Web Terminal') + ) + + username = models.CharField(max_length=20, verbose_name=_('Username')) + name = models.CharField(max_length=20, blank=True, verbose_name=_('Name')) + login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, + verbose_name=_('Login type')) + login_ip = models.GenericIPAddressField(verbose_name=_('Login ip')) + login_city = models.CharField(max_length=100, blank=True, null=True, + verbose_name=_('Login city')) + user_agent = models.CharField(max_length=100, blank=True, null=True, + verbose_name=_('User agent')) + date_login = models.DateTimeField(auto_now_add=True, + verbose_name=_('Date login')) + + class Meta: + db_table = 'login_log' + ordering = ['-date_login', 'username'] + + +class ProxyLog(models.Model): + LOGIN_TYPE_CHOICE = ( + ('ST', 'SSH Terminal'), + ('WT', 'Web Terminal'), + ) + + user = models.CharField(max_length=32, verbose_name=_('User')) + asset = models.CharField(max_length=32, verbose_name=_('Asset')) + system_user = models.CharField(max_length=32, verbose_name=_('System user')) + login_type = models.CharField( + choices=LOGIN_TYPE_CHOICE, max_length=2, blank=True, + null=True, verbose_name=_('Login type')) + terminal = models.CharField( + max_length=32, blank=True, null=True, verbose_name=_('Terminal')) + is_failed = models.BooleanField( + default=False, verbose_name=_('Did connect failed')) + is_finished = models.BooleanField( + default=False, verbose_name=_('Is finished')) + date_start = models.DateTimeField( + auto_created=True, verbose_name=_('Date start')) + date_finished = models.DateTimeField( + null=True, verbose_name=_('Date finished')) + + def __unicode__(self): + return '%s-%s-%s' % (self.user, self.asset, self.system_user) + + def commands(self): + from audits.backends import command_store + return command_store.filter(proxy_log_id=self.id) + + class Meta: + ordering = ['-date_start', 'user'] + + +class CommandLog(models.Model): + proxy_log_id = models.IntegerField(db_index=True) + user = models.CharField(max_length=48, db_index=True) + asset = models.CharField(max_length=128, db_index=True) + system_user = models.CharField(max_length=48, db_index=True) + command_no = models.IntegerField() + command = models.CharField(max_length=1000, blank=True, db_index=True) + output = models.TextField(blank=True) + timestamp = models.FloatField(db_index=True) + + def __unicode__(self): + return '%s: %s' % (self.id, self.command) + + class Meta: + ordering = ['command_no', 'command'] + + +class RecordLog(models.Model): + proxy_log_id = models.IntegerField(db_index=True) + output = models.TextField(verbose_name=_('Output')) + timestamp = models.FloatField(db_index=True) + + def __unicode__(self): + return 'Record: %s' % self.proxy_log_id + + class Meta: + ordering = ['timestamp'] diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py new file mode 100644 index 000000000..2f474ff7e --- /dev/null +++ b/apps/audits/serializers.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# +from __future__ import absolute_import, unicode_literals +from rest_framework import serializers + +from common.utils import timesince +from . import models + + +class ProxyLogSerializer(serializers.ModelSerializer): + time = serializers.SerializerMethodField() + command_length = serializers.SerializerMethodField() + + class Meta: + model = models.ProxyLog + fields = '__all__' + + @staticmethod + def get_time(obj): + if not obj.is_finished: + return '' + else: + return timesince(obj.date_start, since=obj.date_finished) + + @staticmethod + def get_command_length(obj): + return 2 + diff --git a/apps/audits/tasks.py b/apps/audits/tasks.py new file mode 100644 index 000000000..f80aa5f75 --- /dev/null +++ b/apps/audits/tasks.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# ~*~ coding: utf-8 ~*~ +# + +from celery import shared_task +from .utils import write_login_log + + +@shared_task +def write_login_log_async(*args, **kwargs): + write_login_log(*args, **kwargs) + diff --git a/apps/audits/templates/audits/command_log_list.html b/apps/audits/templates/audits/command_log_list.html new file mode 100644 index 000000000..0a0ced6dc --- /dev/null +++ b/apps/audits/templates/audits/command_log_list.html @@ -0,0 +1,108 @@ +{% extends '_base_list.html' %} +{% load i18n %} +{% load static %} +{% block content_left_head %} + + + +{% endblock %} + +{% block table_search %} +
+
+
+ + + to + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+{% endblock %} +{% block table_container %} + + + + + + + + + + + + + + + {% for command in command_list %} + + + + + + + + + + + {% endfor %} + +
IDCommandUsernameIPSystem userProxy logDatetimeOutput
{{ command.id }}{{ command.command }}{{ command.user }}{{ command.asset }}{{ command.system_user }}{{ command.proxy_log_id}}{{ command.timestamp|ts_to_date }}
{{ command.output|to_html|safe }}
+{% endblock %} + +{% block custom_foot_js %} + + + +{% endblock %} + + diff --git a/apps/audits/templates/audits/login_log_list.html b/apps/audits/templates/audits/login_log_list.html new file mode 100644 index 000000000..eb7a4a813 --- /dev/null +++ b/apps/audits/templates/audits/login_log_list.html @@ -0,0 +1,101 @@ +{% extends '_base_list.html' %} +{% load i18n %} +{% load static %} +{% load common_tags %} +{% block content_left_head %} + + +{% endblock %} + + +{% block table_search %} +
+
+
+ + + to + +
+
+
+ +
+
+ +
+
+
+ +
+
+
+{% endblock %} + +{% block table_head %} + {% trans 'ID' %} + {% trans 'Username' %} + {% trans 'Name' %} + {% trans 'Type' %} + {% trans 'UA' %} + {% trans 'IP' %} + {% trans 'City' %} + {% trans 'Date' %} +{% endblock %} + +{% block table_body %} + {% for login_log in login_log_list %} + + + {{ login_log.id }} +{# {{ login_log.id }}#} + + {{ login_log.username }} + {{ login_log.name }} + {{ login_log.get_login_type_display }} + {% if login_log.login_type == 'W' %} + + {{ login_log.user_agent | truncatechars:20 }} + + {% else %} + {{ login_log.terminal }} + {% endif %} + {{ login_log.login_ip }} + {{ login_log.login_city }} + {{ login_log.date_login }} + + {% endfor %} +{% endblock %} + +{% block custom_foot_js %} + + +{% endblock %} + diff --git a/apps/audits/templates/audits/proxy_log_commands_list_modal.html b/apps/audits/templates/audits/proxy_log_commands_list_modal.html new file mode 100644 index 000000000..fca95de6e --- /dev/null +++ b/apps/audits/templates/audits/proxy_log_commands_list_modal.html @@ -0,0 +1,58 @@ +{% load static %} + + + + + + + {% include '_head_css_js.html' %} + + + + + + + +
+
+
+ + + + + + + + + + + + {% for command in object_list %} + + + + + + + {% endfor %} + + + + + + +
IDCommandOutputDatetime
{{ command.command_no }}{{ command.command }}{{ command.output_decode |safe }}{{ command.datetime }}
+
    +
    +
    +
    +
    + + + + diff --git a/apps/audits/templates/audits/proxy_log_detail.html b/apps/audits/templates/audits/proxy_log_detail.html new file mode 100644 index 000000000..909d66fe6 --- /dev/null +++ b/apps/audits/templates/audits/proxy_log_detail.html @@ -0,0 +1,84 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + +{% endblock %} +{% block content %} +
    +
    +
    +
    + +
    +
    +
    +
    + {% trans 'Command log list' %} {{ user_object.name }} +
    + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + {% for command in object_list %} + + + + + + + {% endfor %} + + + + + + +
    IDCommandOutputDatetime
    {{ command.command_no }}{{ command.command }}
    {{ command.output|to_html|safe}}
    {{ command.timestamp|ts_to_date}}
    +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/audits/templates/audits/proxy_log_list.html b/apps/audits/templates/audits/proxy_log_list.html new file mode 100644 index 000000000..6a3c815b0 --- /dev/null +++ b/apps/audits/templates/audits/proxy_log_list.html @@ -0,0 +1,173 @@ +{% extends '_base_list.html' %} +{% load i18n %} +{% load static %} +{% block content_left_head %} + + +{% endblock %} + + +{% block table_search %} +
      +
      +
      + + + to + +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      + +
      +
      +
      +{% endblock %} + +{% block table_head %} + + {% trans 'ID' %} + {% trans 'User' %} + {% trans 'Asset' %} + {% trans 'System user' %} + {% trans 'Terminal' %} + {% trans 'Command' %} + {% trans 'Success' %} + {% trans 'Finished' %} + {% trans 'R/M' %} + {% trans 'Date start' %} + {% trans 'Time' %} +{% endblock %} + +{% block table_body %} + {% for proxy_log in proxy_log_list %} + + + + {{ proxy_log.id }} + + {{ proxy_log.user }} + {{ proxy_log.asset }} + {{ proxy_log.system_user }} + {{ proxy_log.terminal }} + {{ proxy_log.commands.all|length}} + + {% if proxy_log.is_failed %} + + {% else %} + + {% endif %} + + {% if proxy_log.is_finished %} + + + + + + + {% else %} + + + + + + + {% endif %} + {{ proxy_log.date_start }} + {{ proxy_log.date_finished|timeuntil:proxy_log.date_start }} + + {% endfor %} +{% endblock %} + +{% block content_bottom_left %} +
      +
      + +
      + +
      +
      +
      +{% endblock %} + +{% block custom_foot_js %} + + +{% endblock %} + diff --git a/apps/audits/templatetags/example_tags.py b/apps/audits/templatetags/example_tags.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/audits/tests.py b/apps/audits/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/audits/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/audits/urls/__init__.py b/apps/audits/urls/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/audits/urls/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/audits/urls/api_urls.py b/apps/audits/urls/api_urls.py new file mode 100644 index 000000000..7f1f19952 --- /dev/null +++ b/apps/audits/urls/api_urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import url +from rest_framework import routers + +from .. import api + +app_name = 'audits' + +router = routers.DefaultRouter() +router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log') +router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log') +router.register(r'v1/record-log', api.RecordLogViewSet, 'record-log') + +urlpatterns = [ + url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(), + name='proxy-log-receive'), +] + +urlpatterns += router.urls diff --git a/apps/audits/urls/views_urls.py b/apps/audits/urls/views_urls.py new file mode 100644 index 000000000..d28882704 --- /dev/null +++ b/apps/audits/urls/views_urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import url +from .. import views + +app_name = 'audits' + +urlpatterns = [ + url(r'^proxy-log$', views.ProxyLogListView.as_view(), + name='proxy-log-list'), + url(r'^proxy-log/(?P\d+)$', views.ProxyLogDetailView.as_view(), + name='proxy-log-detail'), + # url(r'^proxy-log/(?P\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'), + url(r'^command-log$', views.CommandLogListView.as_view(), + name='command-log-list'), + url(r'^login-log$', views.LoginLogListView.as_view(), + name='login-log-list'), +] + + diff --git a/apps/audits/utils.py b/apps/audits/utils.py new file mode 100644 index 000000000..8e4cd9949 --- /dev/null +++ b/apps/audits/utils.py @@ -0,0 +1,51 @@ +# ~*~ coding: utf-8 ~*~ +# + +from __future__ import unicode_literals +import requests +import ipaddress + +from .models import LoginLog + + +def validate_ip(ip): + try: + ipaddress.ip_address(ip.decode('utf-8')) + return True + except ValueError: + print('valid error') + return False + + +def write_login_log(username, name='', login_type='', + login_ip='', user_agent=''): + if not (login_ip and validate_ip(login_ip)): + login_ip = '0.0.0.0' + if not name: + name = username + login_city = get_ip_city(login_ip) + LoginLog.objects.create(username=username, name=name, login_type=login_type, + login_ip=login_ip, login_city=login_city, user_agent=user_agent) + + +def get_ip_city(ip, timeout=10): + # Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8 + # Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json + + url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip + try: + r = requests.get(url, timeout=timeout) + print(r) + except requests.Timeout: + r = None + city = 'Unknown' + if r and r.status_code == 200: + try: + data = r.json() + if not isinstance(data, int) and data['ret'] == 1: + city = data['country'] + ' ' + data['city'] + except ValueError: + pass + return city + + diff --git a/apps/audits/views.py b/apps/audits/views.py new file mode 100644 index 000000000..94039d1d8 --- /dev/null +++ b/apps/audits/views.py @@ -0,0 +1,239 @@ +# ~*~ coding: utf-8 ~*~ +# +import time +from datetime import datetime + +import pytz +from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView +from django.views.generic.edit import SingleObjectMixin +from django.utils.translation import ugettext as _ +from django.utils import timezone +from django.utils.module_loading import import_string +from django.urls import reverse_lazy +from django.http import HttpResponse +from django.conf import settings +from django.db.models import Q + +from .models import ProxyLog, CommandLog, LoginLog +from .hands import User, Asset, SystemUser, AdminUserRequiredMixin +from audits.backends import command_store +from audits.backends import CommandLogSerializer + + +class ProxyLogListView(AdminUserRequiredMixin, ListView): + model = ProxyLog + template_name = 'audits/proxy_log_list.html' + context_object_name = 'proxy_log_list' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + keyword = user = asset = system_user = date_from_s = date_to_s = '' + ordering = ['is_finished', '-id'] + date_format = '%m/%d/%Y' + + def get_queryset(self): + date_now = timezone.localtime(timezone.now()) + date_to_default = date_now.strftime(self.date_format) + date_from_default = (date_now-timezone.timedelta(7))\ + .strftime(self.date_format) + + self.queryset = super(ProxyLogListView, self).get_queryset() + self.keyword = self.request.GET.get('keyword', '') + self.user = self.request.GET.get('user') + self.asset = self.request.GET.get('asset') + self.system_user = self.request.GET.get('system_user') + self.date_from_s = self.request.GET.get('date_from', date_from_default) + self.date_to_s = self.request.GET.get('date_to', date_to_default) + + filter_kwargs = {} + if self.date_from_s: + date_from = datetime.strptime(self.date_from_s, self.date_format) + date_from.replace(tzinfo=timezone.get_current_timezone()) + filter_kwargs['date_start__gt'] = date_from + if self.date_to_s: + date_to = timezone.datetime.strptime( + self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S') + date_to.replace(tzinfo=timezone.get_current_timezone()) + filter_kwargs['date_start__lt'] = date_to + if self.user: + filter_kwargs['user'] = self.user + if self.asset: + filter_kwargs['asset'] = self.asset + if self.system_user: + filter_kwargs['system_user'] = self.system_user + if self.keyword: + self.queryset = self.queryset.filter( + Q(user__icontains=self.keyword) | + Q(asset__icontains=self.keyword) | + Q(system_user__icontains=self.keyword)).distinct() + return self.queryset + + def get_context_data(self, **kwargs): + context = { + 'app': _('Audits'), + 'action': _('Proxy log list'), + 'user_list': set( + list(ProxyLog.objects.values_list('user', flat=True))), + 'asset_list': set( + list(ProxyLog.objects.values_list('asset', flat=True))), + 'system_user_list': set( + list(ProxyLog.objects.values_list('system_user', flat=True))), + 'keyword': self.keyword, + 'date_from': self.date_from_s, + 'date_to': self.date_to_s, + 'user': self.user, + 'asset': self.asset, + 'system_user': self.system_user, + } + kwargs.update(context) + return super(ProxyLogListView, self).get_context_data(**kwargs) + + +class ProxyLogDetailView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'audits/proxy_log_detail.html' + context_object_name = 'proxy_log' + object = '' + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=ProxyLog.objects.all()) + return super(ProxyLogDetailView, self).get(request, *args, **kwargs) + + def get_queryset(self): + return list(command_store.filter(proxy_log_id=self.object.id)) + + def get_context_data(self, **kwargs): + context = { + 'app': 'Audits', + 'action': 'Proxy log detail', + } + kwargs.update(context) + return super(ProxyLogDetailView, self).get_context_data(**kwargs) + + +# class ProxyLogCommandsListView(AdminUserRequiredMixin, +# SingleObjectMixin, +# ListView): +# template_name = 'audits/proxy_log_commands_list_modal.html' +# object = '' +# +# def get(self, request, *args, **kwargs): +# self.object = self.get_object(queryset=ProxyLog.objects.all()) +# return super(ProxyLogCommandsListView, self).\ +# get(request, *args, **kwargs) +# +# def get_queryset(self): +# return list(self.object.command_log.all()) + + +class CommandLogListView(AdminUserRequiredMixin, ListView): + template_name = 'audits/command_log_list.html' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + context_object_name = 'command_list' + user = asset = system_user = command = date_from_s = date_to_s = '' + date_format = '%m/%d/%Y' + ordering = ['-id'] + + def get_queryset(self): + date_now = timezone.localtime(timezone.now()) + date_to_default = date_now.strftime(self.date_format) + date_from_default = (date_now - timezone.timedelta(7)) \ + .strftime(self.date_format) + self.command = self.request.GET.get('command', '') + self.user = self.request.GET.get('user') + self.asset = self.request.GET.get('asset') + self.system_user = self.request.GET.get('system_user') + self.date_from_s = \ + self.request.GET.get('date_from', date_from_default) + self.date_to_s = \ + self.request.GET.get('date_to', date_to_default) + + filter_kwargs = {} + if self.date_from_s: + date_from = datetime.strptime(self.date_from_s, self.date_format)\ + .replace(tzinfo=timezone.get_current_timezone()) + # date_from_utc = date_from.astimezone(pytz.utc) + date_from_ts = time.mktime(date_from.timetuple()) + filter_kwargs['date_from_ts'] = date_from_ts + if self.date_to_s: + date_to = datetime.strptime( + self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')\ + .replace(tzinfo=timezone.get_current_timezone()) + date_to_ts = time.mktime(date_to.timetuple()) + filter_kwargs['date_to_ts'] = date_to_ts + if self.user: + filter_kwargs['user'] = self.user + if self.asset: + filter_kwargs['asset'] = self.asset + if self.system_user: + filter_kwargs['system_user'] = self.system_user + if self.command: + filter_kwargs['command'] = self.command + self.queryset = command_store.filter(**filter_kwargs).order_by(*self.ordering) + return self.queryset + + def get_context_data(self, **kwargs): + context = { + 'app': _('Audits'), + 'action': _('Command log list'), + 'user_list': User.objects.all().order_by('username'), + 'asset_list': Asset.objects.all().order_by('ip'), + 'system_user_list': SystemUser.objects.all().order_by('username'), + 'command': self.command, + 'date_from': self.date_from_s, + 'date_to': self.date_to_s, + 'user': self.user, + 'asset': self.asset, + 'system_user': self.system_user, + } + kwargs.update(context) + return super(CommandLogListView, self).get_context_data(**kwargs) + + +class LoginLogListView(AdminUserRequiredMixin, ListView): + model = LoginLog + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + template_name = 'audits/login_log_list.html' + context_object_name = 'login_log_list' + keyword = username = date_from_s = date_to_s = '' + + def get_queryset(self): + date_now = timezone.localtime(timezone.now()) + now_s = date_now.strftime('%m/%d/%Y') + seven_days_ago_s = (date_now - timezone.timedelta(7))\ + .strftime('%m/%d/%Y') + self.queryset = super(LoginLogListView, self).get_queryset() + self.keyword = keyword = self.request.GET.get('keyword', '') + self.username = username = self.request.GET.get('username', '') + self.date_from_s = date_from_s = self.request.GET.get( + 'date_from', '%s' % seven_days_ago_s) + self.date_to_s = date_to_s = self.request.GET.get( + 'date_to', '%s' % now_s) + + if date_from_s: + date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y') + self.queryset = self.queryset.filter(date_login__gt=date_from) + if date_to_s: + date_to = timezone.datetime.strptime( + date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S') + self.queryset = self.queryset.filter(date_login__lt=date_to) + if username: + self.queryset = self.queryset.filter(username=username) + if keyword: + self.queryset = self.queryset.filter( + Q(username__contains=keyword) | + Q(name__icontains=keyword) | + Q(login_ip=keyword)).distinct() + return self.queryset + + def get_context_data(self, **kwargs): + context = { + 'app': _('Audits'), + 'action': _('Proxy log list'), + 'user_list': User.objects.all().order_by('username'), + 'keyword': self.keyword, + 'date_from': self.date_from_s, + 'date_to': self.date_to_s, + 'username': self.username, + } + kwargs.update(context) + return super(LoginLogListView, self).get_context_data(**kwargs) diff --git a/apps/common/README.md b/apps/common/README.md new file mode 100644 index 000000000..400f19fc8 --- /dev/null +++ b/apps/common/README.md @@ -0,0 +1,76 @@ +# Common app + +Common app provide common view, function or others. + +Common app shouldn't rely on other apps, because It may lead to cycle +import. + +If your want to implement some function or class, you should think +whether other app use or not. If yes, You should make in common. + +If the ability more relate to your app tightness, It's mean your app +provide this ability, not common, You should write it on your app utils. + + + +## Celery usage + + +Jumpserver use celery to run task async. Using redis as the broker, so +you should run a redis instance + +#### Run redis + + $ yum -y install redis + + or + + $ docker run -name jumpserver-redis -d -p 6379:6379 redis redis-server + + +#### Write tasks in app_name/tasks.py + +ops/tasks.py + +``` +from __future__ import absolute_import + +import time +from celery import shared_task +from common import celery_app + + +@shared_task +def longtime_add(x, y): + print 'long time task begins' + # sleep 5 seconds + time.sleep(5) + print 'long time task finished' + return x + y + + +@celery_app.task(name='hello-world') +def hello(): + print 'hello world!' + +``` + +#### Run celery in development + +``` +$ cd apps +$ celery -A common worker -l info +``` + +#### Test using task + +``` +$ ./manage.py shell +>>> from ops.tasks import longtime_add +>>> res = longtime_add.delay(1, 2) +>>> res.get() +``` + + + + diff --git a/apps/common/__init__.py b/apps/common/__init__.py new file mode 100644 index 000000000..b64e43e83 --- /dev/null +++ b/apps/common/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +# This will make sure the app is always imported when +# Django starts so that shared_task will use this app. +from .celery import app as celery_app diff --git a/apps/common/apps.py b/apps/common/apps.py new file mode 100644 index 000000000..6664a6438 --- /dev/null +++ b/apps/common/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class CommonConfig(AppConfig): + name = 'common' diff --git a/apps/common/celery.py b/apps/common/celery.py new file mode 100644 index 000000000..51de45349 --- /dev/null +++ b/apps/common/celery.py @@ -0,0 +1,21 @@ +# ~*~ coding: utf-8 ~*~ + +from __future__ import absolute_import, unicode_literals +import os +from datetime import timedelta + +from celery import Celery + +# set the default Django settings module for the 'celery' program. +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jumpserver.settings') + +from django.conf import settings + +app = Celery('jumpserver') + +# Using a string here means the worker will not have to +# pickle the object when using Windows. +app.config_from_object('django.conf:settings') +app.autodiscover_tasks(lambda: [app_config.split('.')[0] + for app_config in settings.INSTALLED_APPS]) + diff --git a/apps/common/compat.py b/apps/common/compat.py new file mode 100644 index 000000000..f2e757625 --- /dev/null +++ b/apps/common/compat.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +""" +兼容Python版本 +""" + +import sys + +is_py2 = (sys.version_info[0] == 2) +is_py3 = (sys.version_info[0] == 3) + + +try: + import simplejson as json +except (ImportError, SyntaxError): + import json + + +if is_py2: + + def to_bytes(data): + """若输入为unicode, 则转为utf-8编码的bytes;其他则原样返回。""" + if isinstance(data, unicode): + return data.encode('utf-8') + else: + return data + + def to_string(data): + """把输入转换为str对象""" + return to_bytes(data) + + def to_unicode(data): + """把输入转换为unicode,要求输入是unicode或者utf-8编码的bytes。""" + if isinstance(data, bytes): + return data.decode('utf-8') + else: + return data + + def stringify(input): + if isinstance(input, dict): + return dict([(stringify(key), stringify(value)) for key,value in input.iteritems()]) + elif isinstance(input, list): + return [stringify(element) for element in input] + elif isinstance(input, unicode): + return input.encode('utf-8') + else: + return input + + builtin_str = str + bytes = str + str = unicode + + +elif is_py3: + + def to_bytes(data): + """若输入为str(即unicode),则转为utf-8编码的bytes;其他则原样返回""" + if isinstance(data, str): + return data.encode(encoding='utf-8') + else: + return data + + def to_string(data): + """若输入为bytes,则认为是utf-8编码,并返回str""" + if isinstance(data, bytes): + return data.decode('utf-8') + else: + return data + + def to_unicode(data): + """把输入转换为unicode,要求输入是unicode或者utf-8编码的bytes。""" + return to_string(data) + + def stringify(input): + return input + + builtin_str = str + bytes = bytes + str = str + diff --git a/apps/common/mixins.py b/apps/common/mixins.py new file mode 100644 index 000000000..6a69221c5 --- /dev/null +++ b/apps/common/mixins.py @@ -0,0 +1,62 @@ +# coding: utf-8 + +from django.db import models +from django.http import JsonResponse +from django.utils.timezone import now +from django.utils.translation import ugettext_lazy as _ + + +class NoDeleteQuerySet(models.query.QuerySet): + + def delete(self): + return self.update(is_discard=True, discard_time=now()) + + +class NoDeleteManager(models.Manager): + + def get_all(self): + return NoDeleteQuerySet(self.model, using=self._db) + + def get_queryset(self): + return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=False) + + def get_deleted(self): + return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=True) + + +class NoDeleteModelMixin(models.Model): + is_discard = models.BooleanField(verbose_name=_("is discard"), default=False) + discard_time = models.DateTimeField(verbose_name=_("discard time"), null=True, blank=True) + + objects = NoDeleteManager() + + class Meta: + abstract = True + + def delete(self): + self.is_discard = True + self.discard_time = now() + return self.save() + + +class JSONResponseMixin(object): + """JSON mixin""" + @staticmethod + def render_json_response(context): + return JsonResponse(context) + + +class IDInFilterMixin(object): + + def filter_queryset(self, queryset): + id_list = self.request.query_params.get('id__in') + if id_list: + import json + try: + ids = json.loads(id_list) + except Exception as e: + print e + return queryset + if isinstance(ids, list): + queryset = queryset.filter(id__in=ids) + return queryset diff --git a/apps/common/models.py b/apps/common/models.py new file mode 100644 index 000000000..bd4b2abe9 --- /dev/null +++ b/apps/common/models.py @@ -0,0 +1,5 @@ +from __future__ import unicode_literals + +from django.db import models + +# Create your models here. diff --git a/apps/common/tasks.py b/apps/common/tasks.py new file mode 100644 index 000000000..11d0d711d --- /dev/null +++ b/apps/common/tasks.py @@ -0,0 +1,29 @@ +from __future__ import absolute_import + +# from celery import shared_task +from django.core.mail import send_mail +from django.conf import settings +from common import celery_app as app + + +@app.task +def send_mail_async(*args, **kwargs): + """ Using celery to send email async + + You can use it as django send_mail function + + Example: + send_mail_sync.delay(subject, message, from_mail, recipient_list, fail_silently=False, html_message=None) + + Also you can ignore the from_mail, unlike django send_mail, from_email is not a require args: + + Example: + send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None) + """ + if len(args) == 3: + args = list(args) + args[0] = settings.EMAIL_SUBJECT_PREFIX + args[0] + args.insert(2, settings.EMAIL_HOST_USER) + args = tuple(args) + + send_mail(*args, **kwargs) diff --git a/apps/common/templatetags/__init__.py b/apps/common/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/common/templatetags/common_tags.py b/apps/common/templatetags/common_tags.py new file mode 100644 index 000000000..01d1ab8f3 --- /dev/null +++ b/apps/common/templatetags/common_tags.py @@ -0,0 +1,71 @@ +# ~*~ coding: utf-8 ~*~ + +from django import template +from django.utils import timezone +from django.conf import settings +from django.utils.html import escape +from audits.backends import command_store + +register = template.Library() + + +@register.filter +def join_queryset_attr(queryset, attr, delimiter=', '): + return delimiter.join([getattr(obj, attr, '') for obj in queryset]) + + +@register.filter +def pagination_range(total_page, current_num=1, display=5): + """Return Page range + + :param total_page: Total numbers of paginator + :param current_num: current display page num + :param display: Display as many as [:display:] page + + In order to display many page num on web like: + < 1 2 3 4 5 > + """ + try: + current_num = int(current_num) + except ValueError: + current_num = 1 + + start = current_num - display/2 if current_num > display/2 else 1 + end = start + display if start + display <= total_page else total_page + 1 + + return range(start, end) + + +@register.filter +def join_attr(seq, attr=None, sep=None): + if sep is None: + sep = ', ' + if attr is not None: + seq = [getattr(obj, attr) for obj in seq] + return sep.join(seq) + + +@register.filter +def int_to_str(value): + return str(value) + + +@register.filter +def ts_to_date(ts): + try: + ts = float(ts) + except TypeError: + ts = 0 + dt = timezone.datetime.fromtimestamp(ts).\ + replace(tzinfo=timezone.get_current_timezone()) + return dt.strftime('%Y-%m-%d %H:%M:%S') + + +@register.filter +def to_html(s): + return escape(s).replace('\n', '
      ') + + +@register.filter +def proxy_log_commands(log_id): + return command_store.filter(proxy_log_id=log_id) \ No newline at end of file diff --git a/apps/common/tests.py b/apps/common/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/common/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/common/utils.py b/apps/common/utils.py new file mode 100644 index 000000000..cccfe1aec --- /dev/null +++ b/apps/common/utils.py @@ -0,0 +1,325 @@ +# -*- coding: utf-8 -*- +# + +from __future__ import unicode_literals +from six import string_types +import base64 +import os +from itertools import chain +import string +import logging +import datetime +import time +import hashlib +from email.utils import formatdate +import calendar +import threading + +import paramiko +import sshpubkeys +from itsdangerous import TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, \ + BadSignature, SignatureExpired +from django.shortcuts import reverse as dj_reverse +from django.conf import settings +from django.utils import timezone + +try: + import cStringIO as StringIO +except ImportError: + import StringIO + +from .compat import to_bytes, to_string + +SECRET_KEY = settings.SECRET_KEY + + +def reverse(view_name, urlconf=None, args=None, kwargs=None, + current_app=None, external=False): + url = dj_reverse(view_name, urlconf=urlconf, args=args, + kwargs=kwargs, current_app=current_app) + + if external: + url = settings.SITE_URL.strip('/') + url + return url + + +def get_object_or_none(model, **kwargs): + try: + obj = model.objects.get(**kwargs) + except model.DoesNotExist: + return None + return obj + + +class Signer(object): + def __init__(self, secret_key=SECRET_KEY): + self.secret_key = secret_key + + def sign(self, value): + s = JSONWebSignatureSerializer(self.secret_key) + return s.dumps(value) + + def unsign(self, value): + s = JSONWebSignatureSerializer(self.secret_key) + try: + return s.loads(value) + except BadSignature: + return None + + def sign_t(self, value, expires_in=3600): + s = TimedJSONWebSignatureSerializer(self.secret_key, expires_in=expires_in) + return s.dumps(value) + + def unsign_t(self, value): + s = TimedJSONWebSignatureSerializer(self.secret_key) + try: + return s.loads(value) + except (BadSignature, SignatureExpired): + return None + + +def date_expired_default(): + try: + years = int(settings.CONFIG.DEFAULT_EXPIRED_YEARS) + except TypeError: + years = 70 + return timezone.now() + timezone.timedelta(days=365*years) + + +def combine_seq(s1, s2, callback=None): + for s in (s1, s2): + if not hasattr(s, '__iter__'): + return [] + + seq = chain(s1, s2) + if callback: + seq = map(callback, seq) + return seq + + +def search_object_attr(obj, value='', attr_list=None, ignore_case=False): + """It's provide a method to search a object attribute equal some value + + If object some attribute equal :param: value, return True else return False + + class A(): + name = 'admin' + age = 7 + + :param obj: A object + :param value: A string match object attribute + :param attr_list: Only match attribute in attr_list + :param ignore_case: Ignore case + :return: Boolean + """ + if value == '': + return True + + try: + object_attr = obj.__dict__ + except AttributeError: + return False + + if attr_list is not None: + new_object_attr = {} + for attr in attr_list: + new_object_attr[attr] = object_attr.pop(attr) + object_attr = new_object_attr + + if ignore_case: + if not isinstance(value, string_types): + return False + + if value.lower() in map(string.lower, map(str, object_attr.values())): + return True + else: + if value in object_attr.values(): + return True + return False + + +def get_logger(name=None): + return logging.getLogger('jumpserver.%s' % name) + + +def int_seq(seq): + try: + return map(int, seq) + except ValueError: + return seq + + +def timesince(dt, since='', default="just now"): + """ + Returns string representing "time since" e.g. + 3 days, 5 hours. + """ + + if since is '': + since = datetime.datetime.utcnow() + + if since is None: + return default + + diff = since - dt + + periods = ( + (diff.days / 365, "year", "years"), + (diff.days / 30, "month", "months"), + (diff.days / 7, "week", "weeks"), + (diff.days, "day", "days"), + (diff.seconds / 3600, "hour", "hours"), + (diff.seconds / 60, "minute", "minutes"), + (diff.seconds, "second", "seconds"), + ) + + for period, singular, plural in periods: + if period: + return "%d %s" % (period, singular if period == 1 else plural) + return default + + +def ssh_key_string_to_obj(text): + key_f = StringIO.StringIO(text) + key = None + try: + key = paramiko.RSAKey.from_private_key(key_f) + except paramiko.SSHException: + pass + + try: + key = paramiko.DSSKey.from_private_key(key_f) + except paramiko.SSHException: + pass + return key + + +def ssh_pubkey_gen(private_key=None, username='jumpserver', hostname='localhost'): + if isinstance(private_key, string_types): + private_key = ssh_key_string_to_obj(private_key) + + if not isinstance(private_key, (paramiko.RSAKey, paramiko.DSSKey)): + raise IOError('Invalid private key') + + public_key = "%(key_type)s %(key_content)s %(username)s@%(hostname)s" % { + 'key_type': private_key.get_name(), + 'key_content': private_key.get_base64(), + 'username': username, + 'hostname': hostname, + } + return public_key + + +def ssh_key_gen(length=2048, type='rsa', password=None, username='jumpserver', hostname=None): + """Generate user ssh private and public key + + Use paramiko RSAKey generate it. + :return private key str and public key str + """ + + if hostname is None: + hostname = os.uname()[1] + + f = StringIO.StringIO() + + try: + if type == 'rsa': + private_key_obj = paramiko.RSAKey.generate(length) + elif type == 'dsa': + private_key_obj = paramiko.DSSKey.generate(length) + else: + raise IOError('SSH private key must be `rsa` or `dsa`') + private_key_obj.write_private_key(f, password=password) + private_key = f.getvalue() + public_key = ssh_pubkey_gen(private_key_obj, username=username, hostname=hostname) + return private_key, public_key + except IOError: + raise IOError('These is error when generate ssh key.') + + +def validate_ssh_private_key(text): + key = ssh_key_string_to_obj(text) + if key is None: + return False + else: + return True + + +def validate_ssh_public_key(text): + ssh = sshpubkeys.SSHKey(text) + try: + ssh.parse() + except sshpubkeys.InvalidKeyException: + return False + except NotImplementedError as e: + return False + return True + + +def setattr_bulk(seq, key, value): + def set_attr(obj): + setattr(obj, key, value) + return obj + return map(set_attr, seq) + + +def content_md5(data): + """计算data的MD5值,经过Base64编码并返回str类型。 + + 返回值可以直接作为HTTP Content-Type头部的值 + """ + m = hashlib.md5(to_bytes(data)) + return to_string(base64.b64encode(m.digest())) + +_STRPTIME_LOCK = threading.Lock() + +_GMT_FORMAT = "%a, %d %b %Y %H:%M:%S GMT" +_ISO8601_FORMAT = "%Y-%m-%dT%H:%M:%S.000Z" + + +def to_unixtime(time_string, format_string): + with _STRPTIME_LOCK: + return int(calendar.timegm(time.strptime(time_string, format_string))) + + +def http_date(timeval=None): + """返回符合HTTP标准的GMT时间字符串,用strftime的格式表示就是"%a, %d %b %Y %H:%M:%S GMT"。 + 但不能使用strftime,因为strftime的结果是和locale相关的。 + """ + return formatdate(timeval, usegmt=True) + + +def http_to_unixtime(time_string): + """把HTTP Date格式的字符串转换为UNIX时间(自1970年1月1日UTC零点的秒数)。 + + HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。 + """ + return to_unixtime(time_string, _GMT_FORMAT) + + +def iso8601_to_unixtime(time_string): + """把ISO8601时间字符串(形如,2012-02-24T06:07:48.000Z)转换为UNIX时间,精确到秒。""" + return to_unixtime(time_string, _ISO8601_FORMAT) + + +def http_to_unixtime(time_string): + """把HTTP Date格式的字符串转换为UNIX时间(自1970年1月1日UTC零点的秒数)。 + + HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。 + """ + return to_unixtime(time_string, "%a, %d %b %Y %H:%M:%S GMT") + + +def make_signature(access_key_secret, date=None): + if isinstance(date, int): + date_gmt = http_date(date) + elif date is None: + date_gmt = http_date(int(time.time())) + else: + date_gmt = date + + data = str(access_key_secret) + "\n" + date_gmt + return content_md5(data) + + +signer = Signer() \ No newline at end of file diff --git a/apps/common/views.py b/apps/common/views.py new file mode 100644 index 000000000..5663b8b19 --- /dev/null +++ b/apps/common/views.py @@ -0,0 +1,4 @@ +from __future__ import absolute_import, unicode_literals + +from django.shortcuts import render +from django.views.generic import TemplateView diff --git a/apps/fixtures/fake.json b/apps/fixtures/fake.json new file mode 100644 index 000000000..de7fc89cf --- /dev/null +++ b/apps/fixtures/fake.json @@ -0,0 +1 @@ +[{"model": "assets.idc", "pk": 1, "fields": {"name": "George Fowler", "bandwidth": "200M", "contact": "Charles Gray", "phone": "5-(040)883-6269", "address": "Anderson19827 Monument Alley", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.802Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Donec odio justo, sollicitudin ut, suscipit a, feugiat et, eros."}}, {"model": "assets.idc", "pk": 2, "fields": {"name": "Donna Arnold", "bandwidth": "200M", "contact": "Debra Cole", "phone": "9-(630)719-5400", "address": "Barstow9 Mockingbird Street", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.805Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Proin risus."}}, {"model": "assets.idc", "pk": 3, "fields": {"name": "Maria Wells", "bandwidth": "200M", "contact": "Sharon Lane", "phone": "3-(604)210-2617", "address": "Baldwin Park3061 Summit Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.806Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis."}}, {"model": "assets.idc", "pk": 4, "fields": {"name": "Alice Gonzales", "bandwidth": "200M", "contact": "Jacqueline ", "phone": "8-(630)598-3343", "address": "Monterey Park634 Moose Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.807Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Morbi non lectus."}}, {"model": "assets.idc", "pk": 5, "fields": {"name": "Michelle Murray", "bandwidth": "200M", "contact": "Phyllis Johnston", "phone": "3-(548)603-5738", "address": "Lemon Grove8630 Coleman Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.809Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Nullam molestie nibh in lectus."}}, {"model": "assets.idc", "pk": 6, "fields": {"name": "Ashley Richards", "bandwidth": "200M", "contact": "Sharon Harper", "phone": "3-(018)486-5418", "address": "Taft52469 Waxwing Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.812Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa."}}, {"model": "assets.idc", "pk": 7, "fields": {"name": "Bonnie Myers", "bandwidth": "200M", "contact": "Cheryl Duncan", "phone": "3-(617)055-3027", "address": "Palmdale378 Fisk Crossing", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.814Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc."}}, {"model": "assets.idc", "pk": 8, "fields": {"name": "Andrea Phillips", "bandwidth": "200M", "contact": "Cheryl Rose", "phone": "0-(098)539-4235", "address": "Tulare1 Monterey Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.816Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Aenean fermentum."}}, {"model": "assets.idc", "pk": 9, "fields": {"name": "Theresa Palmer", "bandwidth": "200M", "contact": "Christine Fisher", "phone": "4-(551)769-3945", "address": "Corning39047 Brentwood Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.817Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem."}}, {"model": "assets.idc", "pk": 10, "fields": {"name": "Louise Nelson", "bandwidth": "200M", "contact": "Laura Ellis", "phone": "3-(447)108-5273", "address": "Maricopa0287 Derek Alley", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.819Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."}}, {"model": "assets.idc", "pk": 11, "fields": {"name": "Margaret Adams", "bandwidth": "200M", "contact": "Judith Olson", "phone": "9-(864)241-7871", "address": "Pasadena6 Lyons Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.822Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam."}}, {"model": "assets.idc", "pk": 12, "fields": {"name": "Ashley Jones", "bandwidth": "200M", "contact": "Christine Stephens", "phone": "0-(810)674-3076", "address": "Sanger8591 Lake View Lane", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.824Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Etiam pretium iaculis justo."}}, {"model": "assets.idc", "pk": 13, "fields": {"name": "Tina Fox", "bandwidth": "200M", "contact": "Karen Price", "phone": "2-(516)305-8460", "address": "Anderson04917 4th Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.826Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Suspendisse potenti."}}, {"model": "assets.idc", "pk": 14, "fields": {"name": "Cheryl Freeman", "bandwidth": "200M", "contact": "Virginia Bowman", "phone": "8-(451)880-4093", "address": "Hanford04687 La Follette Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.827Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."}}, {"model": "assets.idc", "pk": 15, "fields": {"name": "Michelle Ruiz", "bandwidth": "200M", "contact": "Andrea Brown", "phone": "6-(332)797-0233", "address": "El Monte86294 Coleman Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.829Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi ut odio."}}, {"model": "assets.idc", "pk": 16, "fields": {"name": "Kelly Elliott", "bandwidth": "200M", "contact": "Rose Sims", "phone": "6-(550)299-9648", "address": "Norco509 Lawn Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.830Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Proin interdum mauris non ligula pellentesque ultrices."}}, {"model": "assets.idc", "pk": 17, "fields": {"name": "Anne Hanson", "bandwidth": "200M", "contact": "Rebecca Spencer", "phone": "7-(636)031-1826", "address": "La Quinta894 Golf Course Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.832Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Etiam faucibus cursus urna."}}, {"model": "assets.idc", "pk": 18, "fields": {"name": "Virginia Banks", "bandwidth": "200M", "contact": "Louise Myers", "phone": "3-(594)256-7316", "address": "El Cerrito9 Nova Trail", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.834Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Etiam faucibus cursus urna."}}, {"model": "assets.idc", "pk": 19, "fields": {"name": "Cheryl Andrews", "bandwidth": "200M", "contact": "Mary Taylor", "phone": "8-(262)459-5236", "address": "Stockton20 Rigney Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.835Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Nulla tempus."}}, {"model": "assets.idc", "pk": 20, "fields": {"name": "Denise Young", "bandwidth": "200M", "contact": "Louise Bailey", "phone": "1-(499)414-9751", "address": "Temple City0 Lake View Terrace", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.837Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Praesent blandit lacinia erat."}}, {"model": "assets.idc", "pk": 21, "fields": {"name": "Louise Hill", "bandwidth": "200M", "contact": "Ruth Myers", "phone": "8-(447)798-9793", "address": "Union City93 Merrick Alley", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.839Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi a ipsum."}}, {"model": "assets.idc", "pk": 22, "fields": {"name": "Phyllis Kelly", "bandwidth": "200M", "contact": "Margaret George", "phone": "5-(287)713-7649", "address": "Mountain View72690 Thierer Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.841Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.idc", "pk": 23, "fields": {"name": "Lori Fernandez", "bandwidth": "200M", "contact": "Janet Bailey", "phone": "1-(708)691-9444", "address": "Ferndale5 Rieder Junction", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.843Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi a ipsum."}}, {"model": "assets.idc", "pk": 24, "fields": {"name": "Sandra Nichols", "bandwidth": "200M", "contact": "Jean Hamilton", "phone": "6-(488)503-4196", "address": "Montclair784 Barnett Junction", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.846Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi vel lectus in quam fringilla rhoncus."}}, {"model": "assets.idc", "pk": 25, "fields": {"name": "Linda Ruiz", "bandwidth": "200M", "contact": "Carolyn Lynch", "phone": "9-(188)046-0328", "address": "Lafayette4059 Gerald Alley", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.850Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Nulla facilisi."}}, {"model": "assets.idc", "pk": 26, "fields": {"name": "Lisa Kelly", "bandwidth": "200M", "contact": "Alice Stewart", "phone": "4-(933)308-5973", "address": "Sausalito2963 Clove Point", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.851Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Duis at velit eu est congue elementum."}}, {"model": "assets.idc", "pk": 27, "fields": {"name": "Brenda Garza", "bandwidth": "200M", "contact": "Theresa Hill", "phone": "7-(450)934-3916", "address": "El Monte7345 Buell Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.853Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem."}}, {"model": "assets.idc", "pk": 28, "fields": {"name": "Mary Williams", "bandwidth": "200M", "contact": "Emily Gutierrez", "phone": "5-(093)171-8204", "address": "Gonzales60421 Elmside Parkway", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.855Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "In sagittis dui vel nisl."}}, {"model": "assets.idc", "pk": 29, "fields": {"name": "Ruth Chapman", "bandwidth": "200M", "contact": "Martha Palmer", "phone": "4-(482)963-8620", "address": "Windsor1 Algoma Lane", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.857Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "In congue."}}, {"model": "assets.idc", "pk": 30, "fields": {"name": "Janet James", "bandwidth": "200M", "contact": "Phyllis Richardson", "phone": "9-(569)564-0435", "address": "Susanville06591 Hoepker Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.858Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam."}}, {"model": "assets.idc", "pk": 31, "fields": {"name": "Denise Parker", "bandwidth": "200M", "contact": "Denise Armstrong", "phone": "2-(467)303-4151", "address": "Hemet4293 Aberg Parkway", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.860Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Integer tincidunt ante vel ipsum."}}, {"model": "assets.idc", "pk": 32, "fields": {"name": "Paula Rogers", "bandwidth": "200M", "contact": "Rose Frazier", "phone": "8-(829)431-2629", "address": "Monterey Park6075 Shoshone Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.862Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Integer ac neque."}}, {"model": "assets.idc", "pk": 33, "fields": {"name": "Kathryn Hughes", "bandwidth": "200M", "contact": "Anne Willis", "phone": "9-(667)008-5710", "address": "South San Francisco087 Clove Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.865Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Integer non velit."}}, {"model": "assets.idc", "pk": 34, "fields": {"name": "Irene Sanders", "bandwidth": "200M", "contact": "Melissa Dean", "phone": "2-(660)780-2387", "address": "Parlier1325 Dorton Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.867Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Cras mi pede, malesuada in, imperdiet et, commodo vulputate, justo."}}, {"model": "assets.idc", "pk": 35, "fields": {"name": "Eugene Garcia", "bandwidth": "200M", "contact": "Pamela Sims", "phone": "2-(198)816-1278", "address": "Torrance30 Pine View Crossing", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.869Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi a ipsum."}}, {"model": "assets.idc", "pk": 36, "fields": {"name": "Lisa Cole", "bandwidth": "200M", "contact": "Linda Perry", "phone": "3-(349)520-3945", "address": "Fountain Valley93467 Chive Lane", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.871Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Vestibulum sed magna at nunc commodo placerat."}}, {"model": "assets.idc", "pk": 37, "fields": {"name": "Stephanie Garcia", "bandwidth": "200M", "contact": "Helen Fuller", "phone": "4-(457)337-1861", "address": "Walnut6952 Continental Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.873Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.idc", "pk": 38, "fields": {"name": "Michelle Matthews", "bandwidth": "200M", "contact": "Amy Lopez", "phone": "7-(925)725-7818", "address": "Exeter1 Northwestern Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.874Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl."}}, {"model": "assets.idc", "pk": 39, "fields": {"name": "Kathy Reed", "bandwidth": "200M", "contact": "Joyce Snyder", "phone": "5-(827)366-0483", "address": "El Centro29814 Ruskin Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.876Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Morbi porttitor lorem id ligula."}}, {"model": "assets.idc", "pk": 40, "fields": {"name": "Rachel Richardson", "bandwidth": "200M", "contact": "Margaret Ramirez", "phone": "8-(518)556-9007", "address": "Yucaipa084 Kenwood Park", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.879Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Suspendisse potenti."}}, {"model": "assets.idc", "pk": 41, "fields": {"name": "Christina Green", "bandwidth": "200M", "contact": "Kimberly Perry", "phone": "7-(653)194-2143", "address": "Vista1 Steensland Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.881Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Praesent id massa id nisl venenatis lacinia."}}, {"model": "assets.idc", "pk": 42, "fields": {"name": "Carolyn Harrison", "bandwidth": "200M", "contact": "Kelly Hansen", "phone": "6-(862)158-9037", "address": "Turlock8430 Springview Street", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.882Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Pellentesque ultrices mattis odio."}}, {"model": "assets.idc", "pk": 43, "fields": {"name": "Maria Burke", "bandwidth": "200M", "contact": "Sarah Johnson", "phone": "0-(663)668-0766", "address": "Visalia30 Elka Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.884Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Aenean fermentum."}}, {"model": "assets.idc", "pk": 44, "fields": {"name": "Sarah Duncan", "bandwidth": "200M", "contact": "Rebecca Mitchell", "phone": "3-(770)877-3378", "address": "Los Gatos63 Parkside Road", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.885Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Donec vitae nisi."}}, {"model": "assets.idc", "pk": 45, "fields": {"name": "Bonnie Young", "bandwidth": "200M", "contact": "Patricia Robertson", "phone": "2-(466)346-7614", "address": "Marysville43 Harbort Terrace", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.887Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Donec quis orci eget orci vehicula condimentum."}}, {"model": "assets.idc", "pk": 46, "fields": {"name": "Jessica Bowman", "bandwidth": "200M", "contact": "Teresa Sullivan", "phone": "4-(272)327-0054", "address": "Torrance057 Saint Paul Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.889Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Nam dui."}}, {"model": "assets.idc", "pk": 47, "fields": {"name": "Theresa Jackson", "bandwidth": "200M", "contact": "Kelly Griffin", "phone": "7-(620)760-0465", "address": "San Marcos09167 Homewood Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.891Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Curabitur in libero ut massa volutpat convallis."}}, {"model": "assets.idc", "pk": 48, "fields": {"name": "Susan Wheeler", "bandwidth": "200M", "contact": "Mildred Black", "phone": "5-(585)212-7866", "address": "San Fernando842 Derek Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.893Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat."}}, {"model": "assets.idc", "pk": 49, "fields": {"name": "Ruby Rice", "bandwidth": "200M", "contact": "Jane Duncan", "phone": "5-(172)190-5718", "address": "San Marino5268 Hauk Crossing", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.896Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Integer tincidunt ante vel ipsum."}}, {"model": "assets.idc", "pk": 50, "fields": {"name": "Jennifer Carroll", "bandwidth": "200M", "contact": "Phyllis Romero", "phone": "3-(042)461-5898", "address": "Newport Beach67 Sutteridge Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.898Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Suspendisse potenti."}}, {"model": "assets.idc", "pk": 51, "fields": {"name": "Lisa Johnston", "bandwidth": "200M", "contact": "Patricia Matthews", "phone": "5-(576)975-6693", "address": "Grover Beach82547 Meadow Valley Junction", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.900Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Pellentesque eget nunc."}}, {"model": "assets.idc", "pk": 52, "fields": {"name": "Irene White", "bandwidth": "200M", "contact": "Cynthia Elliott", "phone": "7-(987)052-3750", "address": "Milpitas89 Darwin Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.901Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Proin eu mi."}}, {"model": "assets.idc", "pk": 53, "fields": {"name": "Betty Gutierrez", "bandwidth": "200M", "contact": "Donna Hall", "phone": "9-(232)498-4535", "address": "Studio City37291 Waubesa Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.903Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Aenean lectus."}}, {"model": "assets.idc", "pk": 54, "fields": {"name": "Gloria Myers", "bandwidth": "200M", "contact": "Alice Cole", "phone": "9-(671)737-8987", "address": "Colton78 Almo Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.904Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Praesent lectus."}}, {"model": "assets.idc", "pk": 55, "fields": {"name": "Rebecca Stanley", "bandwidth": "200M", "contact": "Annie Murray", "phone": "9-(361)405-3699", "address": "Grover Beach4921 Little Fleur Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.906Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Mauris sit amet eros."}}, {"model": "assets.idc", "pk": 56, "fields": {"name": "Dorothy Fox", "bandwidth": "200M", "contact": "Christina Butler", "phone": "2-(485)703-7811", "address": "Pinole8 Maywood Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.908Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum quam sapien, varius ut, blandit non, interdum in, ante."}}, {"model": "assets.idc", "pk": 57, "fields": {"name": "Carol Warren", "bandwidth": "200M", "contact": "Sharon Richards", "phone": "0-(693)292-0574", "address": "Farmersville5 Graedel Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.910Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Donec semper sapien a libero."}}, {"model": "assets.idc", "pk": 58, "fields": {"name": "Brenda Gonzalez", "bandwidth": "200M", "contact": "Sharon Gordon", "phone": "9-(216)331-8575", "address": "San Luis Obispo89254 Buena Vista Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.912Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Fusce posuere felis sed lacus."}}, {"model": "assets.idc", "pk": 59, "fields": {"name": "Sandra Long", "bandwidth": "200M", "contact": "Julia West", "phone": "2-(329)877-9532", "address": "Orland692 Holy Cross Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.913Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci."}}, {"model": "assets.idc", "pk": 60, "fields": {"name": "Laura Flores", "bandwidth": "200M", "contact": "Lillian Mcdonald", "phone": "4-(738)591-7874", "address": "Portola Valley27 Donald Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.915Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Nam nulla."}}, {"model": "assets.idc", "pk": 61, "fields": {"name": "Janet Ward", "bandwidth": "200M", "contact": "Paula Hayes", "phone": "6-(042)994-3055", "address": "Calabasas26153 Westport Crossing", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.917Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum sed magna at nunc commodo placerat."}}, {"model": "assets.idc", "pk": 62, "fields": {"name": "Jacqueline Warren", "bandwidth": "200M", "contact": "Gloria Warren", "phone": "4-(838)513-9148", "address": "Hawaiian Gardens23 Sycamore Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.919Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Curabitur convallis."}}, {"model": "assets.idc", "pk": 63, "fields": {"name": "Phyllis Jordan", "bandwidth": "200M", "contact": "Diane Torres", "phone": "9-(201)528-0082", "address": "Ferndale90 Debra Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.921Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Integer non velit."}}, {"model": "assets.idc", "pk": 64, "fields": {"name": "Andrea Grant", "bandwidth": "200M", "contact": "Julia Lewis", "phone": "3-(876)639-2477", "address": "Maywood38257 Maywood Avenue", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.922Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Duis at velit eu est congue elementum."}}, {"model": "assets.idc", "pk": 65, "fields": {"name": "Rose Ruiz", "bandwidth": "200M", "contact": "Lisa Watson", "phone": "6-(128)481-0698", "address": "Redwood City7 Schmedeman Road", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.923Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.idc", "pk": 66, "fields": {"name": "Jacqueline Porter", "bandwidth": "200M", "contact": "Pamela Kelley", "phone": "7-(990)686-8179", "address": "Davis60 Thackeray Parkway", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.925Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Nulla ac enim."}}, {"model": "assets.idc", "pk": 67, "fields": {"name": "Ruth Montgomery", "bandwidth": "200M", "contact": "Ruby Marshall", "phone": "7-(981)337-2546", "address": "Azusa79310 Dryden Trail", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.927Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "In sagittis dui vel nisl."}}, {"model": "assets.idc", "pk": 68, "fields": {"name": "Shirley Ferguson", "bandwidth": "200M", "contact": "Margaret Fields", "phone": "2-(783)361-5746", "address": "Sutter Creek85 Fairfield Drive", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.929Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Praesent lectus."}}, {"model": "assets.idc", "pk": 69, "fields": {"name": "Nicole Parker", "bandwidth": "200M", "contact": "Brenda Edwards", "phone": "6-(333)659-4826", "address": "Downey216 Longview Street", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.931Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Suspendisse potenti."}}, {"model": "assets.idc", "pk": 70, "fields": {"name": "Kimberly Russell", "bandwidth": "200M", "contact": "Alice Hill", "phone": "0-(293)927-4889", "address": "Hawthorne0 Mosinee Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.932Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Integer tincidunt ante vel ipsum."}}, {"model": "assets.idc", "pk": 71, "fields": {"name": "Andrea Jacobs", "bandwidth": "200M", "contact": "Stephanie Day", "phone": "7-(086)809-9681", "address": "La Mirada52781 New Castle Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.934Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "In eleifend quam a odio."}}, {"model": "assets.idc", "pk": 72, "fields": {"name": "Amanda Jackson", "bandwidth": "200M", "contact": "Linda Miller", "phone": "3-(978)689-6043", "address": "Citrus Heights35 Graedel Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.936Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Morbi ut odio."}}, {"model": "assets.idc", "pk": 73, "fields": {"name": "Louise Fields", "bandwidth": "200M", "contact": "Wanda Peterson", "phone": "9-(512)864-4649", "address": "San Diego74 Westport Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.938Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Aenean fermentum."}}, {"model": "assets.idc", "pk": 74, "fields": {"name": "Janet Murray", "bandwidth": "200M", "contact": "Sara Williams", "phone": "8-(879)484-5554", "address": "Calistoga1023 Susan Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.940Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Etiam justo."}}, {"model": "assets.idc", "pk": 75, "fields": {"name": "Bonnie Berry", "bandwidth": "200M", "contact": "Pamela Montgomery", "phone": "7-(587)471-5818", "address": "San Marino713 Anniversary Road", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.941Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Mauris ullamcorper purus sit amet nulla."}}, {"model": "assets.idc", "pk": 76, "fields": {"name": "Cynthia Stevens", "bandwidth": "200M", "contact": "Tina Smith", "phone": "0-(857)252-4544", "address": "San Diego348 East Street", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.943Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Morbi non quam nec dui luctus rutrum."}}, {"model": "assets.idc", "pk": 77, "fields": {"name": "Lillian Kennedy", "bandwidth": "200M", "contact": "Virginia Burton", "phone": "0-(144)952-1550", "address": "Walnut1069 Arkansas Terrace", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.945Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam."}}, {"model": "assets.idc", "pk": 78, "fields": {"name": "Ruth Robertson", "bandwidth": "200M", "contact": "Susan Morrison", "phone": "3-(760)524-6699", "address": "Trinidad043 Vahlen Point", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.946Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo."}}, {"model": "assets.idc", "pk": 79, "fields": {"name": "Cynthia Fernandez", "bandwidth": "200M", "contact": "Christina Howard", "phone": "2-(615)939-1022", "address": "Lodi1740 Ridgeway Terrace", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.949Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum ac est lacinia nisi venenatis tristique."}}, {"model": "assets.idc", "pk": 80, "fields": {"name": "Denise Lopez", "bandwidth": "200M", "contact": "Amy Spencer", "phone": "6-(705)880-4157", "address": "Chula Vista4396 Golf Course Plaza", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.951Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi vel lectus in quam fringilla rhoncus."}}, {"model": "assets.idc", "pk": 81, "fields": {"name": "Julie Gomez", "bandwidth": "200M", "contact": "Denise Griffin", "phone": "0-(193)258-5116", "address": "Weed67381 Valley Edge Road", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.953Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Integer non velit."}}, {"model": "assets.idc", "pk": 82, "fields": {"name": "Cynthia Lopez", "bandwidth": "200M", "contact": "Evelyn Elliott", "phone": "2-(876)854-1072", "address": "San Juan Bautista2165 Northridge Street", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.954Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Nulla tempus."}}, {"model": "assets.idc", "pk": 83, "fields": {"name": "Katherine Simmons", "bandwidth": "200M", "contact": "Cheryl Burton", "phone": "8-(686)179-3765", "address": "Walnut719 Nobel Trail", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.956Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Fusce posuere felis sed lacus."}}, {"model": "assets.idc", "pk": 84, "fields": {"name": "Denise Burke", "bandwidth": "200M", "contact": "Julia Greene", "phone": "0-(882)410-5635", "address": "Ontario53 Prentice Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.958Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam."}}, {"model": "assets.idc", "pk": 85, "fields": {"name": "Susan Ryan", "bandwidth": "200M", "contact": "Annie Robertson", "phone": "4-(289)334-9104", "address": "Red Bluff6019 Maywood Circle", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.960Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Aenean sit amet justo."}}, {"model": "assets.idc", "pk": 86, "fields": {"name": "Marie Dunn", "bandwidth": "200M", "contact": "Donna Lopez", "phone": "6-(479)409-3049", "address": "Pacific Grove138 Banding Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.961Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Morbi vel lectus in quam fringilla rhoncus."}}, {"model": "assets.idc", "pk": 87, "fields": {"name": "Sandra Richardson", "bandwidth": "200M", "contact": "Denise Ford", "phone": "3-(027)851-1287", "address": "King City61 Pankratz Terrace", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.963Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Aenean fermentum."}}, {"model": "assets.idc", "pk": 88, "fields": {"name": "Kelly Tucker", "bandwidth": "200M", "contact": "Patricia Ruiz", "phone": "4-(597)539-9418", "address": "Beverly Hills26893 1st Parkway", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.965Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Donec semper sapien a libero."}}, {"model": "assets.idc", "pk": 89, "fields": {"name": "Tina Roberts", "bandwidth": "200M", "contact": "Laura Hughes", "phone": "6-(932)236-1859", "address": "West Covina450 Delladonna Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.966Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.idc", "pk": 90, "fields": {"name": "Linda Owens", "bandwidth": "200M", "contact": "Norma Dixon", "phone": "0-(586)362-3812", "address": "Ceres72 Surrey Hill", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.968Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "Aenean sit amet justo."}}, {"model": "assets.idc", "pk": 91, "fields": {"name": "Heather Coleman", "bandwidth": "200M", "contact": "Sarah Schmidt", "phone": "1-(042)372-9699", "address": "Amador City57 Schmedeman Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.970Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Praesent blandit."}}, {"model": "assets.idc", "pk": 92, "fields": {"name": "Katherine Hart", "bandwidth": "200M", "contact": "Judy Martinez", "phone": "6-(125)701-6034", "address": "Hemet2364 Lakeland Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.972Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Nunc purus."}}, {"model": "assets.idc", "pk": 93, "fields": {"name": "Doris Freeman", "bandwidth": "200M", "contact": "Annie Reyes", "phone": "8-(060)927-4284", "address": "Davis1834 Declaration Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.975Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Aenean fermentum."}}, {"model": "assets.idc", "pk": 94, "fields": {"name": "Tina Pierce", "bandwidth": "200M", "contact": "Jennifer Cox", "phone": "8-(762)514-9531", "address": "Trinidad638 Jackson Pass", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.977Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Curabitur at ipsum ac tellus semper interdum."}}, {"model": "assets.idc", "pk": 95, "fields": {"name": "Gloria Walker", "bandwidth": "200M", "contact": "Barbara Peterson", "phone": "3-(368)003-3984", "address": "Beverly Hills06591 Valley Edge Junction", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.978Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Donec ut dolor."}}, {"model": "assets.idc", "pk": 96, "fields": {"name": "Nancy Reid", "bandwidth": "200M", "contact": "Donna Mcdonald", "phone": "2-(491)869-0997", "address": "Gilroy93 Garrison Way", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.980Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.idc", "pk": 97, "fields": {"name": "Judy White", "bandwidth": "200M", "contact": "Denise Russell", "phone": "3-(665)668-4197", "address": "Calipatria8 Carberry Circle", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.982Z", "operator": "BGP\u5168\u7f51\u901a", "created_by": "Fake", "comment": "Nulla tempus."}}, {"model": "assets.idc", "pk": 98, "fields": {"name": "Rachel Taylor", "bandwidth": "200M", "contact": "Rachel Nelson", "phone": "3-(507)131-3666", "address": "Chino Hills14 Anthes Center", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.984Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Proin eu mi."}}, {"model": "assets.idc", "pk": 99, "fields": {"name": "Linda Carroll", "bandwidth": "200M", "contact": "Elizabeth Hansen", "phone": "0-(215)147-9068", "address": "Merced6015 Oak Court", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.985Z", "operator": "\u5317\u4eac\u7535\u4fe1", "created_by": "Fake", "comment": "In sagittis dui vel nisl."}}, {"model": "assets.idc", "pk": 100, "fields": {"name": "Margaret Morris", "bandwidth": "200M", "contact": "Melissa Martinez", "phone": "9-(886)438-1186", "address": "Solvang79 South Place", "intranet": "", "extranet": "", "date_created": "2017-01-07T12:54:14.987Z", "operator": "\u5317\u4eac\u8054\u901a", "created_by": "Fake", "comment": "Morbi a ipsum."}}, {"model": "assets.adminuser", "pk": 1, "fields": {"name": "Judith Robinson", "username": "ruth", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hdHRpcyI.5Sp7NUJKOQNxv-1xJ-zA3A3pUkl2vnOfD3Z5g9LiFtQ", "_private_key": null, "_public_key": "", "comment": "Curabitur convallis.", "date_created": "2017-01-07T12:54:15.188Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 2, "fields": {"name": "Emily Davis", "username": "patricia", "_password": "eyJhbGciOiJIUzI1NiJ9.InF1aXMi.sr0cWp1ZfjO1QWimGNuf1x_MHaNsiEFy7_UxzlJkIfY", "_private_key": null, "_public_key": "", "comment": "Nam tristique tortor eu pede.", "date_created": "2017-01-07T12:54:15.201Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 3, "fields": {"name": "Donna Griffin", "username": "denise", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV1Ig.k74Kbv7It_-9OcFde0stLpx06suYL5M71w_MTMaDa9M", "_private_key": null, "_public_key": "", "comment": "Vestibulum sed magna at nunc commodo placerat.", "date_created": "2017-01-07T12:54:15.209Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 4, "fields": {"name": "Lillian Ryan", "username": "pamela", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxvYm9ydGlzIg.RKcewrE2glcmJtRtDpTt8WptvFfwUjhUDMlcdl1Shuw", "_private_key": null, "_public_key": "", "comment": "Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla.", "date_created": "2017-01-07T12:54:15.213Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 5, "fields": {"name": "Lillian Fisher", "username": "tina", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV0aWFtIg.QEs0SICruIrhYPzqpEG9iKLje7wzoW601XZyyGFsWnk", "_private_key": null, "_public_key": "", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "date_created": "2017-01-07T12:54:15.215Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 6, "fields": {"name": "Frances Little", "username": "donna", "_password": "eyJhbGciOiJIUzI1NiJ9.InNlZCI.8x8y146cvv6phwCp2Q53l_zeUmW1oZkRrbMZG3kbs3w", "_private_key": null, "_public_key": "", "comment": "Nulla justo.", "date_created": "2017-01-07T12:54:15.216Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 7, "fields": {"name": "Emily Carroll", "username": "nancy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImR1aXMi.KS4EioZYRU2pQ7fIKt0kMbzHNljZMDpfMtimVI_Vjxw", "_private_key": null, "_public_key": "", "comment": "Cras non velit nec nisi vulputate nonummy.", "date_created": "2017-01-07T12:54:15.218Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 8, "fields": {"name": "Margaret Hill", "username": "anne", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlbGxlbnRlc3F1ZSI.3yrIK8gbDmlyR-M0hLUJmm7e0Tqrq3F-2hfrwlnJXQ8", "_private_key": null, "_public_key": "", "comment": "Etiam pretium iaculis justo.", "date_created": "2017-01-07T12:54:15.220Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 9, "fields": {"name": "Carol Ward", "username": "sara", "_password": "eyJhbGciOiJIUzI1NiJ9.ImlkIg.lr9X3DQPFH2zptTUg3pRWbYLzWhfDYsw0w_q9pEod3I", "_private_key": null, "_public_key": "", "comment": "Suspendisse ornare consequat lectus.", "date_created": "2017-01-07T12:54:15.222Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 10, "fields": {"name": "Annie Jones", "username": "dorothy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyb3Mi.u6zpIQpfh7cgPYmscg5N0W9W6cx274KgMtp0pz5_OlY", "_private_key": null, "_public_key": "", "comment": "In hac habitasse platea dictumst.", "date_created": "2017-01-07T12:54:15.224Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 11, "fields": {"name": "Theresa Hall", "username": "kelly", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF0Ig.KKCMSzsOJLvrGcheEd9SDxRwZhts01BoZ0xyuxHx4Y0", "_private_key": null, "_public_key": "", "comment": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla.", "date_created": "2017-01-07T12:54:15.226Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 12, "fields": {"name": "Martha King", "username": "beverly", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxhY2luaWEi.k2d8p0z-xevNN7wP2FDZiOuHFRhIiL-MVOtmCJI4vA8", "_private_key": null, "_public_key": "", "comment": "Nunc purus.", "date_created": "2017-01-07T12:54:15.227Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 13, "fields": {"name": "Heather Brooks", "username": "carol", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "_private_key": null, "_public_key": "", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat.", "date_created": "2017-01-07T12:54:15.229Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 14, "fields": {"name": "Beverly Bryant", "username": "elizabeth", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "_private_key": null, "_public_key": "", "comment": "Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl.", "date_created": "2017-01-07T12:54:15.231Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 15, "fields": {"name": "Ruth Cole", "username": "kelly", "_password": "eyJhbGciOiJIUzI1NiJ9.InJpZGljdWx1cyI.qz9Ndt8Jw7Ip8Jg6HzArFfESopFFuiHJEUrXJKWkC-M", "_private_key": null, "_public_key": "", "comment": "Maecenas rhoncus aliquam lacus.", "date_created": "2017-01-07T12:54:15.233Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 16, "fields": {"name": "Kathleen Perry", "username": "sara", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "_private_key": null, "_public_key": "", "comment": "Mauris sit amet eros.", "date_created": "2017-01-07T12:54:15.235Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 17, "fields": {"name": "Margaret Ruiz", "username": "amy", "_password": "eyJhbGciOiJIUzI1NiJ9.InV0Ig.lmRSuoHi4jv9YOiKOSfPjnCwSvHOnUh0UQcZXnEWZzo", "_private_key": null, "_public_key": "", "comment": "Morbi non quam nec dui luctus rutrum.", "date_created": "2017-01-07T12:54:15.236Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 18, "fields": {"name": "Mary Burns", "username": "angela", "_password": "eyJhbGciOiJIUzI1NiJ9.InN1c2NpcGl0Ig.Z61mFiu2oDhYJjR0Be_bppgWlu5yNIbatQroqyG17Hc", "_private_key": null, "_public_key": "", "comment": "Phasellus sit amet erat.", "date_created": "2017-01-07T12:54:15.238Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 19, "fields": {"name": "Diane Peters", "username": "evelyn", "_password": "eyJhbGciOiJIUzI1NiJ9.InNlZCI.8x8y146cvv6phwCp2Q53l_zeUmW1oZkRrbMZG3kbs3w", "_private_key": null, "_public_key": "", "comment": "In est risus, auctor sed, tristique in, tempus sit amet, sem.", "date_created": "2017-01-07T12:54:15.240Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 20, "fields": {"name": "Judith Ortiz", "username": "lisa", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlbmVuYXRpcyI.MHDovdAZ1Y6dl56pKsuIia06fJzbbnMAg6H7y3IQHcE", "_private_key": null, "_public_key": "", "comment": "Nullam porttitor lacus at turpis.", "date_created": "2017-01-07T12:54:15.241Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 21, "fields": {"name": "Helen Griffin", "username": "amanda", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "_private_key": null, "_public_key": "", "comment": "Sed sagittis.", "date_created": "2017-01-07T12:54:15.243Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 22, "fields": {"name": "Irene Vasquez", "username": "susan", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF0Ig.KKCMSzsOJLvrGcheEd9SDxRwZhts01BoZ0xyuxHx4Y0", "_private_key": null, "_public_key": "", "comment": "Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.", "date_created": "2017-01-07T12:54:15.245Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 23, "fields": {"name": "Michelle Lawrence", "username": "theresa", "_password": "eyJhbGciOiJIUzI1NiJ9.InJob25jdXMi.zc47wfesB5fcJ-oBaHagDTV8j2ml3oDL---yZnXFmX4", "_private_key": null, "_public_key": "", "comment": "In hac habitasse platea dictumst.", "date_created": "2017-01-07T12:54:15.247Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 24, "fields": {"name": "Carolyn Mitchell", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "_private_key": null, "_public_key": "", "comment": "Curabitur at ipsum ac tellus semper interdum.", "date_created": "2017-01-07T12:54:15.249Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 25, "fields": {"name": "Amanda Arnold", "username": "ashley", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "_private_key": null, "_public_key": "", "comment": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa.", "date_created": "2017-01-07T12:54:15.250Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 26, "fields": {"name": "Carolyn Patterson", "username": "dorothy", "_password": "eyJhbGciOiJIUzI1NiJ9.InVsdHJpY2VzIg.7CaOCTzCJiIrdVZn5wu5ObQCcCWGmdmgQLjfJvP7IQY", "_private_key": null, "_public_key": "", "comment": "In congue.", "date_created": "2017-01-07T12:54:15.252Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 27, "fields": {"name": "Alice Gibson", "username": "julia", "_password": "eyJhbGciOiJIUzI1NiJ9.ImdyYXZpZGEi.c9OsjuqjuaeTY5RzjeR_FkUfemkuWfqcrHLr1nI4hAI", "_private_key": null, "_public_key": "", "comment": "Nullam varius.", "date_created": "2017-01-07T12:54:15.254Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 28, "fields": {"name": "Sharon Edwards", "username": "sharon", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVsaXQi.a7GlyHrv2neaOA77QcRbPfCEGs0UbmGyg9cV3trKSCg", "_private_key": null, "_public_key": "", "comment": "Proin at turpis a pede posuere nonummy.", "date_created": "2017-01-07T12:54:15.256Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 29, "fields": {"name": "Louise Cole", "username": "lori", "_password": "eyJhbGciOiJIUzI1NiJ9.InV0Ig.lmRSuoHi4jv9YOiKOSfPjnCwSvHOnUh0UQcZXnEWZzo", "_private_key": null, "_public_key": "", "comment": "Donec quis orci eget orci vehicula condimentum.", "date_created": "2017-01-07T12:54:15.258Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 30, "fields": {"name": "Julia Nichols", "username": "mary", "_password": "eyJhbGciOiJIUzI1NiJ9.ImRpY3R1bXN0Ig.owyqiwsx1v5W-7FCwPxXX8ieVl7N7sILLI3SaGMXdn8", "_private_key": null, "_public_key": "", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "date_created": "2017-01-07T12:54:15.259Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 31, "fields": {"name": "Christine Price", "username": "theresa", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbnNlY3RldHVlciI.TzWrjty_1MomQ90WvTAEYz3Ypaemo4ROSK2xWJjBEbc", "_private_key": null, "_public_key": "", "comment": "Etiam pretium iaculis justo.", "date_created": "2017-01-07T12:54:15.261Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 32, "fields": {"name": "Helen Montgomery", "username": "alice", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9kaW8i.1qhr1N7Gn0TJEa_Q7rIWvOTqqMKwFcHXP7BomzX7J7Q", "_private_key": null, "_public_key": "", "comment": "Vivamus tortor.", "date_created": "2017-01-07T12:54:15.262Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 33, "fields": {"name": "Lisa Weaver", "username": "angela", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlc3RpYnVsdW0i.T6kOgaWPNOQhwvRxcDNwPInAoTWO8oQ6iipJWCyeZvs", "_private_key": null, "_public_key": "", "comment": "Integer tincidunt ante vel ipsum.", "date_created": "2017-01-07T12:54:15.265Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 34, "fields": {"name": "Sara Fuller", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.InBhcnR1cmllbnQi.pCsDxJQrN4csmBF4750zGwoownJc2TTeODOOlSY7sz4", "_private_key": null, "_public_key": "", "comment": "Fusce consequat.", "date_created": "2017-01-07T12:54:15.266Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 35, "fields": {"name": "Denise Young", "username": "ruby", "_password": "eyJhbGciOiJIUzI1NiJ9.InF1YW0i.jyCCTLkqnAmQ1fjCgxcCdDDxYQhwb20VCeJO2dN0I-s", "_private_key": null, "_public_key": "", "comment": "In congue.", "date_created": "2017-01-07T12:54:15.269Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 36, "fields": {"name": "Laura Alexander", "username": "nancy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImEi.DmKqiccrpBqvmrAyHjGrnQCuTR7H-csji_L5NxeelbM", "_private_key": null, "_public_key": "", "comment": "Nulla tempus.", "date_created": "2017-01-07T12:54:15.270Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 37, "fields": {"name": "Carolyn Hernandez", "username": "mildred", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFjIg.m7atEKEFx68VZmM2clat-RyHmCQmR0lrKJ2VrzecInw", "_private_key": null, "_public_key": "", "comment": "Sed accumsan felis.", "date_created": "2017-01-07T12:54:15.272Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 38, "fields": {"name": "Cynthia Morales", "username": "elizabeth", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "_private_key": null, "_public_key": "", "comment": "Proin at turpis a pede posuere nonummy.", "date_created": "2017-01-07T12:54:15.274Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 39, "fields": {"name": "Andrea Bailey", "username": "barbara", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFtZXQi.k9EjNQL559Kyrp0ygulJ1FYqzM9PWKz9BZ7NqyeyH2o", "_private_key": null, "_public_key": "", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "date_created": "2017-01-07T12:54:15.276Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 40, "fields": {"name": "Angela Cruz", "username": "julia", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9yY2ki.-H3gNP0GV0UZFR_MqKCCWMiaRDBQRRkfHxX2uojMk74", "_private_key": null, "_public_key": "", "comment": "Vestibulum sed magna at nunc commodo placerat.", "date_created": "2017-01-07T12:54:15.278Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 41, "fields": {"name": "Debra Meyer", "username": "teresa", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlZGUi.VNfxhauAGiZelQ34CO0YMVbRtgnIiH5Z-vY1jjYXhWA", "_private_key": null, "_public_key": "", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "date_created": "2017-01-07T12:54:15.279Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 42, "fields": {"name": "Rachel Thompson", "username": "louise", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5lYyI.LKXtwRVgPGpIFsCWDaqgz1FeQ0uuEIthkh3bbD8r6bI", "_private_key": null, "_public_key": "", "comment": "Pellentesque at nulla.", "date_created": "2017-01-07T12:54:15.281Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 43, "fields": {"name": "Nancy Willis", "username": "ruby", "_password": "eyJhbGciOiJIUzI1NiJ9.InVsdHJpY2VzIg.7CaOCTzCJiIrdVZn5wu5ObQCcCWGmdmgQLjfJvP7IQY", "_private_key": null, "_public_key": "", "comment": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc.", "date_created": "2017-01-07T12:54:15.282Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 44, "fields": {"name": "Emily Coleman", "username": "rose", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vbnRlcyI.U9-mPLi3PtAqPA0X37T_EcxCjKiiMYB8waKn_zTTLqI", "_private_key": null, "_public_key": "", "comment": "In congue.", "date_created": "2017-01-07T12:54:15.284Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 45, "fields": {"name": "Wanda Collins", "username": "julia", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVzdCI.kqn80ndZDQ0Gc7AnT112KsF2joNDpppfPsuPxS6cOwk", "_private_key": null, "_public_key": "", "comment": "Vivamus vel nulla eget eros elementum pellentesque.", "date_created": "2017-01-07T12:54:15.286Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 46, "fields": {"name": "Janice Bennett", "username": "joan", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFsaXF1YW0i.ROd2JUuL9lh3hBqwH2HJ7tf8zsYXtJR776EsV1Jpvnw", "_private_key": null, "_public_key": "", "comment": "Duis consequat dui nec nisi volutpat eleifend.", "date_created": "2017-01-07T12:54:15.289Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 47, "fields": {"name": "Lisa Morales", "username": "lois", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vcmJpIg.eiv33ldiYjx8DZLjUsoxipifqc1NZvZdR-xyFDq2ipc", "_private_key": null, "_public_key": "", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "date_created": "2017-01-07T12:54:15.291Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 48, "fields": {"name": "Dorothy Taylor", "username": "lisa", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVuaW0i.G3tfpkWpHaXsDj426yogQKH9WMk4-ONIo66sphs2Dgs", "_private_key": null, "_public_key": "", "comment": "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.", "date_created": "2017-01-07T12:54:15.293Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 49, "fields": {"name": "Shirley Wright", "username": "melissa", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlaGljdWxhIg.24RL7x_K4-FG6MSYl7ekdNgShs6FvH2AA0I4gSogttU", "_private_key": null, "_public_key": "", "comment": "In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.", "date_created": "2017-01-07T12:54:15.296Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 50, "fields": {"name": "Rachel Howard", "username": "denise", "_password": "eyJhbGciOiJIUzI1NiJ9.InBoYXNlbGx1cyI.Zn-tLzwjTOOALDdNqorcCv8dpUlJWwDa8PhPqRVfR7s", "_private_key": null, "_public_key": "", "comment": "Mauris sit amet eros.", "date_created": "2017-01-07T12:54:15.298Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 51, "fields": {"name": "Diana Price", "username": "laura", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlc3RpYnVsdW0i.T6kOgaWPNOQhwvRxcDNwPInAoTWO8oQ6iipJWCyeZvs", "_private_key": null, "_public_key": "", "comment": "Ut tellus.", "date_created": "2017-01-07T12:54:15.300Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 52, "fields": {"name": "Denise Gutierrez", "username": "mary", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9kaW8i.1qhr1N7Gn0TJEa_Q7rIWvOTqqMKwFcHXP7BomzX7J7Q", "_private_key": null, "_public_key": "", "comment": "Aliquam erat volutpat.", "date_created": "2017-01-07T12:54:15.302Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 53, "fields": {"name": "Joan Turner", "username": "janice", "_password": "eyJhbGciOiJIUzI1NiJ9.InBvdGVudGki.gVzkkI6p2yD2ovfIZrG88LPZYqWz3jIhPNRkRx2okDw", "_private_key": null, "_public_key": "", "comment": "In eleifend quam a odio.", "date_created": "2017-01-07T12:54:15.304Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 54, "fields": {"name": "Dorothy Coleman", "username": "cheryl", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hdXJpcyI.jcR8xjLt9WrET56Nes7q2CdkHYJAWb7Y2d--saQSumY", "_private_key": null, "_public_key": "", "comment": "Nullam molestie nibh in lectus.", "date_created": "2017-01-07T12:54:15.306Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 55, "fields": {"name": "Linda Webb", "username": "jacqueline", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hdXJpcyI.jcR8xjLt9WrET56Nes7q2CdkHYJAWb7Y2d--saQSumY", "_private_key": null, "_public_key": "", "comment": "Duis aliquam convallis nunc.", "date_created": "2017-01-07T12:54:15.308Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 56, "fields": {"name": "Tina Scott", "username": "teresa", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlbGxlbnRlc3F1ZSI.3yrIK8gbDmlyR-M0hLUJmm7e0Tqrq3F-2hfrwlnJXQ8", "_private_key": null, "_public_key": "", "comment": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc.", "date_created": "2017-01-07T12:54:15.310Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 57, "fields": {"name": "Susan Holmes", "username": "jane", "_password": "eyJhbGciOiJIUzI1NiJ9.InJpZGljdWx1cyI.qz9Ndt8Jw7Ip8Jg6HzArFfESopFFuiHJEUrXJKWkC-M", "_private_key": null, "_public_key": "", "comment": "Maecenas pulvinar lobortis est.", "date_created": "2017-01-07T12:54:15.312Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 58, "fields": {"name": "Sandra Fields", "username": "helen", "_password": "eyJhbGciOiJIUzI1NiJ9.InF1YW0i.jyCCTLkqnAmQ1fjCgxcCdDDxYQhwb20VCeJO2dN0I-s", "_private_key": null, "_public_key": "", "comment": "Integer ac leo.", "date_created": "2017-01-07T12:54:15.314Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 59, "fields": {"name": "Joyce Mills", "username": "stephanie", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bmMi.QZCxEf3ITmu1xFtZxZL7B-kLe61BCyaRJg_ryZUsHdw", "_private_key": null, "_public_key": "", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "date_created": "2017-01-07T12:54:15.316Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 60, "fields": {"name": "Alice Davis", "username": "linda", "_password": "eyJhbGciOiJIUzI1NiJ9.ImlhY3VsaXMi._s5XG4x4ntDRnnbi38JeFne1fvF3h3f9nQJRUGL_vq0", "_private_key": null, "_public_key": "", "comment": "Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo.", "date_created": "2017-01-07T12:54:15.318Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 61, "fields": {"name": "Kathryn Young", "username": "sandra", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV0Ig.3tldwz4uRFsW0n3fXSzg--EVXWaEWcxAmrwA76gZUYA", "_private_key": null, "_public_key": "", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "date_created": "2017-01-07T12:54:15.320Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 62, "fields": {"name": "Alice Rivera", "username": "karen", "_password": "eyJhbGciOiJIUzI1NiJ9.ImR1aSI.AYqnix4dp06WLJ645L4MAveLycKVrZSyNjJnIq0fU2g", "_private_key": null, "_public_key": "", "comment": "Vestibulum rutrum rutrum neque.", "date_created": "2017-01-07T12:54:15.321Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 63, "fields": {"name": "Deborah Gordon", "username": "doris", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "_private_key": null, "_public_key": "", "comment": "Duis at velit eu est congue elementum.", "date_created": "2017-01-07T12:54:15.323Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 64, "fields": {"name": "Rose Flores", "username": "martha", "_password": "eyJhbGciOiJIUzI1NiJ9.ImN1cnN1cyI.9mxH1HpaEaQw85lLa7DsTGky0cMIfTCNruY1ev1QuNw", "_private_key": null, "_public_key": "", "comment": "Donec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue.", "date_created": "2017-01-07T12:54:15.325Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 65, "fields": {"name": "Louise Harvey", "username": "elizabeth", "_password": "eyJhbGciOiJIUzI1NiJ9.ImhhYyI.NqFq8iVrrba9qnYT02so-eAKvqMQUN0EXT1JGPAf-EE", "_private_key": null, "_public_key": "", "comment": "Pellentesque viverra pede ac diam.", "date_created": "2017-01-07T12:54:15.327Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 66, "fields": {"name": "Sharon Welch", "username": "christina", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "_private_key": null, "_public_key": "", "comment": "Nulla ac enim.", "date_created": "2017-01-07T12:54:15.329Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 67, "fields": {"name": "Gloria Hunt", "username": "diana", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "_private_key": null, "_public_key": "", "comment": "Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla.", "date_created": "2017-01-07T12:54:15.331Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 68, "fields": {"name": "Bonnie Anderson", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImhlbmRyZXJpdCI.w37x36SBpiyhDWKVAtj2fw-T7HIkb-qBU5LHWA03DMY", "_private_key": null, "_public_key": "", "comment": "Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.", "date_created": "2017-01-07T12:54:15.333Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 69, "fields": {"name": "Emily Baker", "username": "julie", "_password": "eyJhbGciOiJIUzI1NiJ9.ImlkIg.lr9X3DQPFH2zptTUg3pRWbYLzWhfDYsw0w_q9pEod3I", "_private_key": null, "_public_key": "", "comment": "Phasellus in felis.", "date_created": "2017-01-07T12:54:15.334Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 70, "fields": {"name": "Joan Harvey", "username": "andrea", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF1Z3VlIg.crP2_jl_o91zD62WaHCevBI_9ScRk6cXhXtPdAVGOYQ", "_private_key": null, "_public_key": "", "comment": "Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante.", "date_created": "2017-01-07T12:54:15.336Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 71, "fields": {"name": "Lois Martin", "username": "theresa", "_password": "eyJhbGciOiJIUzI1NiJ9.ImludGVyZHVtIg.UHlxBZLjoTZbl5ZIhbnQ1sBwbWSntPA0eH2R4BQWoB0", "_private_key": null, "_public_key": "", "comment": "Vivamus in felis eu sapien cursus vestibulum.", "date_created": "2017-01-07T12:54:15.338Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 72, "fields": {"name": "Sandra Carroll", "username": "rose", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hdXJpcyI.jcR8xjLt9WrET56Nes7q2CdkHYJAWb7Y2d--saQSumY", "_private_key": null, "_public_key": "", "comment": "Donec dapibus.", "date_created": "2017-01-07T12:54:15.340Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 73, "fields": {"name": "Lois Marshall", "username": "maria", "_password": "eyJhbGciOiJIUzI1NiJ9.Imp1c3RvIg.OGeg0BhoHWufHxSObxdYqHFC3zur8llMFj8veLxbAFY", "_private_key": null, "_public_key": "", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "date_created": "2017-01-07T12:54:15.342Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 74, "fields": {"name": "Sara Gonzalez", "username": "ann", "_password": "eyJhbGciOiJIUzI1NiJ9.InZpdmFtdXMi.RbLbJ7X5YWe_D8gaSitbKfO_QqGVcW4iUu3TYdjIPKI", "_private_key": null, "_public_key": "", "comment": "Donec ut dolor.", "date_created": "2017-01-07T12:54:15.344Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 75, "fields": {"name": "Julie Hamilton", "username": "dorothy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF1Z3VlIg.crP2_jl_o91zD62WaHCevBI_9ScRk6cXhXtPdAVGOYQ", "_private_key": null, "_public_key": "", "comment": "Nam ultrices, libero non mattis pulvinar, nulla pede ullamcorper augue, a suscipit nulla elit ac nulla.", "date_created": "2017-01-07T12:54:15.346Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 76, "fields": {"name": "Debra Baker", "username": "cheryl", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "_private_key": null, "_public_key": "", "comment": "Nulla mollis molestie lorem.", "date_created": "2017-01-07T12:54:15.347Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 77, "fields": {"name": "Susan Bailey", "username": "andrea", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlbmVuYXRpcyI.MHDovdAZ1Y6dl56pKsuIia06fJzbbnMAg6H7y3IQHcE", "_private_key": null, "_public_key": "", "comment": "Nulla nisl.", "date_created": "2017-01-07T12:54:15.349Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 78, "fields": {"name": "Joyce Castillo", "username": "michelle", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlbCI.ETImZ-BkJk0sqh2IFBILiQXV2aDn_mEZV3b-qIUDQBo", "_private_key": null, "_public_key": "", "comment": "Etiam justo.", "date_created": "2017-01-07T12:54:15.351Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 79, "fields": {"name": "Doris Snyder", "username": "helen", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1pIg.9Z3NScNPiRxvreLu8pDuhMVg8PIHs91k9_ntiUwuBPQ", "_private_key": null, "_public_key": "", "comment": "Suspendisse potenti.", "date_created": "2017-01-07T12:54:15.353Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 80, "fields": {"name": "Judith Patterson", "username": "diana", "_password": "eyJhbGciOiJIUzI1NiJ9.InV0Ig.lmRSuoHi4jv9YOiKOSfPjnCwSvHOnUh0UQcZXnEWZzo", "_private_key": null, "_public_key": "", "comment": "Morbi non quam nec dui luctus rutrum.", "date_created": "2017-01-07T12:54:15.355Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 81, "fields": {"name": "Nancy Cox", "username": "joan", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxlY3R1cyI.7T1IUgQEmo1rg4yMJ17FiAP48rzB174UhQ0vFbK15QM", "_private_key": null, "_public_key": "", "comment": "Morbi vel lectus in quam fringilla rhoncus.", "date_created": "2017-01-07T12:54:15.357Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 82, "fields": {"name": "Kathleen Thomas", "username": "cynthia", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyYXQi.DYbnQqa9aMUVtPCk3VMA6RFeUmr4NNrdvTORYTQol2s", "_private_key": null, "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est.", "date_created": "2017-01-07T12:54:15.359Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 83, "fields": {"name": "Tammy Warren", "username": "maria", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxhY2luaWEi.k2d8p0z-xevNN7wP2FDZiOuHFRhIiL-MVOtmCJI4vA8", "_private_key": null, "_public_key": "", "comment": "Aliquam erat volutpat.", "date_created": "2017-01-07T12:54:15.361Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 84, "fields": {"name": "Julie Medina", "username": "diane", "_password": "eyJhbGciOiJIUzI1NiJ9.ImhhYyI.NqFq8iVrrba9qnYT02so-eAKvqMQUN0EXT1JGPAf-EE", "_private_key": null, "_public_key": "", "comment": "Vestibulum quam sapien, varius ut, blandit non, interdum in, ante.", "date_created": "2017-01-07T12:54:15.363Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 85, "fields": {"name": "Angela Spencer", "username": "phyllis", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hZ25hIg.n7_lEZwzxnXBn5B4uo3looqSDDSKNqXXAxpJYKKNn7c", "_private_key": null, "_public_key": "", "comment": "Cras in purus eu magna vulputate luctus.", "date_created": "2017-01-07T12:54:15.365Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 86, "fields": {"name": "Jessica Fernandez", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyYXQi.DYbnQqa9aMUVtPCk3VMA6RFeUmr4NNrdvTORYTQol2s", "_private_key": null, "_public_key": "", "comment": "In hac habitasse platea dictumst.", "date_created": "2017-01-07T12:54:15.367Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 87, "fields": {"name": "Shirley Stewart", "username": "rachel", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVsaXQi.a7GlyHrv2neaOA77QcRbPfCEGs0UbmGyg9cV3trKSCg", "_private_key": null, "_public_key": "", "comment": "Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus.", "date_created": "2017-01-07T12:54:15.369Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 88, "fields": {"name": "Katherine Collins", "username": "norma", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vcmJpIg.eiv33ldiYjx8DZLjUsoxipifqc1NZvZdR-xyFDq2ipc", "_private_key": null, "_public_key": "", "comment": "Maecenas pulvinar lobortis est.", "date_created": "2017-01-07T12:54:15.370Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 89, "fields": {"name": "Norma Green", "username": "diane", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "_private_key": null, "_public_key": "", "comment": "Curabitur gravida nisi at nibh.", "date_created": "2017-01-07T12:54:15.372Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 90, "fields": {"name": "Virginia Garcia", "username": "michelle", "_password": "eyJhbGciOiJIUzI1NiJ9.ImN1cmFlOyI.YXVQboZMyJCScWjZTO7GvepNEo2dJ4h46NF_lOFDXbI", "_private_key": null, "_public_key": "", "comment": "Quisque porta volutpat erat.", "date_created": "2017-01-07T12:54:15.375Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 91, "fields": {"name": "Sarah Miller", "username": "julia", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxlY3R1cyI.7T1IUgQEmo1rg4yMJ17FiAP48rzB174UhQ0vFbK15QM", "_private_key": null, "_public_key": "", "comment": "Maecenas pulvinar lobortis est.", "date_created": "2017-01-07T12:54:15.377Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 92, "fields": {"name": "Melissa Bowman", "username": "angela", "_password": "eyJhbGciOiJIUzI1NiJ9.InV0Ig.lmRSuoHi4jv9YOiKOSfPjnCwSvHOnUh0UQcZXnEWZzo", "_private_key": null, "_public_key": "", "comment": "Pellentesque eget nunc.", "date_created": "2017-01-07T12:54:15.379Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 93, "fields": {"name": "Cynthia Palmer", "username": "stephanie", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVsZWlmZW5kIg.1OHmiE1zsH9hdrR2t-pBIR6VwxS3R_fBqR18yfdOBxE", "_private_key": null, "_public_key": "", "comment": "Nulla justo.", "date_created": "2017-01-07T12:54:15.382Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 94, "fields": {"name": "Donna Henderson", "username": "sarah", "_password": "eyJhbGciOiJIUzI1NiJ9.ImlkIg.lr9X3DQPFH2zptTUg3pRWbYLzWhfDYsw0w_q9pEod3I", "_private_key": null, "_public_key": "", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", "date_created": "2017-01-07T12:54:15.384Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 95, "fields": {"name": "Mildred Greene", "username": "anna", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyYXQi.DYbnQqa9aMUVtPCk3VMA6RFeUmr4NNrdvTORYTQol2s", "_private_key": null, "_public_key": "", "comment": "Nulla ut erat id mauris vulputate elementum.", "date_created": "2017-01-07T12:54:15.386Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 96, "fields": {"name": "Jennifer Stevens", "username": "shirley", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlbGxlbnRlc3F1ZSI.3yrIK8gbDmlyR-M0hLUJmm7e0Tqrq3F-2hfrwlnJXQ8", "_private_key": null, "_public_key": "", "comment": "Morbi non quam nec dui luctus rutrum.", "date_created": "2017-01-07T12:54:15.388Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 97, "fields": {"name": "Laura Reid", "username": "alice", "_password": "eyJhbGciOiJIUzI1NiJ9.InRyaXN0aXF1ZSI.2GYDOy1PUPlajGgk0PM4TJZASBBeOEH6rVW9bSdnlBU", "_private_key": null, "_public_key": "", "comment": "Cras non velit nec nisi vulputate nonummy.", "date_created": "2017-01-07T12:54:15.390Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 98, "fields": {"name": "Wanda Reid", "username": "paula", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bmMi.QZCxEf3ITmu1xFtZxZL7B-kLe61BCyaRJg_ryZUsHdw", "_private_key": null, "_public_key": "", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", "date_created": "2017-01-07T12:54:15.391Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 99, "fields": {"name": "Stephanie Carpenter", "username": "amy", "_password": "eyJhbGciOiJIUzI1NiJ9.InByaW1pcyI.OAlhMPsCXTLC41MGIrALVio6iqoIwHbHFj-r4Kg4lso", "_private_key": null, "_public_key": "", "comment": "Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante.", "date_created": "2017-01-07T12:54:15.393Z", "created_by": "Fake"}}, {"model": "assets.adminuser", "pk": 100, "fields": {"name": "Sandra Wagner", "username": "jean", "_password": "eyJhbGciOiJIUzI1NiJ9.InN1c2NpcGl0Ig.Z61mFiu2oDhYJjR0Be_bppgWlu5yNIbatQroqyG17Hc", "_private_key": null, "_public_key": "", "comment": "Nulla suscipit ligula in lacus.", "date_created": "2017-01-07T12:54:15.396Z", "created_by": "Fake"}}, {"model": "assets.systemuser", "pk": 1, "fields": {"name": "Sara Kennedy", "username": "ruby", "_password": "eyJhbGciOiJIUzI1NiJ9.ImRvbmVjIg.ETQR821NXkrnq13LeE4BygCe_fvaFDJggsQ1ghFFfNU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.990Z", "created_by": "Fake", "comment": "Quisque arcu libero, rutrum ac, lobortis vel, dapibus at, diam."}}, {"model": "assets.systemuser", "pk": 2, "fields": {"name": "Sandra Larson", "username": "rebecca", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5lYyI.LKXtwRVgPGpIFsCWDaqgz1FeQ0uuEIthkh3bbD8r6bI", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.992Z", "created_by": "Fake", "comment": "Sed ante."}}, {"model": "assets.systemuser", "pk": 3, "fields": {"name": "Diane Taylor", "username": "rachel", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVzdCI.kqn80ndZDQ0Gc7AnT112KsF2joNDpppfPsuPxS6cOwk", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.994Z", "created_by": "Fake", "comment": "Curabitur convallis."}}, {"model": "assets.systemuser", "pk": 4, "fields": {"name": "Theresa Holmes", "username": "mildred", "_password": "eyJhbGciOiJIUzI1NiJ9.InF1aXMi.sr0cWp1ZfjO1QWimGNuf1x_MHaNsiEFy7_UxzlJkIfY", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.996Z", "created_by": "Fake", "comment": "Nulla ut erat id mauris vulputate elementum."}}, {"model": "assets.systemuser", "pk": 5, "fields": {"name": "Betty Daniels", "username": "sandra", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vcmJpIg.eiv33ldiYjx8DZLjUsoxipifqc1NZvZdR-xyFDq2ipc", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.997Z", "created_by": "Fake", "comment": "Proin interdum mauris non ligula pellentesque ultrices."}}, {"model": "assets.systemuser", "pk": 6, "fields": {"name": "Annie Henderson", "username": "lisa", "_password": "eyJhbGciOiJIUzI1NiJ9.InZvbHV0cGF0Ig.F7uCpzruZ4ZGBU3VNWStgVJgh0kXl9bHDicT6aRqSys", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:14.998Z", "created_by": "Fake", "comment": "Nullam varius."}}, {"model": "assets.systemuser", "pk": 7, "fields": {"name": "Deborah Rodriguez", "username": "phyllis", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbmd1ZSI.ZhepxP8sxBRKPXnwzbjVSMw55yeF3Ha3WBaajS2I78s", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.001Z", "created_by": "Fake", "comment": "In blandit ultrices enim."}}, {"model": "assets.systemuser", "pk": 8, "fields": {"name": "Katherine Green", "username": "linda", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.003Z", "created_by": "Fake", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede."}}, {"model": "assets.systemuser", "pk": 9, "fields": {"name": "Diane Lopez", "username": "rose", "_password": "eyJhbGciOiJIUzI1NiJ9.ImR1aXMi.KS4EioZYRU2pQ7fIKt0kMbzHNljZMDpfMtimVI_Vjxw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.005Z", "created_by": "Fake", "comment": "Aliquam sit amet diam in magna bibendum imperdiet."}}, {"model": "assets.systemuser", "pk": 10, "fields": {"name": "Julie Rivera", "username": "melissa", "_password": "eyJhbGciOiJIUzI1NiJ9.InNhZ2l0dGlzIg.3Bi_u95FE3rtgZOoqk8FyFU9_pncEEajQ0EqTtOvPEc", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.007Z", "created_by": "Fake", "comment": "Ut tellus."}}, {"model": "assets.systemuser", "pk": 11, "fields": {"name": "Angela Henry", "username": "jennifer", "_password": "eyJhbGciOiJIUzI1NiJ9.InNlZCI.8x8y146cvv6phwCp2Q53l_zeUmW1oZkRrbMZG3kbs3w", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.009Z", "created_by": "Fake", "comment": "Aenean sit amet justo."}}, {"model": "assets.systemuser", "pk": 12, "fields": {"name": "Robin Williamson", "username": "patricia", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxpYmVybyI.JSOBTsKXE5mrplDkrXESWTg_SWw6LjpAeHVtzE5__3o", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.010Z", "created_by": "Fake", "comment": "Sed accumsan felis."}}, {"model": "assets.systemuser", "pk": 13, "fields": {"name": "Carol Hudson", "username": "amanda", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1pIg.9Z3NScNPiRxvreLu8pDuhMVg8PIHs91k9_ntiUwuBPQ", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.012Z", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio."}}, {"model": "assets.systemuser", "pk": 14, "fields": {"name": "Kelly James", "username": "carolyn", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV1Ig.k74Kbv7It_-9OcFde0stLpx06suYL5M71w_MTMaDa9M", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.014Z", "created_by": "Fake", "comment": "Pellentesque eget nunc."}}, {"model": "assets.systemuser", "pk": 15, "fields": {"name": "Marilyn Brooks", "username": "janet", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV1Ig.k74Kbv7It_-9OcFde0stLpx06suYL5M71w_MTMaDa9M", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.016Z", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.systemuser", "pk": 16, "fields": {"name": "Annie Hernandez", "username": "louise", "_password": "eyJhbGciOiJIUzI1NiJ9.InZpdGFlIg.hgeyUub3irVAJMeHmqEr9yZ7bLM1VSZtwTsRMf3sPoI", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.018Z", "created_by": "Fake", "comment": "Fusce posuere felis sed lacus."}}, {"model": "assets.systemuser", "pk": 17, "fields": {"name": "Joyce Carpenter", "username": "rachel", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1ldHVzIg.YtPHlU3XHnhjfj2rsVVxVzOZTx_u-Jd2wWJJMarQvls", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.019Z", "created_by": "Fake", "comment": "Morbi ut odio."}}, {"model": "assets.systemuser", "pk": 18, "fields": {"name": "Cynthia Williamson", "username": "lisa", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbnNlcXVhdCI.vLRDCJLof2aVuDu2Ozh-ogfuPPmKCcg9NxF47WcQqig", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.021Z", "created_by": "Fake", "comment": "Phasellus sit amet erat."}}, {"model": "assets.systemuser", "pk": 19, "fields": {"name": "Beverly Coleman", "username": "norma", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVzdCI.kqn80ndZDQ0Gc7AnT112KsF2joNDpppfPsuPxS6cOwk", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.023Z", "created_by": "Fake", "comment": "Nulla nisl."}}, {"model": "assets.systemuser", "pk": 20, "fields": {"name": "Frances Grant", "username": "karen", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFjY3Vtc2FuIg.NEwnlPlaG9Pa0nEXxhV8A18g-06uqxUCQ4zExhAPf3w", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.025Z", "created_by": "Fake", "comment": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc."}}, {"model": "assets.systemuser", "pk": 21, "fields": {"name": "Jennifer Thomas", "username": "mildred", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVuaW0i.G3tfpkWpHaXsDj426yogQKH9WMk4-ONIo66sphs2Dgs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.027Z", "created_by": "Fake", "comment": "Suspendisse ornare consequat lectus."}}, {"model": "assets.systemuser", "pk": 22, "fields": {"name": "Anne Richards", "username": "alice", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyYXQi.DYbnQqa9aMUVtPCk3VMA6RFeUmr4NNrdvTORYTQol2s", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.029Z", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.systemuser", "pk": 23, "fields": {"name": "Tina Lawrence", "username": "joan", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFyY3Ui.BiHl6wce2ufTlU5N6NKWqruNorzmlO6YypVSIuhcTN4", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.030Z", "created_by": "Fake", "comment": "Fusce consequat."}}, {"model": "assets.systemuser", "pk": 24, "fields": {"name": "Angela Fisher", "username": "rebecca", "_password": "eyJhbGciOiJIUzI1NiJ9.InNlZCI.8x8y146cvv6phwCp2Q53l_zeUmW1oZkRrbMZG3kbs3w", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.032Z", "created_by": "Fake", "comment": "Aliquam non mauris."}}, {"model": "assets.systemuser", "pk": 25, "fields": {"name": "Sharon Rice", "username": "kimberly", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbnZhbGxpcyI.B_NDb4qHOmbgsEcxTJAb9xrXBHPzya03jDjrKhXztJU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.034Z", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.systemuser", "pk": 26, "fields": {"name": "Kathy Foster", "username": "marie", "_password": "eyJhbGciOiJIUzI1NiJ9.InRpbmNpZHVudCI.nJRX3abQiMg6iUZpF2Ek_kygvgbo8fIUG4zHAh7o9n4", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.037Z", "created_by": "Fake", "comment": "Maecenas tincidunt lacus at velit."}}, {"model": "assets.systemuser", "pk": 27, "fields": {"name": "Angela Coleman", "username": "marie", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vbGVzdGllIg.3Ati0FpOQfWlYUHeXFmjZ1KOsOaAGFCSfit5ksNR9kE", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.039Z", "created_by": "Fake", "comment": "Maecenas rhoncus aliquam lacus."}}, {"model": "assets.systemuser", "pk": 28, "fields": {"name": "Pamela Hanson", "username": "sarah", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV0Ig.3tldwz4uRFsW0n3fXSzg--EVXWaEWcxAmrwA76gZUYA", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.041Z", "created_by": "Fake", "comment": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla."}}, {"model": "assets.systemuser", "pk": 29, "fields": {"name": "Marie Edwards", "username": "sharon", "_password": "eyJhbGciOiJIUzI1NiJ9.ImRpY3R1bXN0Ig.owyqiwsx1v5W-7FCwPxXX8ieVl7N7sILLI3SaGMXdn8", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.042Z", "created_by": "Fake", "comment": "Duis consequat dui nec nisi volutpat eleifend."}}, {"model": "assets.systemuser", "pk": 30, "fields": {"name": "Louise Lawson", "username": "beverly", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF0Ig.KKCMSzsOJLvrGcheEd9SDxRwZhts01BoZ0xyuxHx4Y0", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.045Z", "created_by": "Fake", "comment": "Duis ac nibh."}}, {"model": "assets.systemuser", "pk": 31, "fields": {"name": "Rose Perkins", "username": "brenda", "_password": "eyJhbGciOiJIUzI1NiJ9.ImRhcGlidXMi._Z9XtQyeuJcMgqBgOxIU0eA5-OWdjiBI0ESFrIm9aYs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.047Z", "created_by": "Fake", "comment": "Donec dapibus."}}, {"model": "assets.systemuser", "pk": 32, "fields": {"name": "Janice Nguyen", "username": "cheryl", "_password": "eyJhbGciOiJIUzI1NiJ9.InRvcnRvciI.OPG_v82TxcKyRgsGZvElzMJ5qUJRa25waGugUWsE_8U", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.048Z", "created_by": "Fake", "comment": "Pellentesque ultrices mattis odio."}}, {"model": "assets.systemuser", "pk": 33, "fields": {"name": "Deborah Mason", "username": "marilyn", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vcmJpIg.eiv33ldiYjx8DZLjUsoxipifqc1NZvZdR-xyFDq2ipc", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.050Z", "created_by": "Fake", "comment": "Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus."}}, {"model": "assets.systemuser", "pk": 34, "fields": {"name": "Michelle Arnold", "username": "gloria", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlbCI.ETImZ-BkJk0sqh2IFBILiQXV2aDn_mEZV3b-qIUDQBo", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.052Z", "created_by": "Fake", "comment": "Donec quis orci eget orci vehicula condimentum."}}, {"model": "assets.systemuser", "pk": 35, "fields": {"name": "Kimberly Graham", "username": "cheryl", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hc3NhIg.0T8CCFHSvP7QtFY2vdFxkhj_w0z-ty4y2EYhGhJfOUs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.055Z", "created_by": "Fake", "comment": "Suspendisse ornare consequat lectus."}}, {"model": "assets.systemuser", "pk": 36, "fields": {"name": "Lois Webb", "username": "rebecca", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlZGUi.VNfxhauAGiZelQ34CO0YMVbRtgnIiH5Z-vY1jjYXhWA", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.058Z", "created_by": "Fake", "comment": "Cras non velit nec nisi vulputate nonummy."}}, {"model": "assets.systemuser", "pk": 37, "fields": {"name": "Theresa Ray", "username": "sara", "_password": "eyJhbGciOiJIUzI1NiJ9.ImRpY3R1bXN0Ig.owyqiwsx1v5W-7FCwPxXX8ieVl7N7sILLI3SaGMXdn8", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.060Z", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam."}}, {"model": "assets.systemuser", "pk": 38, "fields": {"name": "Rachel Walker", "username": "christina", "_password": "eyJhbGciOiJIUzI1NiJ9.InNhcGllbiI.FV7Fd4y2296g887c98VrXRInZMVQulodf4KOSrBCWog", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.062Z", "created_by": "Fake", "comment": "In blandit ultrices enim."}}, {"model": "assets.systemuser", "pk": 39, "fields": {"name": "Christina Rice", "username": "karen", "_password": "eyJhbGciOiJIUzI1NiJ9.Imlwc3VtIg.rZpQHFzRecdHsQN3Et2YmLCm6zfPo_XFOeE-vz-CLe0", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.064Z", "created_by": "Fake", "comment": "Proin risus."}}, {"model": "assets.systemuser", "pk": 40, "fields": {"name": "Ann Dixon", "username": "betty", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV0Ig.3tldwz4uRFsW0n3fXSzg--EVXWaEWcxAmrwA76gZUYA", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.066Z", "created_by": "Fake", "comment": "Fusce posuere felis sed lacus."}}, {"model": "assets.systemuser", "pk": 41, "fields": {"name": "Wanda Cooper", "username": "sandra", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlc3RpYnVsdW0i.T6kOgaWPNOQhwvRxcDNwPInAoTWO8oQ6iipJWCyeZvs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.068Z", "created_by": "Fake", "comment": "Vestibulum ac est lacinia nisi venenatis tristique."}}, {"model": "assets.systemuser", "pk": 42, "fields": {"name": "Shirley Berry", "username": "ruby", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5pc2wi.bGZH4pJ2wkHxRxfDvzi1ePhYmirT4ibQ-uvsullA4pE", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.070Z", "created_by": "Fake", "comment": "Donec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue."}}, {"model": "assets.systemuser", "pk": 43, "fields": {"name": "Janice Burton", "username": "helen", "_password": "eyJhbGciOiJIUzI1NiJ9.InBvc3VlcmUi.HiqInzbNn9wLyMamRM3OfwBYJ9q4n297DvZzFFDwN7w", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.072Z", "created_by": "Fake", "comment": "Nulla nisl."}}, {"model": "assets.systemuser", "pk": 44, "fields": {"name": "Anne Meyer", "username": "dorothy", "_password": "eyJhbGciOiJIUzI1NiJ9.InRlbXB1cyI.InhJYK-kSadev_OeL8065VO6arpVpq6Ns-7Qcs6WkrU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.073Z", "created_by": "Fake", "comment": "Integer non velit."}}, {"model": "assets.systemuser", "pk": 45, "fields": {"name": "Kimberly Chavez", "username": "melissa", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hZ25hIg.n7_lEZwzxnXBn5B4uo3looqSDDSKNqXXAxpJYKKNn7c", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.075Z", "created_by": "Fake", "comment": "Cras mi pede, malesuada in, imperdiet et, commodo vulputate, justo."}}, {"model": "assets.systemuser", "pk": 46, "fields": {"name": "Lori Jacobs", "username": "nancy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFkaXBpc2Npbmci.xA0pKz_H20na1idlwyUjLasNezP4HEJunJ6DQfKy36U", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.078Z", "created_by": "Fake", "comment": "Vivamus in felis eu sapien cursus vestibulum."}}, {"model": "assets.systemuser", "pk": 47, "fields": {"name": "Denise Mitchell", "username": "nicole", "_password": "eyJhbGciOiJIUzI1NiJ9.InRvcnRvciI.OPG_v82TxcKyRgsGZvElzMJ5qUJRa25waGugUWsE_8U", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.080Z", "created_by": "Fake", "comment": "Donec vitae nisi."}}, {"model": "assets.systemuser", "pk": 48, "fields": {"name": "Mary Hayes", "username": "jessica", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5pYmgi.xs16dvVvTgeK6P4sCntrlOibiQ6PQd9Spdj68ir-ctY", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.081Z", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.systemuser", "pk": 49, "fields": {"name": "Joan Harvey", "username": "alice", "_password": "eyJhbGciOiJIUzI1NiJ9.InNvbGxpY2l0dWRpbiI.CN0digeVjRpv1GVr5eUkb13I8noDlYUxEQTJIZiwA6U", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.083Z", "created_by": "Fake", "comment": "Nulla ac enim."}}, {"model": "assets.systemuser", "pk": 50, "fields": {"name": "Stephanie Lawrence", "username": "judith", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.085Z", "created_by": "Fake", "comment": "Maecenas pulvinar lobortis est."}}, {"model": "assets.systemuser", "pk": 51, "fields": {"name": "Doris Olson", "username": "sarah", "_password": "eyJhbGciOiJIUzI1NiJ9.ImxlY3R1cyI.7T1IUgQEmo1rg4yMJ17FiAP48rzB174UhQ0vFbK15QM", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.087Z", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.systemuser", "pk": 52, "fields": {"name": "Jean Washington", "username": "ashley", "_password": "eyJhbGciOiJIUzI1NiJ9.InNpdCI.qhSlAh3rB-ai6rdQ-gxKBSFGhk-AbwiFe_CqQxSS3hM", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.089Z", "created_by": "Fake", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus."}}, {"model": "assets.systemuser", "pk": 53, "fields": {"name": "Shirley Robertson", "username": "annie", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hdHRpcyI.5Sp7NUJKOQNxv-1xJ-zA3A3pUkl2vnOfD3Z5g9LiFtQ", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.091Z", "created_by": "Fake", "comment": "Duis at velit eu est congue elementum."}}, {"model": "assets.systemuser", "pk": 54, "fields": {"name": "Carol Bryant", "username": "deborah", "_password": "eyJhbGciOiJIUzI1NiJ9.InRlbXB1cyI.InhJYK-kSadev_OeL8065VO6arpVpq6Ns-7Qcs6WkrU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.093Z", "created_by": "Fake", "comment": "In hac habitasse platea dictumst."}}, {"model": "assets.systemuser", "pk": 55, "fields": {"name": "Amy Watson", "username": "janice", "_password": "eyJhbGciOiJIUzI1NiJ9.ImlhY3VsaXMi._s5XG4x4ntDRnnbi38JeFne1fvF3h3f9nQJRUGL_vq0", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.095Z", "created_by": "Fake", "comment": "In quis justo."}}, {"model": "assets.systemuser", "pk": 56, "fields": {"name": "Judith Reynolds", "username": "cynthia", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.096Z", "created_by": "Fake", "comment": "Nam dui."}}, {"model": "assets.systemuser", "pk": 57, "fields": {"name": "Janet Nichols", "username": "ann", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFudGUi.MEBUyQoLV79tCcbpomj9Q6JdrivWra1ZLsj5UvGmRNg", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.099Z", "created_by": "Fake", "comment": "Morbi porttitor lorem id ligula."}}, {"model": "assets.systemuser", "pk": 58, "fields": {"name": "Elizabeth Lynch", "username": "andrea", "_password": "eyJhbGciOiJIUzI1NiJ9.Imp1c3RvIg.OGeg0BhoHWufHxSObxdYqHFC3zur8llMFj8veLxbAFY", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.101Z", "created_by": "Fake", "comment": "Vivamus vestibulum sagittis sapien."}}, {"model": "assets.systemuser", "pk": 59, "fields": {"name": "Sandra Welch", "username": "julia", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9yY2ki.-H3gNP0GV0UZFR_MqKCCWMiaRDBQRRkfHxX2uojMk74", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.103Z", "created_by": "Fake", "comment": "Vivamus tortor."}}, {"model": "assets.systemuser", "pk": 60, "fields": {"name": "Virginia Watkins", "username": "anna", "_password": "eyJhbGciOiJIUzI1NiJ9.InBhcnR1cmllbnQi.pCsDxJQrN4csmBF4750zGwoownJc2TTeODOOlSY7sz4", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.104Z", "created_by": "Fake", "comment": "Aenean auctor gravida sem."}}, {"model": "assets.systemuser", "pk": 61, "fields": {"name": "Kathleen Clark", "username": "beverly", "_password": "eyJhbGciOiJIUzI1NiJ9.InZvbHV0cGF0Ig.F7uCpzruZ4ZGBU3VNWStgVJgh0kXl9bHDicT6aRqSys", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.106Z", "created_by": "Fake", "comment": "Nullam molestie nibh in lectus."}}, {"model": "assets.systemuser", "pk": 62, "fields": {"name": "Melissa Lane", "username": "carol", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.108Z", "created_by": "Fake", "comment": "Morbi non quam nec dui luctus rutrum."}}, {"model": "assets.systemuser", "pk": 63, "fields": {"name": "Gloria Meyer", "username": "irene", "_password": "eyJhbGciOiJIUzI1NiJ9.ImZ1c2NlIg.uqw6_p8tfiGPkV4IRtBTFE_YTVbOixNTktMa4AAMrbs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.110Z", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio."}}, {"model": "assets.systemuser", "pk": 64, "fields": {"name": "Kimberly Hill", "username": "irene", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlc3RpYnVsdW0i.T6kOgaWPNOQhwvRxcDNwPInAoTWO8oQ6iipJWCyeZvs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.112Z", "created_by": "Fake", "comment": "Nullam molestie nibh in lectus."}}, {"model": "assets.systemuser", "pk": 65, "fields": {"name": "Tina Hudson", "username": "frances", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9yY2ki.-H3gNP0GV0UZFR_MqKCCWMiaRDBQRRkfHxX2uojMk74", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.114Z", "created_by": "Fake", "comment": "Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue."}}, {"model": "assets.systemuser", "pk": 66, "fields": {"name": "Ruth Stone", "username": "christina", "_password": "eyJhbGciOiJIUzI1NiJ9.InZlc3RpYnVsdW0i.T6kOgaWPNOQhwvRxcDNwPInAoTWO8oQ6iipJWCyeZvs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.116Z", "created_by": "Fake", "comment": "Phasellus in felis."}}, {"model": "assets.systemuser", "pk": 67, "fields": {"name": "Katherine Gilbert", "username": "jennifer", "_password": "eyJhbGciOiJIUzI1NiJ9.InV0Ig.lmRSuoHi4jv9YOiKOSfPjnCwSvHOnUh0UQcZXnEWZzo", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.117Z", "created_by": "Fake", "comment": "Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue."}}, {"model": "assets.systemuser", "pk": 68, "fields": {"name": "Deborah Hamilton", "username": "sandra", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.119Z", "created_by": "Fake", "comment": "Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh."}}, {"model": "assets.systemuser", "pk": 69, "fields": {"name": "Lori Gonzales", "username": "emily", "_password": "eyJhbGciOiJIUzI1NiJ9.ImEi.DmKqiccrpBqvmrAyHjGrnQCuTR7H-csji_L5NxeelbM", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.122Z", "created_by": "Fake", "comment": "Phasellus in felis."}}, {"model": "assets.systemuser", "pk": 70, "fields": {"name": "Melissa Turner", "username": "gloria", "_password": "eyJhbGciOiJIUzI1NiJ9.ImV1Ig.k74Kbv7It_-9OcFde0stLpx06suYL5M71w_MTMaDa9M", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.124Z", "created_by": "Fake", "comment": "Morbi quis tortor id nulla ultrices aliquet."}}, {"model": "assets.systemuser", "pk": 71, "fields": {"name": "Annie Reid", "username": "anna", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.125Z", "created_by": "Fake", "comment": "Donec posuere metus vitae ipsum."}}, {"model": "assets.systemuser", "pk": 72, "fields": {"name": "Cheryl Peterson", "username": "stephanie", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbnNlY3RldHVlciI.TzWrjty_1MomQ90WvTAEYz3Ypaemo4ROSK2xWJjBEbc", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.127Z", "created_by": "Fake", "comment": "Nulla tellus."}}, {"model": "assets.systemuser", "pk": 73, "fields": {"name": "Joan Meyer", "username": "joan", "_password": "eyJhbGciOiJIUzI1NiJ9.Imlwc3VtIg.rZpQHFzRecdHsQN3Et2YmLCm6zfPo_XFOeE-vz-CLe0", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.129Z", "created_by": "Fake", "comment": "Morbi quis tortor id nulla ultrices aliquet."}}, {"model": "assets.systemuser", "pk": 74, "fields": {"name": "Lori Mccoy", "username": "pamela", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5pc2ki.n-Lu5aSHiUvxHk4WAgVl5rBKooF4O9p22BV1JS22TCc", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.131Z", "created_by": "Fake", "comment": "Duis ac nibh."}}, {"model": "assets.systemuser", "pk": 75, "fields": {"name": "Karen Harris", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9kaW8i.1qhr1N7Gn0TJEa_Q7rIWvOTqqMKwFcHXP7BomzX7J7Q", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.133Z", "created_by": "Fake", "comment": "Maecenas leo odio, condimentum id, luctus nec, molestie sed, justo."}}, {"model": "assets.systemuser", "pk": 76, "fields": {"name": "Jessica Edwards", "username": "amy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1vbGVzdGllIg.3Ati0FpOQfWlYUHeXFmjZ1KOsOaAGFCSfit5ksNR9kE", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.136Z", "created_by": "Fake", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat."}}, {"model": "assets.systemuser", "pk": 77, "fields": {"name": "Christine Sims", "username": "louise", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVuaW0i.G3tfpkWpHaXsDj426yogQKH9WMk4-ONIo66sphs2Dgs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.137Z", "created_by": "Fake", "comment": "Vestibulum rutrum rutrum neque."}}, {"model": "assets.systemuser", "pk": 78, "fields": {"name": "Jean Morgan", "username": "annie", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVnZXQi.GK-YPltMyh8RK55dYklRb8Wk7orCpwYZr2QMzH-3qTU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.139Z", "created_by": "Fake", "comment": "Donec ut dolor."}}, {"model": "assets.systemuser", "pk": 79, "fields": {"name": "Kathy Burns", "username": "judy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im11cyI.EMRq4XsUbC_YpCauan3_7VrGk-m6OV8YOqmfntYW-tw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.142Z", "created_by": "Fake", "comment": "Pellentesque ultrices mattis odio."}}, {"model": "assets.systemuser", "pk": 80, "fields": {"name": "Carol Tucker", "username": "shirley", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5vbiI.pwMNExwLCmk9BWKxw3hxw9K9h0YRh102FvLNRKTumRs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.144Z", "created_by": "Fake", "comment": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla."}}, {"model": "assets.systemuser", "pk": 81, "fields": {"name": "Barbara Diaz", "username": "nancy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5hc2NldHVyIg.38imbSTbL6Rd0WDod36c1lGl1uQQNH_uBtIQflPhFHo", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.146Z", "created_by": "Fake", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."}}, {"model": "assets.systemuser", "pk": 82, "fields": {"name": "Pamela Kim", "username": "kelly", "_password": "eyJhbGciOiJIUzI1NiJ9.InNpdCI.qhSlAh3rB-ai6rdQ-gxKBSFGhk-AbwiFe_CqQxSS3hM", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.148Z", "created_by": "Fake", "comment": "Curabitur at ipsum ac tellus semper interdum."}}, {"model": "assets.systemuser", "pk": 83, "fields": {"name": "Brenda Frazier", "username": "nicole", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9yY2ki.-H3gNP0GV0UZFR_MqKCCWMiaRDBQRRkfHxX2uojMk74", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.150Z", "created_by": "Fake", "comment": "Maecenas pulvinar lobortis est."}}, {"model": "assets.systemuser", "pk": 84, "fields": {"name": "Katherine Carter", "username": "paula", "_password": "eyJhbGciOiJIUzI1NiJ9.InNlbXBlciI.M5t2pcCxYWTXgJ_uQtXTa9vfZ3MoWF2KT0MQJChOHP8", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.152Z", "created_by": "Fake", "comment": "Nullam molestie nibh in lectus."}}, {"model": "assets.systemuser", "pk": 85, "fields": {"name": "Phyllis Burke", "username": "margaret", "_password": "eyJhbGciOiJIUzI1NiJ9.InF1aXMi.sr0cWp1ZfjO1QWimGNuf1x_MHaNsiEFy7_UxzlJkIfY", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.154Z", "created_by": "Fake", "comment": "In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem."}}, {"model": "assets.systemuser", "pk": 86, "fields": {"name": "Janice Watson", "username": "kelly", "_password": "eyJhbGciOiJIUzI1NiJ9.Im1hZ25hIg.n7_lEZwzxnXBn5B4uo3looqSDDSKNqXXAxpJYKKNn7c", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.156Z", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio."}}, {"model": "assets.systemuser", "pk": 87, "fields": {"name": "Donna Cruz", "username": "dorothy", "_password": "eyJhbGciOiJIUzI1NiJ9.ImVyYXQi.DYbnQqa9aMUVtPCk3VMA6RFeUmr4NNrdvTORYTQol2s", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.158Z", "created_by": "Fake", "comment": "Cras non velit nec nisi vulputate nonummy."}}, {"model": "assets.systemuser", "pk": 88, "fields": {"name": "Norma Brooks", "username": "ann", "_password": "eyJhbGciOiJIUzI1NiJ9.ImN1YmlsaWEi.68DQVCMmeZQyAGqE4SJAPFBiBwMaPVZ0J7zxj8a0WV8", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.160Z", "created_by": "Fake", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est."}}, {"model": "assets.systemuser", "pk": 89, "fields": {"name": "Frances Coleman", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5vbiI.pwMNExwLCmk9BWKxw3hxw9K9h0YRh102FvLNRKTumRs", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.162Z", "created_by": "Fake", "comment": "Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci."}}, {"model": "assets.systemuser", "pk": 90, "fields": {"name": "Anne Owens", "username": "kathy", "_password": "eyJhbGciOiJIUzI1NiJ9.InNhcGllbiI.FV7Fd4y2296g887c98VrXRInZMVQulodf4KOSrBCWog", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.164Z", "created_by": "Fake", "comment": "Suspendisse accumsan tortor quis turpis."}}, {"model": "assets.systemuser", "pk": 91, "fields": {"name": "Robin Stevens", "username": "denise", "_password": "eyJhbGciOiJIUzI1NiJ9.ImFjIg.m7atEKEFx68VZmM2clat-RyHmCQmR0lrKJ2VrzecInw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.166Z", "created_by": "Fake", "comment": "Proin interdum mauris non ligula pellentesque ultrices."}}, {"model": "assets.systemuser", "pk": 92, "fields": {"name": "Kathleen Ryan", "username": "mildred", "_password": "eyJhbGciOiJIUzI1NiJ9.ImNvbnZhbGxpcyI.B_NDb4qHOmbgsEcxTJAb9xrXBHPzya03jDjrKhXztJU", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.168Z", "created_by": "Fake", "comment": "Maecenas pulvinar lobortis est."}}, {"model": "assets.systemuser", "pk": 93, "fields": {"name": "Theresa Gilbert", "username": "janice", "_password": "eyJhbGciOiJIUzI1NiJ9.ImluIg.Ic5fwxER7rs8gBhvBb4XRyTlZASKuBxVJ42SHALzjZw", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.170Z", "created_by": "Fake", "comment": "Duis mattis egestas metus."}}, {"model": "assets.systemuser", "pk": 94, "fields": {"name": "Christine Harper", "username": "brenda", "_password": "eyJhbGciOiJIUzI1NiJ9.Im51bGxhIg.FTT_U_lKC4cqONw96JU02zWnbRBUo6mQIO4v-HykDdQ", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.172Z", "created_by": "Fake", "comment": "Integer a nibh."}}, {"model": "assets.systemuser", "pk": 95, "fields": {"name": "Lisa Day", "username": "tammy", "_password": "eyJhbGciOiJIUzI1NiJ9.Im9kaW8i.1qhr1N7Gn0TJEa_Q7rIWvOTqqMKwFcHXP7BomzX7J7Q", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.174Z", "created_by": "Fake", "comment": "Quisque ut erat."}}, {"model": "assets.systemuser", "pk": 96, "fields": {"name": "Bonnie Olson", "username": "kelly", "_password": "eyJhbGciOiJIUzI1NiJ9.ImF0Ig.KKCMSzsOJLvrGcheEd9SDxRwZhts01BoZ0xyuxHx4Y0", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.176Z", "created_by": "Fake", "comment": "Sed accumsan felis."}}, {"model": "assets.systemuser", "pk": 97, "fields": {"name": "Donna Barnes", "username": "jessica", "_password": "eyJhbGciOiJIUzI1NiJ9.InRpbmNpZHVudCI.nJRX3abQiMg6iUZpF2Ek_kygvgbo8fIUG4zHAh7o9n4", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.179Z", "created_by": "Fake", "comment": "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis."}}, {"model": "assets.systemuser", "pk": 98, "fields": {"name": "Irene Johnson", "username": "ann", "_password": "eyJhbGciOiJIUzI1NiJ9.Im5lcXVlIg.llRzdBaLUQqiEtGwr8xvk7hjLPiN2BUFmsxHGYDOUc4", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.181Z", "created_by": "Fake", "comment": "Sed accumsan felis."}}, {"model": "assets.systemuser", "pk": 99, "fields": {"name": "Diana Ortiz", "username": "martha", "_password": "eyJhbGciOiJIUzI1NiJ9.InNvY2lpcyI.AU4QgAO8-W3QjsMbYNoucQ3JZDttE9u3T8-u8xrfrkg", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.182Z", "created_by": "Fake", "comment": "Suspendisse ornare consequat lectus."}}, {"model": "assets.systemuser", "pk": 100, "fields": {"name": "Dorothy Riley", "username": "ashley", "_password": "eyJhbGciOiJIUzI1NiJ9.InBlbmF0aWJ1cyI.5tzDeDPjalAXSdJV_M_94f6p_rhCDxd3LYdbK3GNRcM", "protocol": "ssh", "_private_key": "", "_public_key": "", "auth_method": "K", "auto_push": true, "auto_update": true, "sudo": "/user/bin/whoami", "shell": "/bin/bash", "home": "", "uid": null, "date_created": "2017-01-07T12:54:15.184Z", "created_by": "Fake", "comment": "In sagittis dui vel nisl."}}, {"model": "assets.assetgroup", "pk": 1, "fields": {"name": "Default", "created_by": "", "date_created": "2016-11-25T06:50:28.627Z", "comment": "Default asset group", "system_users": []}}, {"model": "assets.assetgroup", "pk": 2, "fields": {"name": "Sara Brown", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.399Z", "comment": "Ut tellus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 3, "fields": {"name": "Jean Fowler", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.401Z", "comment": "Curabitur convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 4, "fields": {"name": "Ashley Bryant", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.402Z", "comment": "Nam dui.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 5, "fields": {"name": "Teresa Franklin", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.403Z", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 6, "fields": {"name": "Marilyn Elliott", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.405Z", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 7, "fields": {"name": "Pamela Schmidt", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.407Z", "comment": "Curabitur gravida nisi at nibh.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 8, "fields": {"name": "Wanda Moore", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.408Z", "comment": "Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 9, "fields": {"name": "Tammy Andrews", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.410Z", "comment": "Cras mi pede, malesuada in, imperdiet et, commodo vulputate, justo.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 10, "fields": {"name": "Rose Hernandez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.412Z", "comment": "Integer a nibh.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 11, "fields": {"name": "Christina Cook", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.413Z", "comment": "Maecenas rhoncus aliquam lacus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 12, "fields": {"name": "Sara Hudson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.415Z", "comment": "Morbi non lectus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 13, "fields": {"name": "Annie Woods", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.416Z", "comment": "Maecenas tincidunt lacus at velit.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 14, "fields": {"name": "Teresa Austin", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.418Z", "comment": "Etiam faucibus cursus urna.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 15, "fields": {"name": "Diana Murphy", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.420Z", "comment": "Pellentesque at nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 16, "fields": {"name": "Kathy Stone", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.421Z", "comment": "Nam ultrices, libero non mattis pulvinar, nulla pede ullamcorper augue, a suscipit nulla elit ac nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 17, "fields": {"name": "Kathleen Bennett", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.423Z", "comment": "In quis justo.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 18, "fields": {"name": "Kathleen Hayes", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.424Z", "comment": "Curabitur gravida nisi at nibh.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 19, "fields": {"name": "Barbara Howard", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.426Z", "comment": "Morbi ut odio.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 20, "fields": {"name": "Joyce Edwards", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.428Z", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 21, "fields": {"name": "Karen Robinson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.429Z", "comment": "Vivamus vestibulum sagittis sapien.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 22, "fields": {"name": "Marie Lee", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.431Z", "comment": "Quisque arcu libero, rutrum ac, lobortis vel, dapibus at, diam.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 23, "fields": {"name": "Anne Hunter", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.432Z", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 24, "fields": {"name": "Stephanie Rodriguez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.433Z", "comment": "Cras in purus eu magna vulputate luctus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 25, "fields": {"name": "Dorothy Ford", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.435Z", "comment": "Nulla mollis molestie lorem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 26, "fields": {"name": "Anna Little", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.437Z", "comment": "Nulla mollis molestie lorem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 27, "fields": {"name": "Irene Fisher", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.438Z", "comment": "Nullam molestie nibh in lectus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 28, "fields": {"name": "Lisa Greene", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.440Z", "comment": "Quisque arcu libero, rutrum ac, lobortis vel, dapibus at, diam.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 29, "fields": {"name": "Jane Shaw", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.442Z", "comment": "Curabitur in libero ut massa volutpat convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 30, "fields": {"name": "Brenda Chapman", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.443Z", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 31, "fields": {"name": "Paula Murphy", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.444Z", "comment": "Maecenas pulvinar lobortis est.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 32, "fields": {"name": "Janice Baker", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.446Z", "comment": "Phasellus sit amet erat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 33, "fields": {"name": "Jessica Palmer", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.448Z", "comment": "Quisque ut erat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 34, "fields": {"name": "Christine Cooper", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.449Z", "comment": "Proin eu mi.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 35, "fields": {"name": "Beverly Bowman", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.451Z", "comment": "Aenean sit amet justo.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 36, "fields": {"name": "Lori Williamson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.453Z", "comment": "Fusce posuere felis sed lacus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 37, "fields": {"name": "Cynthia Vasquez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.455Z", "comment": "Maecenas rhoncus aliquam lacus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 38, "fields": {"name": "Nicole Fisher", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.456Z", "comment": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 39, "fields": {"name": "Christine Arnold", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.458Z", "comment": "Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 40, "fields": {"name": "Andrea Medina", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.460Z", "comment": "Nam dui.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 41, "fields": {"name": "Annie Gutierrez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.462Z", "comment": "Vivamus tortor.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 42, "fields": {"name": "Sara Morrison", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.463Z", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 43, "fields": {"name": "Margaret Ellis", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.465Z", "comment": "Nulla justo.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 44, "fields": {"name": "Rose Ford", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.466Z", "comment": "Nunc nisl.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 45, "fields": {"name": "Heather Bennett", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.468Z", "comment": "Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 46, "fields": {"name": "Nicole Grant", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.470Z", "comment": "Duis aliquam convallis nunc.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 47, "fields": {"name": "Joyce Dunn", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.471Z", "comment": "Integer a nibh.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 48, "fields": {"name": "Linda Hayes", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.473Z", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 49, "fields": {"name": "Louise Peterson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.475Z", "comment": "Donec ut mauris eget massa tempor convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 50, "fields": {"name": "Nicole Schmidt", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.476Z", "comment": "Maecenas leo odio, condimentum id, luctus nec, molestie sed, justo.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 51, "fields": {"name": "Paula Berry", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.478Z", "comment": "In sagittis dui vel nisl.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 52, "fields": {"name": "Mildred Edwards", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.480Z", "comment": "Morbi non lectus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 53, "fields": {"name": "Donna Robinson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.482Z", "comment": "Nam tristique tortor eu pede.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 54, "fields": {"name": "Denise Stone", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.483Z", "comment": "Mauris sit amet eros.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 55, "fields": {"name": "Sara Banks", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.485Z", "comment": "Nulla ac enim.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 56, "fields": {"name": "Kathy Adams", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.486Z", "comment": "Sed sagittis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 57, "fields": {"name": "Amy Spencer", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.488Z", "comment": "Morbi vel lectus in quam fringilla rhoncus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 58, "fields": {"name": "Phyllis Rivera", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.490Z", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 59, "fields": {"name": "Marilyn Mccoy", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.492Z", "comment": "Maecenas ut massa quis augue luctus tincidunt.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 60, "fields": {"name": "Rachel Howell", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.493Z", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 61, "fields": {"name": "Mary Montgomery", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.495Z", "comment": "Aliquam erat volutpat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 62, "fields": {"name": "Norma Palmer", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.497Z", "comment": "In hac habitasse platea dictumst.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 63, "fields": {"name": "Jessica Stewart", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.498Z", "comment": "Morbi non quam nec dui luctus rutrum.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 64, "fields": {"name": "Mary Fox", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.499Z", "comment": "Praesent lectus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 65, "fields": {"name": "Ruth Clark", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.501Z", "comment": "Duis mattis egestas metus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 66, "fields": {"name": "Bonnie Nelson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.503Z", "comment": "Quisque id justo sit amet sapien dignissim vestibulum.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 67, "fields": {"name": "Amanda Dunn", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.504Z", "comment": "Mauris ullamcorper purus sit amet nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 68, "fields": {"name": "Linda Olson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.506Z", "comment": "Nunc purus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 69, "fields": {"name": "Melissa Diaz", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.507Z", "comment": "Nulla tempus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 70, "fields": {"name": "Joan Chavez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.509Z", "comment": "Vestibulum ac est lacinia nisi venenatis tristique.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 71, "fields": {"name": "Jane Richardson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.511Z", "comment": "Proin interdum mauris non ligula pellentesque ultrices.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 72, "fields": {"name": "Jane Wheeler", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.513Z", "comment": "Nullam porttitor lacus at turpis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 73, "fields": {"name": "Ruby Smith", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.515Z", "comment": "In blandit ultrices enim.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 74, "fields": {"name": "Joan Wheeler", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.516Z", "comment": "Curabitur in libero ut massa volutpat convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 75, "fields": {"name": "Sarah Howard", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.518Z", "comment": "Aliquam erat volutpat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 76, "fields": {"name": "Jessica Bowman", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.519Z", "comment": "Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 77, "fields": {"name": "Robin Day", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.521Z", "comment": "Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 78, "fields": {"name": "Beverly Fields", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.522Z", "comment": "Nam nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 79, "fields": {"name": "Julia Foster", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.524Z", "comment": "Vestibulum quam sapien, varius ut, blandit non, interdum in, ante.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 80, "fields": {"name": "Melissa Collins", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.527Z", "comment": "Sed sagittis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 81, "fields": {"name": "Susan Matthews", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.528Z", "comment": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 82, "fields": {"name": "Martha Miller", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.530Z", "comment": "Nullam varius.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 83, "fields": {"name": "Gloria Griffin", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.531Z", "comment": "Phasellus in felis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 84, "fields": {"name": "Evelyn Gilbert", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.533Z", "comment": "In congue.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 85, "fields": {"name": "Jean Ray", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.535Z", "comment": "Phasellus in felis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 86, "fields": {"name": "Sandra Larson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.537Z", "comment": "Praesent blandit.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 87, "fields": {"name": "Jessica Welch", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.539Z", "comment": "Nunc rhoncus dui vel sem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 88, "fields": {"name": "Anne Bell", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.541Z", "comment": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 89, "fields": {"name": "Shirley Wright", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.542Z", "comment": "Mauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 90, "fields": {"name": "Carol Parker", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.545Z", "comment": "Nunc rhoncus dui vel sem.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 91, "fields": {"name": "Ann Murphy", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.546Z", "comment": "Curabitur convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 92, "fields": {"name": "Donna Hayes", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.548Z", "comment": "Quisque porta volutpat erat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 93, "fields": {"name": "Sharon Thompson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.549Z", "comment": "Quisque ut erat.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 94, "fields": {"name": "Ruby Perry", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.550Z", "comment": "Integer non velit.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 95, "fields": {"name": "Gloria Morrison", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.552Z", "comment": "Curabitur in libero ut massa volutpat convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 96, "fields": {"name": "Joan Hayes", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.554Z", "comment": "Praesent id massa id nisl venenatis lacinia.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 97, "fields": {"name": "Helen Rodriguez", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.555Z", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 98, "fields": {"name": "Diana Willis", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.557Z", "comment": "Curabitur convallis.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 99, "fields": {"name": "Dorothy Alexander", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.559Z", "comment": "Mauris lacinia sapien quis libero.", "system_users": []}}, {"model": "assets.assetgroup", "pk": 100, "fields": {"name": "Joyce Henderson", "created_by": "Fake", "date_created": "2017-01-07T12:54:15.560Z", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "system_users": []}}, {"model": "assets.asset", "pk": 1, "fields": {"ip": "0.0.0.0", "other_ip": null, "remote_card_ip": null, "hostname": "judith90", "port": 22, "admin_user": 49, "idc": 94, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.575Z", "comment": "", "groups": [11, 99, 29], "system_users": [99, 53, 41], "tags": []}}, {"model": "assets.asset", "pk": 2, "fields": {"ip": "1.1.1.1", "other_ip": null, "remote_card_ip": null, "hostname": "heather89", "port": 22, "admin_user": 41, "idc": 71, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.626Z", "comment": "", "groups": [88, 30, 51], "system_users": [10, 46, 2], "tags": []}}, {"model": "assets.asset", "pk": 3, "fields": {"ip": "2.2.2.2", "other_ip": null, "remote_card_ip": null, "hostname": "carol73", "port": 22, "admin_user": 90, "idc": 58, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.669Z", "comment": "", "groups": [45, 9, 5], "system_users": [86, 73, 41], "tags": []}}, {"model": "assets.asset", "pk": 4, "fields": {"ip": "3.3.3.3", "other_ip": null, "remote_card_ip": null, "hostname": "emily88", "port": 22, "admin_user": 77, "idc": 83, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.713Z", "comment": "", "groups": [67, 1, 68], "system_users": [33, 79, 66], "tags": []}}, {"model": "assets.asset", "pk": 5, "fields": {"ip": "4.4.4.4", "other_ip": null, "remote_card_ip": null, "hostname": "amy88", "port": 22, "admin_user": 40, "idc": 69, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.758Z", "comment": "", "groups": [51, 65, 14], "system_users": [52, 59, 60], "tags": []}}, {"model": "assets.asset", "pk": 6, "fields": {"ip": "5.5.5.5", "other_ip": null, "remote_card_ip": null, "hostname": "louise76", "port": 22, "admin_user": 98, "idc": 24, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.805Z", "comment": "", "groups": [50, 58, 8], "system_users": [40, 90, 94], "tags": []}}, {"model": "assets.asset", "pk": 7, "fields": {"ip": "6.6.6.6", "other_ip": null, "remote_card_ip": null, "hostname": "rose71", "port": 22, "admin_user": 72, "idc": 73, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.848Z", "comment": "", "groups": [88, 90, 65], "system_users": [87, 84, 92], "tags": []}}, {"model": "assets.asset", "pk": 8, "fields": {"ip": "7.7.7.7", "other_ip": null, "remote_card_ip": null, "hostname": "amanda77", "port": 22, "admin_user": 60, "idc": 53, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.894Z", "comment": "", "groups": [90, 28, 69], "system_users": [83, 67, 12], "tags": []}}, {"model": "assets.asset", "pk": 9, "fields": {"ip": "8.8.8.8", "other_ip": null, "remote_card_ip": null, "hostname": "rachel93", "port": 22, "admin_user": 98, "idc": 53, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.938Z", "comment": "", "groups": [7, 55, 75], "system_users": [71, 87, 36], "tags": []}}, {"model": "assets.asset", "pk": 10, "fields": {"ip": "9.9.9.9", "other_ip": null, "remote_card_ip": null, "hostname": "catherine85", "port": 22, "admin_user": 53, "idc": 49, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:15.983Z", "comment": "", "groups": [80, 50, 44], "system_users": [95, 93, 4], "tags": []}}, {"model": "assets.asset", "pk": 11, "fields": {"ip": "10.10.10.10", "other_ip": null, "remote_card_ip": null, "hostname": "irene88", "port": 22, "admin_user": 17, "idc": 73, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.029Z", "comment": "", "groups": [74, 44, 10], "system_users": [11, 29, 31], "tags": []}}, {"model": "assets.asset", "pk": 12, "fields": {"ip": "11.11.11.11", "other_ip": null, "remote_card_ip": null, "hostname": "judith64", "port": 22, "admin_user": 55, "idc": 73, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.071Z", "comment": "", "groups": [19, 29, 36], "system_users": [5, 61, 1], "tags": []}}, {"model": "assets.asset", "pk": 13, "fields": {"ip": "12.12.12.12", "other_ip": null, "remote_card_ip": null, "hostname": "christina63", "port": 22, "admin_user": 91, "idc": 12, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.113Z", "comment": "", "groups": [92, 42, 75], "system_users": [11, 7, 20], "tags": []}}, {"model": "assets.asset", "pk": 14, "fields": {"ip": "13.13.13.13", "other_ip": null, "remote_card_ip": null, "hostname": "donna86", "port": 22, "admin_user": 11, "idc": 22, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.155Z", "comment": "", "groups": [26, 25, 43], "system_users": [10, 36, 37], "tags": []}}, {"model": "assets.asset", "pk": 15, "fields": {"ip": "14.14.14.14", "other_ip": null, "remote_card_ip": null, "hostname": "ashley65", "port": 22, "admin_user": 19, "idc": 87, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.206Z", "comment": "", "groups": [74, 18, 44], "system_users": [76, 61, 65], "tags": []}}, {"model": "assets.asset", "pk": 16, "fields": {"ip": "15.15.15.15", "other_ip": null, "remote_card_ip": null, "hostname": "cynthia63", "port": 22, "admin_user": 86, "idc": 66, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.248Z", "comment": "", "groups": [63, 38, 31], "system_users": [24, 15, 12], "tags": []}}, {"model": "assets.asset", "pk": 17, "fields": {"ip": "16.16.16.16", "other_ip": null, "remote_card_ip": null, "hostname": "ann83", "port": 22, "admin_user": 10, "idc": 51, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.293Z", "comment": "", "groups": [66, 52, 73], "system_users": [99, 100, 76], "tags": []}}, {"model": "assets.asset", "pk": 18, "fields": {"ip": "17.17.17.17", "other_ip": null, "remote_card_ip": null, "hostname": "bonnie81", "port": 22, "admin_user": 60, "idc": 32, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.337Z", "comment": "", "groups": [3, 6, 5], "system_users": [32, 75, 61], "tags": []}}, {"model": "assets.asset", "pk": 19, "fields": {"ip": "18.18.18.18", "other_ip": null, "remote_card_ip": null, "hostname": "teresa78", "port": 22, "admin_user": 32, "idc": 14, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.384Z", "comment": "", "groups": [67, 47, 46], "system_users": [68, 7, 8], "tags": []}}, {"model": "assets.asset", "pk": 20, "fields": {"ip": "19.19.19.19", "other_ip": null, "remote_card_ip": null, "hostname": "anna68", "port": 22, "admin_user": 6, "idc": 33, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.427Z", "comment": "", "groups": [30, 98, 83], "system_users": [72, 9, 79], "tags": []}}, {"model": "assets.asset", "pk": 21, "fields": {"ip": "20.20.20.20", "other_ip": null, "remote_card_ip": null, "hostname": "ashley68", "port": 22, "admin_user": 39, "idc": 77, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.474Z", "comment": "", "groups": [57, 74, 52], "system_users": [19, 9, 85], "tags": []}}, {"model": "assets.asset", "pk": 22, "fields": {"ip": "21.21.21.21", "other_ip": null, "remote_card_ip": null, "hostname": "kathryn68", "port": 22, "admin_user": 100, "idc": 11, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.522Z", "comment": "", "groups": [66, 70, 18], "system_users": [99, 49, 92], "tags": []}}, {"model": "assets.asset", "pk": 23, "fields": {"ip": "22.22.22.22", "other_ip": null, "remote_card_ip": null, "hostname": "phyllis65", "port": 22, "admin_user": 78, "idc": 54, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.566Z", "comment": "", "groups": [66, 62, 44], "system_users": [26, 45, 53], "tags": []}}, {"model": "assets.asset", "pk": 24, "fields": {"ip": "23.23.23.23", "other_ip": null, "remote_card_ip": null, "hostname": "linda70", "port": 22, "admin_user": 85, "idc": 20, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.612Z", "comment": "", "groups": [23, 99, 28], "system_users": [68, 78, 41], "tags": []}}, {"model": "assets.asset", "pk": 25, "fields": {"ip": "24.24.24.24", "other_ip": null, "remote_card_ip": null, "hostname": "betty66", "port": 22, "admin_user": 41, "idc": 39, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.656Z", "comment": "", "groups": [88, 94, 5], "system_users": [4, 65, 60], "tags": []}}, {"model": "assets.asset", "pk": 26, "fields": {"ip": "25.25.25.25", "other_ip": null, "remote_card_ip": null, "hostname": "rachel78", "port": 22, "admin_user": 96, "idc": 25, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.703Z", "comment": "", "groups": [84, 28, 60], "system_users": [83, 76, 66], "tags": []}}, {"model": "assets.asset", "pk": 27, "fields": {"ip": "26.26.26.26", "other_ip": null, "remote_card_ip": null, "hostname": "theresa79", "port": 22, "admin_user": 100, "idc": 54, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.748Z", "comment": "", "groups": [63, 56, 38], "system_users": [55, 52, 67], "tags": []}}, {"model": "assets.asset", "pk": 28, "fields": {"ip": "27.27.27.27", "other_ip": null, "remote_card_ip": null, "hostname": "marilyn79", "port": 22, "admin_user": 5, "idc": 31, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.791Z", "comment": "", "groups": [39, 74, 61], "system_users": [87, 38, 66], "tags": []}}, {"model": "assets.asset", "pk": 29, "fields": {"ip": "28.28.28.28", "other_ip": null, "remote_card_ip": null, "hostname": "joan71", "port": 22, "admin_user": 2, "idc": 92, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.833Z", "comment": "", "groups": [30, 84, 12], "system_users": [9, 86, 42], "tags": []}}, {"model": "assets.asset", "pk": 30, "fields": {"ip": "29.29.29.29", "other_ip": null, "remote_card_ip": null, "hostname": "louise71", "port": 22, "admin_user": 91, "idc": 98, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.879Z", "comment": "", "groups": [19, 11, 94], "system_users": [77, 43, 95], "tags": []}}, {"model": "assets.asset", "pk": 31, "fields": {"ip": "30.30.30.30", "other_ip": null, "remote_card_ip": null, "hostname": "wanda86", "port": 22, "admin_user": 29, "idc": 8, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.922Z", "comment": "", "groups": [78, 15, 96], "system_users": [55, 16, 98], "tags": []}}, {"model": "assets.asset", "pk": 32, "fields": {"ip": "31.31.31.31", "other_ip": null, "remote_card_ip": null, "hostname": "andrea66", "port": 22, "admin_user": 77, "idc": 83, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:16.963Z", "comment": "", "groups": [53, 28, 43], "system_users": [40, 13, 85], "tags": []}}, {"model": "assets.asset", "pk": 33, "fields": {"ip": "32.32.32.32", "other_ip": null, "remote_card_ip": null, "hostname": "jennifer84", "port": 22, "admin_user": 62, "idc": 61, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.010Z", "comment": "", "groups": [30, 32, 36], "system_users": [55, 71, 53], "tags": []}}, {"model": "assets.asset", "pk": 34, "fields": {"ip": "33.33.33.33", "other_ip": null, "remote_card_ip": null, "hostname": "debra74", "port": 22, "admin_user": 51, "idc": 12, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.056Z", "comment": "", "groups": [57, 41, 16], "system_users": [55, 44, 29], "tags": []}}, {"model": "assets.asset", "pk": 35, "fields": {"ip": "34.34.34.34", "other_ip": null, "remote_card_ip": null, "hostname": "stephanie89", "port": 22, "admin_user": 30, "idc": 100, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.106Z", "comment": "", "groups": [84, 76, 31], "system_users": [83, 17, 41], "tags": []}}, {"model": "assets.asset", "pk": 36, "fields": {"ip": "35.35.35.35", "other_ip": null, "remote_card_ip": null, "hostname": "judy93", "port": 22, "admin_user": 12, "idc": 13, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.154Z", "comment": "", "groups": [54, 70, 14], "system_users": [86, 48, 38], "tags": []}}, {"model": "assets.asset", "pk": 37, "fields": {"ip": "36.36.36.36", "other_ip": null, "remote_card_ip": null, "hostname": "robin85", "port": 22, "admin_user": 76, "idc": 58, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.203Z", "comment": "", "groups": [1, 45, 97], "system_users": [92, 38, 23], "tags": []}}, {"model": "assets.asset", "pk": 38, "fields": {"ip": "37.37.37.37", "other_ip": null, "remote_card_ip": null, "hostname": "paula93", "port": 22, "admin_user": 54, "idc": 93, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.248Z", "comment": "", "groups": [82, 75, 14], "system_users": [58, 92, 25], "tags": []}}, {"model": "assets.asset", "pk": 39, "fields": {"ip": "38.38.38.38", "other_ip": null, "remote_card_ip": null, "hostname": "ruth93", "port": 22, "admin_user": 39, "idc": 2, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.294Z", "comment": "", "groups": [43, 52, 60], "system_users": [9, 43, 62], "tags": []}}, {"model": "assets.asset", "pk": 40, "fields": {"ip": "39.39.39.39", "other_ip": null, "remote_card_ip": null, "hostname": "janet93", "port": 22, "admin_user": 89, "idc": 94, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.340Z", "comment": "", "groups": [66, 15, 87], "system_users": [44, 68, 88], "tags": []}}, {"model": "assets.asset", "pk": 41, "fields": {"ip": "40.40.40.40", "other_ip": null, "remote_card_ip": null, "hostname": "robin89", "port": 22, "admin_user": 47, "idc": 33, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.391Z", "comment": "", "groups": [37, 61, 80], "system_users": [43, 64, 12], "tags": []}}, {"model": "assets.asset", "pk": 42, "fields": {"ip": "41.41.41.41", "other_ip": null, "remote_card_ip": null, "hostname": "norma88", "port": 22, "admin_user": 83, "idc": 4, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.440Z", "comment": "", "groups": [72, 80, 12], "system_users": [22, 6, 92], "tags": []}}, {"model": "assets.asset", "pk": 43, "fields": {"ip": "42.42.42.42", "other_ip": null, "remote_card_ip": null, "hostname": "sara80", "port": 22, "admin_user": 13, "idc": 60, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.491Z", "comment": "", "groups": [97, 36, 51], "system_users": [19, 99, 66], "tags": []}}, {"model": "assets.asset", "pk": 44, "fields": {"ip": "43.43.43.43", "other_ip": null, "remote_card_ip": null, "hostname": "robin88", "port": 22, "admin_user": 95, "idc": 81, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.550Z", "comment": "", "groups": [27, 74, 2], "system_users": [97, 10, 91], "tags": []}}, {"model": "assets.asset", "pk": 45, "fields": {"ip": "44.44.44.44", "other_ip": null, "remote_card_ip": null, "hostname": "julie65", "port": 22, "admin_user": 60, "idc": 35, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.601Z", "comment": "", "groups": [33, 16, 80], "system_users": [69, 70, 66], "tags": []}}, {"model": "assets.asset", "pk": 46, "fields": {"ip": "45.45.45.45", "other_ip": null, "remote_card_ip": null, "hostname": "ashley86", "port": 22, "admin_user": 10, "idc": 51, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.652Z", "comment": "", "groups": [35, 28, 61], "system_users": [39, 67, 45], "tags": []}}, {"model": "assets.asset", "pk": 47, "fields": {"ip": "46.46.46.46", "other_ip": null, "remote_card_ip": null, "hostname": "tammy74", "port": 22, "admin_user": 13, "idc": 29, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.700Z", "comment": "", "groups": [36, 38, 10], "system_users": [80, 59, 41], "tags": []}}, {"model": "assets.asset", "pk": 48, "fields": {"ip": "47.47.47.47", "other_ip": null, "remote_card_ip": null, "hostname": "gloria75", "port": 22, "admin_user": 51, "idc": 34, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.752Z", "comment": "", "groups": [85, 51, 31], "system_users": [44, 86, 36], "tags": []}}, {"model": "assets.asset", "pk": 49, "fields": {"ip": "48.48.48.48", "other_ip": null, "remote_card_ip": null, "hostname": "carolyn81", "port": 22, "admin_user": 73, "idc": 59, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.809Z", "comment": "", "groups": [91, 26, 83], "system_users": [33, 51, 70], "tags": []}}, {"model": "assets.asset", "pk": 50, "fields": {"ip": "49.49.49.49", "other_ip": null, "remote_card_ip": null, "hostname": "pamela73", "port": 22, "admin_user": 30, "idc": 56, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.857Z", "comment": "", "groups": [53, 83, 7], "system_users": [39, 33, 8], "tags": []}}, {"model": "assets.asset", "pk": 51, "fields": {"ip": "50.50.50.50", "other_ip": null, "remote_card_ip": null, "hostname": "patricia89", "port": 22, "admin_user": 14, "idc": 99, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.905Z", "comment": "", "groups": [25, 80, 65], "system_users": [86, 37, 65], "tags": []}}, {"model": "assets.asset", "pk": 52, "fields": {"ip": "51.51.51.51", "other_ip": null, "remote_card_ip": null, "hostname": "tammy63", "port": 22, "admin_user": 81, "idc": 8, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:17.955Z", "comment": "", "groups": [92, 53, 8], "system_users": [99, 9, 43], "tags": []}}, {"model": "assets.asset", "pk": 53, "fields": {"ip": "52.52.52.52", "other_ip": null, "remote_card_ip": null, "hostname": "lillian82", "port": 22, "admin_user": 10, "idc": 4, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.004Z", "comment": "", "groups": [97, 33, 7], "system_users": [94, 98, 60], "tags": []}}, {"model": "assets.asset", "pk": 54, "fields": {"ip": "53.53.53.53", "other_ip": null, "remote_card_ip": null, "hostname": "kelly82", "port": 22, "admin_user": 72, "idc": 64, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.055Z", "comment": "", "groups": [100, 38, 77], "system_users": [47, 64, 28], "tags": []}}, {"model": "assets.asset", "pk": 55, "fields": {"ip": "54.54.54.54", "other_ip": null, "remote_card_ip": null, "hostname": "kathryn81", "port": 22, "admin_user": 83, "idc": 49, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.109Z", "comment": "", "groups": [11, 95, 89], "system_users": [39, 36, 65], "tags": []}}, {"model": "assets.asset", "pk": 56, "fields": {"ip": "55.55.55.55", "other_ip": null, "remote_card_ip": null, "hostname": "kathryn67", "port": 22, "admin_user": 55, "idc": 85, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.164Z", "comment": "", "groups": [83, 100, 2], "system_users": [22, 94, 53], "tags": []}}, {"model": "assets.asset", "pk": 57, "fields": {"ip": "56.56.56.56", "other_ip": null, "remote_card_ip": null, "hostname": "debra81", "port": 22, "admin_user": 75, "idc": 56, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.218Z", "comment": "", "groups": [40, 25, 16], "system_users": [87, 49, 75], "tags": []}}, {"model": "assets.asset", "pk": 58, "fields": {"ip": "57.57.57.57", "other_ip": null, "remote_card_ip": null, "hostname": "joyce94", "port": 22, "admin_user": 64, "idc": 56, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.265Z", "comment": "", "groups": [36, 69, 12], "system_users": [6, 39, 78], "tags": []}}, {"model": "assets.asset", "pk": 59, "fields": {"ip": "58.58.58.58", "other_ip": null, "remote_card_ip": null, "hostname": "patricia91", "port": 22, "admin_user": 91, "idc": 36, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.316Z", "comment": "", "groups": [67, 84, 89], "system_users": [54, 18, 75], "tags": []}}, {"model": "assets.asset", "pk": 60, "fields": {"ip": "59.59.59.59", "other_ip": null, "remote_card_ip": null, "hostname": "tammy94", "port": 22, "admin_user": 79, "idc": 36, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.366Z", "comment": "", "groups": [84, 85, 48], "system_users": [55, 43, 61], "tags": []}}, {"model": "assets.asset", "pk": 61, "fields": {"ip": "60.60.60.60", "other_ip": null, "remote_card_ip": null, "hostname": "heather84", "port": 22, "admin_user": 63, "idc": 95, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.420Z", "comment": "", "groups": [41, 85, 77], "system_users": [72, 89, 37], "tags": []}}, {"model": "assets.asset", "pk": 62, "fields": {"ip": "61.61.61.61", "other_ip": null, "remote_card_ip": null, "hostname": "helen91", "port": 22, "admin_user": 20, "idc": 62, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.468Z", "comment": "", "groups": [91, 23, 100], "system_users": [58, 67, 4], "tags": []}}, {"model": "assets.asset", "pk": 63, "fields": {"ip": "62.62.62.62", "other_ip": null, "remote_card_ip": null, "hostname": "tina80", "port": 22, "admin_user": 76, "idc": 31, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.519Z", "comment": "", "groups": [22, 64, 81], "system_users": [97, 79, 64], "tags": []}}, {"model": "assets.asset", "pk": 64, "fields": {"ip": "64.64.64.64", "other_ip": null, "remote_card_ip": null, "hostname": "cynthia67", "port": 22, "admin_user": 90, "idc": 40, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.580Z", "comment": "", "groups": [16, 31, 86], "system_users": [72, 52, 36], "tags": []}}, {"model": "assets.asset", "pk": 65, "fields": {"ip": "65.65.65.65", "other_ip": null, "remote_card_ip": null, "hostname": "lori83", "port": 22, "admin_user": 95, "idc": 49, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.627Z", "comment": "", "groups": [36, 6, 31], "system_users": [79, 34, 12], "tags": []}}, {"model": "assets.asset", "pk": 66, "fields": {"ip": "66.66.66.66", "other_ip": null, "remote_card_ip": null, "hostname": "lisa91", "port": 22, "admin_user": 34, "idc": 17, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.675Z", "comment": "", "groups": [35, 17, 5], "system_users": [13, 10, 45], "tags": []}}, {"model": "assets.asset", "pk": 67, "fields": {"ip": "67.67.67.67", "other_ip": null, "remote_card_ip": null, "hostname": "paula94", "port": 22, "admin_user": 9, "idc": 11, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.723Z", "comment": "", "groups": [6, 77, 2], "system_users": [83, 13, 89], "tags": []}}, {"model": "assets.asset", "pk": 68, "fields": {"ip": "68.68.68.68", "other_ip": null, "remote_card_ip": null, "hostname": "anne90", "port": 22, "admin_user": 93, "idc": 92, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.770Z", "comment": "", "groups": [83, 22, 81], "system_users": [97, 65, 23], "tags": []}}, {"model": "assets.asset", "pk": 69, "fields": {"ip": "69.69.69.69", "other_ip": null, "remote_card_ip": null, "hostname": "anne86", "port": 22, "admin_user": 52, "idc": 81, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.816Z", "comment": "", "groups": [21, 94, 86], "system_users": [19, 51, 38], "tags": []}}, {"model": "assets.asset", "pk": 70, "fields": {"ip": "70.70.70.70", "other_ip": null, "remote_card_ip": null, "hostname": "evelyn89", "port": 22, "admin_user": 91, "idc": 57, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.862Z", "comment": "", "groups": [11, 37, 5], "system_users": [30, 53], "tags": []}}, {"model": "assets.asset", "pk": 71, "fields": {"ip": "71.71.71.71", "other_ip": null, "remote_card_ip": null, "hostname": "teresa63", "port": 22, "admin_user": 33, "idc": 54, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.912Z", "comment": "", "groups": [69, 12, 8], "system_users": [35, 70, 2], "tags": []}}, {"model": "assets.asset", "pk": 72, "fields": {"ip": "72.72.72.72", "other_ip": null, "remote_card_ip": null, "hostname": "joyce65", "port": 22, "admin_user": 28, "idc": 24, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:18.959Z", "comment": "", "groups": [25, 71, 68], "system_users": [94, 26, 42], "tags": []}}, {"model": "assets.asset", "pk": 73, "fields": {"ip": "73.73.73.73", "other_ip": null, "remote_card_ip": null, "hostname": "beverly80", "port": 22, "admin_user": 77, "idc": 30, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.009Z", "comment": "", "groups": [80, 10, 2], "system_users": [20, 86, 79], "tags": []}}, {"model": "assets.asset", "pk": 74, "fields": {"ip": "74.74.74.74", "other_ip": null, "remote_card_ip": null, "hostname": "cheryl73", "port": 22, "admin_user": 33, "idc": 8, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.056Z", "comment": "", "groups": [84, 22], "system_users": [19, 20, 52], "tags": []}}, {"model": "assets.asset", "pk": 75, "fields": {"ip": "75.75.75.75", "other_ip": null, "remote_card_ip": null, "hostname": "theresa65", "port": 22, "admin_user": 21, "idc": 48, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.103Z", "comment": "", "groups": [63, 22, 59], "system_users": [51, 79, 48], "tags": []}}, {"model": "assets.asset", "pk": 76, "fields": {"ip": "76.76.76.76", "other_ip": null, "remote_card_ip": null, "hostname": "helen78", "port": 22, "admin_user": 37, "idc": 50, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.150Z", "comment": "", "groups": [66, 64, 81], "system_users": [47, 56, 91], "tags": []}}, {"model": "assets.asset", "pk": 77, "fields": {"ip": "77.77.77.77", "other_ip": null, "remote_card_ip": null, "hostname": "debra69", "port": 22, "admin_user": 13, "idc": 74, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.208Z", "comment": "", "groups": [25, 28, 50], "system_users": [83, 58], "tags": []}}, {"model": "assets.asset", "pk": 78, "fields": {"ip": "78.78.78.78", "other_ip": null, "remote_card_ip": null, "hostname": "kathleen68", "port": 22, "admin_user": 23, "idc": 17, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.254Z", "comment": "", "groups": [87, 47, 24], "system_users": [27, 51, 89], "tags": []}}, {"model": "assets.asset", "pk": 79, "fields": {"ip": "79.79.79.79", "other_ip": null, "remote_card_ip": null, "hostname": "wanda79", "port": 22, "admin_user": 77, "idc": 12, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.300Z", "comment": "", "groups": [91, 27, 50], "system_users": [37, 60, 41], "tags": []}}, {"model": "assets.asset", "pk": 80, "fields": {"ip": "80.80.80.80", "other_ip": null, "remote_card_ip": null, "hostname": "denise65", "port": 22, "admin_user": 100, "idc": 29, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.349Z", "comment": "", "groups": [78, 87, 28], "system_users": [77, 88, 66], "tags": []}}, {"model": "assets.asset", "pk": 81, "fields": {"ip": "81.81.81.81", "other_ip": null, "remote_card_ip": null, "hostname": "kathy76", "port": 22, "admin_user": 3, "idc": 59, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.409Z", "comment": "", "groups": [13, 98, 55], "system_users": [27, 7, 58], "tags": []}}, {"model": "assets.asset", "pk": 82, "fields": {"ip": "82.82.82.82", "other_ip": null, "remote_card_ip": null, "hostname": "tina74", "port": 22, "admin_user": 61, "idc": 20, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.471Z", "comment": "", "groups": [92, 45, 61], "system_users": [24, 18, 65], "tags": []}}, {"model": "assets.asset", "pk": 83, "fields": {"ip": "83.83.83.83", "other_ip": null, "remote_card_ip": null, "hostname": "barbara75", "port": 22, "admin_user": 99, "idc": 75, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.521Z", "comment": "", "groups": [69, 86, 8], "system_users": [52, 93, 65], "tags": []}}, {"model": "assets.asset", "pk": 84, "fields": {"ip": "84.84.84.84", "other_ip": null, "remote_card_ip": null, "hostname": "linda89", "port": 22, "admin_user": 67, "idc": 2, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.570Z", "comment": "", "groups": [57, 11, 10], "system_users": [24, 22, 93], "tags": []}}, {"model": "assets.asset", "pk": 85, "fields": {"ip": "85.85.85.85", "other_ip": null, "remote_card_ip": null, "hostname": "angela86", "port": 22, "admin_user": 73, "idc": 46, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.619Z", "comment": "", "groups": [4, 99, 87], "system_users": [80, 56, 4], "tags": []}}, {"model": "assets.asset", "pk": 86, "fields": {"ip": "86.86.86.86", "other_ip": null, "remote_card_ip": null, "hostname": "laura87", "port": 22, "admin_user": 57, "idc": 94, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.669Z", "comment": "", "groups": [4, 52, 46], "system_users": [71, 57, 42], "tags": []}}, {"model": "assets.asset", "pk": 87, "fields": {"ip": "87.87.87.87", "other_ip": null, "remote_card_ip": null, "hostname": "sharon94", "port": 22, "admin_user": 49, "idc": 21, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.717Z", "comment": "", "groups": [95, 22, 64], "system_users": [72, 18, 17], "tags": []}}, {"model": "assets.asset", "pk": 88, "fields": {"ip": "88.88.88.88", "other_ip": null, "remote_card_ip": null, "hostname": "betty94", "port": 22, "admin_user": 34, "idc": 3, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.767Z", "comment": "", "groups": [79, 7, 73], "system_users": [9, 97, 92], "tags": []}}, {"model": "assets.asset", "pk": 89, "fields": {"ip": "89.89.89.89", "other_ip": null, "remote_card_ip": null, "hostname": "katherine71", "port": 22, "admin_user": 98, "idc": 54, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.813Z", "comment": "", "groups": [66, 77, 86], "system_users": [22, 25, 4], "tags": []}}, {"model": "assets.asset", "pk": 90, "fields": {"ip": "90.90.90.90", "other_ip": null, "remote_card_ip": null, "hostname": "mary87", "port": 22, "admin_user": 25, "idc": 46, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.856Z", "comment": "", "groups": [84, 20, 89], "system_users": [96, 54, 75], "tags": []}}, {"model": "assets.asset", "pk": 91, "fields": {"ip": "91.91.91.91", "other_ip": null, "remote_card_ip": null, "hostname": "cheryl81", "port": 22, "admin_user": 29, "idc": 95, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.903Z", "comment": "", "groups": [30, 39, 73], "system_users": [88, 2], "tags": []}}, {"model": "assets.asset", "pk": 92, "fields": {"ip": "92.92.92.92", "other_ip": null, "remote_card_ip": null, "hostname": "helen89", "port": 22, "admin_user": 21, "idc": 89, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.949Z", "comment": "", "groups": [78, 98, 27], "system_users": [87, 70, 85], "tags": []}}, {"model": "assets.asset", "pk": 93, "fields": {"ip": "93.93.93.93", "other_ip": null, "remote_card_ip": null, "hostname": "michelle93", "port": 22, "admin_user": 94, "idc": 25, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:19.993Z", "comment": "", "groups": [99, 69, 42], "system_users": [51, 62, 93], "tags": []}}, {"model": "assets.asset", "pk": 94, "fields": {"ip": "94.94.94.94", "other_ip": null, "remote_card_ip": null, "hostname": "cheryl72", "port": 22, "admin_user": 59, "idc": 74, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.036Z", "comment": "", "groups": [91, 97, 79], "system_users": [44, 95, 41], "tags": []}}, {"model": "assets.asset", "pk": 95, "fields": {"ip": "95.95.95.95", "other_ip": null, "remote_card_ip": null, "hostname": "theresa91", "port": 22, "admin_user": 2, "idc": 87, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.083Z", "comment": "", "groups": [40, 34, 92], "system_users": [19, 51, 49], "tags": []}}, {"model": "assets.asset", "pk": 96, "fields": {"ip": "96.96.96.96", "other_ip": null, "remote_card_ip": null, "hostname": "paula71", "port": 22, "admin_user": 60, "idc": 5, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.127Z", "comment": "", "groups": [30, 90, 63], "system_users": [97, 58, 49], "tags": []}}, {"model": "assets.asset", "pk": 97, "fields": {"ip": "97.97.97.97", "other_ip": null, "remote_card_ip": null, "hostname": "mildred65", "port": 22, "admin_user": 89, "idc": 24, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.171Z", "comment": "", "groups": [19, 77, 65], "system_users": [54, 43, 50], "tags": []}}, {"model": "assets.asset", "pk": 98, "fields": {"ip": "98.98.98.98", "other_ip": null, "remote_card_ip": null, "hostname": "cheryl67", "port": 22, "admin_user": 71, "idc": 68, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.216Z", "comment": "", "groups": [87, 81, 14], "system_users": [54, 67, 66], "tags": []}}, {"model": "assets.asset", "pk": 99, "fields": {"ip": "99.99.99.99", "other_ip": null, "remote_card_ip": null, "hostname": "deborah84", "port": 22, "admin_user": 43, "idc": 6, "mac_address": null, "brand": null, "cpu": null, "memory": null, "disk": null, "os": null, "cabinet_no": null, "cabinet_pos": null, "number": null, "status": "In use", "type": "Server", "env": "Prod", "sn": null, "created_by": "Fake", "is_active": true, "date_created": "2017-01-07T12:54:20.262Z", "comment": "", "groups": [48, 61, 58], "system_users": [81, 18, 38], "tags": []}}, {"model": "audits.loginlog", "pk": 1, "fields": {"username": "admin", "name": "Administrator", "login_type": "W", "login_ip": "127.0.0.1", "login_city": "Unknown", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", "date_login": "2017-01-07T12:55:03.173Z"}}, {"model": "audits.loginlog", "pk": 2, "fields": {"username": "admin", "name": "Administrator", "login_type": "W", "login_ip": "127.0.0.1", "login_city": "Unknown", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36", "date_login": "2017-01-07T13:42:23.455Z"}}, {"model": "captcha.captchastore", "pk": 2, "fields": {"challenge": "IBWH", "response": "ibwh", "hashkey": "d87aab36c90d9c0c7db58b8c962489e7fe230255", "expiration": "2017-01-07T13:46:54.333Z"}}, {"model": "captcha.captchastore", "pk": 3, "fields": {"challenge": "ZEPZ", "response": "zepz", "hashkey": "e6e938b29de009f7297d3446e4ed2c2c971ad6a3", "expiration": "2017-01-07T13:47:00.154Z"}}, {"model": "captcha.captchastore", "pk": 4, "fields": {"challenge": "SEKW", "response": "sekw", "hashkey": "55aa74821b2aea35ff1b6af799d2bf96a6e6f38e", "expiration": "2017-01-07T13:47:04.781Z"}}, {"model": "captcha.captchastore", "pk": 5, "fields": {"challenge": "NOXK", "response": "noxk", "hashkey": "098a92782503249387501ba2930973b25dc31b2d", "expiration": "2017-01-07T13:47:09.478Z"}}, {"model": "captcha.captchastore", "pk": 6, "fields": {"challenge": "FKTB", "response": "fktb", "hashkey": "919d5ed6fe06d1eedb65d1fbe6e55cc2db11aa22", "expiration": "2017-01-07T13:47:14.351Z"}}, {"model": "sessions.session", "pk": "m8l7fuw33rgu7p6x9p5n5bneborp5lf2", "fields": {"session_data": "YTE3NDM3YzAwNmViYzNjZDAyMTM3M2UyMjJhNDEwZDJiYzU5ZDc2Zjp7Il9hdXRoX3VzZXJfaGFzaCI6IjY4ZWFlZmFjOTAzY2Q4NDRhMGE0NGIwMTcxNjJmOWJmMDIyZDg1MjYiLCJfYXV0aF91c2VyX2JhY2tlbmQiOiJkamFuZ28uY29udHJpYi5hdXRoLmJhY2tlbmRzLk1vZGVsQmFja2VuZCIsIl9hdXRoX3VzZXJfaWQiOiIxIn0=", "expire_date": "2017-01-21T13:42:22.874Z"}}, {"model": "sessions.session", "pk": "tes2ijj8mt8o0gwch6ty2ynmd97pbka4", "fields": {"session_data": "YTE3NDM3YzAwNmViYzNjZDAyMTM3M2UyMjJhNDEwZDJiYzU5ZDc2Zjp7Il9hdXRoX3VzZXJfaGFzaCI6IjY4ZWFlZmFjOTAzY2Q4NDRhMGE0NGIwMTcxNjJmOWJmMDIyZDg1MjYiLCJfYXV0aF91c2VyX2JhY2tlbmQiOiJkamFuZ28uY29udHJpYi5hdXRoLmJhY2tlbmRzLk1vZGVsQmFja2VuZCIsIl9hdXRoX3VzZXJfaWQiOiIxIn0=", "expire_date": "2017-01-21T12:55:03.006Z"}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$RwSpXYAYQGbQ$PADpsQmM+cO5Y/R1CVSx3qNV4EbGIm2k+iMBXUtwvNc=", "last_login": "2017-01-07T13:42:22.741Z", "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-11-25T06:50:28.412Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-11-08T06:50:28.412Z", "created_by": "System", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 2, "fields": {"password": "pbkdf2_sha256$30000$OZBcN41jfEVV$UAO8ASzCoh+NSeND9nEs5bowX7PJwfH4nG80vRZDdss=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:23.226Z", "username": "angela85", "name": "Anne Hill", "email": "henry@gigaclub.org", "role": "App", "avatar": "", "wechat": "michelle83", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Suspendisse ornare consequat lectus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:23.226Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 3, "fields": {"password": "pbkdf2_sha256$30000$9PLLsFa0jeoX$Z36tiSWZt0TwPwjxAsXx1c5r8CTdm/grLdsKfX0uygA=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:23.385Z", "username": "kathy77", "name": "Kathleen Mendoza", "email": "kathleen@quinu.com", "role": "Admin", "avatar": "", "wechat": "diana70", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean fermentum.", "is_first_login": false, "date_expired": "2086-12-21T12:52:23.385Z", "created_by": "angela85", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 4, "fields": {"password": "pbkdf2_sha256$30000$WfEtelO8vQBk$3+T98ukgr8kkK5h9bXoaDp/VuLuqZVOTh60eYJzzoMY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:23.537Z", "username": "todd93", "name": "Christina Kennedy", "email": "diane@realcube.edu", "role": "User", "avatar": "", "wechat": "rebecca79", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Cras in purus eu magna vulputate luctus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:23.537Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 5, "fields": {"password": "pbkdf2_sha256$30000$GhvKUJNqM4vv$+3uz5uR29DDzPW+l2tTCTVRFEM/yP2HVKsXMFctJyJQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:23.690Z", "username": "jessica94", "name": "Sarah Ruiz", "email": "sharon@centidel.mil", "role": "Admin", "avatar": "", "wechat": "lillian76", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vivamus vel nulla eget eros elementum pellentesque.", "is_first_login": false, "date_expired": "2086-12-21T12:52:23.690Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 6, "fields": {"password": "pbkdf2_sha256$30000$MJWY8V3WhWKS$btJcCnXV7OphbGvjyRmdHyJ9SeYvcvG6KkYyeqy62iQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:23.854Z", "username": "catherine66", "name": "Angela Watkins", "email": "gloria@brainbox.org", "role": "User", "avatar": "", "wechat": "cheryl94", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "In hac habitasse platea dictumst.", "is_first_login": false, "date_expired": "2086-12-21T12:52:23.854Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 7, "fields": {"password": "pbkdf2_sha256$30000$sJ6kL9uSxx16$m+nR/xBsmvCWCJk8M2hMaFrGFgT8P5rtUyBw1/CFpe4=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.019Z", "username": "karen69", "name": "Robin Morris", "email": "stephanie@trunyx.info", "role": "App", "avatar": "", "wechat": "nancy84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi quis tortor id nulla ultrices aliquet.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.019Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 8, "fields": {"password": "pbkdf2_sha256$30000$ttR0OnIjuhri$krb/jrcHOBOrK3xSU5Y1TBqrk+k+B6HNk9O0P2FkcIk=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.184Z", "username": "beverly81", "name": "Debra Webb", "email": "juan@abata.org", "role": "App", "avatar": "", "wechat": "linda94", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas ut massa quis augue luctus tincidunt.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.184Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 9, "fields": {"password": "pbkdf2_sha256$30000$Hzlo1VFyYVIQ$8MFOZv+C7GBIKslNxhquyIfRWZRBSQQM+Qhy8hfCNo0=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.342Z", "username": "katherine70", "name": "Mildred Frazier", "email": "paula@ntags.mil", "role": "App", "avatar": "", "wechat": "anne68", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi ut odio.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.342Z", "created_by": "beverly81", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 10, "fields": {"password": "pbkdf2_sha256$30000$iCo9CCC0jf1Q$rfYoQJIWw6ahL1CbOHfReLkzuT4PGXEoiSi+Z75gKbk=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.507Z", "username": "julia92", "name": "Samuel Alvarez", "email": "andrea@snaptags.name", "role": "User", "avatar": "", "wechat": "lillian65", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.507Z", "created_by": "jessica94", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 11, "fields": {"password": "pbkdf2_sha256$30000$i8d2P75ayM1A$pEecKqJ8yTf6AmzyWEFXsjQ9mgsz4MHzDaBNh7yfxlA=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.672Z", "username": "janice76", "name": "Brenda Jackson", "email": "karen@fatz.gov", "role": "Admin", "avatar": "", "wechat": "phyllis65", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas rhoncus aliquam lacus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.672Z", "created_by": "catherine66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 12, "fields": {"password": "pbkdf2_sha256$30000$Jm1KQXFCsv9k$4lSsw65lqPFOx/CYlKYfMkjl2ASpZiOR44oULHaR3aM=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.827Z", "username": "robin79", "name": "Melissa Burton", "email": "janice@yacero.biz", "role": "Admin", "avatar": "", "wechat": "sara88", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas pulvinar lobortis est.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.827Z", "created_by": "janice76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 13, "fields": {"password": "pbkdf2_sha256$30000$tmktFzVkg5xT$qTI0QYFy4+12OTb2q51g3YiF3eDWGkHSuEQsNEbu7pg=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:24.984Z", "username": "nicole86", "name": "Janet Wood", "email": "randy@oyope.gov", "role": "App", "avatar": "", "wechat": "ruby78", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:24.984Z", "created_by": "beverly81", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 14, "fields": {"password": "pbkdf2_sha256$30000$E66KrMtBDjsW$Aago1zd54jlN9saa0LTxb1gh03qme/MNj8q7kNEVB0Y=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.139Z", "username": "karen66", "name": "Margaret Walker", "email": "helen@tazz.mil", "role": "App", "avatar": "", "wechat": "heather92", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Suspendisse potenti.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.139Z", "created_by": "robin79", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 15, "fields": {"password": "pbkdf2_sha256$30000$76hmBy30Jbzf$6I3rr8C2MaVi0sTNlTDKI+/FcW1M+yp85WOzNqDQxjg=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.296Z", "username": "maria87", "name": "Stephanie Mccoy", "email": "martha@skippad.mil", "role": "App", "avatar": "", "wechat": "kathleen83", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Duis consequat dui nec nisi volutpat eleifend.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.296Z", "created_by": "catherine66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 16, "fields": {"password": "pbkdf2_sha256$30000$Liu6Gvbeu6VR$hhanNVCmdn/n1gZHG+TXC0GPDAB8m/0ib9i9RZPTFI0=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.447Z", "username": "andrea78", "name": "Brenda Evans", "email": "barbara@devshare.com", "role": "Admin", "avatar": "", "wechat": "tina85", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vivamus vestibulum sagittis sapien.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.447Z", "created_by": "julia92", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 17, "fields": {"password": "pbkdf2_sha256$30000$DAQFtiJXpEiP$vOF5X2H+zAUT7uhmCdUPFp2bJCqBtE2Kem3o3+L4IRE=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.604Z", "username": "paula88", "name": "Helen Williams", "email": "melissa@ntags.name", "role": "User", "avatar": "", "wechat": "deborah70", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Phasellus in felis.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.604Z", "created_by": "beverly81", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 18, "fields": {"password": "pbkdf2_sha256$30000$SIcJNOHqqsr5$KqI2VpSR5RxOpOlH4bfMuFM9tD9Q5giIPsMT9RxmnL8=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.761Z", "username": "jacqueline92", "name": "Robin Barnes", "email": "dorothy@twinder.org", "role": "Admin", "avatar": "", "wechat": "julia89", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Pellentesque at nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.761Z", "created_by": "katherine70", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 19, "fields": {"password": "pbkdf2_sha256$30000$QsZFHs3THlj7$zVV9OIOwD+gryUzZbo7pbxkv8uDKdcM1nSUszFfjmAs=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:25.921Z", "username": "kelly78", "name": "Katherine Wright", "email": "barbara@demivee.gov", "role": "Admin", "avatar": "", "wechat": "frances64", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "In hac habitasse platea dictumst.", "is_first_login": false, "date_expired": "2086-12-21T12:52:25.921Z", "created_by": "andrea78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 20, "fields": {"password": "pbkdf2_sha256$30000$Hd3cPufemVbQ$hQbvcLcMhtccQxfEKS/JhzlWDfp+vYpz/gqgTpHg4+Q=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.076Z", "username": "beverly76", "name": "Denise Simmons", "email": "kathleen@eire.org", "role": "App", "avatar": "", "wechat": "diana81", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.076Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 21, "fields": {"password": "pbkdf2_sha256$30000$hj8H7bt3qjk3$ORh74CK3rQ2T0gfU+Z6mgDtFU+Gc8vId/3MFLCJpP8g=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.234Z", "username": "janice65", "name": "Mildred Jackson", "email": "barbara@demizz.mil", "role": "Admin", "avatar": "", "wechat": "jean69", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam ultrices, libero non mattis pulvinar, nulla pede ullamcorper augue, a suscipit nulla elit ac nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.234Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 22, "fields": {"password": "pbkdf2_sha256$30000$w7Qq1lxJrkQ6$BFSRk0ciwbV5UaN8mJPQvlACypQ2rBwJowJhWYCX07w=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.391Z", "username": "amy72", "name": "Katherine Ellis", "email": "gloria@trilia.gov", "role": "App", "avatar": "", "wechat": "beverly82", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec ut dolor.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.392Z", "created_by": "julia92", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 23, "fields": {"password": "pbkdf2_sha256$30000$eo9UMN24MT8l$tvjY2qxbzWdO4yK7EDIEU6xVloJ5RWwzwwRS3RkQ64E=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.550Z", "username": "tammy86", "name": "Gloria Gordon", "email": "linda@realmix.mil", "role": "User", "avatar": "", "wechat": "doris80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Praesent id massa id nisl venenatis lacinia.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.550Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 24, "fields": {"password": "pbkdf2_sha256$30000$r4aPXYB5JEwH$cbjrQFni5zKeixgm0cUtb8M0JPbqI1ofMumwW/JGdao=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.714Z", "username": "mildred81", "name": "Joyce Alexander", "email": "anne@kare.mil", "role": "Admin", "avatar": "", "wechat": "evelyn80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Quisque ut erat.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.714Z", "created_by": "andrea78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 25, "fields": {"password": "pbkdf2_sha256$30000$T8m3qZIdAwOK$fLVf0XQikOEKVrHaNdWqBTuHA6+JmFjmXxUYXvIeTzg=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:26.874Z", "username": "kelly66", "name": "Gloria Evans", "email": "angela@camido.biz", "role": "App", "avatar": "", "wechat": "mary94", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas ut massa quis augue luctus tincidunt.", "is_first_login": false, "date_expired": "2086-12-21T12:52:26.874Z", "created_by": "angela85", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 26, "fields": {"password": "pbkdf2_sha256$30000$Si73ACdW4cYN$a8gN2oGANCivEplDGRuLmh66rSY5Y9aDr//yhi2qSqU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.032Z", "username": "annie65", "name": "Doris Perry", "email": "andrea@oba.info", "role": "User", "avatar": "", "wechat": "ann67", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Curabitur gravida nisi at nibh.", "is_first_login": false, "date_expired": "2086-12-21T12:52:27.032Z", "created_by": "karen69", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 27, "fields": {"password": "pbkdf2_sha256$30000$hsVyzHgjIKPD$4poOFdTy2/1xkLNzTaYrPfqSULssdyNHHbhn2LtoHBI=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.186Z", "username": "judy73", "name": "Kathryn Bradley", "email": "sara@devpoint.net", "role": "App", "avatar": "", "wechat": "pamela68", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "In hac habitasse platea dictumst.", "is_first_login": false, "date_expired": "2086-12-21T12:52:27.186Z", "created_by": "kelly78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 28, "fields": {"password": "pbkdf2_sha256$30000$F60bkMYvSb2l$tROlP/cKww1zzyiAcrW4gojTzX3DpUbOK1CbrFXKnwY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.340Z", "username": "laura93", "name": "Kimberly White", "email": "diana@oyoba.com", "role": "Admin", "avatar": "", "wechat": "patricia71", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla nisl.", "is_first_login": false, "date_expired": "2086-12-21T12:52:27.340Z", "created_by": "kelly78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 29, "fields": {"password": "pbkdf2_sha256$30000$7XSV48tSQMJh$PAZAeBoPnErTvvCs6WSXgMmLg57i3qHEMjwbdVHy96E=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.645Z", "username": "amanda71", "name": "Alice Ruiz", "email": "denise@divanoodle.name", "role": "App", "avatar": "", "wechat": "sara69", "phone": "", "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Fusce posuere felis sed lacus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:00Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 30, "fields": {"password": "pbkdf2_sha256$30000$QScIVNhIkxIB$jFudx33d/rDduGVzJo4ZI55E+fREIXqz89wOkDziGEM=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.803Z", "username": "alice84", "name": "Diana Ramos", "email": "theresa@pixope.name", "role": "App", "avatar": "", "wechat": "shirley88", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Suspendisse potenti.", "is_first_login": false, "date_expired": "2086-12-21T12:52:27.803Z", "created_by": "judy73", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 31, "fields": {"password": "pbkdf2_sha256$30000$kVVB9uC6NrJJ$bpY5xaRN+BhGL0yTJ0/ei8NxkIHfxP9ViujIX1irurI=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:27.963Z", "username": "rachel83", "name": "Shirley Shaw", "email": "louise@fliptune.biz", "role": "User", "avatar": "", "wechat": "ann64", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean auctor gravida sem.", "is_first_login": false, "date_expired": "2086-12-21T12:52:27.963Z", "created_by": "kelly66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 32, "fields": {"password": "pbkdf2_sha256$30000$u7bwV5CE9uH9$DzYPc65+vFVbxYZzKM5V4GpwNZLZjoNGAvHrWashP5w=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.120Z", "username": "catherine90", "name": "Brenda Richardson", "email": "ruby@abata.name", "role": "User", "avatar": "", "wechat": "elizabeth75", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec vitae nisi.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.120Z", "created_by": "janice65", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 33, "fields": {"password": "pbkdf2_sha256$30000$FNla6OSX7LMc$XrWSfpXUDepFZVH/6+OsEEwTX+LDoZ+VK8pN/2HIzwY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.280Z", "username": "norma66", "name": "Patricia Tucker", "email": "helen@pixope.org", "role": "App", "avatar": "", "wechat": "gloria76", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.280Z", "created_by": "angela85", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 34, "fields": {"password": "pbkdf2_sha256$30000$G5iQIylHo27n$mvi8cu27ggUmIF00kL0MBAorugmprBkwLL0f5aVbfZU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.436Z", "username": "karen93", "name": "Sara Boyd", "email": "virginia@babbleblab.biz", "role": "User", "avatar": "", "wechat": "janet73", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vivamus tortor.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.436Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 35, "fields": {"password": "pbkdf2_sha256$30000$rQcAevcNQL3t$akx7O5vu8QD/JNEaKqapu6vZn5YLdoHJDOstYSM3i7w=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.598Z", "username": "ann82", "name": "Julia Daniels", "email": "anne@twitternation.gov", "role": "Admin", "avatar": "", "wechat": "virginia65", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi porttitor lorem id ligula.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.598Z", "created_by": "andrea78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 36, "fields": {"password": "pbkdf2_sha256$30000$uGBq4adRVnkX$CPqnV0RI5k86wvh5noOtBVxGzftqi6p/zvJqpBCxlVk=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.761Z", "username": "christine89", "name": "Jessica Austin", "email": "louise@zoomzone.edu", "role": "User", "avatar": "", "wechat": "paula72", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Quisque ut erat.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.761Z", "created_by": "katherine70", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 37, "fields": {"password": "pbkdf2_sha256$30000$7wbTCVyAEDDT$guEwB8Hl+dPMSwh1TzmWGrLAiz2c2S9HeM+9IGadtYU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:28.918Z", "username": "lillian91", "name": "Norma Kim", "email": "amanda@wikizz.edu", "role": "App", "avatar": "", "wechat": "carol82", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Integer a nibh.", "is_first_login": false, "date_expired": "2086-12-21T12:52:28.918Z", "created_by": "alice84", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 38, "fields": {"password": "pbkdf2_sha256$30000$azAapR0xFGBu$PB5RMgXYLES6TiSThT59TeCDOPnTSAYP31HgchmPo38=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.073Z", "username": "ann86", "name": "Carolyn Banks", "email": "ann@dynabox.net", "role": "App", "avatar": "", "wechat": "dorothy90", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "In hac habitasse platea dictumst.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.073Z", "created_by": "julia92", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 39, "fields": {"password": "pbkdf2_sha256$30000$YA8pPZ0lcJak$vWEqah1Y8yyhxpCupRGfiK29T4rJIeVkgdKIhvmt9kI=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.230Z", "username": "sarah69", "name": "Christine Tucker", "email": "deborah@yambee.name", "role": "Admin", "avatar": "", "wechat": "emily90", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.230Z", "created_by": "jessica94", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 40, "fields": {"password": "pbkdf2_sha256$30000$qNLSQ2zD1lds$sml2yDj6oAM7azoXD1vryd5HwFtaHmcL50lCZDyKjMQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.388Z", "username": "pamela77", "name": "Jessica Bowman", "email": "diana@vitz.net", "role": "User", "avatar": "", "wechat": "jacqueline77", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.388Z", "created_by": "catherine90", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 41, "fields": {"password": "pbkdf2_sha256$30000$hxNvrviBAd7D$iC7gXK8M1WB02Tu5kJATJ/XHkjF60yUgs+eWKczlx4Y=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.543Z", "username": "carol66", "name": "Anna Cunningham", "email": "angela@oyope.net", "role": "Admin", "avatar": "", "wechat": "ann84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Phasellus id sapien in sapien iaculis congue.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.543Z", "created_by": "catherine66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 42, "fields": {"password": "pbkdf2_sha256$30000$OeD2iwWeooPl$AXR90poGZSZkrpyDYM7ZVL8oJR4ZSocNPvLdfNlQPXw=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.710Z", "username": "angela81", "name": "Lillian Lane", "email": "amanda@tagfeed.gov", "role": "App", "avatar": "", "wechat": "anne78", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nunc nisl.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.710Z", "created_by": "beverly81", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 43, "fields": {"password": "pbkdf2_sha256$30000$pBpixGH4t8l1$vZq5iHgntmwHEqEZU42S8SWlV/OmydEYcorzMQe1FnU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:29.866Z", "username": "katherine66", "name": "Shirley Cox", "email": "barbara@voonyx.gov", "role": "Admin", "avatar": "", "wechat": "joyce76", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc.", "is_first_login": false, "date_expired": "2086-12-21T12:52:29.866Z", "created_by": "annie65", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 44, "fields": {"password": "pbkdf2_sha256$30000$R9lgUFTKdwOz$pxeCoCv1dKCJ3CSO03bPIa3KtWVXlMcVXLwxqcpWgNA=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.023Z", "username": "phyllis63", "name": "Carol Phillips", "email": "diana@meedoo.edu", "role": "Admin", "avatar": "", "wechat": "shirley88", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Etiam vel augue.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.023Z", "created_by": "karen93", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 45, "fields": {"password": "pbkdf2_sha256$30000$O7USMR9UxQcc$b8R4MtRTWN8g7iTsFEc8666pv3sYYsA3EELhpJouSwM=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.184Z", "username": "joan79", "name": "Jacqueline Howell", "email": "bonnie@photospace.org", "role": "App", "avatar": "", "wechat": "jean68", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi quis tortor id nulla ultrices aliquet.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.184Z", "created_by": "amanda70", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 46, "fields": {"password": "pbkdf2_sha256$30000$tfhhpP2F6OVd$ORCbPCQXZCmtAx3vJ/G6+ZuHdHxKdsFoLYc4/h/8xhM=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.338Z", "username": "evelyn89", "name": "Tammy Scott", "email": "cheryl@oyoloo.org", "role": "User", "avatar": "", "wechat": "laura73", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.338Z", "created_by": "janice76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 47, "fields": {"password": "pbkdf2_sha256$30000$PPiqVLrlzdW6$2VKJ8gPkoeK0MdGc4ID53dRd+Wui/+ooGu3PRp/g9gQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.494Z", "username": "louise71", "name": "Marilyn Jenkins", "email": "judy@edgeify.mil", "role": "App", "avatar": "", "wechat": "andrea84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Fusce consequat.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.494Z", "created_by": "joan79", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 48, "fields": {"password": "pbkdf2_sha256$30000$w2ZrNpMmOX6a$6fmZIRAJwBLWHLKA7Wy2YTmSd0sVHRyWHVTe6I+riZY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.650Z", "username": "beverly64", "name": "Phyllis Garcia", "email": "lillian@realbridge.biz", "role": "User", "avatar": "", "wechat": "mary72", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.650Z", "created_by": "janice76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 49, "fields": {"password": "pbkdf2_sha256$30000$HxZSMFnsv4Ek$BMFKazKnc4hqxaF3tRhhst7NvxYJ3/nNoyzOpq3PvII=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.804Z", "username": "judy93", "name": "Debra Jenkins", "email": "michelle@eazzy.info", "role": "User", "avatar": "", "wechat": "anne83", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.804Z", "created_by": "janice65", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 50, "fields": {"password": "pbkdf2_sha256$30000$wqiyDiEfjvrL$hjjzEal4ElxSAZJ0CC0bQFDaCotzEF6e3JwbqR/X1UY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:30.957Z", "username": "joyce82", "name": "Amy Reed", "email": "janice@voolith.biz", "role": "App", "avatar": "", "wechat": "robin75", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean sit amet justo.", "is_first_login": false, "date_expired": "2086-12-21T12:52:30.957Z", "created_by": "kelly66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 51, "fields": {"password": "pbkdf2_sha256$30000$tg88PTs6h0Ii$ILSjXDiJIlC4O7pJwj/XWV6rFUzXAY12oXVlvxATa1M=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:31.116Z", "username": "sandra81", "name": "Lillian Payne", "email": "cheryl@linkbuzz.edu", "role": "App", "avatar": "", "wechat": "julie79", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.", "is_first_login": false, "date_expired": "2086-12-21T12:52:31.116Z", "created_by": "kelly78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 52, "fields": {"password": "pbkdf2_sha256$30000$CruNvtP7dOvB$9KzqRVkQsSve9ptXGdsJTVeE9+BgMAUwhovJTEPRDAE=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:31.280Z", "username": "jean73", "name": "Virginia Turner", "email": "susan@twitterlist.info", "role": "Admin", "avatar": "", "wechat": "sharon63", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla dapibus dolor vel est.", "is_first_login": false, "date_expired": "2086-12-21T12:52:31.280Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 53, "fields": {"password": "pbkdf2_sha256$30000$lx7rSljUmTUQ$CUSqr7UKUoXs/OP2DVnWl+ICeaEi0a3i11Uxt5xqSEw=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:31.443Z", "username": "alice93", "name": "Patricia Ray", "email": "tammy@livepath.mil", "role": "User", "avatar": "", "wechat": "joan82", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "In quis justo.", "is_first_login": false, "date_expired": "2086-12-21T12:52:31.443Z", "created_by": "joan79", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 54, "fields": {"password": "pbkdf2_sha256$30000$llTppeKQ5OTB$U2i0VTCl9zbxeJTsgje3Rn3MJ7XoyweQZA60BwGgFA0=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:31.602Z", "username": "alice77", "name": "Diana Griffin", "email": "gloria@meevee.org", "role": "User", "avatar": "", "wechat": "jessica86", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Duis at velit eu est congue elementum.", "is_first_login": false, "date_expired": "2086-12-21T12:52:31.602Z", "created_by": "laura93", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 55, "fields": {"password": "pbkdf2_sha256$30000$5xI7sT7s6TdH$dS3Wr2FlRaq7TiINiIo76h1xkcQL2jyaFirUiO2xWXM=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:31.768Z", "username": "alice86", "name": "Sandra Price", "email": "theresa@brainlounge.biz", "role": "User", "avatar": "", "wechat": "irene67", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla facilisi.", "is_first_login": false, "date_expired": "2086-12-21T12:52:31.768Z", "created_by": "robin79", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 56, "fields": {"password": "pbkdf2_sha256$30000$KjeEox7RGgi7$q818zeHdhnWBTLd0TE2VqUvJddk6fai38TMOotLmYdo=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:32.130Z", "username": "susan81", "name": "Martha Ellis", "email": "doris@dablist.name", "role": "Admin", "avatar": "", "wechat": "judith81", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci.", "is_first_login": false, "date_expired": "2086-12-21T12:52:32.130Z", "created_by": "admin", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 57, "fields": {"password": "pbkdf2_sha256$30000$TeGYJw754qBz$ExxZf2zoqQ0+G44x0RzNASGwpRnXfJE3mDTUTM5w3Co=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:32.316Z", "username": "ruby86", "name": "Lillian Henry", "email": "paula@skimia.gov", "role": "User", "avatar": "", "wechat": "lisa64", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Maecenas tincidunt lacus at velit.", "is_first_login": false, "date_expired": "2086-12-21T12:52:32.316Z", "created_by": "ann82", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 58, "fields": {"password": "pbkdf2_sha256$30000$cQkJFr3ZTlfB$fzP468HCkphZApoT7ZNKgYhPJF/vFZ5oeTSqmi4LI+U=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:32.602Z", "username": "janice64", "name": "Catherine Taylor", "email": "deborah@rhynyx.gov", "role": "Admin", "avatar": "", "wechat": "kathleen88", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Integer ac neque.", "is_first_login": false, "date_expired": "2086-12-21T12:52:32.602Z", "created_by": "evelyn89", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 59, "fields": {"password": "pbkdf2_sha256$30000$8B71milYawg5$dYJvDULSFcW11C/UuAB4TTNtBtZPwHxU9d3gs2TUbek=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:32.790Z", "username": "sarah83", "name": "Frances Murphy", "email": "tammy@tavu.biz", "role": "Admin", "avatar": "", "wechat": "christina63", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "is_first_login": false, "date_expired": "2086-12-21T12:52:32.791Z", "created_by": "beverly76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 60, "fields": {"password": "pbkdf2_sha256$30000$LtBKybiJ2q20$4pGyxfhLNf+wN6Flo+/YKexyNT8bqu/GNHsL9RxIj0k=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:32.973Z", "username": "anna89", "name": "Virginia Black", "email": "irene@kwilith.biz", "role": "User", "avatar": "", "wechat": "maria76", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean sit amet justo.", "is_first_login": false, "date_expired": "2086-12-21T12:52:32.973Z", "created_by": "beverly76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 61, "fields": {"password": "pbkdf2_sha256$30000$yZq5QyHlU5m9$hj9t0M0gK8clW95GGdrMjRY+J00l9RoTtpzPKHL5SQs=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:33.150Z", "username": "julie79", "name": "Jacqueline Austin", "email": "louise@dabfeed.biz", "role": "Admin", "avatar": "", "wechat": "donna81", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla tempus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:33.150Z", "created_by": "paula88", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 62, "fields": {"password": "pbkdf2_sha256$30000$WfKCFU6X0VkZ$QCMrUUMMyuqBMO9m/jNxBot656J+j3e2pCi3CXH5CeY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:33.332Z", "username": "sarah82", "name": "Ruby Diaz", "email": "carolyn@jabbersphere.name", "role": "App", "avatar": "", "wechat": "catherine66", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Pellentesque at nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:33.333Z", "created_by": "catherine90", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 63, "fields": {"password": "pbkdf2_sha256$30000$FE3SjWCoXrsK$f9q7mftDUCo0pc2Uldt8EXddQDykjxDGdlcbT56layA=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:33.511Z", "username": "elizabeth89", "name": "Kathleen Simpson", "email": "beverly@blogspan.biz", "role": "App", "avatar": "", "wechat": "teresa66", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam dui.", "is_first_login": false, "date_expired": "2086-12-21T12:52:33.511Z", "created_by": "anna89", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 64, "fields": {"password": "pbkdf2_sha256$30000$LNzJwHfega6R$D4JFOQGleYEto6UoKFjCJCvKYnfooW15PbveajBkbdg=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:33.670Z", "username": "carol76", "name": "Annie Ray", "email": "doris@skinte.gov", "role": "App", "avatar": "", "wechat": "anne92", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Fusce congue, diam id ornare imperdiet, sapien urna pretium nisl, ut volutpat sapien arcu sed augue.", "is_first_login": false, "date_expired": "2086-12-21T12:52:33.670Z", "created_by": "alice86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 65, "fields": {"password": "pbkdf2_sha256$30000$W4LaaippsgHG$06mSsGuWdcfOKopupu87jKGGBnopwWRSgaetuK2gvUE=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:33.844Z", "username": "heather87", "name": "Melissa Jordan", "email": "sarah@roodel.edu", "role": "User", "avatar": "", "wechat": "lois78", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.", "is_first_login": false, "date_expired": "2086-12-21T12:52:33.844Z", "created_by": "judy93", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 66, "fields": {"password": "pbkdf2_sha256$30000$V40F9UBQ7kIh$79Mmu5Mr5d4xSJeox1tCxr0sGXPWpfcw8VNIYaGr04k=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:34.023Z", "username": "lillian76", "name": "Judy Ramirez", "email": "michelle@ntags.biz", "role": "Admin", "avatar": "", "wechat": "anna72", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec ut mauris eget massa tempor convallis.", "is_first_login": false, "date_expired": "2086-12-21T12:52:34.023Z", "created_by": "jessica94", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 67, "fields": {"password": "pbkdf2_sha256$30000$EitWtsVzBkwD$WLBwVYdrPaY406UNpcHOgGurcGXnqL0ezEmsAUeLHvc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:34.191Z", "username": "jennifer74", "name": "Shirley Lewis", "email": "evelyn@oba.info", "role": "Admin", "avatar": "", "wechat": "sara81", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Proin at turpis a pede posuere nonummy.", "is_first_login": false, "date_expired": "2086-12-21T12:52:34.191Z", "created_by": "susan81", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 68, "fields": {"password": "pbkdf2_sha256$30000$pu9htijpdzFJ$a39FbTT8eS3FTIzGB5EnUApMfJ5UGecbMhvzyCVl1FY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:34.352Z", "username": "evelyn86", "name": "Beverly Armstrong", "email": "jessica@trunyx.biz", "role": "Admin", "avatar": "", "wechat": "margaret80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla justo.", "is_first_login": false, "date_expired": "2086-12-21T12:52:34.352Z", "created_by": "ann82", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 69, "fields": {"password": "pbkdf2_sha256$30000$EmaO9AD7S2R6$VjjM+HRxfGzTVsMu6Nbr2yCZgj42ZPZwQNmSStKyAfo=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:34.691Z", "username": "judy80", "name": "Debra Ford", "email": "stephanie@vinte.info", "role": "Admin", "avatar": "", "wechat": "denise80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean auctor gravida sem.", "is_first_login": false, "date_expired": "2086-12-21T12:52:34.692Z", "created_by": "tammy86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 70, "fields": {"password": "pbkdf2_sha256$30000$F8BFfWD00Kem$fwGYdZCPM8RQz4Dn/b8O2iZLlw/ZKriO+2lyyCj+MRU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:34.865Z", "username": "angela86", "name": "Lois Garrett", "email": "judith@photofeed.name", "role": "Admin", "avatar": "", "wechat": "maria69", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec ut mauris eget massa tempor convallis.", "is_first_login": false, "date_expired": "2086-12-21T12:52:34.865Z", "created_by": "andrea78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 71, "fields": {"password": "pbkdf2_sha256$30000$yuARiwRGX5KM$XGe+zvbDx7OgNevaQ1e+IQYzto9HGso4ArsAU2NPneY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:35.116Z", "username": "janet93", "name": "Frances Greene", "email": "maria@dynazzy.net", "role": "Admin", "avatar": "", "wechat": "karen67", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Integer a nibh.", "is_first_login": false, "date_expired": "2086-12-21T12:52:35.116Z", "created_by": "pamela77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 72, "fields": {"password": "pbkdf2_sha256$30000$cV4VdBuf34IH$FcmU2NNw1IPgMJB52lDcu1mgr5D2pspsJNI6Npu9NQk=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:35.336Z", "username": "janice70", "name": "Phyllis Robinson", "email": "norma@zoombeat.edu", "role": "Admin", "avatar": "", "wechat": "stephanie88", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nunc rhoncus dui vel sem.", "is_first_login": false, "date_expired": "2086-12-21T12:52:35.336Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 73, "fields": {"password": "pbkdf2_sha256$30000$WdsdwzsYISRj$Cdx+uX71Ve2oPUXw8qL+IwpaREoa6S998pDZ0+heLRs=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:35.511Z", "username": "teresa83", "name": "Theresa Brooks", "email": "amy@jayo.name", "role": "App", "avatar": "", "wechat": "jean63", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Pellentesque at nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:35.511Z", "created_by": "judy73", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 74, "fields": {"password": "pbkdf2_sha256$30000$Y4bm1G8Y8UGA$fpYpO2Nmof8HY6H32ZlyTa1ynse96DbLM+v4wLVmFkc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:35.682Z", "username": "joyce83", "name": "Sara Stephens", "email": "michelle@youfeed.biz", "role": "User", "avatar": "", "wechat": "sandra74", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio.", "is_first_login": false, "date_expired": "2086-12-21T12:52:35.682Z", "created_by": "heather87", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 75, "fields": {"password": "pbkdf2_sha256$30000$zIQ5QlWXV6h3$u9wSHapv1vEZ96vHngXMdc2OyL+wn3OUg6PuDGSnrJw=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:35.848Z", "username": "ann81", "name": "Doris Berry", "email": "doris@quatz.gov", "role": "App", "avatar": "", "wechat": "deborah86", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nulla tempus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:35.848Z", "created_by": "lillian76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 76, "fields": {"password": "pbkdf2_sha256$30000$MbwwujjXk5gr$kuw4CRByFRci+e5Sew6YbIHy1zoqoexdphSgg6ptuiQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.019Z", "username": "carolyn90", "name": "Lois Perry", "email": "frances@aibox.com", "role": "App", "avatar": "", "wechat": "heather80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec quis orci eget orci vehicula condimentum.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.019Z", "created_by": "teresa83", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 77, "fields": {"password": "pbkdf2_sha256$30000$HyaYhcYaDCYB$AZ8q5NszGhX5nyOT1TNpEqcaeKjM4cX6+LLKXqbElvQ=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.216Z", "username": "cynthia65", "name": "Heather Jacobs", "email": "helen@twitterlist.edu", "role": "Admin", "avatar": "", "wechat": "maria63", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aenean auctor gravida sem.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.216Z", "created_by": "rachel83", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 78, "fields": {"password": "pbkdf2_sha256$30000$LkX2glKCejQw$sakufoenj9xKfZ4heQJLAs5pMQwYD3Upn6VlcmGmaEg=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.403Z", "username": "nicole64", "name": "Lori Warren", "email": "rose@skipfire.edu", "role": "Admin", "avatar": "", "wechat": "kelly69", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nullam sit amet turpis elementum ligula vehicula consequat.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.403Z", "created_by": "amanda70", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 79, "fields": {"password": "pbkdf2_sha256$30000$zw5gvUH3knFc$3jrUQzmkuD9hIPpK7qJ9L8vmqezH4lZ6PlrstNDwFyk=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.579Z", "username": "teresa80", "name": "Christina Garza", "email": "andrea@skaboo.mil", "role": "App", "avatar": "", "wechat": "janet93", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.580Z", "created_by": "christine89", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 80, "fields": {"password": "pbkdf2_sha256$30000$tSoZS23M4RcP$QDCvzicGcYRX3ll7/QPHqk4q4m1DwHq8fcPWC9xwk1I=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.740Z", "username": "ann78", "name": "Janice Hernandez", "email": "maria@miboo.net", "role": "Admin", "avatar": "", "wechat": "louise80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nunc purus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.740Z", "created_by": "tammy86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 81, "fields": {"password": "pbkdf2_sha256$30000$qodF8b2rsUwI$P10Ne68RKyZMfBBDYI6FBbsKGqoBYAwTfsesACU9+B8=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:36.902Z", "username": "norma69", "name": "Rose Nichols", "email": "sharon@cogibox.biz", "role": "User", "avatar": "", "wechat": "debra86", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Ut at dolor quis odio consequat varius.", "is_first_login": false, "date_expired": "2086-12-21T12:52:36.902Z", "created_by": "lillian76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 82, "fields": {"password": "pbkdf2_sha256$30000$kSn682qFdSQo$qnySA1YJIpwpYT77xP41DAfdxhWXwuux5/VV18Tc1pc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:37.065Z", "username": "andrea90", "name": "Maria Carter", "email": "norma@rhycero.org", "role": "App", "avatar": "", "wechat": "shirley80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Donec dapibus.", "is_first_login": false, "date_expired": "2086-12-21T12:52:37.065Z", "created_by": "catherine66", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 83, "fields": {"password": "pbkdf2_sha256$30000$uqLUdyj8ULjN$PO3VzMecerkrCL1x204DHBOBmRr4rrDYlJh94N97rV0=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:37.229Z", "username": "julia73", "name": "Elizabeth Kennedy", "email": "susan@wikibox.org", "role": "User", "avatar": "", "wechat": "ruby94", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ac est lacinia nisi venenatis tristique.", "is_first_login": false, "date_expired": "2086-12-21T12:52:37.229Z", "created_by": "carol76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 84, "fields": {"password": "pbkdf2_sha256$30000$d0zO0S5eJ7Vj$ZqbKl1w5PLc8I1yVoJsaiSabzuZTKizurwUIwzIpzCc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:37.397Z", "username": "lisa74", "name": "Maria Walker", "email": "andrea@midel.name", "role": "User", "avatar": "", "wechat": "laura67", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Pellentesque ultrices mattis odio.", "is_first_login": false, "date_expired": "2086-12-21T12:52:37.397Z", "created_by": "angela85", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 85, "fields": {"password": "pbkdf2_sha256$30000$lMcKNNYkTbe3$yDK3YYCr9vFtjNC1bR2smTO9GTyG12bS0+MWIbziMRc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:37.713Z", "username": "sara90", "name": "Norma Montgomery", "email": "bonnie@lajo.net", "role": "User", "avatar": "", "wechat": "ruby81", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aliquam quis turpis eget elit sodales scelerisque.", "is_first_login": false, "date_expired": "2086-12-21T12:52:37.713Z", "created_by": "kathy77", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 86, "fields": {"password": "pbkdf2_sha256$30000$RItOrQzBf06n$VhqoFLlG6F2esOjt/PZmBsaZvJlTyI5dsajwSXVCx1A=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:37.875Z", "username": "robin80", "name": "Christina Simmons", "email": "jacqueline@rhyzio.name", "role": "Admin", "avatar": "", "wechat": "alice84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Curabitur at ipsum ac tellus semper interdum.", "is_first_login": false, "date_expired": "2086-12-21T12:52:37.875Z", "created_by": "angela86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 87, "fields": {"password": "pbkdf2_sha256$30000$grbRl6fxuFcd$PwPRtf7Ir/a4K1WiKWNfdXZsFUDysK9pg+V9iBnkI5g=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.037Z", "username": "debra69", "name": "Julia Howell", "email": "stephanie@brainlounge.edu", "role": "User", "avatar": "", "wechat": "nicole91", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam tristique tortor eu pede.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.037Z", "created_by": "ann78", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 88, "fields": {"password": "pbkdf2_sha256$30000$t3OQuHszrevr$dds5JmCV9oAA/a0PMtvJ6j+gTzFQk6+U2gKyLv5EqNc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.203Z", "username": "martha76", "name": "Nicole Bell", "email": "michelle@realpoint.net", "role": "App", "avatar": "", "wechat": "barbara84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.203Z", "created_by": "alice84", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 89, "fields": {"password": "pbkdf2_sha256$30000$SLe6nPTTdkc7$V8vx2XTxptHqCryTCzqu33QZwLkASrsvbNDLU+/H6qo=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.374Z", "username": "amanda75", "name": "Ashley Mendoza", "email": "marilyn@meevee.info", "role": "App", "avatar": "", "wechat": "stephanie83", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.374Z", "created_by": "ruby86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 90, "fields": {"password": "pbkdf2_sha256$30000$MUkaDyYjimDW$VB9iQirPadB33Ddo4/fvG1A1n7XrcSOAdhYRFIcOIL4=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.550Z", "username": "marie81", "name": "Louise Hansen", "email": "phyllis@fliptune.net", "role": "User", "avatar": "", "wechat": "kathleen75", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Aliquam non mauris.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.550Z", "created_by": "alice86", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 91, "fields": {"password": "pbkdf2_sha256$30000$jywfr24yJ7av$sZQ2J9j9DNT9926NdOVkUDq5s+tOG9Ku2z1f46E2gFY=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.720Z", "username": "sara77", "name": "Amy Armstrong", "email": "kathleen@twinte.info", "role": "App", "avatar": "", "wechat": "marie69", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Nam dui.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.720Z", "created_by": "norma69", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 92, "fields": {"password": "pbkdf2_sha256$30000$ErSg6QiIIv6Y$rDVl4liwWVzUpJgpwV0NNlVzV7BnGZ1wQiStL7AoQXo=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:38.878Z", "username": "andrea76", "name": "Barbara Alexander", "email": "nancy@topiczoom.org", "role": "User", "avatar": "", "wechat": "rose80", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Proin at turpis a pede posuere nonummy.", "is_first_login": false, "date_expired": "2086-12-21T12:52:38.878Z", "created_by": "carol76", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 93, "fields": {"password": "pbkdf2_sha256$30000$hHj0RLZOrDyZ$NgfXqbNAf9yOJQ6Wwq0TqhfNO4lEO8mDobMs+GcvS0k=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:39.034Z", "username": "rose89", "name": "Helen Kelly", "email": "sandra@brainverse.biz", "role": "Admin", "avatar": "", "wechat": "emily67", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Quisque erat eros, viverra eget, congue eget, semper rutrum, nulla.", "is_first_login": false, "date_expired": "2086-12-21T12:52:39.034Z", "created_by": "julie79", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 94, "fields": {"password": "pbkdf2_sha256$30000$w7PrvuI8x9FD$jYBdtRm/i97vtnbhU3G2Ps6f0aQzUeqNScwMRP2Zpqw=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:39.193Z", "username": "alice82", "name": "Margaret Lopez", "email": "ruby@zoombeat.name", "role": "App", "avatar": "", "wechat": "carolyn66", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Praesent blandit.", "is_first_login": false, "date_expired": "2086-12-21T12:52:39.193Z", "created_by": "jessica94", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 95, "fields": {"password": "pbkdf2_sha256$30000$bihp9lOWgk9j$SxJ7HcHPBS1bXVWTuWyTKFMJhbqBXcK09gBpyEkcHeU=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:39.351Z", "username": "patricia82", "name": "Anna Bradley", "email": "diane@jabberstorm.gov", "role": "App", "avatar": "", "wechat": "frances84", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Morbi porttitor lorem id ligula.", "is_first_login": false, "date_expired": "2086-12-21T12:52:39.352Z", "created_by": "rachel83", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 96, "fields": {"password": "pbkdf2_sha256$30000$KvBh6zMbJgu7$AHAwvZvZUTYhlK5J7/d2W8GU4t5bQl+Jw/mAUkdQRVA=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2017-01-07T12:52:39.508Z", "username": "judith78", "name": "Bonnie Sims", "email": "ruby@leexo.biz", "role": "User", "avatar": "", "wechat": "andrea63", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", "is_first_login": false, "date_expired": "2086-12-21T12:52:39.508Z", "created_by": "paula88", "user_permissions": [], "groups": []}}, {"model": "users.user", "pk": 97, "fields": {"password": "", "last_login": null, "first_name": "", "last_name": "", "is_active": false, "date_joined": "2017-01-07T13:35:54.890Z", "username": "luna", "name": "luna", "email": "luna@jumpserver.org", "role": "App", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "", "is_first_login": false, "date_expired": "2086-12-21T13:35:54.890Z", "created_by": "System", "user_permissions": [], "groups": []}}, {"model": "applications.terminal", "pk": 1, "fields": {"name": "luna", "remote_addr": "127.0.0.1", "type": "Web", "user": null, "url": "", "is_accepted": true, "date_created": "2017-01-07T13:35:54.880Z", "comment": ""}}] diff --git a/apps/fixtures/init.json b/apps/fixtures/init.json new file mode 100644 index 000000000..8707430c9 --- /dev/null +++ b/apps/fixtures/init.json @@ -0,0 +1 @@ +[{"model": "users.usergroup", "pk": 1, "fields": {"is_discard": false, "discard_time": null, "name": "Default", "comment": "Default user group for all user", "date_created": "2016-11-25T06:50:28.410Z", "created_by": "System"}}, {"model": "assets.assetgroup", "pk": 1, "fields": {"name": "Default", "created_by": "", "date_created": "2016-11-25T06:50:28.627Z", "comment": "Default asset group", "system_users": []}}, {"model": "users.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$30000$RwSpXYAYQGbQ$PADpsQmM+cO5Y/R1CVSx3qNV4EbGIm2k+iMBXUtwvNc=", "last_login": null, "first_name": "", "last_name": "", "is_active": true, "date_joined": "2016-11-25T06:50:28.412Z", "username": "admin", "name": "Administrator", "email": "admin@jumpserver.org", "role": "Admin", "avatar": "", "wechat": "", "phone": null, "enable_otp": false, "secret_key_otp": "", "_private_key": "", "_public_key": "", "comment": "Administrator is the super user of system", "is_first_login": false, "date_expired": "2086-11-08T06:50:28.412Z", "created_by": "System", "user_permissions": [], "groups": [1]}}] \ No newline at end of file diff --git a/apps/jumpserver/__init__.py b/apps/jumpserver/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/jumpserver/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/jumpserver/middleware.py b/apps/jumpserver/middleware.py new file mode 100644 index 000000000..2ed94c6a8 --- /dev/null +++ b/apps/jumpserver/middleware.py @@ -0,0 +1,14 @@ +# ~*~ coding: utf-8 ~*~ + +import pytz +from django.utils import timezone +from django.utils.deprecation import MiddlewareMixin + + +class TimezoneMiddleware(MiddlewareMixin): + def process_request(self, request): + tzname = request.META.get('TZ') + if tzname: + timezone.activate(pytz.timezone(tzname)) + else: + timezone.deactivate() diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py new file mode 100644 index 000000000..758a93221 --- /dev/null +++ b/apps/jumpserver/settings.py @@ -0,0 +1,328 @@ +""" +Django settings for jumpserver project. + +Generated by 'django-admin startproject' using Django 1.10. + +For more information on this file, see +https://docs.djangoproject.com/en/1.10/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.10/ref/settings/ +""" + +import os +import sys + +from django.urls import reverse_lazy + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +PROJECT_DIR = os.path.dirname(BASE_DIR) + +sys.path.append(PROJECT_DIR) + +# Import project config setting +try: + from config import config as env_config, env + + CONFIG = env_config.get(env, 'default')() +except ImportError: + CONFIG = type('_', (), {'__getattr__': None})() + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = CONFIG.SECRET_KEY + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = CONFIG.DEBUG or False + + +# Absolute url for some case, for example email link +SITE_URL = CONFIG.SITE_URL or 'http://localhost' + + +# LOG LEVEL +LOG_LEVEL = 'DEBUG' if DEBUG else CONFIG.LOG_LEVEL or 'WARNING' + +ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or [] + +# Application definition + +INSTALLED_APPS = [ + 'users.apps.UsersConfig', + 'assets.apps.AssetsConfig', + 'perms.apps.PermsConfig', + 'ops.apps.OpsConfig', + 'audits.apps.AuditsConfig', + 'common.apps.CommonConfig', + 'applications.apps.ApplicationsConfig', + 'rest_framework', + 'bootstrapform', + 'captcha', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'jumpserver.middleware.TimezoneMiddleware', +] + +ROOT_URLCONF = 'jumpserver.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates'), ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.i18n', + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.static', + 'django.template.context_processors.request', + 'django.template.context_processors.media', + ], + }, + }, +] + +# WSGI_APPLICATION = 'jumpserver.wsgi.applications' + +LOGIN_REDIRECT_URL = reverse_lazy('index') +LOGIN_URL = reverse_lazy('users:login') + +# Database +# https://docs.djangoproject.com/en/1.10/ref/settings/#databases + +if CONFIG.DB_ENGINE == 'sqlite': + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': CONFIG.DB_NAME or os.path.join(BASE_DIR, 'db.sqlite3'), + } + } +else: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.%s' % CONFIG.DB_ENGINE, + 'NAME': CONFIG.DB_NAME, + 'HOST': CONFIG.DB_HOST, + 'PORT': CONFIG.DB_PORT, + 'USER': CONFIG.DB_USER, + 'PASSWORD': CONFIG.DB_PASSWORD, + } + } + +# Password validation +# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators +# +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Logging setting +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' + }, + 'main': { + 'datefmt': '%Y-%m-%d %H:%M:%S', + 'format': '%(asctime)s [%(module)s %(levelname)s] %(message)s', + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + }, + 'handlers': { + 'null': { + 'level': 'DEBUG', + 'class': 'logging.NullHandler', + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'main' + }, + 'file': { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'formatter': 'main', + 'filename': os.path.join(PROJECT_DIR, 'logs', 'jumpserver.log') + }, + 'ansible_logs': { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'formatter': 'main', + 'filename': os.path.join(PROJECT_DIR, 'logs', 'ansible.log') + }, + }, + 'loggers': { + 'django': { + 'handlers': ['null'], + 'propagate': False, + 'level': LOG_LEVEL, + }, + 'django.request': { + 'handlers': ['console', 'file'], + 'level': LOG_LEVEL, + 'propagate': False, + }, + 'django.server': { + 'handlers': ['console', 'file'], + 'level': LOG_LEVEL, + 'propagate': False, + }, + 'jumpserver': { + 'handlers': ['console', 'file'], + 'level': LOG_LEVEL, + }, + 'jumpserver.users.api': { + 'handlers': ['console', 'file'], + 'level': LOG_LEVEL, + }, + 'jumpserver.users.view': { + 'handlers': ['console', 'file'], + 'level': LOG_LEVEL, + }, + 'ops.ansible_api': { + 'handlers': ['console', 'ansible_logs'], + 'level': LOG_LEVEL, + } + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.10/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# I18N translation +LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'), ] + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + +STATIC_URL = '/static/' + +STATICFILES_DIRS = ( + os.path.join(BASE_DIR, "static"), +) + +# Media files (File, ImageField) will be save these + +MEDIA_URL = '/media/' + +MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/') + '/' + +# Use django-bootstrap-form to format template, input max width arg +BOOTSTRAP_COLUMN_COUNT = 11 + +# Init data or generate fake data source for development +FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ] + +# Email config +EMAIL_HOST = CONFIG.EMAIL_HOST +EMAIL_PORT = CONFIG.EMAIL_PORT +EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER +EMAIL_HOST_PASSWORD = CONFIG.EMAIL_HOST_PASSWORD +EMAIL_USE_SSL = CONFIG.EMAIL_USE_SSL +EMAIL_USE_TLS = CONFIG.EMAIL_USE_TLS +EMAIL_SUBJECT_PREFIX = CONFIG.EMAIL_SUBJECT_PREFIX + +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': ( + 'users.permissions.IsSuperUser', + ), + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'users.authentication.AccessKeyAuthentication', + 'users.authentication.AccessTokenAuthentication', + 'users.authentication.PrivateTokenAuthentication', + 'users.authentication.SessionAuthentication', + ), + # 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',), +} + +# Custom User Auth model +AUTH_USER_MODEL = 'users.User' + +# Celery using redis as broker +BROKER_URL = 'redis://%(password)s%(host)s:%(port)s/3' % { + 'password': CONFIG.REDIS_PASSWORD + ':' if CONFIG.REDIS_PASSWORD else '', + 'host': CONFIG.REDIS_HOST or '127.0.0.1', + 'port': CONFIG.REDIS_PORT or 6379, +} +CELERY_RESULT_BACKEND = BROKER_URL + +# TERMINAL_HEATBEAT_INTERVAL = CONFIG.TERMINAL_HEATBEAT_INTERVAL or 30 + +# crontab job +# CELERYBEAT_SCHEDULE = { +# Check applications is alive every 10m +# 'check_terminal_alive': { +# 'task': 'applications.tasks.check_terminal_alive', +# 'schedule': timedelta(seconds=TERMINAL_HEATBEAT_INTERVAL), +# 'args': (), +# }, +# } + + +# Cache use redis +CACHES = { + 'default': { + 'BACKEND': 'redis_cache.RedisCache', + 'LOCATION': 'redis://%(password)s%(host)s:%(port)s/4' % { + 'password': CONFIG.REDIS_PASSWORD + '@' if CONFIG.REDIS_PASSWORD else '', + 'host': CONFIG.REDIS_HOST or '127.0.0.1', + 'port': CONFIG.REDIS_PORT or 6379, + } + } +} + +# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html +CAPTCHA_IMAGE_SIZE = (75, 33) +CAPTCHA_FOREGROUND_COLOR = '#001100' + +COMMAND_STORE_BACKEND = 'audits.backends.command.db' +RECORD_STORE_BACKEND = 'audits.backends.record.db' +CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE diff --git a/apps/jumpserver/urls.py b/apps/jumpserver/urls.py new file mode 100644 index 000000000..e49bafb67 --- /dev/null +++ b/apps/jumpserver/urls.py @@ -0,0 +1,48 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +"""jumpserver URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.10/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import url, include +from django.conf import settings +from django.conf.urls.static import static +from django.views.generic.base import TemplateView + + +urlpatterns = [ + url(r'^captcha/', include('captcha.urls')), + url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'), + url(r'^users/', include('users.urls.views_urls', namespace='users')), + url(r'^assets/', include('assets.urls.views_urls', namespace='assets')), + url(r'^perms/', include('perms.urls.views_urls', namespace='perms')), + url(r'^audits/', include('audits.urls.views_urls', namespace='audits')), + url(r'^applications/', include('applications.urls.views_urls', namespace='applications')), + url(r'^ops/', include('ops.urls.view_urls', namespace='ops')), + + # Api url view map + url(r'^api/users/', include('users.urls.api_urls', namespace='api-users')), + url(r'^api/assets/', include('assets.urls.api_urls', namespace='api-assets')), + url(r'^api/perms/', include('perms.urls.api_urls', namespace='api-perms')), + url(r'^api/audits/', include('audits.urls.api_urls', namespace='api-audits')), + url(r'^api/applications/', include('applications.urls.api_urls', namespace='api-applications')), + url(r'^api/ops/', include('ops.urls.api_urls', namespace='api-ops')), + +] + + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + diff --git a/apps/jumpserver/views.py b/apps/jumpserver/views.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/jumpserver/wsgi.py b/apps/jumpserver/wsgi.py new file mode 100644 index 000000000..16f477b3f --- /dev/null +++ b/apps/jumpserver/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for jumpserver project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings") + +application = get_wsgi_application() diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo new file mode 100644 index 000000000..a04d6205c Binary files /dev/null and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po new file mode 100644 index 000000000..cda86f2c0 --- /dev/null +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -0,0 +1,2371 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Jumpserver 0.3.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-22 21:30+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: ibuler \n" +"Language-Team: Jumpserver team\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: assets/forms.py:53 assets/forms.py:208 +#: assets/templates/assets/admin_user_detail.html:191 perms/forms.py:27 +#: perms/templates/perms/asset_permission_asset.html:139 users/forms.py:124 +msgid "Select asset groups" +msgstr "添加到资产组" + +#: assets/forms.py:56 +#, fuzzy +#| msgid "Select assets" +msgid "Select asset tags" +msgstr "选择资产" + +#: assets/forms.py:58 +#, fuzzy +#| msgid "System user" +msgid "Select asset system users" +msgstr "系统" + +#: assets/forms.py:59 +#, fuzzy +#| msgid "Select assets" +msgid "Select asset admin user" +msgstr "选择资产" + +#: assets/forms.py:71 assets/forms.py:107 assets/forms.py:140 +#: assets/forms.py:198 assets/forms.py:270 +#: perms/templates/perms/asset_permission_create_update.html:40 +#: templates/_nav.html:21 +msgid "Asset" +msgstr "资产" + +#: assets/forms.py:74 assets/forms.py:110 assets/forms.py:143 +#: assets/forms.py:201 assets/forms.py:273 perms/forms.py:25 users/forms.py:122 +msgid "Select assets" +msgstr "选择资产" + +#: assets/forms.py:96 +#, fuzzy +#| msgid "System user" +msgid "Select asset system user" +msgstr "系统" + +#: assets/forms.py:129 assets/forms.py:186 assets/forms.py:258 +#: assets/models.py:15 assets/models.py:94 assets/models.py:159 +#: assets/models.py:243 assets/templates/assets/admin_user_detail.html:46 +#: assets/templates/assets/admin_user_list.html:10 +#: assets/templates/assets/asset_group_detail.html:46 +#: assets/templates/assets/asset_group_list.html:12 +#: assets/templates/assets/idc_list.html:12 +#: assets/templates/assets/system_user_asset_group.html:53 +#: assets/templates/assets/system_user_detail.html:51 +#: assets/templates/assets/system_user_list.html:10 ops/models.py:18 +#: ops/models.py:36 ops/models.py:48 ops/models.py:65 ops/models.py:397 +#: ops/templates/cron/list.html:26 ops/templates/sudo/list.html:26 +#: perms/models.py:19 +#: perms/templates/perms/asset_permission_create_update.html:33 +#: perms/templates/perms/asset_permission_detail.html:56 +#: perms/templates/perms/asset_permission_list.html:12 +#: perms/templates/perms/asset_permission_user.html:66 users/models.py:23 +#: users/models.py:75 users/templates/users/_select_user_modal.html:13 +#: users/templates/users/user_asset_permission.html:66 +#: users/templates/users/user_detail.html:58 +#: users/templates/users/user_granted_asset.html:129 +#: users/templates/users/user_group_detail.html:90 +#: users/templates/users/user_group_list.html:25 +#: users/templates/users/user_list.html:26 +msgid "Name" +msgstr "名称" + +#: assets/forms.py:148 assets/forms.py:213 +msgid "If also set private key, use that first" +msgstr "如果设置私钥,则优先使用私钥" + +#: assets/forms.py:187 assets/forms.py:259 assets/models.py:95 +#: assets/models.py:160 assets/templates/assets/admin_user_detail.html:50 +#: assets/templates/assets/admin_user_list.html:11 +#: assets/templates/assets/system_user_detail.html:55 +#: assets/templates/assets/system_user_list.html:11 +#: ops/templates/cron/list.html:27 ops/templates/sudo/list.html:27 +#: perms/templates/perms/asset_permission_user.html:67 users/forms.py:13 +#: users/models.py:74 users/templates/users/_select_user_modal.html:14 +#: users/templates/users/login.html:53 +#: users/templates/users/user_detail.html:62 +#: users/templates/users/user_list.html:27 +#: users/templates/users/user_update.html:6 +msgid "Username" +msgstr "用户名" + +#: assets/forms.py:204 templates/_nav.html:22 +msgid "Asset group" +msgstr "资产组" + +#: assets/models.py:16 +msgid "Bandwidth" +msgstr "带宽" + +#: assets/models.py:17 assets/templates/assets/idc_list.html:14 +msgid "Contact" +msgstr "联系人" + +#: assets/models.py:18 assets/templates/assets/idc_list.html:15 +#: users/models.py:81 users/templates/users/user_detail.html:71 +msgid "Phone" +msgstr "手机" + +#: assets/models.py:19 +msgid "Address" +msgstr "地址" + +#: assets/models.py:20 +msgid "Intranet" +msgstr "" + +#: assets/models.py:21 +msgid "Extranet" +msgstr "" + +#: assets/models.py:22 assets/models.py:246 assets/models.py:324 +msgid "Date added" +msgstr "加入日期" + +#: assets/models.py:23 +msgid "Operator" +msgstr "运营商" + +#: assets/models.py:24 assets/models.py:64 assets/models.py:102 +#: assets/models.py:173 assets/models.py:245 assets/models.py:322 +#: assets/models.py:370 assets/templates/assets/admin_user_detail.html:58 +#: assets/templates/assets/asset_detail.html:114 +#: assets/templates/assets/asset_group_detail.html:54 +#: assets/templates/assets/asset_tag_detail.html:49 +#: assets/templates/assets/system_user_detail.html:101 perms/models.py:29 +#: perms/templates/perms/asset_permission_detail.html:88 users/models.py:90 +#: users/templates/users/user_detail.html:90 +msgid "Created by" +msgstr "创建者" + +#: assets/models.py:25 assets/models.py:66 assets/models.py:100 +#: assets/models.py:174 assets/models.py:247 assets/models.py:325 +#: assets/templates/assets/admin_user_detail.html:62 +#: assets/templates/assets/admin_user_list.html:14 +#: assets/templates/assets/asset_detail.html:122 +#: assets/templates/assets/asset_group_detail.html:58 +#: assets/templates/assets/asset_group_list.html:14 +#: assets/templates/assets/system_user_asset_group.html:56 +#: assets/templates/assets/system_user_detail.html:105 +#: assets/templates/assets/system_user_list.html:15 perms/models.py:31 +#: perms/templates/perms/asset_permission_detail.html:92 users/models.py:24 +#: users/models.py:86 users/templates/users/user_detail.html:102 +#: users/templates/users/user_group_detail.html:94 +#: users/templates/users/user_group_list.html:28 +msgid "Comment" +msgstr "备注" + +#: assets/models.py:32 assets/models.py:257 +#, fuzzy +#| msgid "As default" +msgid "Default" +msgstr "默认使用" + +#: assets/models.py:32 users/models.py:224 +msgid "System" +msgstr "系统" + +#: assets/models.py:32 +#, fuzzy +#| msgid "As default" +msgid "Default IDC" +msgstr "默认使用" + +#: assets/models.py:62 +msgid "KEY" +msgstr "KEY" + +#: assets/models.py:63 +msgid "VALUE" +msgstr "VALUE" + +#: assets/models.py:74 assets/models.py:75 +msgid "status" +msgstr "状态" + +#: assets/models.py:74 +#, fuzzy +#| msgid "Admin user" +msgid "In use" +msgstr "管理用户" + +#: assets/models.py:75 +#, fuzzy +#| msgid "Auto push" +msgid "Out of use" +msgstr "自动推送" + +#: assets/models.py:76 assets/models.py:77 assets/models.py:78 +#: assets/models.py:79 assets/models.py:80 assets/models.py:81 +msgid "type" +msgstr "" + +#: assets/models.py:76 +msgid "Server" +msgstr "" + +#: assets/models.py:77 +msgid "VM" +msgstr "" + +#: assets/models.py:78 +msgid "Switch" +msgstr "" + +#: assets/models.py:79 +#, fuzzy +#| msgid "Role" +msgid "Router" +msgstr "角色" + +#: assets/models.py:80 +msgid "Firewall" +msgstr "" + +#: assets/models.py:81 +msgid "Storage" +msgstr "" + +#: assets/models.py:82 assets/models.py:83 assets/models.py:84 +msgid "env" +msgstr "" + +#: assets/models.py:82 +msgid "Production" +msgstr "" + +#: assets/models.py:83 +msgid "Development" +msgstr "" + +#: assets/models.py:84 +#, fuzzy +msgid "Testing" +msgstr "设置" + +#: assets/models.py:96 assets/models.py:161 users/forms.py:15 +#: users/templates/users/login.html:56 +#: users/templates/users/reset_password.html:52 +#: users/templates/users/user_create.html:9 +#: users/templates/users/user_create.html:11 +#: users/templates/users/user_update.html:13 +#: users/templates/users/user_update.html:15 +msgid "Password" +msgstr "密码" + +#: assets/models.py:97 assets/models.py:163 +msgid "SSH private key" +msgstr "ssh密钥" + +#: assets/models.py:98 assets/models.py:164 +msgid "SSH public key" +msgstr "ssh公钥" + +#: assets/models.py:99 assets/models.py:165 +#: assets/templates/assets/admin_user_create_update.html:43 +#: assets/templates/assets/system_user_create_update.html:44 +#: assets/templates/assets/system_user_detail.html:71 +msgid "As default" +msgstr "默认使用" + +#: assets/models.py:162 assets/templates/assets/system_user_detail.html:59 +msgid "Protocol" +msgstr "协议" + +#: assets/models.py:166 +#: assets/templates/assets/system_user_create_update.html:50 +#: assets/templates/assets/system_user_detail.html:63 +msgid "Auto push" +msgstr "自动推送" + +#: assets/models.py:167 +msgid "Auto update pass/key" +msgstr "自动更新密码/密钥" + +#: assets/models.py:168 assets/templates/assets/system_user_detail.html:75 +#: templates/_nav.html:46 +msgid "Sudo" +msgstr "Sudo" + +#: assets/models.py:169 assets/templates/assets/system_user_detail.html:80 +msgid "Shell" +msgstr "Shell" + +#: assets/models.py:170 assets/templates/assets/system_user_detail.html:86 +#: templates/_header_bar.html:41 templates/_nav.html:4 +msgid "Home" +msgstr "仪表盘" + +#: assets/models.py:171 assets/templates/assets/system_user_detail.html:92 +msgid "Uid" +msgstr "Uid" + +#: assets/models.py:257 +#, fuzzy +#| msgid "Create asset group" +msgid "Default asset group" +msgstr "创建资产组" + +#: assets/models.py:291 assets/templates/assets/admin_user_detail.html:92 +#: assets/templates/assets/asset_detail.html:54 +#: assets/templates/assets/asset_group_detail.html:88 +#: assets/templates/assets/asset_list.html:58 +#: assets/templates/assets/asset_tag_detail.html:84 +#: assets/templates/assets/system_user_asset.html:50 +#: perms/templates/perms/asset_permission_asset.html:67 +#: users/templates/users/user_granted_asset.html:67 +msgid "IP" +msgstr "IP" + +#: assets/models.py:292 assets/templates/assets/asset_detail.html:58 +msgid "Other IP" +msgstr "其它IP" + +#: assets/models.py:293 assets/templates/assets/asset_detail.html:62 +msgid "Remote card IP" +msgstr "远控卡IP" + +#: assets/models.py:294 assets/templates/assets/admin_user_detail.html:91 +#: assets/templates/assets/asset_detail.html:50 +#: assets/templates/assets/asset_group_detail.html:87 +#: assets/templates/assets/asset_list.html:57 +#: assets/templates/assets/asset_tag_detail.html:83 +#: assets/templates/assets/system_user_asset.html:49 +#: perms/templates/perms/asset_permission_asset.html:66 +#: users/templates/users/user_granted_asset.html:66 +msgid "Hostname" +msgstr "主机名" + +#: assets/models.py:295 assets/templates/assets/admin_user_detail.html:93 +#: assets/templates/assets/asset_detail.html:66 +#: assets/templates/assets/asset_group_detail.html:89 +#: assets/templates/assets/asset_list.html:59 +#: assets/templates/assets/asset_tag_detail.html:85 +#: assets/templates/assets/system_user_asset.html:51 +#: perms/templates/perms/asset_permission_asset.html:68 +#: users/templates/users/user_granted_asset.html:68 +msgid "Port" +msgstr "端口" + +#: assets/models.py:296 assets/templates/assets/asset_detail.html:184 +msgid "Asset groups" +msgstr "用户组" + +#: assets/models.py:298 templates/_nav.html:24 +msgid "Admin user" +msgstr "管理用户" + +#: assets/models.py:299 +msgid "System User" +msgstr "系统用户" + +#: assets/models.py:301 templates/_nav.html:23 +msgid "IDC" +msgstr "机房" + +#: assets/models.py:303 assets/templates/assets/asset_detail.html:70 +msgid "Mac address" +msgstr "Mac地址" + +#: assets/models.py:304 +msgid "Brand" +msgstr "品牌" + +#: assets/models.py:305 assets/templates/assets/asset_detail.html:74 +msgid "CPU" +msgstr "CPU" + +#: assets/models.py:306 assets/templates/assets/asset_detail.html:78 +msgid "Memory" +msgstr "内存" + +#: assets/models.py:307 assets/templates/assets/asset_detail.html:82 +msgid "Disk" +msgstr "硬盘" + +#: assets/models.py:308 assets/templates/assets/asset_detail.html:86 +msgid "OS" +msgstr "操作系统" + +#: assets/models.py:309 +msgid "Cabinet number" +msgstr "机柜编号" + +#: assets/models.py:310 +msgid "Cabinet position" +msgstr "机柜层号" + +#: assets/models.py:311 assets/templates/assets/asset_detail.html:110 +msgid "Asset number" +msgstr "资产编号" + +#: assets/models.py:313 assets/templates/assets/asset_detail.html:90 +msgid "Asset status" +msgstr "资产状态" + +#: assets/models.py:316 assets/templates/assets/asset_detail.html:98 +msgid "Asset type" +msgstr "系统类型" + +#: assets/models.py:319 assets/templates/assets/asset_detail.html:102 +msgid "Asset environment" +msgstr "资产环境" + +#: assets/models.py:321 assets/templates/assets/asset_detail.html:106 +msgid "Serial number" +msgstr "序列号" + +#: assets/models.py:323 assets/templates/assets/asset_detail.html:94 +msgid "Is active" +msgstr "是否激活" + +#: assets/templates/assets/admin_user_create_update.html:16 +#: assets/templates/assets/admin_user_list.html:5 +#, fuzzy +#| msgid "Create user" +msgid "Create admin user" +msgstr "创建用户" + +#: assets/templates/assets/admin_user_create_update.html:35 +#: assets/templates/assets/system_user_create_update.html:36 +#, fuzzy +#| msgid "Auto update pass/key" +msgid "Auto generate key" +msgstr "自动更新密码/密钥" + +#: assets/templates/assets/admin_user_create_update.html:53 +#: assets/templates/assets/admin_user_detail.html:144 +#: assets/templates/assets/asset_create.html:33 +#: assets/templates/assets/asset_update.html:61 +#: assets/templates/assets/system_user_create_update.html:71 +#: assets/templates/assets/system_user_detail.html:144 +#: perms/templates/perms/asset_permission_create_update.html:67 +#: users/templates/users/_user.html:70 +#: users/templates/users/user_detail.html:151 +#: users/templates/users/user_detail.html:159 +msgid "Reset" +msgstr "重置" + +#: assets/templates/assets/admin_user_create_update.html:54 +#: assets/templates/assets/asset_create.html:34 +#: assets/templates/assets/asset_group_list.html:51 +#: assets/templates/assets/asset_list.html:105 +#: assets/templates/assets/asset_tags_list.html:50 +#: assets/templates/assets/asset_update.html:62 +#: assets/templates/assets/system_user_create_update.html:72 +#: ops/templates/cron/list.html:47 ops/templates/sudo/list.html:47 +#: perms/templates/perms/asset_permission_create_update.html:68 +#: perms/templates/perms/asset_permission_list.html:65 +#: users/templates/users/_user.html:71 +#: users/templates/users/forgot_password.html:44 +#: users/templates/users/user_asset_permission.html:144 +#: users/templates/users/user_group_list.html:40 +#: users/templates/users/user_list.html:47 +msgid "Submit" +msgstr "提交" + +#: assets/templates/assets/admin_user_detail.html:19 +#: assets/templates/assets/asset_group_detail.html:18 +#: assets/templates/assets/asset_tag_detail.html:18 +#: assets/templates/assets/system_user_asset.html:19 +#: assets/templates/assets/system_user_asset_group.html:19 +#: assets/templates/assets/system_user_detail.html:19 +#: perms/templates/perms/asset_permission_asset.html:20 +#: perms/templates/perms/asset_permission_detail.html:20 +#: perms/templates/perms/asset_permission_user.html:20 +msgid "Detail" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:54 +#: assets/templates/assets/asset_group_detail.html:50 +#: assets/templates/assets/asset_tag_detail.html:53 +#: assets/templates/assets/system_user_detail.html:97 perms/models.py:30 +#: perms/templates/perms/asset_permission_detail.html:84 +#, fuzzy +#| msgid "Date added" +msgid "Date created" +msgstr "加入日期" + +#: assets/templates/assets/admin_user_detail.html:72 +#: assets/templates/assets/asset_group_detail.html:68 +#: assets/templates/assets/asset_tag_detail.html:64 +#: assets/templates/assets/system_user_asset_group.html:34 +#: perms/templates/perms/asset_permission_asset.html:47 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset list of " +msgstr "资产组列表" + +#: assets/templates/assets/admin_user_detail.html:94 +#: assets/templates/assets/asset_group_detail.html:90 +#: assets/templates/assets/asset_tag_detail.html:86 +#, fuzzy +msgid "Alive" +msgstr "激活" + +#: assets/templates/assets/admin_user_detail.html:117 +#: assets/templates/assets/system_user_detail.html:117 +#: perms/templates/perms/asset_permission_detail.html:104 +msgid "Quick update" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:123 +msgid "Get install script" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:126 +#: assets/templates/assets/system_user_detail.html:126 +msgid "Get" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:132 +#: assets/templates/assets/system_user_detail.html:132 +#: perms/templates/perms/asset_permission_detail.html:124 +msgid "Retest asset connectivity" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:135 +#: assets/templates/assets/system_user_detail.html:135 +#: perms/templates/perms/asset_permission_detail.html:127 +msgid "Start" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:141 +#: assets/templates/assets/system_user_detail.html:141 +#, fuzzy +#| msgid "ssh private key" +msgid "Reset private key" +msgstr "ssh密钥" + +#: assets/templates/assets/admin_user_detail.html:155 +msgid "Replace asset admin user with this" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:163 +#: assets/templates/assets/system_user_asset.html:89 +#, fuzzy +#| msgid "Select assets" +msgid "Select asset" +msgstr "选择资产" + +#: assets/templates/assets/admin_user_detail.html:172 +#: assets/templates/assets/admin_user_detail.html:200 +msgid "Replace" +msgstr "" + +#: assets/templates/assets/admin_user_detail.html:183 +msgid "Replace asset admin user with this admin user" +msgstr "" + +#: assets/templates/assets/admin_user_list.html:9 +#: assets/templates/assets/system_user_list.html:9 +#, fuzzy +#| msgid "IDC" +msgid "ID" +msgstr "机房" + +#: assets/templates/assets/admin_user_list.html:12 +#: assets/templates/assets/asset_group_list.html:13 +#: assets/templates/assets/asset_tags_list.html:13 +#: assets/templates/assets/idc_list.html:13 +#: assets/templates/assets/system_user_asset_group.html:54 +#: assets/templates/assets/system_user_list.html:12 +#: ops/templates/cron/list.html:30 ops/templates/sudo/list.html:30 +#: users/templates/users/_select_user_modal.html:17 +#: users/templates/users/user_list.html:30 +msgid "Asset num" +msgstr "资产数量" + +#: assets/templates/assets/admin_user_list.html:13 +msgid "Lost connection" +msgstr "" + +#: assets/templates/assets/admin_user_list.html:33 +#: assets/templates/assets/system_user_list.html:35 +msgid "Script" +msgstr "" + +#: assets/templates/assets/admin_user_list.html:35 +#: assets/templates/assets/asset_detail.html:156 +#: assets/templates/assets/system_user_list.html:37 +msgid "Refresh" +msgstr "" + +#: assets/templates/assets/admin_user_list.html:36 +#: assets/templates/assets/asset_group_list.html:32 +#: assets/templates/assets/asset_list.html:83 +#: assets/templates/assets/asset_tags_list.html:31 +#: assets/templates/assets/idc_list.html:32 +#: assets/templates/assets/system_user_list.html:38 +#: ops/templates/cron/list.html:79 ops/templates/sudo/list.html:79 +#: perms/templates/perms/asset_permission_list.html:46 +#: users/templates/users/user_detail.html:167 +#: users/templates/users/user_group_list.html:64 +#: users/templates/users/user_list.html:79 +msgid "Update" +msgstr "更新" + +#: assets/templates/assets/admin_user_list.html:37 +#: assets/templates/assets/asset_group_list.html:33 +#: assets/templates/assets/asset_list.html:84 +#: assets/templates/assets/asset_tags_list.html:32 +#: assets/templates/assets/idc_list.html:33 +#: assets/templates/assets/system_user_list.html:39 +#: ops/templates/cron/list.html:80 ops/templates/sudo/list.html:80 +#: perms/templates/perms/asset_permission_list.html:47 +#: users/templates/users/user_group_detail.html:129 +#: users/templates/users/user_group_detail.html:132 +#: users/templates/users/user_group_list.html:65 +#: users/templates/users/user_list.html:80 +msgid "Delete" +msgstr "删除" + +#: assets/templates/assets/asset_create.html:9 +#: assets/templates/assets/asset_update.html:14 +msgid "Basic" +msgstr "" + +#: assets/templates/assets/asset_create.html:16 +#: assets/templates/assets/asset_update.html:21 +msgid "Group" +msgstr "" + +#: assets/templates/assets/asset_create.html:21 +#: assets/templates/assets/asset_update.html:26 +#, fuzzy +#| msgid "Asset number" +msgid "Asset user" +msgstr "资产编号" + +#: assets/templates/assets/asset_create.html:26 +#: assets/templates/assets/asset_update.html:52 +#: perms/templates/perms/asset_permission_create_update.html:45 +#, fuzzy +#| msgid "Other IP" +msgid "Other" +msgstr "其它IP" + +#: assets/templates/assets/asset_detail.html:20 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset detail" +msgstr "资产组列表" + +#: assets/templates/assets/asset_detail.html:23 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset login log" +msgstr "资产组列表" + +#: assets/templates/assets/asset_detail.html:118 +#: users/templates/users/user_detail.html:94 +msgid "Date joined" +msgstr "创建日期" + +#: assets/templates/assets/asset_detail.html:133 +#: users/templates/users/user_detail.html:113 +#: users/templates/users/user_group_detail.html:115 +msgid "Quick modify" +msgstr "快速修改" + +#: assets/templates/assets/asset_detail.html:139 +#: ops/templates/cron/list.html:31 ops/templates/sudo/list.html:31 +#: perms/models.py:27 +#: perms/templates/perms/asset_permission_create_update.html:47 +#: users/templates/users/_select_user_modal.html:18 +#: users/templates/users/user_detail.html:119 +#: users/templates/users/user_list.html:31 +#, fuzzy +msgid "Active" +msgstr "激活" + +#: assets/templates/assets/asset_detail.html:153 +msgid "Rrefresh hardware" +msgstr "" + +#: assets/templates/assets/asset_detail.html:161 +#, fuzzy +#| msgid "Create user" +msgid "Test admin user" +msgstr "创建用户" + +#: assets/templates/assets/asset_detail.html:164 +#: assets/templates/assets/asset_detail.html:172 +#, fuzzy +msgid "Test" +msgstr "设置" + +#: assets/templates/assets/asset_detail.html:169 +#, fuzzy +#| msgid "System user" +msgid "Test system users" +msgstr "系统" + +#: assets/templates/assets/asset_detail.html:192 +#, fuzzy +#| msgid "Join user groups" +msgid "Join asset groups" +msgstr "添加到用户组" + +#: assets/templates/assets/asset_detail.html:201 +#: perms/templates/perms/asset_permission_asset.html:148 +#: perms/templates/perms/asset_permission_detail.html:164 +#: perms/templates/perms/asset_permission_user.html:148 +#: users/templates/users/user_detail.html:195 +msgid "Join" +msgstr "加入" + +#: assets/templates/assets/asset_group_detail.html:20 +#, fuzzy +#| msgid "Asset group" +msgid "Asset group perm" +msgstr "资产组" + +#: assets/templates/assets/asset_group_detail.html:113 +#: assets/templates/assets/asset_tag_detail.html:109 +#, fuzzy +#| msgid "System user" +msgid "Associate system user" +msgstr "系统" + +#: assets/templates/assets/asset_group_detail.html:119 +#: assets/templates/assets/asset_tag_detail.html:115 +#, fuzzy +#| msgid "System user" +msgid "repush system user" +msgstr "系统" + +#: assets/templates/assets/asset_group_detail.html:129 +#: assets/templates/assets/asset_tag_detail.html:125 +#, fuzzy +#| msgid "System user" +msgid "Select system user" +msgstr "系统" + +#: assets/templates/assets/asset_group_detail.html:138 +#: assets/templates/assets/asset_tag_detail.html:134 +msgid "Associate" +msgstr "" + +#: assets/templates/assets/asset_group_detail.html:157 +#: assets/templates/assets/asset_tag_detail.html:153 +#, fuzzy +#| msgid "Asset group" +msgid "Add asset to this group" +msgstr "资产组" + +#: assets/templates/assets/asset_group_detail.html:165 +#: assets/templates/assets/asset_tag_detail.html:161 +#, fuzzy +#| msgid "Select assets" +msgid "Select asset user" +msgstr "选择资产" + +#: assets/templates/assets/asset_group_detail.html:174 +#: assets/templates/assets/asset_tag_detail.html:170 +#: assets/templates/assets/system_user_asset_group.html:96 +#: perms/templates/perms/asset_permission_asset.html:120 +#: perms/templates/perms/asset_permission_user.html:120 +#: users/templates/users/user_group_detail.html:124 +#, fuzzy +#| msgid "Address" +msgid "Add" +msgstr "地址" + +#: assets/templates/assets/asset_group_list.html:5 assets/views.py:157 +#: assets/views.py:234 +msgid "Create asset group" +msgstr "创建资产组" + +#: assets/templates/assets/asset_group_list.html:43 +#: assets/templates/assets/asset_list.html:98 +#: assets/templates/assets/asset_tags_list.html:42 +#: ops/templates/cron/list.html:41 ops/templates/sudo/list.html:41 +#: perms/templates/perms/asset_permission_list.html:57 +#: users/templates/users/user_group_list.html:36 +#: users/templates/users/user_list.html:41 +msgid "Delete selected" +msgstr "批量删除" + +#: assets/templates/assets/asset_group_list.html:44 +#: assets/templates/assets/asset_list.html:99 +#: assets/templates/assets/asset_tags_list.html:43 +#: ops/templates/cron/list.html:42 ops/templates/sudo/list.html:42 +#: perms/templates/perms/asset_permission_list.html:58 +#: users/templates/users/user_list.html:42 +msgid "Update selected" +msgstr "批量更新" + +#: assets/templates/assets/asset_group_list.html:45 +#: assets/templates/assets/asset_list.html:100 +#: assets/templates/assets/asset_tags_list.html:44 +#: ops/templates/cron/list.html:43 ops/templates/sudo/list.html:43 +#: perms/templates/perms/asset_permission_list.html:59 +#: users/templates/users/user_list.html:43 +msgid "Deactive selected" +msgstr "禁用所选" + +#: assets/templates/assets/asset_group_list.html:46 +#: assets/templates/assets/asset_list.html:101 +#: assets/templates/assets/asset_tags_list.html:45 +#: perms/templates/perms/asset_permission_list.html:60 +msgid "Export selected" +msgstr "批量导出" + +#: assets/templates/assets/asset_list.html:21 +msgid "Create asset" +msgstr "创建资产" + +#: assets/templates/assets/asset_list.html:60 +msgid "Type" +msgstr "" + +#: assets/templates/assets/asset_list.html:61 +#: assets/templates/assets/asset_update.html:31 +msgid "Hardware" +msgstr "" + +#: assets/templates/assets/asset_list.html:62 +msgid "Valid" +msgstr "" + +#: assets/templates/assets/asset_tag_detail.html:45 +#: assets/templates/assets/asset_tags_list.html:12 +#, fuzzy +#| msgid "Name" +msgid "Tag Name" +msgstr "名称" + +#: assets/templates/assets/asset_tags_list.html:5 +#, fuzzy +#| msgid "Create asset" +msgid "Create tag" +msgstr "创建资产" + +#: assets/templates/assets/asset_update.html:40 +#, fuzzy +#| msgid "Confirm delete" +msgid "Configuration" +msgstr "确认删除" + +#: assets/templates/assets/asset_update.html:47 +#, fuzzy +msgid "Location" +msgstr "激活" + +#: assets/templates/assets/delete_confirm.html:6 +#: perms/templates/perms/delete_confirm.html:6 +#: users/templates/users/user_delete_confirm.html:6 +msgid "Confirm delete" +msgstr "确认删除" + +#: assets/templates/assets/idc_list.html:5 assets/views.py:287 +#, fuzzy +#| msgid "Created by" +msgid "Create IDC" +msgstr "创建者" + +#: assets/templates/assets/idc_list.html:16 +#, fuzzy +#| msgid "Operator" +msgid "operation" +msgstr "运营商" + +#: assets/templates/assets/system_user_asset.html:22 +#: assets/templates/assets/system_user_detail.html:23 +#, fuzzy +#| msgid "Create asset group" +msgid "Associate assets and asset groups" +msgstr "创建资产组" + +#: assets/templates/assets/system_user_asset.html:30 +#, fuzzy +#| msgid "Asset group list" +msgid "Assets attached of " +msgstr "资产组列表" + +#: assets/templates/assets/system_user_asset.html:52 +msgid "Reachable" +msgstr "" + +#: assets/templates/assets/system_user_asset.html:81 +#, fuzzy +#| msgid "User assets" +msgid "Attach to assets " +msgstr "用户资产" + +#: assets/templates/assets/system_user_asset.html:98 +#: assets/templates/assets/system_user_asset.html:126 +msgid "Attach" +msgstr "" + +#: assets/templates/assets/system_user_asset.html:109 +#, fuzzy +#| msgid "Select asset groups" +msgid "Attach to asset groups" +msgstr "添加到资产组" + +#: assets/templates/assets/system_user_asset.html:117 +#, fuzzy +#| msgid "Asset group" +msgid "Add asset group" +msgstr "资产组" + +#: assets/templates/assets/system_user_asset_group.html:22 +#, fuzzy +#| msgid "User assets" +msgid "Associate assets" +msgstr "用户资产" + +#: assets/templates/assets/system_user_asset_group.html:26 +#, fuzzy +#| msgid "Create asset group" +msgid "Associate asset groups" +msgstr "创建资产组" + +#: assets/templates/assets/system_user_asset_group.html:55 +msgid "Unavailable num" +msgstr "" + +#: assets/templates/assets/system_user_asset_group.html:79 +#, fuzzy +#| msgid "Asset group list" +msgid "Add asset group to this system user" +msgstr "资产组列表" + +#: assets/templates/assets/system_user_asset_group.html:87 +#, fuzzy +#| msgid "Select asset groups" +msgid "Select asset group" +msgstr "添加到资产组" + +#: assets/templates/assets/system_user_create_update.html:16 +#: assets/templates/assets/system_user_list.html:5 assets/views.py:469 +#, fuzzy +#| msgid "Create user" +msgid "Create system user" +msgstr "创建用户" + +#: assets/templates/assets/system_user_create_update.html:56 +#: assets/templates/assets/system_user_detail.html:67 +#, fuzzy +#| msgid "Auto update pass/key" +msgid "Auto update" +msgstr "自动更新密码/密钥" + +#: assets/templates/assets/system_user_detail.html:123 +msgid "Get mannual install script" +msgstr "" + +#: assets/templates/assets/system_user_list.html:13 +#, fuzzy +#| msgid "Asset group" +msgid "Asset group num" +msgstr "资产组" + +#: assets/templates/assets/system_user_list.html:14 ops/models.py:69 +msgid "Unreachable" +msgstr "" + +#: assets/views.py:156 assets/views.py:182 assets/views.py:214 +#: assets/views.py:233 assets/views.py:257 assets/views.py:339 +#: assets/views.py:438 assets/views.py:468 assets/views.py:491 +#: assets/views.py:509 templates/_nav.html:18 +msgid "Assets" +msgstr "资产管理" + +#: assets/views.py:183 +msgid "Asset group list" +msgstr "资产组列表" + +#: assets/views.py:215 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset group detail" +msgstr "资产组列表" + +#: assets/views.py:258 +msgid "IDC list" +msgstr "" + +#: assets/views.py:286 assets/views.py:313 +#, fuzzy +#| msgid "Assets" +msgid "assets" +msgstr "资产管理" + +#: assets/views.py:314 +#, fuzzy +#| msgid "Update" +msgid "Update IDC" +msgstr "更新" + +#: assets/views.py:340 +#, fuzzy +#| msgid "Admin user" +msgid "Admin user list" +msgstr "管理用户" + +#: assets/views.py:376 +#, fuzzy, python-format +#| msgid "Create user %s success." +msgid "Create admin user %s successfully." +msgstr "创建用户 %s 成功" + +#: assets/views.py:439 +#, fuzzy +#| msgid "System user" +msgid "System user list" +msgstr "系统" + +#: assets/views.py:475 +#, fuzzy, python-format +#| msgid "Create user %s success." +msgid "Create system user %s successfully." +msgstr "创建用户 %s 成功" + +#: assets/views.py:492 +#, fuzzy +#| msgid "Update user" +msgid "Update system user" +msgstr "编辑用户" + +#: assets/views.py:510 +#, fuzzy +#| msgid "System user" +msgid "System user detail" +msgstr "系统" + +#: assets/views.py:601 assets/views.py:619 assets/views.py:648 +#: assets/views.py:667 +msgid "Tag" +msgstr "" + +#: assets/views.py:602 assets/views.py:620 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset Tags list" +msgstr "资产组列表" + +#: assets/views.py:649 assets/views.py:668 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset Tags detail" +msgstr "资产组列表" + +#: common/mixins.py:28 +msgid "is discard" +msgstr "" + +#: common/mixins.py:29 +msgid "discard time" +msgstr "" + +#: ops/api/exc.py:10 +msgid "Service temporarily unavailable, try again later." +msgstr "" + +#: ops/api/exc.py:15 +msgid "This service maybe implemented in the future, but now not implemented!" +msgstr "" + +#: ops/models.py:17 ops/models.py:35 ops/models.py:47 +msgid "UUID" +msgstr "" + +#: ops/models.py:19 +msgid "Start Time" +msgstr "" + +#: ops/models.py:20 +msgid "End Time" +msgstr "" + +#: ops/models.py:21 +msgid "Exit Code" +msgstr "" + +#: ops/models.py:22 +msgid "Is Completed" +msgstr "" + +#: ops/models.py:23 +#, fuzzy +#| msgid "Hostname" +msgid "Hosts" +msgstr "主机名" + +#: ops/models.py:66 +msgid "Success" +msgstr "" + +#: ops/models.py:67 +msgid "Skipped" +msgstr "" + +#: ops/models.py:68 +msgid "Failed" +msgstr "" + +#: ops/models.py:70 +msgid "NoHost" +msgstr "" + +#: ops/models.py:217 +msgid "Host_Alias" +msgstr "" + +#: ops/models.py:218 ops/models.py:226 ops/models.py:234 ops/models.py:242 +msgid "Host_Items" +msgstr "" + +#: ops/models.py:225 +#, fuzzy +#| msgid "User list" +msgid "User_Alias" +msgstr "用户列表" + +#: ops/models.py:233 +msgid "Command_Alias" +msgstr "" + +#: ops/models.py:241 +msgid "Runas_Alias" +msgstr "" + +#: ops/models.py:253 +#, fuzzy +#| msgid "Password" +msgid "Is_NoPassword" +msgstr "密码" + +#: ops/models.py:267 +msgid "Extra_Item" +msgstr "" + +#: ops/models.py:398 +msgid "Description of a crontab entry" +msgstr "" + +#: ops/models.py:399 +msgid "Month" +msgstr "" + +#: ops/models.py:400 +msgid "Month of the year the job should run ( 1-12, *, */2, etc )" +msgstr "" + +#: ops/models.py:401 +msgid "WeekDay" +msgstr "" + +#: ops/models.py:402 +msgid "" +"Day of the week that the job should run ( 0-6 for Sunday-Saturday, *, etc )" +msgstr "" + +#: ops/models.py:404 +msgid "Day" +msgstr "" + +#: ops/models.py:405 +msgid "Day of the month the job should run ( 1-31, *, */2, etc )" +msgstr "" + +#: ops/models.py:406 +msgid "Hour" +msgstr "" + +#: ops/models.py:407 +msgid "Hour when the job should run ( 0-23, *, */2, etc )" +msgstr "" + +#: ops/models.py:408 +msgid "Minute" +msgstr "" + +#: ops/models.py:409 +msgid "Minute when the job should run ( 0-59, *, */2, etc )" +msgstr "" + +#: ops/models.py:410 +msgid "Job" +msgstr "" + +#: ops/models.py:411 +msgid "" +"The command to execute or, if env is set, the value of environment variable. " +"Required if state=present." +msgstr "" + +#: ops/models.py:413 +#: perms/templates/perms/asset_permission_create_update.html:36 +#: templates/_nav.html:12 templates/_user_profile.html:14 users/models.py:71 +#: users/templates/users/_user_bulk_update_modal.html:14 +msgid "User" +msgstr "用户" + +#: ops/models.py:414 +msgid "The specific user whose crontab should be modified." +msgstr "" + +#: ops/templates/cron/list.html:18 ops/templates/sudo/list.html:18 +#: users/templates/users/user_list.html:18 +#, fuzzy +#| msgid "Create user" +msgid "Import user" +msgstr "创建用户" + +#: ops/templates/cron/list.html:19 ops/templates/sudo/list.html:19 +#: users/templates/users/_user.html:17 users/templates/users/user_create.html:4 +#: users/templates/users/user_list.html:19 users/views.py:102 +msgid "Create user" +msgstr "创建用户" + +#: ops/templates/cron/list.html:28 ops/templates/sudo/list.html:28 +#: users/models.py:78 users/templates/users/_select_user_modal.html:15 +#: users/templates/users/_user_bulk_update_modal.html:9 +#: users/templates/users/user_detail.html:82 +#: users/templates/users/user_list.html:28 +msgid "Role" +msgstr "角色" + +#: ops/templates/cron/list.html:29 ops/templates/sudo/list.html:29 +#: templates/_nav.html:13 users/models.py:77 +#: users/templates/users/_select_user_modal.html:16 +#: users/templates/users/user_detail.html:178 +#: users/templates/users/user_list.html:29 +msgid "User group" +msgstr "用户组" + +#: ops/templates/cron/list.html:32 ops/templates/sudo/list.html:32 +#: users/templates/users/user_group_list.html:29 +#: users/templates/users/user_list.html:32 +#, fuzzy +msgid "Action" +msgstr "激活" + +#: ops/templates/cron/list.html:116 ops/templates/cron/list.html:178 +#: ops/templates/sudo/list.html:116 ops/templates/sudo/list.html:178 +#: users/templates/users/user_detail.html:329 +#: users/templates/users/user_detail.html:354 +#: users/templates/users/user_group_detail.html:169 +#: users/templates/users/user_group_list.html:102 +#: users/templates/users/user_group_list.html:125 +#: users/templates/users/user_list.html:116 +#: users/templates/users/user_list.html:178 +msgid "Are you sure?" +msgstr "" + +#: ops/templates/cron/list.html:117 ops/templates/sudo/list.html:117 +#: users/templates/users/user_list.html:117 +msgid "This will delete the selected users !!!" +msgstr "" + +#: ops/templates/cron/list.html:121 ops/templates/cron/list.html:183 +#: ops/templates/sudo/list.html:121 ops/templates/sudo/list.html:183 +#: templates/_modal.html:16 users/templates/users/user_detail.html:334 +#: users/templates/users/user_detail.html:359 +#: users/templates/users/user_detail.html:383 +#: users/templates/users/user_group_detail.html:174 +#: users/templates/users/user_group_list.html:107 +#: users/templates/users/user_group_list.html:130 +#: users/templates/users/user_list.html:121 +#: users/templates/users/user_list.html:183 +#, fuzzy +#| msgid "Confirm delete" +msgid "Confirm" +msgstr "确认删除" + +# msgid "Deleted!" +# msgstr "删除" +#: ops/templates/cron/list.html:125 ops/templates/cron/list.html:161 +#: ops/templates/sudo/list.html:125 ops/templates/sudo/list.html:161 +#: users/templates/users/user_list.html:125 +#: users/templates/users/user_list.html:161 +#, fuzzy +#| msgid "has been deleted." +msgid "User Deleted." +msgstr "已被删除" + +#: ops/templates/cron/list.html:126 ops/templates/cron/list.html:131 +#: ops/templates/cron/list.html:162 ops/templates/cron/list.html:167 +#: ops/templates/sudo/list.html:126 ops/templates/sudo/list.html:131 +#: ops/templates/sudo/list.html:162 ops/templates/sudo/list.html:167 +#: users/templates/users/user_list.html:126 +#: users/templates/users/user_list.html:131 +#: users/templates/users/user_list.html:162 +#: users/templates/users/user_list.html:167 +#, fuzzy +#| msgid "Delete" +msgid "User Delete" +msgstr "删除" + +#: ops/templates/cron/list.html:130 ops/templates/cron/list.html:166 +#: ops/templates/sudo/list.html:130 ops/templates/sudo/list.html:166 +#: users/templates/users/user_list.html:130 +#: users/templates/users/user_list.html:166 +#, fuzzy +#| msgid "User detail" +msgid "User Deleting failed." +msgstr "用户详情" + +#: ops/templates/cron/list.html:179 ops/templates/sudo/list.html:179 +#: users/templates/users/user_list.html:179 +msgid "This will delete the selected user." +msgstr "" + +#: ops/templates/cron/list.html:215 ops/templates/sudo/list.html:215 +#: users/templates/users/user_list.html:215 +msgid "The selected users has been updated successfully." +msgstr "" + +#: ops/templates/cron/list.html:216 ops/templates/sudo/list.html:216 +#: users/templates/users/user_list.html:216 +#, fuzzy +#| msgid "Update" +msgid "User Updated" +msgstr "更新" + +#: ops/templates/cron/list.html:232 ops/templates/sudo/list.html:232 +#: users/templates/users/user_list.html:232 +msgid "Import User Success." +msgstr "" + +#: perms/forms.py:21 +#, fuzzy +#| msgid "Select assets" +msgid "Select users" +msgstr "选择资产" + +#: perms/forms.py:23 perms/templates/perms/asset_permission_user.html:139 +#, fuzzy +#| msgid "Select asset groups" +msgid "Select user groups" +msgstr "添加到资产组" + +#: perms/forms.py:29 perms/templates/perms/asset_permission_detail.html:155 +#: users/forms.py:126 +#, fuzzy +#| msgid "System user" +msgid "Select system users" +msgstr "系统" + +#: perms/models.py:26 +#, fuzzy +#| msgid "SSH private key" +msgid "Private for" +msgstr "ssh密钥" + +#: perms/models.py:28 perms/templates/perms/asset_permission_detail.html:80 +#: users/models.py:89 users/templates/users/user_detail.html:86 +msgid "Date expired" +msgstr "失效日期" + +#: perms/templates/perms/asset_permission_asset.html:24 +#: perms/templates/perms/asset_permission_detail.html:24 +#: perms/templates/perms/asset_permission_user.html:24 +#, fuzzy +#| msgid "Join user groups" +msgid "Users and user groups" +msgstr "添加到用户组" + +#: perms/templates/perms/asset_permission_asset.html:29 +#: perms/templates/perms/asset_permission_detail.html:29 +#: perms/templates/perms/asset_permission_user.html:29 +#, fuzzy +#| msgid "Select asset groups" +msgid "Assets and asset groups" +msgstr "添加到资产组" + +#: perms/templates/perms/asset_permission_asset.html:69 +#: perms/templates/perms/asset_permission_list.html:18 +#: perms/templates/perms/asset_permission_user.html:69 +#: users/templates/users/user_asset_permission.html:73 +#: users/templates/users/user_granted_asset.html:71 +msgid "Is valid" +msgstr "" + +#: perms/templates/perms/asset_permission_asset.html:103 +msgid "Add asset to this permission" +msgstr "" + +#: perms/templates/perms/asset_permission_asset.html:111 +#, fuzzy +#| msgid "Select assets" +msgid "Select asset " +msgstr "选择资产" + +#: perms/templates/perms/asset_permission_asset.html:131 +msgid "Add asset group to this permission" +msgstr "" + +#: perms/templates/perms/asset_permission_create_update.html:17 +#, fuzzy +#| msgid "Create asset group" +msgid "Create asset permission " +msgstr "创建资产组" + +#: perms/templates/perms/asset_permission_detail.html:60 +#: perms/templates/perms/asset_permission_list.html:13 +#, fuzzy +#| msgid "User group" +msgid "User count" +msgstr "用户组" + +#: perms/templates/perms/asset_permission_detail.html:64 +#: perms/templates/perms/asset_permission_list.html:14 +#, fuzzy +#| msgid "User group list" +msgid "User group count" +msgstr "用户组列表" + +#: perms/templates/perms/asset_permission_detail.html:68 +#: perms/templates/perms/asset_permission_list.html:15 +#: users/templates/users/user_granted_asset.html:130 +#, fuzzy +#| msgid "Asset group" +msgid "Asset count" +msgstr "资产组" + +#: perms/templates/perms/asset_permission_detail.html:72 +#: perms/templates/perms/asset_permission_list.html:16 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset group count" +msgstr "资产组列表" + +#: perms/templates/perms/asset_permission_detail.html:76 +#: perms/templates/perms/asset_permission_list.html:17 +#, fuzzy +#| msgid "System user" +msgid "System user count" +msgstr "系统" + +#: perms/templates/perms/asset_permission_detail.html:133 +#, fuzzy +#| msgid "System user" +msgid "Repush system user" +msgstr "系统" + +#: perms/templates/perms/asset_permission_detail.html:136 +msgid "Push" +msgstr "" + +#: perms/templates/perms/asset_permission_detail.html:147 +#: templates/_nav.html:25 users/templates/users/user_granted_asset.html:69 +#: users/templates/users/user_granted_asset.html:131 +msgid "System user" +msgstr "系统" + +#: perms/templates/perms/asset_permission_list.html:5 +#, fuzzy +#| msgid "Create perm" +msgid "Create permission" +msgstr "创建权限" + +#: perms/templates/perms/asset_permission_user.html:47 +#, fuzzy +#| msgid "User list" +msgid "User list of " +msgstr "用户列表" + +#: perms/templates/perms/asset_permission_user.html:68 users/models.py:76 +#: users/templates/users/user_detail.html:66 +msgid "Email" +msgstr "邮件" + +#: perms/templates/perms/asset_permission_user.html:103 +msgid "Add user to asset permission" +msgstr "" + +#: perms/templates/perms/asset_permission_user.html:111 +#, fuzzy +#| msgid "Select assets" +msgid "Select user" +msgstr "选择资产" + +#: perms/templates/perms/asset_permission_user.html:131 +#, fuzzy +#| msgid "Asset group list" +msgid "Add user group to asset permission" +msgstr "资产组列表" + +#: perms/views.py:29 perms/views.py:66 perms/views.py:89 perms/views.py:107 +#: perms/views.py:146 perms/views.py:181 templates/_nav.html:30 +msgid "Perms" +msgstr "权限管理" + +#: perms/views.py:30 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset permission list" +msgstr "资产组列表" + +#: perms/views.py:67 +#, fuzzy +#| msgid "Create asset group" +msgid "Create asset permission" +msgstr "创建资产组" + +#: perms/views.py:73 +#, fuzzy, python-format +#| msgid "Create user %s success." +msgid "Create asset permission %s successfully." +msgstr "创建用户 %s 成功" + +#: perms/views.py:85 +#, fuzzy, python-format +#| msgid "Create user %s success." +msgid "Update asset permission %s successfully." +msgstr "创建用户 %s 成功" + +#: perms/views.py:90 +msgid "Update asset permission" +msgstr "" + +#: perms/views.py:108 +#, fuzzy +#| msgid "Asset environment" +msgid "Asset permission detail" +msgstr "资产环境" + +#: perms/views.py:147 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset permission user list" +msgstr "资产组列表" + +#: perms/views.py:182 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset permission asset list" +msgstr "资产组列表" + +#: templates/_header_bar.html:8 +msgid "Search" +msgstr "搜索" + +#: templates/_header_bar.html:14 +msgid "Welcome to use Jumpserver system" +msgstr "欢迎使用Jumpserver开源跳板机系统" + +#: templates/_header_bar.html:18 +msgid "Help" +msgstr "帮助" + +#: templates/_header_bar.html:24 templates/_user_profile.html:21 +msgid "Logout" +msgstr "注销登录" + +#: templates/_header_bar.html:28 users/templates/users/login.html:42 +#: users/templates/users/login.html:61 +msgid "Login" +msgstr "登录" + +#: templates/_modal.html:15 +msgid "Close" +msgstr "" + +#: templates/_nav.html:9 users/templates/users/user_group_create.html:24 +#: users/templates/users/user_group_detail.html:102 users/views.py:89 +#: users/views.py:102 users/views.py:138 users/views.py:149 users/views.py:159 +#: users/views.py:172 users/views.py:197 users/views.py:219 users/views.py:320 +msgid "Users" +msgstr "用户管理" + +#: templates/_nav.html:26 +msgid "Label" +msgstr "标签" + +#: templates/_nav.html:33 users/templates/users/user_asset_permission.html:23 +#: users/templates/users/user_detail.html:24 +#: users/templates/users/user_granted_asset.html:23 +#, fuzzy +#| msgid "Asset type" +msgid "Asset permission" +msgstr "系统类型" + +#: templates/_nav.html:43 +msgid "Job Center" +msgstr "作业中心" + +#: templates/_nav.html:47 +msgid "Cron" +msgstr "Cron" + +#: templates/_nav.html:53 +msgid "Audits" +msgstr "审计" + +#: templates/_nav.html:58 +msgid "File" +msgstr "文件" + +#: templates/_nav.html:61 +msgid "File upload" +msgstr "文件上传" + +#: templates/_nav.html:62 +msgid "File download" +msgstr "文件下载" + +#: templates/_nav.html:67 +msgid "Settings" +msgstr "设置" + +#: templates/_nav.html:72 +msgid "Visit us" +msgstr "访问官网" + +#: templates/_user_profile.html:19 users/templates/users/_user.html:63 +msgid "Profile" +msgstr "个人信息" + +#: templates/base.html:27 +#, python-format +msgid "" +"\n" +" Your information was incomplete. Please click this link to complete your information.\n" +" " +msgstr "" + +#: templates/base.html:36 +msgid "" +"\n" +" Your ssh-public-key has been expired. Please click this link to update your ssh-public-key.\n" +" " +msgstr "" + +#: templates/captcha/image.html:3 +msgid "Play CAPTCHA as audio file" +msgstr "" + +#: templates/captcha/text_field.html:4 +msgid "Captcha" +msgstr "验证码" + +#: templates/rest_framework/base.html:128 +#, fuzzy +msgid "Filters" +msgstr "过滤" + +#: users/forms.py:33 users/forms.py:58 +#: users/templates/users/user_detail.html:186 +msgid "Join user groups" +msgstr "添加到用户组" + +#: users/forms.py:75 +#, fuzzy +#| msgid "Name" +msgid "name" +msgstr "名称" + +#: users/forms.py:76 +#, fuzzy +#| msgid "Avatar" +msgid "avatar" +msgstr "头像" + +#: users/forms.py:77 +#, fuzzy +#| msgid "Wechat" +msgid "wechat" +msgstr "微信" + +#: users/forms.py:78 +#, fuzzy +#| msgid "Phone" +msgid "phone" +msgstr "手机" + +#: users/forms.py:79 +#, fuzzy +#| msgid "Enable OTP" +msgid "enable otp" +msgstr "二次验证" + +#: users/forms.py:84 users/models.py:85 +msgid "ssh public key" +msgstr "ssh公钥" + +#: users/forms.py:85 +msgid "ssh-rsa AAAA..." +msgstr "" + +#: users/forms.py:86 +msgid "Paste your id_ras.pub here." +msgstr "" + +#: users/forms.py:91 +msgid "Public key should not be the same as your old one." +msgstr "" + +#: users/forms.py:99 users/forms.py:102 users/serializers.py:32 +#: users/serializers.py:35 +#, fuzzy +#| msgid "ssh private key" +msgid "Not a valid ssh public key" +msgstr "ssh密钥" + +#: users/models.py:70 users/models.py:220 +msgid "Administrator" +msgstr "管理员" + +#: users/models.py:79 +msgid "Avatar" +msgstr "头像" + +#: users/models.py:80 users/templates/users/user_detail.html:77 +msgid "Wechat" +msgstr "微信" + +#: users/models.py:82 users/templates/users/_user.html:57 +#: users/templates/users/user_detail.html:133 +msgid "Enable OTP" +msgstr "二次验证" + +#: users/models.py:84 +msgid "ssh private key" +msgstr "ssh密钥" + +#: users/models.py:223 +msgid "Administrator is the super user of system" +msgstr "Administrator是初始的超级管理员" + +#: users/templates/users/_select_user_modal.html:5 +#, fuzzy +#| msgid "Select assets" +msgid "Please Select User" +msgstr "选择资产" + +#: users/templates/users/_user.html:33 +msgid "Account" +msgstr "账户" + +#: users/templates/users/_user.html:43 +msgid "Security and Role" +msgstr "角色安全" + +#: users/templates/users/_user_bulk_update_modal.html:4 +#, fuzzy +#| msgid "Update user" +msgid "Update User" +msgstr "编辑用户" + +#: users/templates/users/_user_bulk_update_modal.html:6 +msgid "Hint: only change the field you want to update." +msgstr "" + +#: users/templates/users/_user_bulk_update_modal.html:13 +#, fuzzy +#| msgid "Admin user" +msgid "Admin" +msgstr "管理用户" + +#: users/templates/users/_user_bulk_update_modal.html:19 +msgid "Groups" +msgstr "" + +#: users/templates/users/_user_bulk_update_modal.html:21 +#, fuzzy +#| msgid "Select asset groups" +msgid "Select Group" +msgstr "添加到资产组" + +#: users/templates/users/_user_bulk_update_modal.html:31 +#, fuzzy +#| msgid "Enable OTP" +msgid "Enable-OTP" +msgstr "二次验证" + +#: users/templates/users/_user_import_modal.html:4 +msgid "Import User" +msgstr "" + +#: users/templates/users/_user_import_modal.html:6 +msgid "Hint: your excel should organized in the following format." +msgstr "" + +#: users/templates/users/_user_import_modal.html:7 +msgid "* You should have a very worksheet named `users`." +msgstr "" + +#: users/templates/users/_user_import_modal.html:8 +msgid "" +"* Rows in this worksheet: username, email, enable_opt(0, 1), role(one of " +"['Admin', 'User'])" +msgstr "" + +#: users/templates/users/_user_import_modal.html:12 +msgid "Excel" +msgstr "" + +#: users/templates/users/_user_update_pk_modal.html:4 +#, fuzzy +#| msgid "SSH private key" +msgid "Update User SSH Public Key" +msgstr "ssh密钥" + +#: users/templates/users/first_login.html:18 users/views.py:320 +#, fuzzy +#| msgid "Last login" +msgid "First Login" +msgstr "最后登录" + +#: users/templates/users/first_login.html:35 +#, fuzzy +#| msgid "System" +msgid "Step" +msgstr "系统" + +#: users/templates/users/first_login.html:57 +msgid "first step" +msgstr "" + +#: users/templates/users/first_login.html:58 +msgid "prev step" +msgstr "" + +#: users/templates/users/first_login.html:60 +#, fuzzy +#| msgid "Submit" +msgid "submit" +msgstr "提交" + +#: users/templates/users/forgot_password.html:26 +#: users/templates/users/login.html:64 +msgid "Forgot password" +msgstr "忘记密码" + +#: users/templates/users/forgot_password.html:33 +msgid "Input your email, that will send a mail to your" +msgstr "输入您的邮箱, 将会发一封重置短信邮件到您的邮箱中" + +#: users/templates/users/login.html:47 +msgid "Captcha invalid" +msgstr "验证码错误" + +#: users/templates/users/reset_password.html:45 +#: users/templates/users/user_detail.html:148 users/utils.py:99 +msgid "Reset password" +msgstr "重置密码" + +#: users/templates/users/reset_password.html:55 +msgid "Password again" +msgstr "再次输入密码" + +#: users/templates/users/reset_password.html:57 +#, fuzzy +msgid "Setting" +msgstr "设置" + +#: users/templates/users/user_asset_permission.html:20 +#: users/templates/users/user_detail.html:21 +#: users/templates/users/user_granted_asset.html:20 users/views.py:149 +msgid "User detail" +msgstr "用户详情" + +#: users/templates/users/user_asset_permission.html:26 +#: users/templates/users/user_detail.html:26 +#: users/templates/users/user_granted_asset.html:26 +#, fuzzy +#| msgid "Asset type" +msgid "Asset granted" +msgstr "系统类型" + +#: users/templates/users/user_asset_permission.html:29 +#: users/templates/users/user_detail.html:27 +#: users/templates/users/user_granted_asset.html:29 +msgid "Login history" +msgstr "" + +#: users/templates/users/user_asset_permission.html:47 +#, fuzzy +#| msgid "Asset type" +msgid "Asset permission of " +msgstr "系统类型" + +#: users/templates/users/user_asset_permission.html:67 +#, fuzzy +#| msgid "User" +msgid "User " +msgstr "用户" + +#: users/templates/users/user_asset_permission.html:68 +#, fuzzy +#| msgid "User group" +msgid "User group " +msgstr "用户组" + +#: users/templates/users/user_asset_permission.html:69 +#, fuzzy +#| msgid "Asset" +msgid "Asset " +msgstr "资产" + +#: users/templates/users/user_asset_permission.html:70 +#, fuzzy +#| msgid "Asset group" +msgid "Asset group " +msgstr "资产组" + +#: users/templates/users/user_asset_permission.html:71 +#, fuzzy +#| msgid "System user" +msgid "System user " +msgstr "系统" + +#: users/templates/users/user_asset_permission.html:115 +#, fuzzy +#| msgid "Create perm" +msgid "Quick create permission for user" +msgstr "创建权限" + +#: users/templates/users/user_create.html:13 +msgid "Reset link will be generated and sent to the user. " +msgstr "生成重置密码连接,通过邮件发送给用户" + +#: users/templates/users/user_detail.html:98 +msgid "Last login" +msgstr "最后登录" + +#: users/templates/users/user_detail.html:156 +msgid "Reset ssh key" +msgstr "重置密钥" + +#: users/templates/users/user_detail.html:164 +#, fuzzy +#| msgid "Update user" +msgid "Update ssh key" +msgstr "编辑用户" + +#: users/templates/users/user_detail.html:246 +msgid "UserGroup Update Success!" +msgstr "" + +#: users/templates/users/user_detail.html:270 +#: users/templates/users/user_detail.html:282 +#, fuzzy +#| msgid "Create account successfully" +msgid "Update Successfully!" +msgstr "创建账户成功" + +#: users/templates/users/user_detail.html:319 +msgid "E-mail sent successfully. An e-mail has been sent to the user\\" +msgstr "" + +#: users/templates/users/user_detail.html:320 +#, fuzzy +#| msgid "Password" +msgid "Password-Reset" +msgstr "密码" + +#: users/templates/users/user_detail.html:330 +#: users/templates/users/user_detail.html:355 +msgid "This will reset the user\\" +msgstr "" + +#: users/templates/users/user_detail.html:344 +msgid "" +"The reset-ssh-public-key E-mail has been sent successfully. Please inform " +"the user to update his new ssh public key." +msgstr "" + +#: users/templates/users/user_detail.html:345 +#, fuzzy +#| msgid "SSH private key" +msgid "SSH-Public-Key Reset" +msgstr "ssh密钥" + +#: users/templates/users/user_detail.html:372 +msgid "Successfully updated the SSH public key." +msgstr "" + +#: users/templates/users/user_detail.html:373 +#: users/templates/users/user_detail.html:378 +#, fuzzy +#| msgid "SSH private key" +msgid "User SSH Public Key Update" +msgstr "ssh密钥" + +#: users/templates/users/user_detail.html:376 +msgid "Failed to update the user\\" +msgstr "" + +#: users/templates/users/user_granted_asset.html:47 +#, fuzzy +#| msgid "Create asset group" +msgid "Granted assets of " +msgstr "创建资产组" + +#: users/templates/users/user_granted_asset.html:110 +#, fuzzy +#| msgid "Asset group list" +msgid "Asset groups granted of " +msgstr "资产组列表" + +#: users/templates/users/user_group_create.html:26 +#, fuzzy +#| msgid "Select assets" +msgid "Select User" +msgstr "选择资产" + +#: users/templates/users/user_group_create.html:38 +msgid "Cancel" +msgstr "" + +#: users/templates/users/user_group_create.html:39 +#, fuzzy +#| msgid "Confirm delete" +msgid "confirm" +msgstr "确认删除" + +#: users/templates/users/user_group_detail.html:70 users/views.py:219 +#, fuzzy +#| msgid "Asset group list" +msgid "User Group Detail" +msgstr "资产组列表" + +#: users/templates/users/user_group_detail.html:98 +#, fuzzy +#| msgid "Create asset" +msgid "Created at" +msgstr "创建资产" + +#: users/templates/users/user_group_detail.html:121 +#, fuzzy +#| msgid "User" +msgid "Add User" +msgstr "用户" + +#: users/templates/users/user_group_detail.html:170 +msgid "This will delete the current group, but will not delete any user of it." +msgstr "" + +#: users/templates/users/user_group_detail.html:223 +msgid "The selected users has been added to current group." +msgstr "" + +#: users/templates/users/user_group_list.html:18 +#, fuzzy +#| msgid "Asset group" +msgid "Add User Group" +msgstr "资产组" + +#: users/templates/users/user_group_list.html:26 +#, fuzzy +#| msgid "User group" +msgid "User Amount" +msgstr "用户组" + +#: users/templates/users/user_group_list.html:27 +#, fuzzy +#| msgid "Asset group" +msgid "Asset Amount" +msgstr "资产组" + +#: users/templates/users/user_group_list.html:85 +#, fuzzy +#| msgid "Delete" +msgid "Group Deleted." +msgstr "删除" + +#: users/templates/users/user_group_list.html:86 +#: users/templates/users/user_group_list.html:91 +#, fuzzy +#| msgid "Delete" +msgid "Group Delete" +msgstr "删除" + +#: users/templates/users/user_group_list.html:90 +msgid "Group Deleting failed." +msgstr "" + +#: users/templates/users/user_group_list.html:103 +msgid "" +"This will delete the selected group, but will not remove any user in this " +"group." +msgstr "" + +#: users/templates/users/user_group_list.html:126 +msgid "This will delete the selected groups !!!" +msgstr "" + +#: users/templates/users/user_group_list.html:134 +#, fuzzy +#| msgid "User group list" +msgid "UserGroups Deleted." +msgstr "用户组列表" + +#: users/templates/users/user_group_list.html:135 +#: users/templates/users/user_group_list.html:140 +#, fuzzy +#| msgid "User group list" +msgid "UserGroups Delete" +msgstr "用户组列表" + +#: users/templates/users/user_group_list.html:139 +msgid "UserGroup Deleting failed." +msgstr "" + +#: users/templates/users/user_update.html:3 users/views.py:138 +msgid "Update user" +msgstr "编辑用户" + +#: users/utils.py:48 +msgid "Begin to generate ssh private key ..." +msgstr "开始生成ssh密钥" + +#: users/utils.py:60 +msgid "Finish to generate ssh private key ..." +msgstr "生成ssh密钥成功" + +#: users/utils.py:64 +msgid "These is error when generate ssh key." +msgstr "创建密钥失败" + +#: users/utils.py:68 +msgid "Create account successfully" +msgstr "创建账户成功" + +#: users/utils.py:70 +#, python-format +msgid "" +"\n" +" Hello %(name)s:\n" +"
      \n" +" Your account has been created successfully\n" +"
      \n" +" click " +"here to set your password\n" +"
      \n" +" This link is valid for 1 hour. After it expires, request new one\n" +"\n" +"
      \n" +" ---\n" +"\n" +"
      \n" +" Login direct\n" +"\n" +"
      \n" +" " +msgstr "" +"\n" +" 你好 %(name)s:\n" +"
      \n" +" 恭喜您,您的账号已经创建成功
      \n" +" 请点击这" +"里设置密码
      \n" +" 这个链接有效期1小时, 超过时间您可以 重新申请\n" +"\n" +"
      \n" +" ---\n" +"\n" +"
      \n" +" Login direct\n" +"\n" +"
      \n" +" " + +#: users/utils.py:101 +#, python-format +msgid "" +"\n" +" Hello %(name)s:\n" +"
      \n" +" Please click the link below to reset your password, if not your request, " +"concern your account security\n" +"
      \n" +" Click " +"here reset password\n" +"
      \n" +" This link is valid for 1 hour. After it expires, request new one<\n" +"\n" +"
      \n" +" ---\n" +"\n" +"
      \n" +" Login direct\n" +"\n" +"
      \n" +" " +msgstr "" +"\n" +" 您好 %(name)s:\n" +"
      \n" +" 请点击下面链接重置密码, 如果不是您申请的,请关注账号安全\n" +"
      \n" +" 请点击这" +"里设置密码 /a>\n" +"
      \n" +" 这个链接有效期1小时, 超过时间您可以
      重新申请\n" +"\n" +"
      \n" +" ---\n" +"\n" +"
      \n" +" 直接登录\n" +"\n" +"
      \n" +" " + +#: users/utils.py:132 +#, fuzzy +#| msgid "SSH private key" +msgid "SSH Key Reset" +msgstr "ssh密钥" + +#: users/utils.py:134 +#, python-format +msgid "" +"\n" +" Hello %(name)s:\n" +"
      \n" +" Your ssh public key has been reset by site administrator.\n" +" Please login and reset your ssh public key.\n" +"
      \n" +" Login direct\n" +"\n" +"
      \n" +" " +msgstr "" + +#: users/views.py:75 +msgid "Logout success" +msgstr "退出登录成功" + +#: users/views.py:76 +msgid "Logout success, return login page" +msgstr "退出登录成功,返回到登录页面" + +#: users/views.py:89 +msgid "User list" +msgstr "用户列表" + +#: users/views.py:98 +#, fuzzy, python-format +#| msgid "Create user %s success." +msgid "Create user %s successfully." +msgstr "创建用户 %s 成功" + +#: users/views.py:159 +msgid "User group list" +msgstr "用户组列表" + +#: users/views.py:172 +msgid "Create user group" +msgstr "创建用户组" + +#: users/views.py:198 +#, fuzzy +#| msgid "Update user" +msgid "Update User Group" +msgstr "编辑用户" + +#: users/views.py:235 +msgid "Email address invalid, input again" +msgstr "邮箱地址错误,重新输入" + +#: users/views.py:246 +msgid "Send reset password message" +msgstr "发送重置密码邮件" + +#: users/views.py:247 +msgid "Send reset password mail success, login your mail box and follow it " +msgstr "" +"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" + +#: users/views.py:259 +msgid "Reset password success" +msgstr "重置密码成功" + +#: users/views.py:260 +msgid "Reset password success, return to login page" +msgstr "重置密码成功,返回到登录页面" + +#: users/views.py:276 users/views.py:289 +msgid "Token invalid or expired" +msgstr "Token错误或失效" + +#: users/views.py:285 +msgid "Password not same" +msgstr "密码不一致" + +#: users/views.py:447 +msgid "Invalid file." +msgstr "" + +#: users/views.py:461 +#, fuzzy +#| msgid "ssh private key" +msgid "Not a valid Excel file." +msgstr "ssh密钥" + +#~ msgid "Network" +#~ msgstr "网络" + +#, fuzzy +#~| msgid "Asset number" +#~ msgid "Asset users" +#~ msgstr "资产编号" + +#, fuzzy +#~| msgid "Created by" +#~ msgid "Create idc" +#~ msgstr "创建者" + +#~ msgid "Admin password" +#~ msgstr "管理员密码" + +#, fuzzy +#~| msgid "Create user %s success." +#~ msgid "Update system user %s successfully." +#~ msgstr "创建用户 %s 成功" + +#, fuzzy +#~| msgid "Create perm" +#~ msgid "Create perm " +#~ msgstr "创建权限" + +#~ msgid "Create perm" +#~ msgstr "创建权限" + +#~ msgid "User assets" +#~ msgstr "用户资产" + +#~ msgid "User log" +#~ msgstr "登录日志" + +#, fuzzy +#~| msgid "Create user %s success." +#~ msgid "Update admin user %s successfully." +#~ msgstr "创建用户 %s 成功" + +#~ msgid "Perm" +#~ msgstr "权限" + +#~ msgid "Username or password invalid" +#~ msgstr "用户名或密码错误" diff --git a/apps/manage.py b/apps/manage.py new file mode 100644 index 000000000..d24c5fd38 --- /dev/null +++ b/apps/manage.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +import os +import sys +import errno + +if __name__ == "__main__": + try: + os.makedirs('../logs') + except: + pass + + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/apps/media/avatar/default/default1.png b/apps/media/avatar/default/default1.png new file mode 100644 index 000000000..b90e5efd7 Binary files /dev/null and b/apps/media/avatar/default/default1.png differ diff --git a/apps/media/avatar/default/default2.png b/apps/media/avatar/default/default2.png new file mode 100644 index 000000000..5afa17403 Binary files /dev/null and b/apps/media/avatar/default/default2.png differ diff --git a/apps/media/avatar/default/default3.png b/apps/media/avatar/default/default3.png new file mode 100644 index 000000000..e13e00c70 Binary files /dev/null and b/apps/media/avatar/default/default3.png differ diff --git a/apps/media/avatar/default/default4.png b/apps/media/avatar/default/default4.png new file mode 100644 index 000000000..213295c9c Binary files /dev/null and b/apps/media/avatar/default/default4.png differ diff --git a/apps/media/avatar/default/default5.png b/apps/media/avatar/default/default5.png new file mode 100644 index 000000000..1893c0aea Binary files /dev/null and b/apps/media/avatar/default/default5.png differ diff --git a/apps/media/avatar/default/default6.png b/apps/media/avatar/default/default6.png new file mode 100644 index 000000000..448775e55 Binary files /dev/null and b/apps/media/avatar/default/default6.png differ diff --git a/apps/media/avatar/广宏伟蓝底.jpg b/apps/media/avatar/广宏伟蓝底.jpg new file mode 100644 index 000000000..c25759210 Binary files /dev/null and b/apps/media/avatar/广宏伟蓝底.jpg differ diff --git a/apps/media/files/user_import_template.xlsx b/apps/media/files/user_import_template.xlsx new file mode 100644 index 000000000..5c06ab198 Binary files /dev/null and b/apps/media/files/user_import_template.xlsx differ diff --git a/apps/ops/__init__.py b/apps/ops/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/ops/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/ops/api/__init__.py b/apps/ops/api/__init__.py new file mode 100644 index 000000000..c8b15abe0 --- /dev/null +++ b/apps/ops/api/__init__.py @@ -0,0 +1 @@ +from views import * \ No newline at end of file diff --git a/apps/ops/api/exc.py b/apps/ops/api/exc.py new file mode 100644 index 000000000..81deb805c --- /dev/null +++ b/apps/ops/api/exc.py @@ -0,0 +1,16 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, print_function + +from rest_framework.exceptions import APIException +from django.utils.translation import ugettext as _ + + +class ServiceUnavailable(APIException): + status_code = default_code = 503 + default_detail = _('Service temporarily unavailable, try again later.') + + +class ServiceNotImplemented(APIException): + status_code = default_code = 501 + default_detail = _('This service maybe implemented in the future, but now not implemented!') + diff --git a/apps/ops/api/permissions.py b/apps/ops/api/permissions.py new file mode 100644 index 000000000..0fc0d0861 --- /dev/null +++ b/apps/ops/api/permissions.py @@ -0,0 +1,19 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from rest_framework import permissions + + +class AdminUserRequired(permissions.BasePermission): + """ + Custom permission to only allow admin user to access the resource. + """ + + def has_object_permission(self, request, view, obj): + # Read permissions are allowed to any request, + # so we'll always allow GET, HEAD or OPTIONS requests. + if request.method in permissions.SAFE_METHODS: + return True + + # Write permissions are only allowed to the admin role. + return request.user.is_staff diff --git a/apps/ops/api/serializers.py b/apps/ops/api/serializers.py new file mode 100644 index 000000000..24abe7e2a --- /dev/null +++ b/apps/ops/api/serializers.py @@ -0,0 +1,65 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from ops.models import * +from rest_framework import serializers + + +class HostAliaSerializer(serializers.ModelSerializer): + + class Meta: + model = HostAlia + + +class CmdAliaSerializer(serializers.ModelSerializer): + + class Meta: + model = CmdAlia + + +class UserAliaSerializer(serializers.ModelSerializer): + + class Meta: + model = UserAlia + + +class RunasAliaSerializer(serializers.ModelSerializer): + + class Meta: + model = RunasAlia + + +class ExtraconfSerializer(serializers.ModelSerializer): + + class Meta: + model = Extra_conf + + +class PrivilegeSerializer(serializers.ModelSerializer): + + class Meta: + model = Privilege + + +class SudoSerializer(serializers.ModelSerializer): + + class Meta: + model = Sudo + + +class CronTableSerializer(serializers.ModelSerializer): + + class Meta: + model = CronTable + +class TaskSerializer(serializers.ModelSerializer): + sub_tasks = serializers.PrimaryKeyRelatedField(many=True, read_only=True) + + class Meta: + model = Task + read_only_fields = ('record',) + +class SubTaskSerializer(serializers.ModelSerializer): + + class Meta: + model = SubTask diff --git a/apps/ops/api/views.py b/apps/ops/api/views.py new file mode 100644 index 000000000..eaacb2b76 --- /dev/null +++ b/apps/ops/api/views.py @@ -0,0 +1,79 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals +from rest_framework import viewsets + +from serializers import * +from permissions import * + +__all__ = ["HostAliaViewSet", + "CmdAliaViewSet", + "UserAliaViewSet", + "RunasAliaViewSet", + "ExtraconfViewSet", + "PrivilegeViewSet", + "SudoViewSet", + "CronTableViewSet", + "TaskViewSet", + "SubTaskViewSet", + ] + + +class HostAliaViewSet(viewsets.ModelViewSet): + queryset = HostAlia.objects.all() + serializer_class = HostAliaSerializer + permission_classes = (AdminUserRequired,) + + +class CmdAliaViewSet(viewsets.ModelViewSet): + queryset = CmdAlia.objects.all() + serializer_class = CmdAliaSerializer + permission_classes = (AdminUserRequired,) + + +class UserAliaViewSet(viewsets.ModelViewSet): + queryset = UserAlia.objects.all() + serializer_class = UserAliaSerializer + permission_classes = (AdminUserRequired,) + + +class RunasAliaViewSet(viewsets.ModelViewSet): + queryset = RunasAlia.objects.all() + serializer_class = RunasAliaSerializer + permission_classes = (AdminUserRequired,) + + +class ExtraconfViewSet(viewsets.ModelViewSet): + queryset = Extra_conf.objects.all() + serializer_class = ExtraconfSerializer + permission_classes = (AdminUserRequired,) + + +class PrivilegeViewSet(viewsets.ModelViewSet): + queryset = Privilege.objects.all() + serializer_class = PrivilegeSerializer + permission_classes = (AdminUserRequired,) + + +class SudoViewSet(viewsets.ModelViewSet): + queryset = Sudo.objects.all() + serializer_class = SudoSerializer + permission_classes = (AdminUserRequired,) + + +class CronTableViewSet(viewsets.ModelViewSet): + queryset = CronTable.objects.all() + serializer_class = CronTableSerializer + permission_classes = (AdminUserRequired,) + +class TaskViewSet(viewsets.ModelViewSet): + queryset = Task.objects.all() + serializer_class = TaskSerializer + permission_classes = (AdminUserRequired,) + +class SubTaskViewSet(viewsets.ModelViewSet): + queryset = SubTask.objects.all() + serializer_class = SubTaskSerializer + permission_classes = (AdminUserRequired,) + + + diff --git a/apps/ops/apps.py b/apps/ops/apps.py new file mode 100644 index 000000000..35f09c4b7 --- /dev/null +++ b/apps/ops/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class OpsConfig(AppConfig): + name = 'ops' diff --git a/apps/ops/migrations/__init__.py b/apps/ops/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/ops/models/__init__.py b/apps/ops/models/__init__.py new file mode 100644 index 000000000..b7bfa1e0d --- /dev/null +++ b/apps/ops/models/__init__.py @@ -0,0 +1,6 @@ +from ansible import * +from cron import * +from sudo import * +from utils import * +from task import * + diff --git a/apps/ops/models/ansible.py b/apps/ops/models/ansible.py new file mode 100644 index 000000000..3cf059644 --- /dev/null +++ b/apps/ops/models/ansible.py @@ -0,0 +1,291 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, absolute_import + +import logging +import json + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +__all__ = ["TaskRecord", "AnsiblePlay", "AnsibleTask", "AnsibleHostResult"] + + +logger = logging.getLogger(__name__) + + +class TaskRecord(models.Model): + uuid = models.CharField(max_length=128, verbose_name=_('UUID'), primary_key=True) + name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) + start = models.DateTimeField(auto_now_add=True, verbose_name=_('Start Time')) + end = models.DateTimeField(blank=True, null=True, verbose_name=_('End Time')) + exit_code = models.IntegerField(default=0, verbose_name=_('Exit Code')) + completed = models.BooleanField(default=False, verbose_name=_('Is Completed')) + hosts = models.TextField(blank=True, null=True, verbose_name=_('Hosts')) + + def __unicode__(self): + return "%s" % self.uuid + + @property + def total_hosts(self): + return self.hosts.split(',') + + @classmethod + def generate_fake(cls, count=20): + from random import seed + from uuid import uuid4 + import forgery_py + + seed() + for i in range(count): + tasker = cls(uuid=str(uuid4()), + name=forgery_py.name.full_name(), + ) + try: + tasker.save() + logger.debug('Generate fake tasker: %s' % tasker.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class AnsiblePlay(models.Model): + tasker = models.ForeignKey(TaskRecord, related_name='plays', blank=True, null=True) + uuid = models.CharField(max_length=128, verbose_name=_('UUID'), primary_key=True) + name = models.CharField(max_length=128, verbose_name=_('Name')) + + def __unicode__(self): + return "%s<%s>" % (self.name, self.uuid) + + def to_dict(self): + return {"uuid": self.uuid, "name": self.name} + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + from uuid import uuid4 + import forgery_py + + seed() + for i in range(count): + play = cls(uuid=str(uuid4()), + name=forgery_py.name.full_name(), + ) + try: + play.tasker = choice(TaskRecord.objects.all()) + play.save() + logger.debug('Generate fake play: %s' % play.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class AnsibleTask(models.Model): + play = models.ForeignKey(AnsiblePlay, related_name='tasks', blank=True, null=True) + uuid = models.CharField(max_length=128, verbose_name=_('UUID'), primary_key=True) + name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) + + def __unicode__(self): + return "%s<%s>" % (self.name, self.uuid) + + def to_dict(self): + return {"uuid": self.uuid, "name": self.name} + + def failed(self): + pass + + def success(self): + pass + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + from uuid import uuid4 + import forgery_py + + seed() + for i in range(count): + task = cls(uuid=str(uuid4()), + name=forgery_py.name.full_name(), + ) + try: + task.play = choice(AnsiblePlay.objects.all()) + task.save() + logger.debug('Generate fake play: %s' % task.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class AnsibleHostResult(models.Model): + task = models.ForeignKey(AnsibleTask, related_name='host_results', blank=True, null=True) + name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) + success = models.TextField(blank=True, verbose_name=_('Success')) + skipped = models.TextField(blank=True, verbose_name=_('Skipped')) + failed = models.TextField(blank=True, verbose_name=_('Failed')) + unreachable = models.TextField(blank=True, verbose_name=_('Unreachable')) + no_host = models.TextField(blank=True, verbose_name=_('NoHost')) + + def __unicode__(self): + return "%s %s<%s>" % (self.name, str(self.is_success), self.task.uuid) + + @property + def is_failed(self): + if self.failed or self.unreachable or self.no_host: + return True + return False + + @property + def is_success(self): + return not self.is_failed + + @property + def _success_data(self): + if self.success: + return json.loads(self.success) + elif self.skipped: + return json.loads(self.skipped) + + @property + def _failed_data(self): + if self.failed: + return json.loads(self.failed) + elif self.unreachable: + return json.loads(self.unreachable) + elif self.no_host: + return {"msg": self.no_host} + + @property + def failed_msg(self): + return self._failed_data.get("msg") + + @staticmethod + def __filter_disk(ansible_devices, exclude_devices): + """ + 过滤磁盘设备,丢弃掉不需要的设备 + + :param ansible_devices: 对应的facts字段 + :param exclude_devices: 一个需要被丢弃的设备,匹配规则是startwith, 比如需要丢弃sr0子类的 ['sr'] + :return: 过滤获取的结果 + """ + for start_str in exclude_devices: + for key in ansible_devices.keys(): + if key.startswith(start_str): + ansible_devices.pop(key) + return ansible_devices + + @staticmethod + def __filter_interface(ansible_interfaces, exclude_interface): + """ + 过滤网卡设备,丢弃掉不需要的网卡, 比如lo + + :param ansible_interface: 对应的facts字段 + :param exclude_interface: 一个需要被丢弃的设备,匹配规则是startwith, 比如需要丢弃lo子类的 ['lo'] + :return: 过滤获取的结果 + """ + for interface in ansible_interfaces: + for start_str in exclude_interface: + if interface.startswith(start_str): + i = ansible_interfaces.index(interface) + ansible_interfaces.pop(i) + return ansible_interfaces + + @staticmethod + def __gather_interface(facts, interfaces): + """ + 收集所有interface的具体信息 + + :param facts: ansible faces + :param interfaces: 需要收集的intreface列表 + :return: interface的详情 + """ + result = {} + for key in interfaces: + gather_key = "ansible_" + key + if gather_key in facts.keys(): + result[key] = facts.get(gather_key) + return result + + def __deal_setup(self): + """ + 处理ansible setup模块收集到的数据,提取资产需要的部分 + + :return: {"msg": , "data": }, 注意msg是异常信息, 有msg时 data为None + """ + result = self._success_data + module_name = result['invocation'].get('module_name') if result.get('invocation') else None + if module_name is not None: + if module_name != "setup": + return {"msg": "the property only for ansible setup module result!, can't support other module", "data":None} + else: + data = {} + facts =result.get('ansible_facts') + interfaces = self.__filter_interface(facts.get('ansible_interfaces'), ['lo']) + + cpu_describe = "%s %s" % (facts.get('ansible_processor')[0], facts.get('ansible_processor')[1]) if len(facts.get('ansible_processor')) >= 2 else "" + + data['sn'] = facts.get('ansible_product_serial') + data['env'] = facts.get('ansible_env') + data['os'] = "%s %s(%s)" % (facts.get('ansible_distribution'), + facts.get('ansible_distribution_version'), + facts.get('ansible_distribution_release')) + data['mem'] = facts.get('ansible_memtotal_mb') + data['cpu'] = "%s %d核" % (cpu_describe, facts.get('ansible_processor_count')) + data['disk'] = self.__filter_disk(facts.get('ansible_devices'), ['sr']) + data['interface'] = self.__gather_interface(facts, interfaces) + return {"msg": None, "data": data} + else: + return {"msg": "there result isn't ansible setup module result! can't process this data format", "data": None} + + @property + def deal_setup(self): + try: + return self.__deal_setup() + except Exception as e: + return {"msg": "deal with setup data failed, %s" % e.message, "data": None} + + def __deal_ping(self): + """ + 处理ansible ping模块收集到的数据 + + :return: {"msg": , "data": {"success": }}, 注意msg是异常信息, 有msg时 data为None + """ + result = self._success_data + module_name = result['invocation'].get('module_name') if result.get('invocation') else None + if module_name is not None: + if module_name != "ping": + return {"msg": "the property only for ansible setup module result!, can't support other module", "data":None} + else: + ping = True if result.get('ping') == "pong" else False + + return {"msg": None, "data": {"success": ping}} + else: + return {"msg": "there isn't module_name field! can't process this data format", "data": None} + + @property + def deal_ping(self): + try: + return self.__deal_ping() + except Exception as e: + return {"msg": "deal with ping data failed, %s" % e.message, "data": None} + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + import forgery_py + + seed() + for i in range(count): + result = cls(name=forgery_py.name.full_name(), + success=forgery_py.lorem_ipsum.sentence(), + failed=forgery_py.lorem_ipsum.sentence(), + skipped=forgery_py.lorem_ipsum.sentence(), + unreachable=forgery_py.lorem_ipsum.sentence(), + no_host=forgery_py.lorem_ipsum.sentence(), + ) + try: + result.task = choice(AnsibleTask.objects.all()) + result.save() + logger.debug('Generate fake HostResult: %s' % result.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue diff --git a/apps/ops/models/cron.py b/apps/ops/models/cron.py new file mode 100644 index 000000000..766c46ece --- /dev/null +++ b/apps/ops/models/cron.py @@ -0,0 +1,61 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, absolute_import + +import logging + +from django.db import models +from assets.models import Asset +from django.utils.translation import ugettext_lazy as _ + +logger = logging.getLogger(__name__) + +__all__ = ["CronTable"] + + +class CronTable(models.Model): + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Name'), + help_text=_("Description of a crontab entry")) + month = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Month'), + help_text=_("Month of the year the job should run ( 1-12, *, */2, etc )")) + weekday = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('WeekDay'), + help_text=_("Day of the week that the job should run" + " ( 0-6 for Sunday-Saturday, *, etc )")) + day = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Day'), + help_text=_("Day of the month the job should run ( 1-31, *, */2, etc )")) + hour = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hour'), + help_text=_("Hour when the job should run ( 0-23, *, */2, etc )")) + minute = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Minute'), + help_text=_("Minute when the job should run ( 0-59, *, */2, etc )")) + job = models.CharField(max_length=4096, blank=True, null=True, verbose_name=_('Job'), + help_text=_("The command to execute or, if env is set, the value of " + "environment variable. Required if state=present.")) + user = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('User'), + help_text=_("The specific user whose crontab should be modified.")) + asset = models.ForeignKey(Asset, null=True, blank=True, related_name='crontables') + + @property + def describe(self): + return "http://docs.ansible.com/ansible/cron_module.html" + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + import forgery_py + + seed() + for i in range(count): + cron = cls(name=forgery_py.name.full_name(), + month=str(choice(range(1,13))), + weekday=str(choice(range(0,7))), + day=str(choice(range(1,32))), + hour=str(choice(range(0,24))), + minute=str(choice(range(0,60))), + job=forgery_py.lorem_ipsum.sentence(), + user=forgery_py.name.first_name(), + ) + try: + cron.save() + logger.debug('Generate fake cron: %s' % cron.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue \ No newline at end of file diff --git a/apps/ops/models/sudo.py b/apps/ops/models/sudo.py new file mode 100644 index 000000000..13713064c --- /dev/null +++ b/apps/ops/models/sudo.py @@ -0,0 +1,321 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, absolute_import + +import logging + +from jinja2 import Template +from django.db import models +from django.utils.timezone import now +from assets.models import Asset, AssetGroup +from django.utils.translation import ugettext_lazy as _ + +logger = logging.getLogger(__name__) + +__all__ = ["HostAlia", "UserAlia", "CmdAlia", "RunasAlia", "Privilege", "Extra_conf", "Sudo"] + + +class HostAlia(models.Model): + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Host_Alias')) + host_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + + def __unicode__(self): + return self.name + + @classmethod + def generate_fake(cls, count=20): + from random import seed + import forgery_py + + seed() + for i in range(count): + hostA = cls(name=forgery_py.name.full_name(), + host_items=forgery_py.lorem_ipsum.sentence(), + ) + try: + hostA.save() + logger.debug('Generate fake host alia: %s' % hostA.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class UserAlia(models.Model): + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('User_Alias')) + user_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + + def __unicode__(self): + return self.name + + @classmethod + def generate_fake(cls, count=20): + from random import seed + import forgery_py + + seed() + for i in range(count): + userA = cls(name=forgery_py.name.full_name(), + user_items=forgery_py.lorem_ipsum.sentence(), + ) + try: + userA.save() + logger.debug('Generate fake host alia: %s' % userA.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class CmdAlia(models.Model): + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Command_Alias')) + cmd_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + + def __unicode__(self): + return self.name + + @classmethod + def generate_fake(cls, count=20): + from random import seed + import forgery_py + + seed() + for i in range(count): + cmdA = cls(name=forgery_py.name.full_name(), + cmd_items=forgery_py.lorem_ipsum.sentence(), + ) + try: + cmdA.save() + logger.debug('Generate fake command alia: %s' % cmdA.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class RunasAlia(models.Model): + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Runas_Alias')) + runas_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + + def __unicode__(self): + return self.name + + @classmethod + def generate_fake(cls, count=20): + from random import seed + import forgery_py + + seed() + for i in range(count): + runas = cls(name=forgery_py.name.full_name(), + runas_items=forgery_py.lorem_ipsum.sentence(), + ) + try: + runas.save() + logger.debug('Generate fake RunAs alia: %s' % runas.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class Privilege(models.Model): + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) + user = models.ForeignKey(UserAlia, blank=True, null=True, related_name='privileges') + host = models.ForeignKey(HostAlia, blank=True, null=True, related_name='privileges') + runas = models.ForeignKey(RunasAlia, blank=True, null=True, related_name='privileges') + command = models.ForeignKey(CmdAlia, blank=True, null=True, related_name='privileges') + nopassword = models.BooleanField(default=True, verbose_name=_('Is_NoPassword')) + comment = models.TextField(blank=True, null=True, verbose_name=_('Comment')) + + def __unicode__(self): + return "[%s %s %s %s %s]" % (self.user.name, + self.host.name, + self.runas.name, + self.command.name, + self.nopassword) + + def to_tuple(self): + return self.user.name, self.host.name, self.runas.name, self.command.name, self.nopassword + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + import forgery_py + + seed() + for i in range(count): + pri = cls(name=forgery_py.name.full_name(), + comment=forgery_py.lorem_ipsum.sentence(), + ) + try: + pri.user = choice(UserAlia.objects.all()) + pri.host = choice(HostAlia.objects.all()) + pri.runas = choice(RunasAlia.objects.all()) + pri.command = choice(CmdAlia.objects.all()) + pri.save() + logger.debug('Generate fake privileges: %s' % pri.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue + + +class Extra_conf(models.Model): + line = models.TextField(blank=True, null=True, verbose_name=_('Extra_Item'), + help_text=_('The extra sudo config line.')) + + def __unicode__(self): + return self.line + + +class Sudo(models.Model): + """ + Sudo配置文件对象, 用于配置sudo的配置文件 + + :param extra_lines: [, ,...] + :param privileges: [(user, host, runas, command, nopassword),] + """ + + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'), + help_text=_('Name for this sudo')) + created_time = models.DateTimeField(verbose_name=_('Created Time'), auto_created=True, + help_text=_('The create time of this sudo')) + modify_time = models.DateTimeField(auto_now=True, verbose_name=_('Modify Time'), + help_text=_('The recent modify time of this sudo')) + assets = models.ManyToManyField(Asset, blank=True, related_name='sudos') + asset_groups = models.ManyToManyField(AssetGroup, blank=True, related_name='sudos') + extra_lines = models.ManyToManyField(Extra_conf, related_name='sudos', blank=True) + privilege_items = models.ManyToManyField(Privilege, related_name='sudos', blank=True) + + @property + def all_assets(self): + assets = list(self.assets.all()) + for group in self.asset_groups.all(): + for asset in group.assets.all(): + if asset not in assets: + assets.append(asset) + return assets + + @property + def users(self): + return {privilege.user.name: privilege.user.user_items.split(',') for privilege in self.privilege_items.all()} + + @property + def commands(self): + return {privilege.command.name: privilege.command.cmd_items.split(',') for privilege in self.privilege_items.all()} + + @property + def hosts(self): + return {privilege.host.name: privilege.host.host_items.split(',') for privilege in self.privilege_items.all()} + + @property + def runas(self): + return {privilege.runas.name: privilege.runas.runas_items.split(',') for privilege in self.privilege_items.all()} + + @property + def extras(self): + return [extra.line for extra in self.extra_lines.all()] + + @property + def privileges(self): + return [privilege.to_tuple() for privilege in self.privilege_items.all()] + + @property + def content(self): + template = Template(self.__sudoers_jinja2_tmp__) + context = {"User_Alias": self.users, + "Cmnd_Alias": self.commands, + "Host_Alias": self.hosts, + "Runas_Alias": self.runas, + "Extra_Lines": self.extras, + "Privileges": self.privileges} + return template.render(context) + + @property + def __sudoers_jinja2_tmp__(self): + return """# management by JumpServer +# This file MUST be edited with the 'visudo' command as root. +# +# Please consider adding local content in /etc/sudoers.d/ instead of +# directly modifying this file. +# +# See the man page for details on how to write a sudoers file. +# +Defaults env_reset +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# JumpServer Generate Other Configure is here +{% if Extra_Lines -%} +{% for line in Extra_Lines -%} +{{ line }} +{% endfor %} +{%- endif %} + +# Host alias specification +{% if Host_Alias -%} +{% for flag, items in Host_Alias.iteritems() -%} +Host_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# User alias specification +{% if User_Alias -%} +{% for flag, items in User_Alias.iteritems() -%} +User_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + + +# Cmnd alias specification +{% if Cmnd_Alias -%} +{% for flag, items in Cmnd_Alias.iteritems() -%} +Cmnd_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# Run as alias specification +{% if Runas_Alias -%} +{% for flag, items in Runas_Alias.iteritems() -%} +Runas_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# User privilege specification +root ALL=(ALL:ALL) ALL + +# JumpServer Generate User privilege is here. +# Note privileges is a tuple list like [(user, host, runas, command, nopassword),] +{% if Privileges -%} +{% for User_Flag, Host_Flag, Runas_Flag, Command_Flag, NopassWord in Privileges -%} +{% if NopassWord -%} +{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) NOPASSWD: {{ Command_Flag }} +{%- else -%} +{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) {{ Command_Flag }} +{%- endif %} +{% endfor %} +{%- endif %} + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL + +# Allow members of group sudo to execute any command +%sudo ALL=(ALL:ALL) ALL + +# See sudoers(5) for more information on "#include" directives: + +#includedir /etc/sudoers.d +""" + + @classmethod + def generate_fake(cls, count=20): + from random import seed, choice + import forgery_py + + seed() + for i in range(count): + sudo = cls(name=forgery_py.name.full_name(), + created_time=now() + ) + try: + sudo.save() + sudo.privilege_items = [choice(Privilege.objects.all())] + sudo.save() + logger.debug('Generate fake cron: %s' % sudo.name) + except Exception as e: + print('Error: %s, continue...' % e.message) + continue \ No newline at end of file diff --git a/apps/ops/models/task.py b/apps/ops/models/task.py new file mode 100644 index 000000000..babfbefa5 --- /dev/null +++ b/apps/ops/models/task.py @@ -0,0 +1,58 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, absolute_import + +import logging + +from uuid import uuid4 +from assets.models import Asset +from ops.models import TaskRecord + +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +__all__ = ["Task", "SubTask"] + + +logger = logging.getLogger(__name__) + + +class Task(models.Model): + record = models.OneToOneField(TaskRecord) + name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) + is_gather_facts = models.BooleanField(default=False, verbose_name=_('Is Gather Ansible Facts')) + assets = models.ManyToManyField(Asset, related_name='tasks') + + def __unicode__(self): + return "%s" % self.name + + @property + def ansible_assets(self): + return [] + + def run(self): + from ops.utils.ansible_api import ADHocRunner, Config + conf = Config() + gather_facts = "yes" if self.is_gather_facts else "no" + play_source = { + "name": "Ansible Play", + "hosts": "default", + "gather_facts": gather_facts, + "tasks": [ + dict(action=dict(module='ping')), + ] + } + hoc = ADHocRunner(conf, play_source, *self.ansible_assets) + uuid = "tasker-" + uuid4().hex + ext_code, result = hoc.run("test_task", uuid) + print(ext_code) + print(result) + + +class SubTask(models.Model): + task = models.ForeignKey(Task, related_name='sub_tasks', verbose_name=_('Ansible Task')) + module_name = models.CharField(max_length=128, verbose_name=_('Ansible Module Name')) + module_args = models.CharField(max_length=512, blank=True, verbose_name=_("Ansible Module Args")) + register = models.CharField(max_length=128, blank=True, verbose_name=_('Ansible Task Register')) + + def __unicode__(self): + return "%s %s" % (self.module_name, self.module_args) diff --git a/apps/ops/models/utils.py b/apps/ops/models/utils.py new file mode 100644 index 000000000..17c7cbab1 --- /dev/null +++ b/apps/ops/models/utils.py @@ -0,0 +1,14 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from ansible import * +from cron import * +from sudo import * + +__all__ = ["generate_fake"] + + +def generate_fake(): + for cls in (TaskRecord, AnsiblePlay, AnsibleTask, AnsibleHostResult, CronTable, + HostAlia, UserAlia, CmdAlia, RunasAlia, Privilege, Sudo): + cls.generate_fake() \ No newline at end of file diff --git a/apps/ops/tasks/__init__.py b/apps/ops/tasks/__init__.py new file mode 100644 index 000000000..6fe598964 --- /dev/null +++ b/apps/ops/tasks/__init__.py @@ -0,0 +1 @@ +from taskers import * \ No newline at end of file diff --git a/apps/ops/tasks/_celery_tasks.py b/apps/ops/tasks/_celery_tasks.py new file mode 100644 index 000000000..13fe8d0c1 --- /dev/null +++ b/apps/ops/tasks/_celery_tasks.py @@ -0,0 +1,48 @@ +from __future__ import absolute_import, unicode_literals + +from celery import shared_task + +from common import celery_app +from ops.utils.ansible_api import Config, ADHocRunner + + +@shared_task(name="get_asset_hardware_info") +def get_asset_hardware_info(task_name, task_uuid, *assets): + conf = Config() + play_source = { + "name": "Get host hardware information", + "hosts": "default", + "gather_facts": "no", + "tasks": [ + dict(action=dict(module='setup')) + ] + } + hoc = ADHocRunner(conf, play_source, *assets) + ext_code, result = hoc.run(task_name, task_uuid) + return ext_code, result + + +@shared_task(name="asset_test_ping_check") +def asset_test_ping_check(task_name, task_uuid, *assets): + conf = Config() + play_source = { + "name": "Test host connection use ping", + "hosts": "default", + "gather_facts": "no", + "tasks": [ + dict(action=dict(module='ping')) + ] + } + hoc = ADHocRunner(conf, play_source, *assets) + ext_code, result = hoc.run(task_name, task_uuid) + return ext_code, result + + +@shared_task(name="add_user_to_assert") +def add_user_to_asset(): + pass + + +@celery_app.task(name='hello-world') +def hello(): + print('hello world!') diff --git a/apps/ops/tasks/taskers.py b/apps/ops/tasks/taskers.py new file mode 100644 index 000000000..3a724b049 --- /dev/null +++ b/apps/ops/tasks/taskers.py @@ -0,0 +1,126 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from ops.tasks import _celery_tasks + +from ops.models import TaskRecord +from uuid import uuid1 +from celery.result import AsyncResult + +__all__ = ["get_result", + "start_get_hardware_info", + "start_ping_test", + "get_hardware_info", + "get_ping_test"] + + +def get_result(task_id): + result = AsyncResult(task_id) + if result.ready(): + return {"Completed": True, "data": result.get()} + else: + return {"Completed": False, "data": None} + + +def __get_result_by_tasker_id(tasker_uuid, deal_method): + tasker = TaskRecord.objects.get(uuid=tasker_uuid) + total = tasker.total_hosts + total_len = len(total) + host_results = [] + + # 存储数据 + for play in tasker.plays.all(): + for t in play.tasks.all(): + task = {'name': t.name, 'uuid': t.uuid, 'percentage': 0, 'completed': {'success': {}, 'failed': {}}} + completed = [] + count = 0 + for h in t.host_results.all(): + completed.append(h.name) + count += 1 + if h.is_success: + result = getattr(h, deal_method) + if result.get('msg') is None: + task['completed']['success'][h.name] = result.get('data') + else: + task['completed']['failed'][h.name] = result.get('msg') + else: + task['completed']['failed'][h.name] = h.failed_msg + + # 计算进度 + task['percentage'] = float(count * 100 / total_len) + task['waited'] = list(set(total) - set(completed)) + + host_results.append(task) + + return host_results + + +def start_get_hardware_info(*assets): + name = "Get host hardware information" + uuid = "tasker-" + uuid1().hex + _celery_tasks.get_asset_hardware_info.delay(name, uuid, *assets) + return uuid + + +def __get_hardware_info(tasker_uuid): + return __get_result_by_tasker_id(tasker_uuid, 'deal_setup') + + +def get_hardware_info(tasker_uuid): + """ + + :param assets: 资产列表 + :return: 返回数据结构样列 + {u'data': [{u'completed': { + u'failed': {u'192.168.232.135': u'Authentication failure.'}, + u'success': {u'192.168.1.119': {u'cpu': u'GenuineIntel Intel Xeon E312xx (Sandy Bridge) 6\u6838', + u'disk': {: }, + u'env': {: }, + u'interface': {: }, + u'mem': 3951, + u'os': u'Ubuntu 16.04(xenial)', + u'sn': u'NA'}}}, + u'name': u'', + u'percentage': 100.0, + u'uuid': u'87cfedfe-ba55-44ff-bc43-e7e73b869ca1', + u'waited': []} + ], + u'msg': None} + """ + try: + return {"msg": None, "data": __get_hardware_info(tasker_uuid)} + except Exception as e: + return {"msg": "query data failed!, %s" % e.message, "data": None} + + +def start_ping_test(*assets): + name = "Test host connection" + uuid = "tasker-" + uuid1().hex + _celery_tasks.asset_test_ping_check.delay(name, uuid, *assets) + return uuid + + +def __get_ping_test(tasker_uuid): + return __get_result_by_tasker_id(tasker_uuid, 'deal_ping') + + +def get_ping_test(tasker_uuid): + """ + + :param assets: 资产列表 + :return: 返回数据结构样列 + {u'data': [{u'completed': { + u'failed': {u'192.168.232.135': u'Authentication failure.'}, + u'success': {u'192.168.1.119': {u'success': True}}}, + u'name': u'', + u'percentage': 100.0, + u'uuid': u'3e6e0d3b-bee0-4383-b19e-bec6ba55d346', + u'waited': []} + ], + u'msg': None} + """ + try: + return {"msg": None, "data": __get_ping_test(tasker_uuid)} + except Exception as e: + return {"msg": "query data failed!, %s" % e.message, "data": None} + diff --git a/apps/ops/templates/cron/_cron.html b/apps/ops/templates/cron/_cron.html new file mode 100644 index 000000000..59d03e5ee --- /dev/null +++ b/apps/ops/templates/cron/_cron.html @@ -0,0 +1,97 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      +
      {% block user_template_title %}{% trans 'Create user' %}{% endblock %}
      + +
      +
      +
      + {% csrf_token %} +

      {% trans 'Account' %}

      + {% block username %} {% endblock %} + {{ form.email|bootstrap_horizontal }} + {{ form.name|bootstrap_horizontal }} + {{ form.groups|bootstrap_horizontal }} + +
      + {% block password %} {% endblock %} + +
      +

      {% trans 'Security and Role' %}

      + {{ form.role|bootstrap_horizontal }} +
      + +
      +
      + + +
      + {{ form.date_expired.errors }} +
      +
      +{# {{ form.date_expired|bootstrap_horizontal }}#} +
      + +
      + {{ form.enable_otp }} +
      +
      +
      +

      {% trans 'Profile' %}

      + {{ form.phone|bootstrap_horizontal }} + {{ form.wechat|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
      +
      +
      + + +
      +
      +
      +
      +
      +
      +
      +
      +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/ops/templates/cron/create.html b/apps/ops/templates/cron/create.html new file mode 100644 index 000000000..291a5656a --- /dev/null +++ b/apps/ops/templates/cron/create.html @@ -0,0 +1,16 @@ +{% extends 'cron/_cron.html' %} +{% load i18n %} +{% load bootstrap %} +{% block user_template_title %}{% trans "Create user" %}{% endblock %} +{% block username %} + {{ form.username|bootstrap_horizontal }} +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + {% trans 'Reset link will be generated and sent to the user. ' %} +
      +
      +{% endblock %} \ No newline at end of file diff --git a/apps/ops/templates/cron/detail.html b/apps/ops/templates/cron/detail.html new file mode 100644 index 000000000..6188962ff --- /dev/null +++ b/apps/ops/templates/cron/detail.html @@ -0,0 +1,280 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + + + +{% endblock %} +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {{ cron.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + +
      {% trans 'Name' %}:{{ cron.name }}
      +
      +
      +
      +
      +
      +
      + {% trans 'Quick modify' %} +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      {% trans 'Active' %}: +
      +
      + + +
      +
      +
      {% trans 'Enable OTP' %}: +
      +
      + + +
      +
      +
      {% trans 'Reset password' %}: + + + +
      {% trans 'Reset ssh key' %}: + + + +
      {% trans 'Update ssh key' %}: + + + +
      +
      +
      + +
      +
      + {% trans 'User group' %} +
      +
      + + + + + + + + + + + + {% for group in user_object.groups.all %} + + + + + {% endfor %} + +
      + +
      + +
      {{ group.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + {% include 'users/_user_update_pk_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/ops/templates/cron/list.html b/apps/ops/templates/cron/list.html new file mode 100644 index 000000000..d1a2c78bc --- /dev/null +++ b/apps/ops/templates/cron/list.html @@ -0,0 +1,231 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %} +{% endblock %} +{% block table_container %} + +{##} + + + + + + + + + + + + + +
      +{#
      #} + +
      {% trans 'Name' %}{% trans 'Time(minute-hour-day-month-weekday)' %}{% trans 'Job' %}{% trans 'User' %}{% trans 'Action' %}
      +
      +
      + +
      + +
      +
      +
      +{% include "users/_user_bulk_update_modal.html" %} +{#{% include "users/_user_import_modal.html" %}#} +{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} + diff --git a/apps/ops/templates/cron/update.html b/apps/ops/templates/cron/update.html new file mode 100644 index 000000000..f033e1ed8 --- /dev/null +++ b/apps/ops/templates/cron/update.html @@ -0,0 +1,20 @@ +{% extends 'cron/_cron.html' %} +{% load i18n %} +{% block user_template_title %}{% trans "Update user" %}{% endblock %} +{% block username %} +
      + +
      + +
      +
      +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + +
      +
      +{% endblock %} diff --git a/apps/ops/templates/sudo/_sudo.html b/apps/ops/templates/sudo/_sudo.html new file mode 100644 index 000000000..59d03e5ee --- /dev/null +++ b/apps/ops/templates/sudo/_sudo.html @@ -0,0 +1,97 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      +
      {% block user_template_title %}{% trans 'Create user' %}{% endblock %}
      + +
      +
      +
      + {% csrf_token %} +

      {% trans 'Account' %}

      + {% block username %} {% endblock %} + {{ form.email|bootstrap_horizontal }} + {{ form.name|bootstrap_horizontal }} + {{ form.groups|bootstrap_horizontal }} + +
      + {% block password %} {% endblock %} + +
      +

      {% trans 'Security and Role' %}

      + {{ form.role|bootstrap_horizontal }} +
      + +
      +
      + + +
      + {{ form.date_expired.errors }} +
      +
      +{# {{ form.date_expired|bootstrap_horizontal }}#} +
      + +
      + {{ form.enable_otp }} +
      +
      +
      +

      {% trans 'Profile' %}

      + {{ form.phone|bootstrap_horizontal }} + {{ form.wechat|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
      +
      +
      + + +
      +
      +
      +
      +
      +
      +
      +
      +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/ops/templates/sudo/create.html b/apps/ops/templates/sudo/create.html new file mode 100644 index 000000000..19727e102 --- /dev/null +++ b/apps/ops/templates/sudo/create.html @@ -0,0 +1,16 @@ +{% extends 'sudo/_sudo.html' %} +{% load i18n %} +{% load bootstrap %} +{% block user_template_title %}{% trans "Create user" %}{% endblock %} +{% block username %} + {{ form.username|bootstrap_horizontal }} +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + {% trans 'Reset link will be generated and sent to the user. ' %} +
      +
      +{% endblock %} \ No newline at end of file diff --git a/apps/ops/templates/sudo/detail.html b/apps/ops/templates/sudo/detail.html new file mode 100644 index 000000000..cf6b8e879 --- /dev/null +++ b/apps/ops/templates/sudo/detail.html @@ -0,0 +1,280 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + + + +{% endblock %} +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {{ sudo.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + +
      {% trans 'Name' %}:{{ sudo.name }}
      +
      +
      +
      +
      +
      +
      + {% trans 'Quick modify' %} +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      {% trans 'Active' %}: +
      +
      + + +
      +
      +
      {% trans 'Enable OTP' %}: +
      +
      + + +
      +
      +
      {% trans 'Reset password' %}: + + + +
      {% trans 'Reset ssh key' %}: + + + +
      {% trans 'Update ssh key' %}: + + + +
      +
      +
      + +
      +
      + {% trans 'User group' %} +
      +
      + + + + + + + + + + + + {% for group in user_object.groups.all %} + + + + + {% endfor %} + +
      + +
      + +
      {{ group.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + {% include 'users/_user_update_pk_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/ops/templates/sudo/list.html b/apps/ops/templates/sudo/list.html new file mode 100644 index 000000000..8da993251 --- /dev/null +++ b/apps/ops/templates/sudo/list.html @@ -0,0 +1,226 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %} +{% endblock %} +{% block table_container %} + +{##} + + + + + + + + + + + + + +
      + + {% trans 'Name' %}{% trans 'Privileges' %}{% trans 'Extra Lines' %}{% trans 'Action' %}
      +
      +
      + +
      + +
      +
      +
      +{#{% include "users/_user_bulk_update_modal.html" %}#} +{#{% include "users/_user_import_modal.html" %}#} +{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} + diff --git a/apps/ops/templates/sudo/update.html b/apps/ops/templates/sudo/update.html new file mode 100644 index 000000000..3172d23f4 --- /dev/null +++ b/apps/ops/templates/sudo/update.html @@ -0,0 +1,20 @@ +{% extends 'sudo/_sudo.html' %} +{% load i18n %} +{% block user_template_title %}{% trans "Update user" %}{% endblock %} +{% block username %} +
      + +
      + +
      +
      +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + +
      +
      +{% endblock %} diff --git a/apps/ops/templates/task/_task.html b/apps/ops/templates/task/_task.html new file mode 100644 index 000000000..59d03e5ee --- /dev/null +++ b/apps/ops/templates/task/_task.html @@ -0,0 +1,97 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      +
      {% block user_template_title %}{% trans 'Create user' %}{% endblock %}
      + +
      +
      +
      + {% csrf_token %} +

      {% trans 'Account' %}

      + {% block username %} {% endblock %} + {{ form.email|bootstrap_horizontal }} + {{ form.name|bootstrap_horizontal }} + {{ form.groups|bootstrap_horizontal }} + +
      + {% block password %} {% endblock %} + +
      +

      {% trans 'Security and Role' %}

      + {{ form.role|bootstrap_horizontal }} +
      + +
      +
      + + +
      + {{ form.date_expired.errors }} +
      +
      +{# {{ form.date_expired|bootstrap_horizontal }}#} +
      + +
      + {{ form.enable_otp }} +
      +
      +
      +

      {% trans 'Profile' %}

      + {{ form.phone|bootstrap_horizontal }} + {{ form.wechat|bootstrap_horizontal }} + {{ form.comment|bootstrap_horizontal }} +
      +
      +
      + + +
      +
      +
      +
      +
      +
      +
      +
      +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} diff --git a/apps/ops/templates/task/create.html b/apps/ops/templates/task/create.html new file mode 100644 index 000000000..19727e102 --- /dev/null +++ b/apps/ops/templates/task/create.html @@ -0,0 +1,16 @@ +{% extends 'sudo/_sudo.html' %} +{% load i18n %} +{% load bootstrap %} +{% block user_template_title %}{% trans "Create user" %}{% endblock %} +{% block username %} + {{ form.username|bootstrap_horizontal }} +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + {% trans 'Reset link will be generated and sent to the user. ' %} +
      +
      +{% endblock %} \ No newline at end of file diff --git a/apps/ops/templates/task/detail.html b/apps/ops/templates/task/detail.html new file mode 100644 index 000000000..cf6b8e879 --- /dev/null +++ b/apps/ops/templates/task/detail.html @@ -0,0 +1,280 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + + + +{% endblock %} +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {{ sudo.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + +
      {% trans 'Name' %}:{{ sudo.name }}
      +
      +
      +
      +
      +
      +
      + {% trans 'Quick modify' %} +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      {% trans 'Active' %}: +
      +
      + + +
      +
      +
      {% trans 'Enable OTP' %}: +
      +
      + + +
      +
      +
      {% trans 'Reset password' %}: + + + +
      {% trans 'Reset ssh key' %}: + + + +
      {% trans 'Update ssh key' %}: + + + +
      +
      +
      + +
      +
      + {% trans 'User group' %} +
      +
      + + + + + + + + + + + + {% for group in user_object.groups.all %} + + + + + {% endfor %} + +
      + +
      + +
      {{ group.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + {% include 'users/_user_update_pk_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/ops/templates/task/list.html b/apps/ops/templates/task/list.html new file mode 100644 index 000000000..7109e4fe8 --- /dev/null +++ b/apps/ops/templates/task/list.html @@ -0,0 +1,225 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %} +{% endblock %} +{% block table_container %} + +{##} + + + + + + + + + + + + + + +
      + + {% trans 'Name' %}{% trans 'UUID' %}{% trans 'Start' %}{% trans 'Completed' %}{% trans 'Action' %}
      +
      +
      + +
      + +
      +
      +
      +{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} + diff --git a/apps/ops/templates/task/update.html b/apps/ops/templates/task/update.html new file mode 100644 index 000000000..3172d23f4 --- /dev/null +++ b/apps/ops/templates/task/update.html @@ -0,0 +1,20 @@ +{% extends 'sudo/_sudo.html' %} +{% load i18n %} +{% block user_template_title %}{% trans "Update user" %}{% endblock %} +{% block username %} +
      + +
      + +
      +
      +{% endblock %} +{% block password %} +

      {% trans 'Password' %}

      +
      + +
      + +
      +
      +{% endblock %} diff --git a/apps/ops/tests/__init__.py b/apps/ops/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/ops/tests/tests.py b/apps/ops/tests/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/ops/tests/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/ops/urls/__init__.py b/apps/ops/urls/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/ops/urls/api_urls.py b/apps/ops/urls/api_urls.py new file mode 100644 index 000000000..77141ed35 --- /dev/null +++ b/apps/ops/urls/api_urls.py @@ -0,0 +1,21 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from rest_framework.routers import DefaultRouter +from ops import api as v1_api + +__all__ = ["urlpatterns"] + +api_router = DefaultRouter() +api_router.register(r'v1/host_alia', v1_api.HostAliaViewSet) +api_router.register(r'v1/user_alia', v1_api.UserAliaViewSet) +api_router.register(r'v1/cmd_alia', v1_api.CmdAliaViewSet) +api_router.register(r'v1/runas_alia', v1_api.RunasAliaViewSet) +api_router.register(r'v1/extra_conf', v1_api.ExtraconfViewSet) +api_router.register(r'v1/privilege', v1_api.PrivilegeViewSet) +api_router.register(r'v1/sudo', v1_api.SudoViewSet) +api_router.register(r'v1/cron', v1_api.CronTableViewSet) +api_router.register(r'v1/task', v1_api.TaskViewSet) +api_router.register(r'v1/subtask', v1_api.SubTaskViewSet) + +urlpatterns = api_router.urls \ No newline at end of file diff --git a/apps/ops/urls/view_urls.py b/apps/ops/urls/view_urls.py new file mode 100644 index 000000000..9e9c68253 --- /dev/null +++ b/apps/ops/urls/view_urls.py @@ -0,0 +1,28 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + + +from django.conf.urls import url +from ops import views as page_view + +__all__ = ["urlpatterns"] + +urlpatterns = [ + # Resource Sudo url + url(r'^sudo/list$', page_view.SudoListView.as_view(), name='page-sudo-list'), + url(r'^sudo/create$', page_view.SudoCreateView.as_view(), name='page-sudo-create'), + url(r'^sudo/(?P[0-9]+)/detail$', page_view.SudoDetailView.as_view(), name='page-sudo-detail'), + url(r'^sudo/(?P[0-9]+)/update$', page_view.SudoUpdateView.as_view(), name='page-sudo-update'), + + # Resource Cron url + url(r'^cron/list$', page_view.CronListView.as_view(), name='page-cron-list'), + url(r'^cron/create$', page_view.CronCreateView.as_view(), name='page-cron-create'), + url(r'^cron/(?P[0-9]+)/detail$', page_view.CronDetailView.as_view(), name='page-cron-detail'), + url(r'^cron/(?P[0-9]+)/update$', page_view.CronUpdateView.as_view(), name='page-cron-update'), + + # TResource Task url + url(r'^task/list$', page_view.TaskListView.as_view(), name='page-task-list'), + url(r'^task/create$', page_view.TaskCreateView.as_view(), name='page-task-create'), + url(r'^task/(?P[0-9]+)/detail$', page_view.TaskDetailView.as_view(), name='page-task-detail'), + url(r'^task/(?P[0-9]+)/update$', page_view.TaskUpdateView.as_view(), name='page-task-update'), +] \ No newline at end of file diff --git a/apps/ops/utils/__init__.py b/apps/ops/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/ops/utils/ansible_api.py b/apps/ops/utils/ansible_api.py new file mode 100644 index 000000000..3f3345c5f --- /dev/null +++ b/apps/ops/utils/ansible_api.py @@ -0,0 +1,522 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals, print_function + +import os +import json +import logging +import traceback +import ansible.constants as default_config + +from uuid import uuid4 +from django.utils import timezone +from ansible.executor.task_queue_manager import TaskQueueManager +from ansible.inventory import Inventory, Host, Group +from ansible.vars import VariableManager +from ansible.parsing.dataloader import DataLoader +from ansible.executor import playbook_executor +from ansible.utils.display import Display +from ansible.playbook.play import Play +from ansible.plugins.callback import CallbackBase + +from ops.models import TaskRecord, AnsiblePlay, AnsibleTask, AnsibleHostResult + +__all__ = ["ADHocRunner", "Config"] + + +logger = logging.getLogger(__name__) + + +class AnsibleError(StandardError): + pass + + +class Config(object): + """Ansible运行时配置类, 用于初始化Ansible的一些默认配置. + """ + def __init__(self, verbosity=None, inventory=None, listhosts=None, subset=None, module_paths=None, extra_vars=None, + forks=10, ask_vault_pass=False, vault_password_files=None, new_vault_password_file=None, + output_file=None, tags=None, skip_tags=None, one_line=None, tree=None, ask_sudo_pass=False, ask_su_pass=False, + sudo=None, sudo_user=None, become=None, become_method=None, become_user=None, become_ask_pass=False, + ask_pass=False, private_key_file=None, remote_user=None, connection="smart", timeout=10, ssh_common_args=None, + sftp_extra_args=None, scp_extra_args=None, ssh_extra_args=None, poll_interval=None, seconds=None, check=False, + syntax=None, diff=None, force_handlers=None, flush_cache=None, listtasks=None, listtags=None, module_path=None): + self.verbosity = verbosity + self.inventory = inventory + self.listhosts = listhosts + self.subset = subset + self.module_paths = module_paths + self.extra_vars = extra_vars + self.forks = forks + self.ask_vault_pass = ask_vault_pass + self.vault_password_files = vault_password_files + self.new_vault_password_file = new_vault_password_file + self.output_file = output_file + self.tags = tags + self.skip_tags = skip_tags + self.one_line = one_line + self.tree = tree + self.ask_sudo_pass = ask_sudo_pass + self.ask_su_pass = ask_su_pass + self.sudo = sudo + self.sudo_user = sudo_user + self.become = become + self.become_method = become_method + self.become_user = become_user + self.become_ask_pass = become_ask_pass + self.ask_pass = ask_pass + self.private_key_file = private_key_file + self.remote_user = remote_user + self.connection = connection + self.timeout = timeout + self.ssh_common_args = ssh_common_args + self.sftp_extra_args = sftp_extra_args + self.scp_extra_args = scp_extra_args + self.ssh_extra_args = ssh_extra_args + self.poll_interval = poll_interval + self.seconds = seconds + self.check = check + self.syntax = syntax + self.diff = diff + self.force_handlers = force_handlers + self.flush_cache = flush_cache + self.listtasks = listtasks + self.listtags = listtags + self.module_path = module_path + self.__overwrite_default() + + def __overwrite_default(self): + """上面并不能包含Ansible所有的配置, 如果有其他的配置, + 可以通过替换default_config模块里面的变量进行重载,  + 比如 default_config.DEFAULT_ASK_PASS = False. + """ + default_config.HOST_KEY_CHECKING = False + + +class InventoryMixin(object): + """提供生成Ansible inventory对象的方法 + """ + + def gen_inventory(self): + """用于生成动态构建Ansible Inventory. + self.hosts: [ + {"host": , + "port": , + "user": , + "pass": , + "key": , + "group": + "other_host_var": }, + {...}, + ] + self.group_vars: { + "groupName1": {"var1": , "var2": , ...}, + "groupName2": {"var1": , "var2": , ...}, + } + + :return: 返回一个Ansible的inventory对象 + """ + + # TODO: 验证输入 + + # 创建Ansible Group,如果没有则创建default组 + for asset in self.hosts: + g_name = asset.get('group', 'default') + if g_name not in [g.name for g in self.groups]: + group = Group(name=g_name) + self.groups.append(group) + + # 添加组变量到相应的组上 + for group_name, variables in self.group_vars.iteritems(): + for g in self.groups: + if g.name == group_name: + for v_name, v_value in variables.iteritems(): + g.set_variable(v_name, v_value) + + # 往组里面添加Host + for asset in self.hosts: + # 添加Host链接的常用变量(host,port,user,pass,key) + host = Host(name=asset['name'], port=asset['port']) + host.set_variable('ansible_host', asset['ip']) + host.set_variable('ansible_port', asset['port']) + host.set_variable('ansible_user', asset['username']) + + # 添加密码和秘钥 + if asset.get('password'): + host.set_variable('ansible_ssh_pass', asset['password']) + if asset.get('key'): + host.set_variable('ansible_ssh_private_key_file', asset['key']) + + # 添加become支持 + become = asset.get("become", None) + if become is not None: + host.set_variable("ansible_become", True) + host.set_variable("ansible_become_method", become.get('method')) + host.set_variable("ansible_become_user", become.get('user')) + host.set_variable("ansible_become_pass", become.get('pass')) + else: + host.set_variable("ansible_become", False) + + # 添加其他Host的额外变量 + for key, value in asset.iteritems(): + if key not in ["name", "port", "ip", "username", "password", "key"]: + host.set_variable(key, value) + + # 将host添加到组里面 + for g in self.groups: + if g.name == asset.get('group', 'default'): + g.add_host(host) + + # 将组添加到Inventory里面,生成真正的inventory对象 + inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=[]) + for g in self.groups: + inventory.add_group(g) + self.variable_manager.set_inventory(inventory) + return inventory + + +class CallbackModule(CallbackBase): + """处理和分析Ansible运行结果,并保存数据. + """ + CALLBACK_VERSION = 2.0 + CALLBACK_TYPE = 'stdout' + CALLBACK_NAME = 'json' + + def __init__(self, tasker_id, display=None): + super(CallbackModule, self).__init__(display) + self.results = [] + self.output = {} + self.tasker_id = tasker_id + + def _new_play(self, play): + """将Play保持到数据里面 + """ + ret = { + 'tasker': self.tasker_id, + 'name': play.name, + 'uuid': str(play._uuid), + 'tasks': [] + } + + try: + tasker = TaskRecord.objects.get(uuid=self.tasker_id) + play = AnsiblePlay(tasker, name=ret['name'], uuid=ret['uuid']) + play.save() + except Exception as e: + traceback.print_exc() + logger.error("Save ansible play uuid to database error!, %s" % e.message) + + return ret + + def _new_task(self, task): + """将Task保持到数据库里,需要和Play进行关联 + """ + ret = { + 'name': task.name, + 'uuid': str(task._uuid), + 'failed': {}, + 'unreachable': {}, + 'skipped': {}, + 'no_hosts': {}, + 'success': {} + } + + try: + play = AnsiblePlay.objects.get(uuid=self.__play_uuid) + task = AnsibleTask(play=play, uuid=ret['uuid'], name=ret['name']) + task.save() + except Exception as e: + logger.error("Save ansible task uuid to database error!, %s" % e.message) + + return ret + + @property + def __task_uuid(self): + return self.results[-1]['tasks'][-1]['uuid'] + + @property + def __play_uuid(self): + return self.results[-1]['uuid'] + + def save_task_result(self, result, status): + try: + task = AnsibleTask.objects.get(uuid=self.__task_uuid) + host_result = AnsibleHostResult(task=task, name=result._host) + if status == "failed": + host_result.failed = json.dumps(result._result) + elif status == "unreachable": + host_result.unreachable = json.dumps(result._result) + elif status == "skipped": + host_result.skipped = json.dumps(result._result) + elif status == "success": + host_result.success = json.dumps(result._result) + else: + logger.error("No such status(failed|unreachable|skipped|success), please check!") + host_result.save() + except Exception as e: + logger.error("Save Ansible host result to database error!, %s" % e.message) + + @staticmethod + def save_no_host_result(task): + try: + task = AnsibleTask.objects.get(uuid=task._uuid) + host_result = AnsibleHostResult(task=task, no_host="no host to run this task") + host_result.save() + except Exception as e: + logger.error("Save Ansible host result to database error!, %s" % e.message) + + def v2_runner_on_failed(self, result, ignore_errors=False): + self.save_task_result(result, "failed") + host = result._host + self.results[-1]['tasks'][-1]['failed'][host.name] = result._result + + def v2_runner_on_unreachable(self, result): + self.save_task_result(result, "unreachable") + host = result._host + self.results[-1]['tasks'][-1]['unreachable'][host.name] = result._result + + def v2_runner_on_skipped(self, result): + self.save_task_result(result, "skipped") + host = result._host + self.results[-1]['tasks'][-1]['skipped'][host.name] = result._result + + def v2_runner_on_no_hosts(self, task): + self.save_no_host_result(task) + self.results[-1]['tasks'][-1]['no_hosts']['msg'] = "no host to run this task" + + def v2_runner_on_ok(self, result): + self.save_task_result(result, "success") + host = result._host + self.results[-1]['tasks'][-1]['success'][host.name] = result._result + + def v2_playbook_on_play_start(self, play): + self.results.append(self._new_play(play)) + + def v2_playbook_on_task_start(self, task, is_conditional): + self.results[-1]['tasks'].append(self._new_task(task)) + + def v2_playbook_on_stats(self, stats): + """AdHoc模式下这个钩子不会执行 + """ + hosts = sorted(stats.processed.keys()) + + summary = {} + for h in hosts: + s = stats.summarize(h) + summary[h] = s + + self.output['plays'] = self.results + self.output['stats'] = summary + print("summary: %s", summary) + + +class PlayBookRunner(InventoryMixin): + """用于执行AnsiblePlaybook的接口.简化Playbook对象的使用. + """ + + def __init__(self, config, palybook_path, playbook_var, become_pass, *hosts, **group_vars): + """ + + :param config: Config实例 + :param palybook_path: playbook的路径 + :param playbook_var: 执行Playbook时的变量 + :param become_pass: sudo passsword + :param hosts: 可变位置参数, 为一个资产列表, 每一个资产用dict表示, 以下是这个dict必须包含的key + [{ + "name": "asset_name", + "ip": "asset_ip", + "port": "asset_port", + "username": "asset_user", + "password": "asset_pass", + "key": "asset_private_key", + "group": "asset_group_name", + ... + }] + :param group_vars: 可变关键字参数, 是资产组变量, 记录对应的资产组变量 + "groupName1": {"group_variable1": "value1",...} + "groupName2": {"group_variable1": "value1",...} + """ + + self.options = config + + # 设置verbosity级别, 及命令行的--verbose选项 + self.display = Display() + self.display.verbosity = self.options.verbosity + playbook_executor.verbosity = self.options.verbosity + + # sudo成其他用户的配置 + self.options.become = True + self.options.become_method = 'sudo' + self.options.become_user = 'root' + passwords = {'become_pass': become_pass} + + # 传入playbook的路径,以及执行需要的变量 + pb_dir = os.path.dirname(__file__) + playbook = "%s/%s" % (pb_dir, palybook_path) + + # 生成Ansible inventory, 这些变量Mixin都会用到 + self.hosts = hosts + self.group_vars = group_vars + self.loader = DataLoader() + self.variable_manager = VariableManager() + self.groups = [] + self.variable_manager.extra_vars = playbook_var + self.inventory = self.gen_inventory() + + # 初始化playbook的executor + self.pbex = playbook_executor.PlaybookExecutor( + playbooks=[playbook], + inventory=self.inventory, + variable_manager=self.variable_manager, + loader=self.loader, + options=self.options, + passwords=passwords) + + def run(self): + """执行Playbook, 记录执行日志, 处理执行结果. + :return: 对象 + """ + self.pbex.run() + stats = self.pbex._tqm._stats + + # 测试执行是否成功 + run_success = True + hosts = sorted(stats.processed.keys()) + for h in hosts: + t = stats.summarize(h) + if t['unreachable'] > 0 or t['failures'] > 0: + run_success = False + + # TODO: 记录执行日志, 处理执行结果. + + return stats + + +class ADHocRunner(InventoryMixin): + """ADHoc接口 + """ + def __init__(self, play_data, config=None, *hosts, **group_vars): + """ + :param hosts: 见PlaybookRunner参数 + :param group_vars: 见PlaybookRunner参数 + :param config: Config实例 + + :param play_data: + play_data = dict( + name="Ansible Ad-Hoc", + hosts=pattern, + gather_facts=True, + tasks=[dict(action=dict(module='service', args={'name': 'vsftpd', 'state': 'restarted'}), async=async, poll=poll)] + ) + """ + self.options = config if config != None else Config() + + # 设置verbosity级别, 及命令行的--verbose选项 + self.display = Display() + self.display.verbosity = self.options.verbosity + + # sudo的配置移到了Host级别去了,因此这里不再需要处理 + self.passwords = None + + # 生成Ansible inventory, 这些变量Mixin都会用到 + self.hosts = hosts + self.group_vars = group_vars + self.loader = DataLoader() + self.variable_manager = VariableManager() + self.groups = [] + self.inventory = self.gen_inventory() + + self.play = Play().load(play_data, variable_manager=self.variable_manager, loader=self.loader) + + @staticmethod + def update_db_tasker(tasker_id, ext_code): + try: + tasker = TaskRecord.objects.get(uuid=tasker_id) + tasker.end = timezone.now() + tasker.completed = True + tasker.exit_code = ext_code + tasker.save() + except Exception as e: + logger.error("Update Tasker Status into database error!, %s" % e.message) + + def create_db_tasker(self, name, uuid): + try: + hosts = [host.get('name') for host in self.hosts] + tasker = TaskRecord(name=name, uuid=uuid, hosts=','.join(hosts), start=timezone.now()) + tasker.save() + except Exception as e: + logger.error("Save Tasker to database error!, %s" % e.message) + + def run(self, tasker_name, tasker_uuid): + """执行ADHoc, 执行完后, 修改AnsiblePlay的状态为完成状态. + + :param tasker_uuid 用于标示此次task + """ + # 初始化callback插件,以及Tasker + + self.create_db_tasker(tasker_name, tasker_uuid) + self.results_callback = CallbackModule(tasker_uuid) + + tqm = None + # TODO:日志和结果分析 + try: + tqm = TaskQueueManager( + inventory=self.inventory, + variable_manager=self.variable_manager, + loader=self.loader, + stdout_callback=self.results_callback, + options=self.options, + passwords=self.passwords + ) + ext_code = tqm.run(self.play) + result = self.results_callback.results + + # 任务运行结束, 标示任务完成 + self.update_db_tasker(tasker_uuid, ext_code) + + ret = json.dumps(result) + return ext_code, ret + + finally: + if tqm: + tqm.cleanup() + + +def test_run(): + conf = Config() + assets = [ + { + "name": "192.168.1.119", + "ip": "192.168.1.119", + "port": "22", + "username": "root", + "password": "tongfang_test", + "key": "asset_private_key", + }, + { + "name": "192.168.232.135", + "ip": "192.168.232.135", + "port": "22", + "username": "yumaojun", + "password": "xxx", + "key": "asset_private_key", + "become": {"method": "sudo", "user": "root", "pass": "xxx"} + }, + ] + # 初始化Play + play_source = { + "name": "Ansible Play", + "hosts": "default", + "gather_facts": "no", + "tasks": [ + dict(action=dict(module='ping')), + ] + } + hoc = ADHocRunner(conf, play_source, *assets) + uuid = "tasker-" + uuid4().hex + ext_code, result = hoc.run("test_task", uuid) + print(ext_code) + print(result) + + +if __name__ == "__main__": + test_run() diff --git a/apps/ops/utils/mixins.py b/apps/ops/utils/mixins.py new file mode 100644 index 000000000..9f925a420 --- /dev/null +++ b/apps/ops/utils/mixins.py @@ -0,0 +1,13 @@ +# ~*~ coding: utf-8 ~*~ + + +class CreateSudoPrivilegesMixin(object): + + def create_privilege(self): + pass + + +class ListSudoPrivilegesMixin(object): + + def get_all_privilege(self): + pass \ No newline at end of file diff --git a/apps/ops/views.py b/apps/ops/views.py new file mode 100644 index 000000000..cf07aee59 --- /dev/null +++ b/apps/ops/views.py @@ -0,0 +1,87 @@ +# ~*~ coding: utf-8 ~*~ +from __future__ import unicode_literals + +from django.conf import settings +from django.views.generic.list import ListView, MultipleObjectMixin +from django.views.generic.edit import CreateView, DeleteView, UpdateView +from django.views.generic.detail import DetailView, SingleObjectMixin + +from users.utils import AdminUserRequiredMixin +from ops.utils.mixins import CreateSudoPrivilegesMixin, ListSudoPrivilegesMixin +from ops.models import * + + +class SudoListView(AdminUserRequiredMixin, ListSudoPrivilegesMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + model = Sudo + context_object_name = 'sudos' + template_name = 'sudo/list.html' + + +class SudoCreateView(AdminUserRequiredMixin, CreateSudoPrivilegesMixin, CreateView): + model = Sudo + template_name = 'sudo/create.html' + + +class SudoUpdateView(AdminUserRequiredMixin, UpdateView): + model = Sudo + template_name = 'sudo/update.html' + + +class SudoDetailView(DetailView): + model = Sudo + context_object_name = 'sudo' + template_name = 'sudo/detail.html' + + +class CronListView(AdminUserRequiredMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + model = CronTable + context_object_name = 'crons' + template_name = 'cron/list.html' + + +class CronCreateView(AdminUserRequiredMixin, CreateView): + model = CronTable + template_name = 'cron/create.html' + + +class CronUpdateView(AdminUserRequiredMixin, UpdateView): + model = CronTable + template_name = 'cron/update.html' + + +class CronDetailView(DetailView): + model = CronTable + context_object_name = 'cron' + template_name = 'cron/detail.html' + +class TaskListView(AdminUserRequiredMixin, ListView): + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + model = Task + context_object_name = 'tasks' + template_name = 'task/list.html' + + def get_context_data(self, **kwargs): + context = { + 'task': 'Assets', + 'action': 'Create asset', + } + kwargs.update(context) + return super(TaskListView, self).get_context_data(**kwargs) + + +class TaskCreateView(AdminUserRequiredMixin, CreateView): + model = Task + template_name = 'task/create.html' + + +class TaskUpdateView(AdminUserRequiredMixin, UpdateView): + model = Task + template_name = 'task/update.html' + + +class TaskDetailView(DetailView): + model = Task + context_object_name = 'task' + template_name = 'task/detail.html' diff --git a/apps/perms/__init__.py b/apps/perms/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/perms/api.py b/apps/perms/api.py new file mode 100644 index 000000000..0854feb0a --- /dev/null +++ b/apps/perms/api.py @@ -0,0 +1,263 @@ +# ~*~ coding: utf-8 ~*~ +# + +from django.shortcuts import get_object_or_404 +from rest_framework.views import APIView, Response +from rest_framework.generics import ListAPIView, get_object_or_404 +from rest_framework import viewsets +from users.permissions import IsValidUser, IsSuperUser, IsAppUser +from common.utils import get_object_or_none +from .utils import get_user_granted_assets, get_user_granted_asset_groups, \ + get_user_asset_permissions, get_user_group_asset_permissions, \ + get_user_group_granted_assets, get_user_group_granted_asset_groups +from .models import AssetPermission +from .hands import AssetGrantedSerializer, User, UserGroup, AssetGroup, Asset, \ + AssetGroup, AssetGroupSerializer, SystemUser +from . import serializers +from .utils import associate_system_users_and_assets + + +class AssetPermissionViewSet(viewsets.ModelViewSet): + queryset = AssetPermission.objects.all() + serializer_class = serializers.AssetPermissionSerializer + permission_classes = (IsSuperUser,) + + def get_queryset(self): + queryset = super(AssetPermissionViewSet, self).get_queryset() + user_id = self.request.query_params.get('user', '') + user_group_id = self.request.query_params.get('user_group', '') + + if user_id and user_id.isdigit(): + user = get_object_or_404(User, id=int(user_id)) + queryset = get_user_asset_permissions(user) + + if user_group_id: + user_group = get_object_or_404(UserGroup, id=user_group_id) + queryset = get_user_group_asset_permissions(user_group) + return queryset + + # Todo: 忘记为何要重写get_serializer_class了 + def get_serializer_class(self): + if getattr(self, 'user_id', ''): + return serializers.UserAssetPermissionSerializer + return serializers.AssetPermissionSerializer + + def associate_system_users_and_assets(self, serializer): + assets = serializer.validated_data.get('assets', []) + asset_groups = serializer.validated_data.get('asset_groups', []) + system_users = serializer.validated_data.get('system_users', []) + if serializer.partial: + instance = self.get_object() + assets.extend(list(instance.assets.all())) + asset_groups.extend(list(instance.asset_groups.all())) + system_users.extend(list(instance.system_users.all())) + print('Run') + associate_system_users_and_assets(system_users, assets, asset_groups) + + def perform_create(self, serializer): + self.associate_system_users_and_assets(serializer) + return super(AssetPermissionViewSet, self).perform_create(serializer) + + def perform_update(self, serializer): + self.associate_system_users_and_assets(serializer) + return super(AssetPermissionViewSet, self).perform_update(serializer) + + +class RevokeUserAssetPermission(APIView): + permission_classes = (IsSuperUser,) + + def put(self, request, *args, **kwargs): + permission_id = str(request.data.get('id', '')) + user_id = str(request.data.get('user_id', '')) + + if permission_id and user_id and permission_id.isdigit() and user_id.isdigit(): + asset_permission = get_object_or_404(AssetPermission, id=int(permission_id)) + user = get_object_or_404(User, id=int(user_id)) + + if asset_permission and user: + asset_permission.users.remove(user) + return Response({'msg': 'success'}) + return Response({'msg': 'failed'}, status=404) + + +class RemoveSystemUserAssetPermission(APIView): + """将系统用户从授权中移除, Detail页面会调用""" + permission_classes = (IsSuperUser,) + + def put(self, request, *args, **kwargs): + response = [] + asset_permission_id = kwargs.pop('pk') + system_users_id = request.data.get('system_users') + print(system_users_id) + asset_permission = get_object_or_404( + AssetPermission, id=asset_permission_id) + if not isinstance(system_users_id, list): + system_users_id = [system_users_id] + for system_user_id in system_users_id: + system_user = get_object_or_none(SystemUser, id=system_user_id) + if system_user: + asset_permission.system_users.remove(system_user) + response.append(system_user.to_json()) + return Response(response, status=200) + + +class RevokeUserGroupAssetPermission(APIView): + permission_classes = (IsSuperUser,) + + def put(self, request, *args, **kwargs): + permission_id = str(request.data.get('id', '')) + user_group_id = str(request.data.get('user_group_id', '')) + + if permission_id and user_group_id and permission_id.isdigit() and user_group_id.isdigit(): + asset_permission = get_object_or_404(AssetPermission, id=int(permission_id)) + user_group = get_object_or_404(UserGroup, id=int(user_group_id)) + + if asset_permission and user_group: + asset_permission.user_groups.remove(user_group) + return Response({'msg': 'success'}) + return Response({'msg': 'failed'}, status=404) + + +class UserGrantedAssetsApi(ListAPIView): + permission_classes = (IsSuperUser,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + + queryset = [] + if user_id: + user = get_object_or_404(User, id=user_id) + for k, v in get_user_granted_assets(user).items(): + k.system_users_granted = v + queryset.append(k) + return queryset + + +class UserGrantedAssetGroupsApi(ListAPIView): + permission_classes = (IsSuperUser,) + serializer_class = AssetGroupSerializer + + def get_queryset(self): + user_id = self.kwargs.get('pk', '') + + if user_id: + user = get_object_or_404(User, id=user_id) + queryset = get_user_granted_asset_groups(user) + else: + queryset = [] + return queryset + + +class MyGrantedAssetsApi(ListAPIView): + """授权给用户的资产列表 + [{'hostname': 'x','ip': 'x', .., + 'system_users_granted': [{'name': 'x', .}, ...] + """ + permission_classes = (IsValidUser,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + queryset = [] + user = self.request.user + if user: + for asset, system_users in get_user_granted_assets(user).items(): + asset.system_users_granted = system_users + queryset.append(asset) + return queryset + + +class MyGrantedAssetsGroupsApi(APIView): + """授权给用户的资产组列表, 非直接通过授权规则授权的资产组列表, 而是授权资产的所有 + 资产组之和""" + permission_classes = (IsValidUser,) + + def get(self, request, *args, **kwargs): + asset_groups = {} + user = request.user + + if user: + assets = get_user_granted_assets(user) + for asset in assets: + for asset_group in asset.groups.all(): + if asset_group.id in asset_groups: + asset_groups[asset_group.id]['assets_amount'] += 1 + else: + asset_groups[asset_group.id] = { + 'id': asset_group.id, + 'name': asset_group.name, + 'comment': asset_group.comment, + 'assets_amount': 1 + } + asset_groups_json = asset_groups.values() + return Response(asset_groups_json, status=200) + + +class MyAssetGroupAssetsApi(ListAPIView): + """授权用户资产组下的资产列表, 非该资产组的所有资产,而是被授权的""" + permission_classes = (IsValidUser,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + queryset = [] + asset_group_id = self.kwargs.get('pk', -1) + user = self.request.user + asset_group = get_object_or_none(AssetGroup, id=asset_group_id) + + if user and asset_group: + assets = get_user_granted_assets(user) + for asset in asset_group.assets.all(): + if asset in assets: + asset.system_users_granted = assets[asset] + queryset.append(asset) + return queryset + + +class UserGroupGrantedAssetsApi(ListAPIView): + permission_classes = (IsSuperUser,) + serializer_class = AssetGrantedSerializer + + def get_queryset(self): + user_group_id = self.kwargs.get('pk', '') + + if user_group_id: + user_group = get_object_or_404(UserGroup, id=user_group_id) + queryset = get_user_group_granted_assets(user_group) + else: + queryset = [] + return queryset + + +class UserGroupGrantedAssetGroupsApi(ListAPIView): + permission_classes = (IsSuperUser,) + serializer_class = AssetGroupSerializer + + def get_queryset(self): + user_group_id = self.kwargs.get('pk', '') + + if user_group_id: + user_group = get_object_or_404(UserGroup, id=user_group_id) + queryset = get_user_group_granted_asset_groups(user_group) + else: + queryset = [] + return queryset + + +class ValidateUserAssetPermissionView(APIView): + permission_classes = (IsAppUser,) + + @staticmethod + def get(request): + user_id = request.query_params.get('user_id', '') + asset_id = request.query_params.get('asset_id', '') + system_id = request.query_params.get('system_user_id', '') + + user = get_object_or_404(User, id=user_id) + asset = get_object_or_404(Asset, id=asset_id) + system_user = get_object_or_404(SystemUser, id=system_id) + + assets_granted = get_user_granted_assets(user) + if system_user in assets_granted.get(asset, []): + return Response({'msg': True}, status=200) + else: + return Response({'msg': False}, status=403) diff --git a/apps/perms/apps.py b/apps/perms/apps.py new file mode 100644 index 000000000..d40373e08 --- /dev/null +++ b/apps/perms/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class PermsConfig(AppConfig): + name = 'perms' diff --git a/apps/perms/forms.py b/apps/perms/forms.py new file mode 100644 index 000000000..d99dfa3be --- /dev/null +++ b/apps/perms/forms.py @@ -0,0 +1,40 @@ +# ~*~ coding: utf-8 ~*~ + +from __future__ import absolute_import, unicode_literals +from django import forms +from django.utils.translation import ugettext_lazy as _ + +# from .hands import User, UserGroup, Asset, AssetGroup, SystemUser +from .models import AssetPermission + + +class AssetPermissionForm(forms.ModelForm): + class Meta: + model = AssetPermission + fields = [ + 'name', 'users', 'user_groups', 'assets', 'asset_groups', + 'system_users', 'is_active', 'date_expired', 'comment', + ] + widgets = { + 'users': forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select users')}), + 'user_groups': forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select user groups')}), + 'assets': forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select assets')}), + 'asset_groups': forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select asset groups')}), + 'system_users': forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select system users')}), + } + help_texts = { + 'name': '* required', + 'user_groups': '* User or user group at least one required', + 'asset_groups': '* Asset or Asset group at least one required', + 'system_users': '* required', + } diff --git a/apps/perms/hands.py b/apps/perms/hands.py new file mode 100644 index 000000000..dd8e61090 --- /dev/null +++ b/apps/perms/hands.py @@ -0,0 +1,15 @@ +# ~*~ coding: utf-8 ~*~ +# + +from users.utils import AdminUserRequiredMixin +from users.models import User, UserGroup +from assets.models import Asset, AssetGroup, SystemUser +from assets.serializers import AssetGrantedSerializer, AssetGroupSerializer + + +def push_system_user(assets, system_user): + print('Push system user %s' % system_user.name) + for asset in assets: + print('\tAsset: %s' % asset.ip) + + diff --git a/apps/perms/migrations/__init__.py b/apps/perms/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/perms/models.py b/apps/perms/models.py new file mode 100644 index 000000000..1cdd39558 --- /dev/null +++ b/apps/perms/models.py @@ -0,0 +1,91 @@ +from __future__ import unicode_literals, absolute_import +import functools + +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.utils import timezone +from django.db.models.signals import m2m_changed + +from users.models import User, UserGroup +from assets.models import Asset, AssetGroup, SystemUser +from common.utils import date_expired_default, combine_seq + + +class AssetPermission(models.Model): + # PRIVATE_FOR_CHOICE = ( + # ('N', 'None'), + # ('U', 'user'), + # ('G', 'user group'), + # ) + name = models.CharField( + max_length=128, unique=True, verbose_name=_('Name')) + users = models.ManyToManyField( + User, related_name='asset_permissions', blank=True) + user_groups = models.ManyToManyField( + UserGroup, related_name='asset_permissions', blank=True) + assets = models.ManyToManyField( + Asset, related_name='granted_by_permissions', blank=True) + asset_groups = models.ManyToManyField( + AssetGroup, related_name='granted_by_permissions', blank=True) + system_users = models.ManyToManyField( + SystemUser, related_name='granted_by_permissions') + is_active = models.BooleanField( + default=True, verbose_name=_('Active')) + date_expired = models.DateTimeField( + default=date_expired_default, verbose_name=_('Date expired')) + created_by = models.CharField( + max_length=128, blank=True, verbose_name=_('Created by')) + date_created = models.DateTimeField( + auto_now_add=True, verbose_name=_('Date created')) + comment = models.TextField(verbose_name=_('Comment'), blank=True) + + def __unicode__(self): + return self.name + + @property + def is_valid(self): + if self.date_expired < timezone.now() and self.is_active: + return True + return True + + def get_granted_users(self): + return list(set(self.users.all()) | self.get_granted_user_groups_member()) + + def get_granted_user_groups_member(self): + users = set() + for user_group in self.user_groups.all(): + for user in user_group.users.all(): + setattr(user, 'is_inherit_from_user_groups', True) + setattr(user, 'inherit_from_user_groups', + getattr(user, b'inherit_from_user_groups', set()).add(user_group)) + users.add(user) + return users + + def get_granted_assets(self): + return list(set(self.assets.all()) | self.get_granted_asset_groups_member()) + + def get_granted_asset_groups_member(self): + assets = set() + for asset_group in self.asset_groups.all(): + for asset in asset_group.assets.all(): + setattr(asset, 'is_inherit_from_asset_groups', True) + setattr(asset, 'inherit_from_asset_groups', + getattr(asset, b'inherit_from_user_groups', set()).add(asset_group)) + assets.add(asset) + return assets + + class Meta: + db_table = 'asset_permission' + + +# def change_permission(sender, **kwargs): +# print('Sender: %s' % sender) +# for k, v in kwargs.items(): +# print('%s: %s' % (k, v)) +# print() + +# +# m2m_changed.connect(change_permission, sender=AssetPermission.assets.through) + + + diff --git a/apps/perms/serializers.py b/apps/perms/serializers.py new file mode 100644 index 000000000..8d2e605e2 --- /dev/null +++ b/apps/perms/serializers.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# + +from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers +from common.utils import get_object_or_none +from .models import AssetPermission +from .hands import User + + +class AssetPermissionSerializer(serializers.ModelSerializer): + class Meta: + model = AssetPermission + fields = '__all__' + + +class UserAssetPermissionSerializer(AssetPermissionSerializer): + is_inherited = serializers.SerializerMethodField() + + @staticmethod + def get_is_inherited(obj): + if getattr(obj, 'inherited', ''): + return True + else: + return False + diff --git a/apps/perms/templates/perms/asset_permission_asset.html b/apps/perms/templates/perms/asset_permission_asset.html new file mode 100644 index 000000000..2cf96cb56 --- /dev/null +++ b/apps/perms/templates/perms/asset_permission_asset.html @@ -0,0 +1,194 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {% trans 'Asset list of ' %} {{ asset_permission.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + + + + + + {% for asset in page_obj %} + + + + + + + + + {% endfor %} + +
      {% trans 'Hostname' %}{% trans 'IP' %}{% trans 'Port' %}{% trans 'Is valid' %}
      {{ asset.hostname }}{{ asset.ip }}{{ user.port }} + {% if asset.is_active %} + + {% else %} + + {% endif %} + + +
      +
      + {% include '_pagination.html' %} +
      +
      +
      +
      +
      +
      +
      + {% trans 'Add asset to this permission' %} +
      +
      + + + + + + + + + + + +
      + +
      + +
      +
      +
      + +
      +
      + {% trans 'Add asset group to this permission' %} +
      +
      + + + + + + + + + + + + {% for asset_group in asset_groups %} + + + + + {% endfor %} + +
      + +
      + +
      {{ asset_group.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/perms/templates/perms/asset_permission_create_update.html b/apps/perms/templates/perms/asset_permission_create_update.html new file mode 100644 index 000000000..8d7c10924 --- /dev/null +++ b/apps/perms/templates/perms/asset_permission_create_update.html @@ -0,0 +1,94 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      +
      {% trans 'Create asset permission ' %}
      + +
      +
      +
      + {% csrf_token %} +

      {% trans 'Name' %}

      + {{ form.name|bootstrap_horizontal }} +
      +

      {% trans 'User' %}

      + {{ form.users|bootstrap_horizontal }} + {{ form.user_groups|bootstrap_horizontal }} +
      +

      {% trans 'Asset' %}

      + {{ form.assets|bootstrap_horizontal }} + {{ form.asset_groups|bootstrap_horizontal }} + {{ form.system_users |bootstrap_horizontal }} +
      +

      {% trans 'Other' %}

      +
      + +
      + {{ form.is_active }} +
      +
      + +
      + +
      +
      + + +
      + {{ form.date_expired.errors }} +
      +
      + {{ form.comment|bootstrap_horizontal }} + +
      +
      + + +
      +
      +
      +
      +
      +
      +
      +
      +{% endblock %} +{% block custom_foot_js %} + + +{% endblock %} \ No newline at end of file diff --git a/apps/perms/templates/perms/asset_permission_detail.html b/apps/perms/templates/perms/asset_permission_detail.html new file mode 100644 index 000000000..c7d47b3ca --- /dev/null +++ b/apps/perms/templates/perms/asset_permission_detail.html @@ -0,0 +1,269 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {{ asset_permission.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {% trans 'Name' %}:{{ asset_permission.name }}
      {% trans 'User count' %}:{{ asset_permission.users.count }}
      {% trans 'User group count' %}:{{ asset_permission.users.count }}
      {% trans 'Asset count' %}:{{ asset_permission.assets.count }}
      {% trans 'Asset group count' %}:{{ asset_permission.asset_groups.count }}
      {% trans 'System user count' %}:{{ asset_permission.system_users.count }}
      {% trans 'Date expired' %}:{{ asset_permission.date_expired }}
      {% trans 'Date created' %}:{{ asset_permission.date_created }}
      {% trans 'Created by' %}:{{ asset_permission.created_by }}
      {% trans 'Comment' %}:{{ asset_permission.comment }}
      +
      +
      +
      + +
      +
      +
      + {% trans 'Quick update' %} +
      +
      + + + + + + + + + + + + + + + + +
      Active: +
      +
      + + +
      +
      +
      {% trans 'Retest asset connectivity' %}: + + + +
      {% trans 'Repush system user' %}: + + + +
      +
      +
      + +
      +
      + {% trans 'System user' %} +
      +
      + + + + + + + + + + + + {% for system_user in system_users %} + + + + + {% endfor %} + +
      + +
      + +
      {{ system_user.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/perms/templates/perms/asset_permission_list.html b/apps/perms/templates/perms/asset_permission_list.html new file mode 100644 index 000000000..43bab6e70 --- /dev/null +++ b/apps/perms/templates/perms/asset_permission_list.html @@ -0,0 +1,71 @@ +{% extends '_base_list.html' %} +{% load i18n %} +{% block content_left_head %} + + {% trans "Create permission" %} + +{% endblock %} + +{% block table_head %} + {% trans 'ID' %} + {% trans 'Name' %} + {% trans 'User' %} + {% trans 'User group' %} + {% trans 'Asset' %} + {% trans 'Asset group' %} + {% trans 'System user' %} + {% trans 'Is valid' %} + {% trans 'Action' %} +{% endblock %} + +{% block table_body %} + {% for asset_permission in asset_permission_list %} + + {{ asset_permission.id }} + + + {{ asset_permission.name }} + + + {{ asset_permission.users.count }} + {{ asset_permission.user_groups.count }} + {{ asset_permission.assets.count }} + {{ asset_permission.asset_groups.count }} + {{ asset_permission.system_users.count }} + + {% if asset_permission.is_valid %} + + {% else %} + + {% endif %} + + + {% trans 'Update' %} + + {% trans 'Delete' %} + + + + {% endfor %} +{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/perms/templates/perms/asset_permission_user.html b/apps/perms/templates/perms/asset_permission_user.html new file mode 100644 index 000000000..f91682c83 --- /dev/null +++ b/apps/perms/templates/perms/asset_permission_user.html @@ -0,0 +1,198 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
      +
      +
      +
      + +
      +
      +
      +
      + {% trans 'User list of ' %} {{ asset_permission.name }} +
      + + + + + + + + + + +
      +
      +
      + + + + + + + + + + + + {% for user in page_obj %} + + + + + + + + + {% endfor %} + +
      {% trans 'Name' %}{% trans 'Username' %}{% trans 'Email' %}{% trans 'Is valid' %}
      {{ user.name }}{{ user.username }}{{ user.email }} + {% if user.is_expired and user.is_active %} + + {% else %} + + {% endif %} + + +
      +
      + {% include '_pagination.html' %} +
      +
      +
      +
      +
      +
      +
      + {% trans 'Add user to asset permission' %} +
      +
      + + + + + + + + + + + +
      + +
      + +
      +
      +
      + +
      +
      + {% trans 'Add user group to asset permission' %} +
      +
      + + + + + + + + + + + + {% for user_group in user_groups %} + + + + + {% endfor %} + +
      + +
      + +
      {{ user_group.name }} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/perms/templates/perms/delete_confirm.html b/apps/perms/templates/perms/delete_confirm.html new file mode 100644 index 000000000..777d1dbf9 --- /dev/null +++ b/apps/perms/templates/perms/delete_confirm.html @@ -0,0 +1,15 @@ +{% load i18n %} + + + + + {% trans 'Confirm delete' %} + + +
      + {% csrf_token %} +

      Are you sure you want to delete "{{ object.name }}"?

      + +
      + + \ No newline at end of file diff --git a/apps/perms/templatetags/perms/example_tags.py b/apps/perms/templatetags/perms/example_tags.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/perms/tests.py b/apps/perms/tests.py new file mode 100644 index 000000000..4fd76b0f2 --- /dev/null +++ b/apps/perms/tests.py @@ -0,0 +1,4 @@ +from django.test import TestCase + +from django.contrib.sessions.backends import file, db, cache +from django.contrib.auth.views import login \ No newline at end of file diff --git a/apps/perms/urls/__init__.py b/apps/perms/urls/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/apps/perms/urls/__init__.py @@ -0,0 +1 @@ + diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py new file mode 100644 index 000000000..db2d74829 --- /dev/null +++ b/apps/perms/urls/api_urls.py @@ -0,0 +1,62 @@ +# coding:utf-8 + +from django.conf.urls import url +from rest_framework import routers +from .. import api + +app_name = 'perms' + +router = routers.DefaultRouter() +router.register('v1/asset-permissions', + api.AssetPermissionViewSet, + 'asset-permission') + +urlpatterns = [ + # 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等 + url(r'^v1/user/my/assets/$', + api.MyGrantedAssetsApi.as_view(), + name='my-assets'), + url(r'^v1/user/my/asset-groups/$', + api.MyGrantedAssetsGroupsApi.as_view(), + name='my-asset-groups'), + url(r'^v1/user/my/asset-group/(?P[0-9]+)/assets/$', + api.MyAssetGroupAssetsApi.as_view(), + name='user-my-asset-group-assets'), + + # 查询某个用户授权的资产和资产组 + url(r'^v1/user/(?P[0-9]+)/assets/$', + api.UserGrantedAssetsApi.as_view(), + name='user-assets'), + url(r'^v1/user/(?P[0-9]+)/asset-groups/$', + api.UserGrantedAssetGroupsApi.as_view(), + name='user-asset-groups'), + + # 查询某个用户组授权的资产和资产组 + url(r'^v1/user-group/(?P[0-9]+)/assets/$', + api.UserGroupGrantedAssetsApi.as_view(), + name='user-group-assets'), + url(r'^v1/user-group/(?P[0-9]+)/asset-groups/$', + api.UserGroupGrantedAssetGroupsApi.as_view(), + name='user-group-asset-groups'), + + # 回收用户或用户组授权 + url(r'^v1/asset-permissions/user/revoke/$', + api.RevokeUserAssetPermission.as_view(), + name='revoke-user-asset-permission'), + url(r'^v1/asset-permissions/user-group/revoke/$', + api.RevokeUserGroupAssetPermission.as_view(), + name='revoke-user-group-asset-permission'), + + # 验证用户是否有某个资产和系统用户的权限 + url(r'v1/asset-permission/user/validate/$', + api.ValidateUserAssetPermissionView.as_view(), + name='validate-user-asset-permission'), + + # 删除asset permission中的某个系统用户 + url(r'^v1/asset-permissions/(?P[0-9]+)/system-user/remove/$', + api.RemoveSystemUserAssetPermission.as_view(), + name='remove-system-user-asset-permission'), +] + +urlpatterns += router.urls + diff --git a/apps/perms/urls/views_urls.py b/apps/perms/urls/views_urls.py new file mode 100644 index 000000000..b73d39fab --- /dev/null +++ b/apps/perms/urls/views_urls.py @@ -0,0 +1,23 @@ +# coding:utf-8 + +from django.conf.urls import url +from .. import views + +app_name = 'perms' + +urlpatterns = [ + url(r'^asset-permission$', views.AssetPermissionListView.as_view(), name='asset-permission-list'), + url(r'^asset-permission/create$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'), + url(r'^asset-permission/(?P[0-9]+)/update$', views.AssetPermissionUpdateView.as_view(), + name='asset-permission-update'), + url(r'^asset-permission/(?P[0-9]+)$', views.AssetPermissionDetailView.as_view(), + name='asset-permission-detail'), + url(r'^asset-permission/(?P[0-9]+)/delete$', views.AssetPermissionDeleteView.as_view(), + name='asset-permission-delete'), + url(r'^asset-permission/(?P[0-9]+)/user$', views.AssetPermissionUserView.as_view(), + name='asset-permission-user-list'), + url(r'^asset-permission/(?P[0-9]+)/asset$', views.AssetPermissionAssetView.as_view(), + name='asset-permission-asset-list'), +] + + diff --git a/apps/perms/utils.py b/apps/perms/utils.py new file mode 100644 index 000000000..efad6cbce --- /dev/null +++ b/apps/perms/utils.py @@ -0,0 +1,244 @@ +# coding: utf-8 + +from __future__ import absolute_import, unicode_literals + +from common.utils import setattr_bulk +from .hands import User, UserGroup, Asset, AssetGroup, SystemUser, \ + push_system_user + + +def get_user_group_granted_asset_groups(user_group): + """Return asset groups granted of the user group + + :param user_group: Instance of :class: ``UserGroup`` + :return: {asset_group1: {system_user1, }, + asset_group2: {system_user1, system_user2}} + """ + asset_groups = {} + asset_permissions = user_group.asset_permissions.all() + + for asset_permission in asset_permissions: + if not asset_permission.is_valid: + continue + for asset_group in asset_permission.asset_groups.all(): + if asset_group in asset_groups: + asset_groups[asset_group] |= set(asset_permission.system_users.all()) + else: + asset_groups[asset_group] = set(asset_permission.system_users.all()) + return asset_groups + + +def get_user_group_granted_assets(user_group): + """Return assets granted of the user group + + :param user_group: Instance of :class: ``UserGroup`` + :return: {asset1: {system_user1, }, asset1: {system_user1, system_user2]} + """ + assets = {} + asset_permissions = user_group.asset_permissions.all() + + for asset_permission in asset_permissions: + if not asset_permission.is_valid: + continue + for asset in asset_permission.get_granted_assets(): + if not asset.is_active: + continue + if asset in assets: + assets[asset] |= set(asset_permission.system_users.all()) + else: + assets[asset] = set(asset_permission.system_users.all()) + return assets + + +def get_user_granted_asset_groups_direct(user): + """Return asset groups granted of the user direct nor inherit from user group + + :param user: Instance of :class: ``User`` + :return: {asset_group: {system_user1, }, + asset_group2: {system_user1, system_user2]} + """ + asset_groups = {} + asset_permissions_direct = user.asset_permissions.all() + + for asset_permission in asset_permissions_direct: + if not asset_permission.is_valid: + continue + for asset_group in asset_permission.asset_groups.all(): + if asset_group in asset_groups: + asset_groups[asset_group] |= set(asset_permission.system_users.all()) + else: + setattr(asset_group, 'inherited', False) + asset_groups[asset_group] = set(asset_permission.system_users.all()) + + return asset_groups + + +def get_user_granted_asset_groups_inherit_from_user_groups(user): + """Return asset groups granted of the user and inherit from user group + + :param user: Instance of :class: ``User`` + :return: {asset_group: {system_user1, }, + asset_group2: {system_user1, system_user2]} + """ + asset_groups = {} + user_groups = user.groups.all() + asset_permissions = set() + + # Get asset permission list of user groups for this user + for user_group in user_groups: + asset_permissions |= set(user_group.asset_permissions.all()) + + # Get asset groups granted from user groups + for asset_permission in asset_permissions: + if not asset_permission.is_valid: + continue + for asset_group in asset_permission.asset_groups.all(): + if asset_group in asset_groups: + asset_groups[asset_group] |= set(asset_permission.system_users.all()) + else: + setattr(asset_group, 'inherited', True) + asset_groups[asset_group] = set(asset_permission.system_users.all()) + + return asset_groups + + +def get_user_granted_asset_groups(user): + """Get user granted asset groups all, include direct and inherit from user group + + :param user: Instance of :class: ``User`` + :return: {asset1: {system_user1, system_user2}, asset2: {...}} + """ + + asset_groups_inherit_from_user_groups = \ + get_user_granted_asset_groups_inherit_from_user_groups(user) + asset_groups_direct = get_user_granted_asset_groups_direct(user) + asset_groups = asset_groups_inherit_from_user_groups + + # Merge direct granted and inherit from user group + for asset_group, system_users in asset_groups_direct.items(): + if asset_group in asset_groups: + asset_groups[asset_group] |= asset_groups_direct[asset_group] + else: + asset_groups[asset_group] = asset_groups_direct[asset_group] + return asset_groups + + +def get_user_granted_assets_direct(user): + """Return assets granted of the user directly + + :param user: Instance of :class: ``User`` + :return: {asset1: {system_user1, system_user2}, asset2: {...}} + """ + assets = {} + asset_permissions_direct = user.asset_permissions.all() + + for asset_permission in asset_permissions_direct: + if not asset_permission.is_valid: + continue + for asset in asset_permission.get_granted_assets(): + if not asset.is_active: + continue + if asset in assets: + assets[asset] |= set(asset_permission.system_users.all()) + else: + setattr(asset, 'inherited', False) + assets[asset] = set(asset_permission.system_users.all()) + return assets + + +def get_user_granted_assets_inherit_from_user_groups(user): + """Return assets granted of the user inherit from user groups + + :param user: Instance of :class: ``User`` + :return: {asset1: {system_user1, system_user2}, asset2: {...}} + """ + assets = {} + user_groups = user.groups.all() + + for user_group in user_groups: + assets_inherited = get_user_group_granted_assets(user_group) + for asset in assets_inherited: + if not asset.is_active: + continue + if asset in assets: + assets[asset] |= assets_inherited[asset] + else: + setattr(asset, 'inherited', True) + assets[asset] = assets_inherited[asset] + return assets + + +def get_user_granted_assets(user): + """Return assets granted of the user inherit from user groups + + :param user: Instance of :class: ``User`` + :return: {asset1: {system_user1, system_user2}, asset2: {...}} + """ + assets_direct = get_user_granted_assets_direct(user) + assets_inherited = get_user_granted_assets_inherit_from_user_groups(user) + assets = assets_inherited + + for asset in assets_direct: + if not asset.is_active: + continue + if asset in assets: + assets[asset] |= assets_direct[asset] + else: + assets[asset] = assets_direct[asset] + return assets + + +def get_user_group_asset_permissions(user_group): + permissions = user_group.asset_permissions.all() + return permissions + + +def get_user_asset_permissions(user): + user_group_permissions = set() + direct_permissions = set(setattr_bulk(user.asset_permissions.all(), 'inherited', 0)) + + for user_group in user.groups.all(): + permissions = get_user_group_asset_permissions(user_group) + user_group_permissions |= set(permissions) + user_group_permissions = set(setattr_bulk(user_group_permissions, 'inherited', 1)) + return direct_permissions | user_group_permissions + + +def get_user_groups_granted_in_asset(asset): + pass + + +def get_users_granted_in_asset(asset): + pass + + +def get_user_groups_granted_in_asset_group(asset): + pass + + +def get_users_granted_in_asset_group(asset): + pass + + +def associate_system_users_and_assets(system_users, assets, asset_groups): + """关联系统用户和资产, 目的是保存它们的关系, 然后新加入的资产或系统 + 用户时,推送系统用户到资产 + + Todo: 这里需要最终Api定下来更改一下, 现在策略是以系统用户为核心推送, 一个系统用户 + 推送一次 + """ + assets_all = set(assets) + + for asset_group in asset_groups: + assets_all |= set(asset_group.assets.all()) + + for system_user in system_users: + assets_need_push = [] + if system_user.auto_push: + assets_need_push.extend( + [asset for asset in assets_all + if asset not in system_user.assets.all() + ] + ) + system_user.assets.add(*(tuple(assets_all))) + push_system_user(assets_need_push, system_user) diff --git a/apps/perms/views.py b/apps/perms/views.py new file mode 100644 index 000000000..b1aac2f9a --- /dev/null +++ b/apps/perms/views.py @@ -0,0 +1,228 @@ +# ~*~ coding: utf-8 ~*~ + +from __future__ import unicode_literals, absolute_import +import functools + +from django.utils.translation import ugettext as _ +from django.conf import settings +from django.db.models import Q +from django.views.generic import ListView, CreateView, UpdateView +from django.views.generic.edit import DeleteView, FormView +from django.urls import reverse_lazy +from django.contrib.messages.views import SuccessMessageMixin +from django.views.generic.detail import DetailView, SingleObjectMixin + +from common.utils import search_object_attr +from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \ + Asset, AssetGroup +from .models import AssetPermission +from .forms import AssetPermissionForm +from .utils import associate_system_users_and_assets + + +class AssetPermissionListView(AdminUserRequiredMixin, ListView): + model = AssetPermission + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + context_object_name = 'asset_permission_list' + template_name = 'perms/asset_permission_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Asset permission list'), + 'keyword': self.keyword, + } + kwargs.update(context) + return super(AssetPermissionListView, self).get_context_data(**kwargs) + + def get_queryset(self): + self.queryset = super(AssetPermissionListView, self).get_queryset() + self.keyword = keyword = self.request.GET.get('keyword', '') + self.sort = sort = self.request.GET.get('sort', '-date_created') + + if keyword: + self.queryset = self.queryset\ + .filter(Q(users__name__contains=keyword) | + Q(users__username__contains=keyword) | + Q(user_groups__name__contains=keyword) | + Q(assets__ip__contains=keyword) | + Q(assets__hostname__contains=keyword) | + Q(system_users__username__icontains=keyword) | + Q(system_users__name__icontains=keyword) | + Q(asset_groups__name__icontains=keyword) | + Q(comment__icontains=keyword) | + Q(name__icontains=keyword)).distinct() + if sort: + self.queryset = self.queryset.order_by(sort) + return self.queryset + + +class AssetPermissionCreateView(AdminUserRequiredMixin, + SuccessMessageMixin, + CreateView): + model = AssetPermission + form_class = AssetPermissionForm + template_name = 'perms/asset_permission_create_update.html' + success_url = reverse_lazy('perms:asset-permission-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Create asset permission'), + } + kwargs.update(context) + return super(AssetPermissionCreateView, self).get_context_data(**kwargs) + + def get_success_message(self, cleaned_data): + success_message = _( + 'Create asset permission %s ' + 'successfully.' % (reverse_lazy('perms:asset-permission-detail', + kwargs={'pk': self.object.pk}), + self.object.name,)) + return success_message + + def form_valid(self, form): + assets = form.cleaned_data['assets'] + asset_groups = form.cleaned_data['asset_groups'] + system_users = form.cleaned_data['system_users'] + associate_system_users_and_assets(system_users, assets, asset_groups) + response = super(AssetPermissionCreateView, self).form_valid(form) + self.object.created_by = self.request.user.name + self.object.save() + return response + + +class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView): + model = AssetPermission + form_class = AssetPermissionForm + template_name = 'perms/asset_permission_create_update.html' + success_message = _('Update asset permission ' + ' %s successfully.') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Update asset permission') + } + kwargs.update(context) + return super(AssetPermissionUpdateView, self).get_context_data(**kwargs) + + def get_success_url(self): + success_url = reverse_lazy('perms:asset-permission-detail', + kwargs={'pk': self.object.pk}) + return success_url + + def form_valid(self, form): + assets = form.cleaned_data['assets'] + asset_groups = form.cleaned_data['asset_groups'] + system_users = form.cleaned_data['system_users'] + associate_system_users_and_assets(system_users, assets, asset_groups) + return super(AssetPermissionUpdateView, self).form_valid(form) + + +class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): + template_name = 'perms/asset_permission_detail.html' + context_object_name = 'asset_permission' + model = AssetPermission + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Asset permission detail'), + 'system_users_remain': [ + system_user for system_user in SystemUser.objects.all() + if system_user not in self.object.system_users.all()], + 'system_users': self.object.system_users.all(), + } + kwargs.update(context) + return super(AssetPermissionDetailView, self).get_context_data(**kwargs) + + +class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView): + model = AssetPermission + template_name = 'perms/delete_confirm.html' + success_url = reverse_lazy('perms:asset-permission-list') + + +class AssetPermissionUserView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/asset_permission_user.html' + context_object_name = 'asset_permission' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AssetPermission.objects.all()) + self.keyword = self.request.GET.get('keyword', '') + return super(AssetPermissionUserView, self).get(request, *args, **kwargs) + + def get_queryset(self): + queryset = self.object.get_granted_users() + if self.keyword: + search_func = functools.partial( + search_object_attr, + value=self.keyword, + attr_list=['username', 'name', 'email'], + ignore_case=True) + queryset = filter(search_func, queryset) + return queryset + + def get_context_data(self, **kwargs): + users_granted = self.get_queryset() + user_groups_granted = self.object.user_groups.all() + context = { + 'app': _('Perms'), + 'action': _('Asset permission user list'), + 'users_remain': [ + user for user in User.objects.all() + if user not in users_granted], + 'user_groups': self.object.user_groups.all(), + 'user_groups_remain': [ + user_group for user_group in UserGroup.objects.all() + if user_group not in user_groups_granted], + 'keyword': self.keyword, + } + kwargs.update(context) + return super(AssetPermissionUserView, self).get_context_data(**kwargs) + + +class AssetPermissionAssetView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/asset_permission_asset.html' + context_object_name = 'asset_permission' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AssetPermission.objects.all()) + self.keyword = self.request.GET.get('keyword', '') + return super(AssetPermissionAssetView, self)\ + .get(request, *args, **kwargs) + + def get_queryset(self): + queryset = self.object.get_granted_assets() + if self.keyword: + search_func = functools.partial( + search_object_attr, value=self.keyword, + attr_list=['hostname', 'ip'], + ignore_case=True) + queryset = filter(search_func, queryset) + return queryset + + def get_context_data(self, **kwargs): + assets_granted = self.get_queryset() + asset_groups_granted = self.object.user_groups.all() + context = { + 'app': _('Perms'), + 'action': _('Asset permission asset list'), + 'assets_remain': [ + asset for asset in Asset.objects.all() + if asset not in assets_granted], + 'asset_groups': self.object.asset_groups.all(), + 'asset_groups_remain': [ + asset_group for asset_group in AssetGroup.objects.all() + if asset_group not in asset_groups_granted], + 'keyword': self.keyword, + } + kwargs.update(context) + return super(AssetPermissionAssetView, self).get_context_data(**kwargs) diff --git a/apps/static/css/animate.css b/apps/static/css/animate.css new file mode 100644 index 000000000..0f9fba11e --- /dev/null +++ b/apps/static/css/animate.css @@ -0,0 +1,2848 @@ +@charset "UTF-8"; + +/*! +Animate.css - http://daneden.me/animate +Licensed under the MIT license + +Copyright (c) 2013 Daniel Eden + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +.animated { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + z-index: 100; +} + +.animated.infinite { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} + +.animated.hinge { + -webkit-animation-duration: 2s; + animation-duration: 2s; +} + +@-webkit-keyframes bounce { + 0%, 20%, 50%, 80%, 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 40% { + -webkit-transform: translateY(-30px); + transform: translateY(-30px); + } + + 60% { + -webkit-transform: translateY(-15px); + transform: translateY(-15px); + } +} + +@keyframes bounce { + 0%, 20%, 50%, 80%, 100% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 40% { + -webkit-transform: translateY(-30px); + -ms-transform: translateY(-30px); + transform: translateY(-30px); + } + + 60% { + -webkit-transform: translateY(-15px); + -ms-transform: translateY(-15px); + transform: translateY(-15px); + } +} + +.bounce { + -webkit-animation-name: bounce; + animation-name: bounce; +} + +@-webkit-keyframes flash { + 0%, 50%, 100% { + opacity: 1; + } + + 25%, 75% { + opacity: 0; + } +} + +@keyframes flash { + 0%, 50%, 100% { + opacity: 1; + } + + 25%, 75% { + opacity: 0; + } +} + +.flash { + -webkit-animation-name: flash; + animation-name: flash; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes pulse { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 50% { + -webkit-transform: scale(1.1); + transform: scale(1.1); + } + + 100% { + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes pulse { + 0% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + + 50% { + -webkit-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); + } + + 100% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} + +.pulse { + -webkit-animation-name: pulse; + animation-name: pulse; +} + +@-webkit-keyframes rubberBand { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 30% { + -webkit-transform: scaleX(1.25) scaleY(0.75); + transform: scaleX(1.25) scaleY(0.75); + } + + 40% { + -webkit-transform: scaleX(0.75) scaleY(1.25); + transform: scaleX(0.75) scaleY(1.25); + } + + 60% { + -webkit-transform: scaleX(1.15) scaleY(0.85); + transform: scaleX(1.15) scaleY(0.85); + } + + 100% { + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes rubberBand { + 0% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + + 30% { + -webkit-transform: scaleX(1.25) scaleY(0.75); + -ms-transform: scaleX(1.25) scaleY(0.75); + transform: scaleX(1.25) scaleY(0.75); + } + + 40% { + -webkit-transform: scaleX(0.75) scaleY(1.25); + -ms-transform: scaleX(0.75) scaleY(1.25); + transform: scaleX(0.75) scaleY(1.25); + } + + 60% { + -webkit-transform: scaleX(1.15) scaleY(0.85); + -ms-transform: scaleX(1.15) scaleY(0.85); + transform: scaleX(1.15) scaleY(0.85); + } + + 100% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} + +.rubberBand { + -webkit-animation-name: rubberBand; + animation-name: rubberBand; +} + +@-webkit-keyframes shake { + 0%, 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 10%, 30%, 50%, 70%, 90% { + -webkit-transform: translateX(-10px); + transform: translateX(-10px); + } + + 20%, 40%, 60%, 80% { + -webkit-transform: translateX(10px); + transform: translateX(10px); + } +} + +@keyframes shake { + 0%, 100% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 10%, 30%, 50%, 70%, 90% { + -webkit-transform: translateX(-10px); + -ms-transform: translateX(-10px); + transform: translateX(-10px); + } + + 20%, 40%, 60%, 80% { + -webkit-transform: translateX(10px); + -ms-transform: translateX(10px); + transform: translateX(10px); + } +} + +.shake { + -webkit-animation-name: shake; + animation-name: shake; +} + +@-webkit-keyframes swing { + 20% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + + 40% { + -webkit-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 60% { + -webkit-transform: rotate(5deg); + transform: rotate(5deg); + } + + 80% { + -webkit-transform: rotate(-5deg); + transform: rotate(-5deg); + } + + 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@keyframes swing { + 20% { + -webkit-transform: rotate(15deg); + -ms-transform: rotate(15deg); + transform: rotate(15deg); + } + + 40% { + -webkit-transform: rotate(-10deg); + -ms-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 60% { + -webkit-transform: rotate(5deg); + -ms-transform: rotate(5deg); + transform: rotate(5deg); + } + + 80% { + -webkit-transform: rotate(-5deg); + -ms-transform: rotate(-5deg); + transform: rotate(-5deg); + } + + 100% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +.swing { + -webkit-transform-origin: top center; + -ms-transform-origin: top center; + transform-origin: top center; + -webkit-animation-name: swing; + animation-name: swing; +} + +@-webkit-keyframes tada { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 10%, 20% { + -webkit-transform: scale(0.9) rotate(-3deg); + transform: scale(0.9) rotate(-3deg); + } + + 30%, 50%, 70%, 90% { + -webkit-transform: scale(1.1) rotate(3deg); + transform: scale(1.1) rotate(3deg); + } + + 40%, 60%, 80% { + -webkit-transform: scale(1.1) rotate(-3deg); + transform: scale(1.1) rotate(-3deg); + } + + 100% { + -webkit-transform: scale(1) rotate(0); + transform: scale(1) rotate(0); + } +} + +@keyframes tada { + 0% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + + 10%, 20% { + -webkit-transform: scale(0.9) rotate(-3deg); + -ms-transform: scale(0.9) rotate(-3deg); + transform: scale(0.9) rotate(-3deg); + } + + 30%, 50%, 70%, 90% { + -webkit-transform: scale(1.1) rotate(3deg); + -ms-transform: scale(1.1) rotate(3deg); + transform: scale(1.1) rotate(3deg); + } + + 40%, 60%, 80% { + -webkit-transform: scale(1.1) rotate(-3deg); + -ms-transform: scale(1.1) rotate(-3deg); + transform: scale(1.1) rotate(-3deg); + } + + 100% { + -webkit-transform: scale(1) rotate(0); + -ms-transform: scale(1) rotate(0); + transform: scale(1) rotate(0); + } +} + +.tada { + -webkit-animation-name: tada; + animation-name: tada; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes wobble { + 0% { + -webkit-transform: translateX(0%); + transform: translateX(0%); + } + + 15% { + -webkit-transform: translateX(-25%) rotate(-5deg); + transform: translateX(-25%) rotate(-5deg); + } + + 30% { + -webkit-transform: translateX(20%) rotate(3deg); + transform: translateX(20%) rotate(3deg); + } + + 45% { + -webkit-transform: translateX(-15%) rotate(-3deg); + transform: translateX(-15%) rotate(-3deg); + } + + 60% { + -webkit-transform: translateX(10%) rotate(2deg); + transform: translateX(10%) rotate(2deg); + } + + 75% { + -webkit-transform: translateX(-5%) rotate(-1deg); + transform: translateX(-5%) rotate(-1deg); + } + + 100% { + -webkit-transform: translateX(0%); + transform: translateX(0%); + } +} + +@keyframes wobble { + 0% { + -webkit-transform: translateX(0%); + -ms-transform: translateX(0%); + transform: translateX(0%); + } + + 15% { + -webkit-transform: translateX(-25%) rotate(-5deg); + -ms-transform: translateX(-25%) rotate(-5deg); + transform: translateX(-25%) rotate(-5deg); + } + + 30% { + -webkit-transform: translateX(20%) rotate(3deg); + -ms-transform: translateX(20%) rotate(3deg); + transform: translateX(20%) rotate(3deg); + } + + 45% { + -webkit-transform: translateX(-15%) rotate(-3deg); + -ms-transform: translateX(-15%) rotate(-3deg); + transform: translateX(-15%) rotate(-3deg); + } + + 60% { + -webkit-transform: translateX(10%) rotate(2deg); + -ms-transform: translateX(10%) rotate(2deg); + transform: translateX(10%) rotate(2deg); + } + + 75% { + -webkit-transform: translateX(-5%) rotate(-1deg); + -ms-transform: translateX(-5%) rotate(-1deg); + transform: translateX(-5%) rotate(-1deg); + } + + 100% { + -webkit-transform: translateX(0%); + -ms-transform: translateX(0%); + transform: translateX(0%); + } +} + +.wobble { + -webkit-animation-name: wobble; + animation-name: wobble; +} + +@-webkit-keyframes bounceIn { + 0% { + opacity: 0; + -webkit-transform: scale(.3); + transform: scale(.3); + } + + 50% { + opacity: 1; + -webkit-transform: scale(1.05); + transform: scale(1.05); + } + + 70% { + -webkit-transform: scale(.9); + transform: scale(.9); + } + + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes bounceIn { + 0% { + opacity: 0; + -webkit-transform: scale(.3); + -ms-transform: scale(.3); + transform: scale(.3); + } + + 50% { + opacity: 1; + -webkit-transform: scale(1.05); + -ms-transform: scale(1.05); + transform: scale(1.05); + } + + 70% { + -webkit-transform: scale(.9); + -ms-transform: scale(.9); + transform: scale(.9); + } + + 100% { + opacity: 1; + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} + +.bounceIn { + -webkit-animation-name: bounceIn; + animation-name: bounceIn; +} + +@-webkit-keyframes bounceInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateY(30px); + transform: translateY(30px); + } + + 80% { + -webkit-transform: translateY(-10px); + transform: translateY(-10px); + } + + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes bounceInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateY(30px); + -ms-transform: translateY(30px); + transform: translateY(30px); + } + + 80% { + -webkit-transform: translateY(-10px); + -ms-transform: translateY(-10px); + transform: translateY(-10px); + } + + 100% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.bounceInDown { + -webkit-animation-name: bounceInDown; + animation-name: bounceInDown; +} + +@-webkit-keyframes bounceInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateX(30px); + transform: translateX(30px); + } + + 80% { + -webkit-transform: translateX(-10px); + transform: translateX(-10px); + } + + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes bounceInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateX(30px); + -ms-transform: translateX(30px); + transform: translateX(30px); + } + + 80% { + -webkit-transform: translateX(-10px); + -ms-transform: translateX(-10px); + transform: translateX(-10px); + } + + 100% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.bounceInLeft { + -webkit-animation-name: bounceInLeft; + animation-name: bounceInLeft; +} + +@-webkit-keyframes bounceInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateX(-30px); + transform: translateX(-30px); + } + + 80% { + -webkit-transform: translateX(10px); + transform: translateX(10px); + } + + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes bounceInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateX(-30px); + -ms-transform: translateX(-30px); + transform: translateX(-30px); + } + + 80% { + -webkit-transform: translateX(10px); + -ms-transform: translateX(10px); + transform: translateX(10px); + } + + 100% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.bounceInRight { + -webkit-animation-name: bounceInRight; + animation-name: bounceInRight; +} + +@-webkit-keyframes bounceInUp { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateY(-30px); + transform: translateY(-30px); + } + + 80% { + -webkit-transform: translateY(10px); + transform: translateY(10px); + } + + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes bounceInUp { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + -ms-transform: translateY(2000px); + transform: translateY(2000px); + } + + 60% { + opacity: 1; + -webkit-transform: translateY(-30px); + -ms-transform: translateY(-30px); + transform: translateY(-30px); + } + + 80% { + -webkit-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + + 100% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.bounceInUp { + -webkit-animation-name: bounceInUp; + animation-name: bounceInUp; +} + +@-webkit-keyframes bounceOut { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 25% { + -webkit-transform: scale(.95); + transform: scale(.95); + } + + 50% { + opacity: 1; + -webkit-transform: scale(1.1); + transform: scale(1.1); + } + + 100% { + opacity: 0; + -webkit-transform: scale(.3); + transform: scale(.3); + } +} + +@keyframes bounceOut { + 0% { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + + 25% { + -webkit-transform: scale(.95); + -ms-transform: scale(.95); + transform: scale(.95); + } + + 50% { + opacity: 1; + -webkit-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); + } + + 100% { + opacity: 0; + -webkit-transform: scale(.3); + -ms-transform: scale(.3); + transform: scale(.3); + } +} + +.bounceOut { + -webkit-animation-name: bounceOut; + animation-name: bounceOut; +} + +@-webkit-keyframes bounceOutDown { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +@keyframes bounceOutDown { + 0% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + -ms-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +.bounceOutDown { + -webkit-animation-name: bounceOutDown; + animation-name: bounceOutDown; +} + +@-webkit-keyframes bounceOutLeft { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateX(20px); + transform: translateX(20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +@keyframes bounceOutLeft { + 0% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateX(20px); + -ms-transform: translateX(20px); + transform: translateX(20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +.bounceOutLeft { + -webkit-animation-name: bounceOutLeft; + animation-name: bounceOutLeft; +} + +@-webkit-keyframes bounceOutRight { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +@keyframes bounceOutRight { + 0% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateX(-20px); + -ms-transform: translateX(-20px); + transform: translateX(-20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +.bounceOutRight { + -webkit-animation-name: bounceOutRight; + animation-name: bounceOutRight; +} + +@-webkit-keyframes bounceOutUp { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateY(20px); + transform: translateY(20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +@keyframes bounceOutUp { + 0% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 20% { + opacity: 1; + -webkit-transform: translateY(20px); + -ms-transform: translateY(20px); + transform: translateY(20px); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +.bounceOutUp { + -webkit-animation-name: bounceOutUp; + animation-name: bounceOutUp; +} + +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +.fadeIn { + -webkit-animation-name: fadeIn; + animation-name: fadeIn; +} + +@-webkit-keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.fadeInDown { + -webkit-animation-name: fadeInDown; + animation-name: fadeInDown; +} + +@-webkit-keyframes fadeInDownBig { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeInDownBig { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.fadeInDownBig { + -webkit-animation-name: fadeInDownBig; + animation-name: fadeInDownBig; +} + +@-webkit-keyframes fadeInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes fadeInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-20px); + -ms-transform: translateX(-20px); + transform: translateX(-20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.fadeInLeft { + -webkit-animation-name: fadeInLeft; + animation-name: fadeInLeft; +} + +@-webkit-keyframes fadeInLeftBig { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes fadeInLeftBig { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.fadeInLeftBig { + -webkit-animation-name: fadeInLeftBig; + animation-name: fadeInLeftBig; +} + +@-webkit-keyframes fadeInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(20px); + transform: translateX(20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes fadeInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(40px); + -ms-transform: translateX(40px); + transform: translateX(40px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.fadeInRight { + -webkit-animation-name: fadeInRight; + animation-name: fadeInRight; +} + +@-webkit-keyframes fadeInRightBig { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes fadeInRightBig { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.fadeInRightBig { + -webkit-animation-name: fadeInRightBig; + animation-name: fadeInRightBig; +} + +@-webkit-keyframes fadeInUp { + 0% { + opacity: 0; + -webkit-transform: translateY(20px); + transform: translateY(20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeInUp { + 0% { + opacity: 0; + -webkit-transform: translateY(20px); + -ms-transform: translateY(20px); + transform: translateY(20px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.fadeInUp { + -webkit-animation-name: fadeInUp; + animation-name: fadeInUp; +} + +@-webkit-keyframes fadeInUpBig { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes fadeInUpBig { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + -ms-transform: translateY(2000px); + transform: translateY(2000px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.fadeInUpBig { + -webkit-animation-name: fadeInUpBig; + animation-name: fadeInUpBig; +} + +@-webkit-keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.fadeOut { + -webkit-animation-name: fadeOut; + animation-name: fadeOut; +} + +@-webkit-keyframes fadeOutDown { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(20px); + transform: translateY(20px); + } +} + +@keyframes fadeOutDown { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(20px); + -ms-transform: translateY(20px); + transform: translateY(20px); + } +} + +.fadeOutDown { + -webkit-animation-name: fadeOutDown; + animation-name: fadeOutDown; +} + +@-webkit-keyframes fadeOutDownBig { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +@keyframes fadeOutDownBig { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + -ms-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +.fadeOutDownBig { + -webkit-animation-name: fadeOutDownBig; + animation-name: fadeOutDownBig; +} + +@-webkit-keyframes fadeOutLeft { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + } +} + +@keyframes fadeOutLeft { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-20px); + -ms-transform: translateX(-20px); + transform: translateX(-20px); + } +} + +.fadeOutLeft { + -webkit-animation-name: fadeOutLeft; + animation-name: fadeOutLeft; +} + +@-webkit-keyframes fadeOutLeftBig { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +@keyframes fadeOutLeftBig { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +.fadeOutLeftBig { + -webkit-animation-name: fadeOutLeftBig; + animation-name: fadeOutLeftBig; +} + +@-webkit-keyframes fadeOutRight { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(20px); + transform: translateX(20px); + } +} + +@keyframes fadeOutRight { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(20px); + -ms-transform: translateX(20px); + transform: translateX(20px); + } +} + +.fadeOutRight { + -webkit-animation-name: fadeOutRight; + animation-name: fadeOutRight; +} + +@-webkit-keyframes fadeOutRightBig { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +@keyframes fadeOutRightBig { + 0% { + opacity: 1; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +.fadeOutRightBig { + -webkit-animation-name: fadeOutRightBig; + animation-name: fadeOutRightBig; +} + +@-webkit-keyframes fadeOutUp { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + } +} + +@keyframes fadeOutUp { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } +} + +.fadeOutUp { + -webkit-animation-name: fadeOutUp; + animation-name: fadeOutUp; +} + +@-webkit-keyframes fadeOutUpBig { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +@keyframes fadeOutUpBig { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +.fadeOutUpBig { + -webkit-animation-name: fadeOutUpBig; + animation-name: fadeOutUpBig; +} + +@-webkit-keyframes flip { + 0% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1); + transform: perspective(400px) translateZ(0) rotateY(0) scale(1); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1); + transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1); + transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95); + transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 100% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1); + transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +@keyframes flip { + 0% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1); + -ms-transform: perspective(400px) translateZ(0) rotateY(0) scale(1); + transform: perspective(400px) translateZ(0) rotateY(0) scale(1); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1); + -ms-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1); + transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1); + -ms-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1); + transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95); + -ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95); + transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 100% { + -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1); + -ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1); + transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +.animated.flip { + -webkit-backface-visibility: visible; + -ms-backface-visibility: visible; + backface-visibility: visible; + -webkit-animation-name: flip; + animation-name: flip; +} + +@-webkit-keyframes flipInX { + 0% { + -webkit-transform: perspective(400px) rotateX(90deg); + transform: perspective(400px) rotateX(90deg); + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotateX(-10deg); + transform: perspective(400px) rotateX(-10deg); + } + + 70% { + -webkit-transform: perspective(400px) rotateX(10deg); + transform: perspective(400px) rotateX(10deg); + } + + 100% { + -webkit-transform: perspective(400px) rotateX(0deg); + transform: perspective(400px) rotateX(0deg); + opacity: 1; + } +} + +@keyframes flipInX { + 0% { + -webkit-transform: perspective(400px) rotateX(90deg); + -ms-transform: perspective(400px) rotateX(90deg); + transform: perspective(400px) rotateX(90deg); + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotateX(-10deg); + -ms-transform: perspective(400px) rotateX(-10deg); + transform: perspective(400px) rotateX(-10deg); + } + + 70% { + -webkit-transform: perspective(400px) rotateX(10deg); + -ms-transform: perspective(400px) rotateX(10deg); + transform: perspective(400px) rotateX(10deg); + } + + 100% { + -webkit-transform: perspective(400px) rotateX(0deg); + -ms-transform: perspective(400px) rotateX(0deg); + transform: perspective(400px) rotateX(0deg); + opacity: 1; + } +} + +.flipInX { + -webkit-backface-visibility: visible !important; + -ms-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInX; + animation-name: flipInX; +} + +@-webkit-keyframes flipInY { + 0% { + -webkit-transform: perspective(400px) rotateY(90deg); + transform: perspective(400px) rotateY(90deg); + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotateY(-10deg); + transform: perspective(400px) rotateY(-10deg); + } + + 70% { + -webkit-transform: perspective(400px) rotateY(10deg); + transform: perspective(400px) rotateY(10deg); + } + + 100% { + -webkit-transform: perspective(400px) rotateY(0deg); + transform: perspective(400px) rotateY(0deg); + opacity: 1; + } +} + +@keyframes flipInY { + 0% { + -webkit-transform: perspective(400px) rotateY(90deg); + -ms-transform: perspective(400px) rotateY(90deg); + transform: perspective(400px) rotateY(90deg); + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotateY(-10deg); + -ms-transform: perspective(400px) rotateY(-10deg); + transform: perspective(400px) rotateY(-10deg); + } + + 70% { + -webkit-transform: perspective(400px) rotateY(10deg); + -ms-transform: perspective(400px) rotateY(10deg); + transform: perspective(400px) rotateY(10deg); + } + + 100% { + -webkit-transform: perspective(400px) rotateY(0deg); + -ms-transform: perspective(400px) rotateY(0deg); + transform: perspective(400px) rotateY(0deg); + opacity: 1; + } +} + +.flipInY { + -webkit-backface-visibility: visible !important; + -ms-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInY; + animation-name: flipInY; +} + +@-webkit-keyframes flipOutX { + 0% { + -webkit-transform: perspective(400px) rotateX(0deg); + transform: perspective(400px) rotateX(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: perspective(400px) rotateX(90deg); + transform: perspective(400px) rotateX(90deg); + opacity: 0; + } +} + +@keyframes flipOutX { + 0% { + -webkit-transform: perspective(400px) rotateX(0deg); + -ms-transform: perspective(400px) rotateX(0deg); + transform: perspective(400px) rotateX(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: perspective(400px) rotateX(90deg); + -ms-transform: perspective(400px) rotateX(90deg); + transform: perspective(400px) rotateX(90deg); + opacity: 0; + } +} + +.flipOutX { + -webkit-animation-name: flipOutX; + animation-name: flipOutX; + -webkit-backface-visibility: visible !important; + -ms-backface-visibility: visible !important; + backface-visibility: visible !important; +} + +@-webkit-keyframes flipOutY { + 0% { + -webkit-transform: perspective(400px) rotateY(0deg); + transform: perspective(400px) rotateY(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: perspective(400px) rotateY(90deg); + transform: perspective(400px) rotateY(90deg); + opacity: 0; + } +} + +@keyframes flipOutY { + 0% { + -webkit-transform: perspective(400px) rotateY(0deg); + -ms-transform: perspective(400px) rotateY(0deg); + transform: perspective(400px) rotateY(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: perspective(400px) rotateY(90deg); + -ms-transform: perspective(400px) rotateY(90deg); + transform: perspective(400px) rotateY(90deg); + opacity: 0; + } +} + +.flipOutY { + -webkit-backface-visibility: visible !important; + -ms-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipOutY; + animation-name: flipOutY; +} + +@-webkit-keyframes lightSpeedIn { + 0% { + -webkit-transform: translateX(100%) skewX(-30deg); + transform: translateX(100%) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: translateX(-20%) skewX(30deg); + transform: translateX(-20%) skewX(30deg); + opacity: 1; + } + + 80% { + -webkit-transform: translateX(0%) skewX(-15deg); + transform: translateX(0%) skewX(-15deg); + opacity: 1; + } + + 100% { + -webkit-transform: translateX(0%) skewX(0deg); + transform: translateX(0%) skewX(0deg); + opacity: 1; + } +} + +@keyframes lightSpeedIn { + 0% { + -webkit-transform: translateX(100%) skewX(-30deg); + -ms-transform: translateX(100%) skewX(-30deg); + transform: translateX(100%) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: translateX(-20%) skewX(30deg); + -ms-transform: translateX(-20%) skewX(30deg); + transform: translateX(-20%) skewX(30deg); + opacity: 1; + } + + 80% { + -webkit-transform: translateX(0%) skewX(-15deg); + -ms-transform: translateX(0%) skewX(-15deg); + transform: translateX(0%) skewX(-15deg); + opacity: 1; + } + + 100% { + -webkit-transform: translateX(0%) skewX(0deg); + -ms-transform: translateX(0%) skewX(0deg); + transform: translateX(0%) skewX(0deg); + opacity: 1; + } +} + +.lightSpeedIn { + -webkit-animation-name: lightSpeedIn; + animation-name: lightSpeedIn; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; +} + +@-webkit-keyframes lightSpeedOut { + 0% { + -webkit-transform: translateX(0%) skewX(0deg); + transform: translateX(0%) skewX(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: translateX(100%) skewX(-30deg); + transform: translateX(100%) skewX(-30deg); + opacity: 0; + } +} + +@keyframes lightSpeedOut { + 0% { + -webkit-transform: translateX(0%) skewX(0deg); + -ms-transform: translateX(0%) skewX(0deg); + transform: translateX(0%) skewX(0deg); + opacity: 1; + } + + 100% { + -webkit-transform: translateX(100%) skewX(-30deg); + -ms-transform: translateX(100%) skewX(-30deg); + transform: translateX(100%) skewX(-30deg); + opacity: 0; + } +} + +.lightSpeedOut { + -webkit-animation-name: lightSpeedOut; + animation-name: lightSpeedOut; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; +} + +@-webkit-keyframes rotateIn { + 0% { + -webkit-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(-200deg); + transform: rotate(-200deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +@keyframes rotateIn { + 0% { + -webkit-transform-origin: center center; + -ms-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(-200deg); + -ms-transform: rotate(-200deg); + transform: rotate(-200deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: center center; + -ms-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +.rotateIn { + -webkit-animation-name: rotateIn; + animation-name: rotateIn; +} + +@-webkit-keyframes rotateInDownLeft { + 0% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +@keyframes rotateInDownLeft { + 0% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +.rotateInDownLeft { + -webkit-animation-name: rotateInDownLeft; + animation-name: rotateInDownLeft; +} + +@-webkit-keyframes rotateInDownRight { + 0% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +@keyframes rotateInDownRight { + 0% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +.rotateInDownRight { + -webkit-animation-name: rotateInDownRight; + animation-name: rotateInDownRight; +} + +@-webkit-keyframes rotateInUpLeft { + 0% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +@keyframes rotateInUpLeft { + 0% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +.rotateInUpLeft { + -webkit-animation-name: rotateInUpLeft; + animation-name: rotateInUpLeft; +} + +@-webkit-keyframes rotateInUpRight { + 0% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +@keyframes rotateInUpRight { + 0% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } + + 100% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } +} + +.rotateInUpRight { + -webkit-animation-name: rotateInUpRight; + animation-name: rotateInUpRight; +} + +@-webkit-keyframes rotateOut { + 0% { + -webkit-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(200deg); + transform: rotate(200deg); + opacity: 0; + } +} + +@keyframes rotateOut { + 0% { + -webkit-transform-origin: center center; + -ms-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: center center; + -ms-transform-origin: center center; + transform-origin: center center; + -webkit-transform: rotate(200deg); + -ms-transform: rotate(200deg); + transform: rotate(200deg); + opacity: 0; + } +} + +.rotateOut { + -webkit-animation-name: rotateOut; + animation-name: rotateOut; +} + +@-webkit-keyframes rotateOutDownLeft { + 0% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } +} + +@keyframes rotateOutDownLeft { + 0% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } +} + +.rotateOutDownLeft { + -webkit-animation-name: rotateOutDownLeft; + animation-name: rotateOutDownLeft; +} + +@-webkit-keyframes rotateOutDownRight { + 0% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } +} + +@keyframes rotateOutDownRight { + 0% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } +} + +.rotateOutDownRight { + -webkit-animation-name: rotateOutDownRight; + animation-name: rotateOutDownRight; +} + +@-webkit-keyframes rotateOutUpLeft { + 0% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } +} + +@keyframes rotateOutUpLeft { + 0% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: left bottom; + -ms-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); + opacity: 0; + } +} + +.rotateOutUpLeft { + -webkit-animation-name: rotateOutUpLeft; + animation-name: rotateOutUpLeft; +} + +@-webkit-keyframes rotateOutUpRight { + 0% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } +} + +@keyframes rotateOutUpRight { + 0% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; + } + + 100% { + -webkit-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + opacity: 0; + } +} + +.rotateOutUpRight { + -webkit-animation-name: rotateOutUpRight; + animation-name: rotateOutUpRight; +} + +@-webkit-keyframes slideInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes slideInDown { + 0% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } + + 100% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +.slideInDown { + -webkit-animation-name: slideInDown; + animation-name: slideInDown; +} + +@-webkit-keyframes slideInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes slideInLeft { + 0% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } + + 100% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.slideInLeft { + -webkit-animation-name: slideInLeft; + animation-name: slideInLeft; +} + +@-webkit-keyframes slideInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } + + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes slideInRight { + 0% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } + + 100% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} + +.slideInRight { + -webkit-animation-name: slideInRight; + animation-name: slideInRight; +} + +@-webkit-keyframes slideOutLeft { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +@keyframes slideOutLeft { + 0% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(-2000px); + -ms-transform: translateX(-2000px); + transform: translateX(-2000px); + } +} + +.slideOutLeft { + -webkit-animation-name: slideOutLeft; + animation-name: slideOutLeft; +} + +@-webkit-keyframes slideOutRight { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +@keyframes slideOutRight { + 0% { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(2000px); + -ms-transform: translateX(2000px); + transform: translateX(2000px); + } +} + +.slideOutRight { + -webkit-animation-name: slideOutRight; + animation-name: slideOutRight; +} + +@-webkit-keyframes slideOutUp { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +@keyframes slideOutUp { + 0% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-2000px); + -ms-transform: translateY(-2000px); + transform: translateY(-2000px); + } +} + +.slideOutUp { + -webkit-animation-name: slideOutUp; + animation-name: slideOutUp; +} + +@-webkit-keyframes slideOutDown { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +@keyframes slideOutDown { + 0% { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(2000px); + -ms-transform: translateY(2000px); + transform: translateY(2000px); + } +} + +.slideOutDown { + -webkit-animation-name: slideOutDown; + animation-name: slideOutDown; +} + +@-webkit-keyframes hinge { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, 60% { + -webkit-transform: rotate(80deg); + transform: rotate(80deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40% { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 80% { + -webkit-transform: rotate(60deg) translateY(0); + transform: rotate(60deg) translateY(0); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + 100% { + -webkit-transform: translateY(700px); + transform: translateY(700px); + opacity: 0; + } +} + +@keyframes hinge { + 0% { + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + -webkit-transform-origin: top left; + -ms-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, 60% { + -webkit-transform: rotate(80deg); + -ms-transform: rotate(80deg); + transform: rotate(80deg); + -webkit-transform-origin: top left; + -ms-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40% { + -webkit-transform: rotate(60deg); + -ms-transform: rotate(60deg); + transform: rotate(60deg); + -webkit-transform-origin: top left; + -ms-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 80% { + -webkit-transform: rotate(60deg) translateY(0); + -ms-transform: rotate(60deg) translateY(0); + transform: rotate(60deg) translateY(0); + -webkit-transform-origin: top left; + -ms-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + 100% { + -webkit-transform: translateY(700px); + -ms-transform: translateY(700px); + transform: translateY(700px); + opacity: 0; + } +} + +.hinge { + -webkit-animation-name: hinge; + animation-name: hinge; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollIn { + 0% { + opacity: 0; + -webkit-transform: translateX(-100%) rotate(-120deg); + transform: translateX(-100%) rotate(-120deg); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } +} + +@keyframes rollIn { + 0% { + opacity: 0; + -webkit-transform: translateX(-100%) rotate(-120deg); + -ms-transform: translateX(-100%) rotate(-120deg); + transform: translateX(-100%) rotate(-120deg); + } + + 100% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + -ms-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } +} + +.rollIn { + -webkit-animation-name: rollIn; + animation-name: rollIn; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollOut { + 0% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(100%) rotate(120deg); + transform: translateX(100%) rotate(120deg); + } +} + +@keyframes rollOut { + 0% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + -ms-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } + + 100% { + opacity: 0; + -webkit-transform: translateX(100%) rotate(120deg); + -ms-transform: translateX(100%) rotate(120deg); + transform: translateX(100%) rotate(120deg); + } +} + +.rollOut { + -webkit-animation-name: rollOut; + animation-name: rollOut; +} \ No newline at end of file diff --git a/apps/static/css/bootstrap.min.css b/apps/static/css/bootstrap.min.css new file mode 100644 index 000000000..4af8905e5 --- /dev/null +++ b/apps/static/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:before,:after{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.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}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px;line-height:1.5 \0}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px;line-height:1.33 \0}_:-ms-fullscreen,:root input[type=date],_:-ms-fullscreen,:root input[type=time],_:-ms-fullscreen,:root input[type=datetime-local],_:-ms-fullscreen,:root input[type=month]{line-height:1.42857143}_:-ms-fullscreen.input-sm,:root input[type=date].input-sm,_:-ms-fullscreen.input-sm,:root input[type=time].input-sm,_:-ms-fullscreen.input-sm,:root input[type=datetime-local].input-sm,_:-ms-fullscreen.input-sm,:root input[type=month].input-sm{line-height:1.5}_:-ms-fullscreen.input-lg,:root input[type=date].input-lg,_:-ms-fullscreen.input-lg,:root input[type=time].input-lg,_:-ms-fullscreen.input-lg,:root input[type=datetime-local].input-lg,_:-ms-fullscreen.input-lg,:root input[type=month].input-lg{line-height:1.33}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important;visibility:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/apps/static/css/colorbox.css b/apps/static/css/colorbox.css new file mode 100644 index 000000000..0a6710404 --- /dev/null +++ b/apps/static/css/colorbox.css @@ -0,0 +1,50 @@ +/* + Colorbox Core Style: + The following CSS is consistent between example themes and should not be altered. +*/ +#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} +#cboxWrapper {max-width:none;} +#cboxOverlay{position:fixed; width:100%; height:100%;} +#cboxMiddleLeft, #cboxBottomLeft{clear:left;} +#cboxContent{position:relative;} +#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;} +#cboxTitle{margin:0;} +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} +#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} +.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;} +.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;} +#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;} + +/* + User Style: + Change the following styles to modify the appearance of Colorbox. They are + ordered & tabbed in a way that represents the nesting of the generated HTML. +*/ +#cboxOverlay{background:#fff; opacity: 0.9; filter: alpha(opacity = 90);} +#colorbox{outline:0;} + #cboxContent{margin-top:32px; overflow:visible; background:#000;} + .cboxIframe{background:#fff;} + #cboxError{padding:50px; border:1px solid #ccc;} + #cboxLoadedContent{background:#000; padding:1px;} + #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;} + #cboxLoadingOverlay{background:#000;} + #cboxTitle{position:absolute; top:-22px; left:0; color:#000;} + #cboxCurrent{position:absolute; top:-22px; right:205px; text-indent:-9999px;} + + /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */ + #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; text-indent:-9999px; width:20px; height:20px; position:absolute; top:-20px; background:url(images/controls.png) no-repeat 0 0;} + + /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */ + #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;} + + #cboxPrevious{background-position:0px 0px; right:44px;} + #cboxPrevious:hover{background-position:0px -25px;} + #cboxNext{background-position:-25px 0px; right:22px;} + #cboxNext:hover{background-position:-25px -25px;} + #cboxClose{background-position:-50px 0px; right:0;} + #cboxClose:hover{background-position:-50px -25px;} + .cboxSlideshow_on #cboxPrevious, .cboxSlideshow_off #cboxPrevious{right:66px;} + .cboxSlideshow_on #cboxSlideshow{background-position:-75px -25px; right:44px;} + .cboxSlideshow_on #cboxSlideshow:hover{background-position:-100px -25px;} + .cboxSlideshow_off #cboxSlideshow{background-position:-100px 0px; right:44px;} + .cboxSlideshow_off #cboxSlideshow:hover{background-position:-75px -25px;} diff --git a/apps/static/css/font-awesome.css b/apps/static/css/font-awesome.css new file mode 100644 index 000000000..4040b3cf8 --- /dev/null +++ b/apps/static/css/font-awesome.css @@ -0,0 +1,1672 @@ +/*! + * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.2.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.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; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.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: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + 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; +} +@-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: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.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: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 { + 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-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"; +} diff --git a/apps/static/css/font-awesome.min.css b/apps/static/css/font-awesome.min.css new file mode 100644 index 000000000..ec53d4d6d --- /dev/null +++ b/apps/static/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.2.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.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.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}.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}@-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: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{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-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"} \ No newline at end of file diff --git a/apps/static/css/images/jbox-button1.png b/apps/static/css/images/jbox-button1.png new file mode 100644 index 000000000..7d8a6a4b2 Binary files /dev/null and b/apps/static/css/images/jbox-button1.png differ diff --git a/apps/static/css/images/jbox-close.gif b/apps/static/css/images/jbox-close.gif new file mode 100644 index 000000000..83ffe0b6c Binary files /dev/null and b/apps/static/css/images/jbox-close.gif differ diff --git a/apps/static/css/images/jbox-icons.png b/apps/static/css/images/jbox-icons.png new file mode 100644 index 000000000..c35abcffc Binary files /dev/null and b/apps/static/css/images/jbox-icons.png differ diff --git a/apps/static/css/jumpserver.css b/apps/static/css/jumpserver.css new file mode 100644 index 000000000..a7a6d0af4 --- /dev/null +++ b/apps/static/css/jumpserver.css @@ -0,0 +1,279 @@ +.red-fonts { + color: #ed5565; +} + +.form-group.required .control-label:after { + content: " *"; + color: red; +} + +.n-invalid {border: 1px solid #f00;} + + +.primary-panel .ibox-title { + color: #ffffff; + background-color: #1AB394; +} + +.primary-panel .ibox-content { + border: 1px solid #1AB394; +} + +.info-panel .ibox-title { + color: #ffffff; + background-color: #23c6c8; +} + +.info-panel .ibox-content { + border: 1px solid #23c6c8;; +} + + +th a { + color: #676a6c; +} + +.select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: #1ab394 !important; + color: white; + } + +.select2-selection--single, +.select2-selection--multiple { + border: 1px solid #e5e6e7 !important; + cursor: text !important; + } + +.select2-container--forcus { + border: 1px solid #1AB394 !important; + } + +.select2-selection__choice, +.chosen-container-multi .chosen-choices li.search-choice { + background: #f1f1f1 !important; + border: 1px solid #e5e6e7 !important; + /*border: 1px solid #ededed;*/ + border-radius: 2px !important; + box-shadow: none !important; + color: #333333 !important; + cursor: default !important; + line-height: 13px !important; + /*margin: 3px 0 3px 5px !important;*/ + padding: 3px 20px 3px 5px !important; + position: relative !important; + } + +.select2-container--default.select2-container--focus .select2-selection--multiple { + border: 1px solid #1ab394 !important; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3) !important; +} + +.passwordBox2 { + max-width: 660px; + margin: 0 auto; + padding: 100px 20px 20px 20px; +} + +.no-borders-tr td { + border-top: none !important; +} + +table.dataTable tbody > tr.selected, table.dataTable tbody > tr > .selected { + background-color: #1ab394 !important; +} +table.dataTable tbody tr.selected a, +table.dataTable tbody th.selected a, +table.dataTable tbody td.selected a, +table.dataTable tbody tr.selected td i.text-navy, +table.dataTable tbody th.selected td i.text-navy, +table.dataTable tbody td.selected td i.text-navy +{ + color: white !important; +} + +.m-0 { + margin: 0px !important; +} +.m-t-0 { + margin-top: 0px !important; +} +.m-b-0 { + margin-bottom: 0px !important; +} +.m-l-0 { + margin-left: 0px !important; +} +.m-r-0 { + margin-right: 0px !important; +} +.m-5 { + margin: 5px !important; +} +.m-t-5 { + margin-top: 5px !important; +} +.m-b-5 { + margin-bottom: 5px !important; +} +.m-l-5 { + margin-left: 5px !important; +} +.m-r-5 { + margin-right: 5px !important; +} +.m-10 { + margin: 10px !important; +} +.m-t-10 { + margin-top: 10px !important; +} +.m-b-10 { + margin-bottom: 10px !important; +} +.m-l-10 { + margin-left: 10px !important; +} +.m-r-10 { + margin-right: 10px !important; +} +.m-15 { + margin: 15px !important; +} +.m-t-15 { + margin-top: 15px !important; +} +.m-b-15 { + margin-bottom: 15px !important; +} +.m-l-15 { + margin-left: 15px !important; +} +.m-r-15 { + margin-right: 15px !important; +} +.m-20 { + margin: 20px !important; +} +.m-t-20 { + margin-top: 20px !important; +} +.m-b-20 { + margin-bottom: 20px !important; +} +.m-l-20 { + margin-left: 20px !important; +} +.m-r-20 { + margin-right: 20px !important; +} +.m-25 { + margin: 25px !important; +} +.m-t-25 { + margin-top: 25px !important; +} +.m-b-25 { + margin-bottom: 25px !important; +} +.m-l-25 { + margin-left: 25px !important; +} +.m-r-25 { + margin-right: 25px !important; +} +.m-30 { + margin: 30px !important; +} +.m-t-30 { + margin-top: 30px !important; +} +.m-b-30 { + margin-bottom: 30px !important; +} +.m-l-30 { + margin-left: 30px !important; +} +.m-r-30 { + margin-right: 30px !important; +} + +.ydxbd { + font-size: 12px; + width: 100%; + overflow: hidden; + padding-top: 15px; + margin-bottom: 15px; + display: block; + background: #f4f4f4; + padding-left: 10px; + padding-bottom: 15px; +} +.mar { + margin-left: 2px; + line-height: 0px; +} +.mar-j { + margin-left: 3px; + margin-right: 3px; +} + +.form-asset-on p{ + margin-bottom:0px; +} + +.form-asset-on button{ + background: #f1f1f1; + margin-right: 2px; +} + +.form-asset-on{ + border: 1px solid #e5e6e7; + padding-top:5px; + padding-bottom: 0px; + padding-left: 5px; + padding-right: 5px; + min-height:34px; + height: 100%; +} + +.mgl-5 { + margin-left: 5px; + font-size: 12px; +} +.c02 { + color: #999; +} + +.tagBtnList { + font-size: 12px; + line-height: 32px; + margin: -5px 0 0 0; + padding-left: 0px; +} + +.tagBtn2 { + margin: 0 5px 5px 0; + font-size: 12px; + vertical-align: middle; +} + +div.dataTables_wrapper div.dataTables_filter, +.dataTables_length { + float: right !important; +} + +div.dataTables_wrapper div.dataTables_filter { + margin-left: 15px; +} + +.simple-tag { + background-color: #f3f3f4; + border: 1px solid #e7eaec; + border-radius: 2px; + color: inherit; + display: inline-block; + font-size: 10px; + margin-right: 5px; + margin-top: 5px; + padding: 5px 12px; +} diff --git a/apps/static/css/patterns/congruent_pentagon.png b/apps/static/css/patterns/congruent_pentagon.png new file mode 100644 index 000000000..c71266032 Binary files /dev/null and b/apps/static/css/patterns/congruent_pentagon.png differ diff --git a/apps/static/css/patterns/header-profile-skin-1.png b/apps/static/css/patterns/header-profile-skin-1.png new file mode 100644 index 000000000..41c5c089b Binary files /dev/null and b/apps/static/css/patterns/header-profile-skin-1.png differ diff --git a/apps/static/css/patterns/header-profile-skin-2.png b/apps/static/css/patterns/header-profile-skin-2.png new file mode 100644 index 000000000..df46d46e5 Binary files /dev/null and b/apps/static/css/patterns/header-profile-skin-2.png differ diff --git a/apps/static/css/patterns/header-profile-skin-3.png b/apps/static/css/patterns/header-profile-skin-3.png new file mode 100644 index 000000000..7a80132da Binary files /dev/null and b/apps/static/css/patterns/header-profile-skin-3.png differ diff --git a/apps/static/css/patterns/header-profile.png b/apps/static/css/patterns/header-profile.png new file mode 100644 index 000000000..7dea7f2c7 Binary files /dev/null and b/apps/static/css/patterns/header-profile.png differ diff --git a/apps/static/css/patterns/otis_redding.png b/apps/static/css/patterns/otis_redding.png new file mode 100644 index 000000000..7fa3533a0 Binary files /dev/null and b/apps/static/css/patterns/otis_redding.png differ diff --git a/apps/static/css/patterns/shattered.png b/apps/static/css/patterns/shattered.png new file mode 100644 index 000000000..90ed42b85 Binary files /dev/null and b/apps/static/css/patterns/shattered.png differ diff --git a/apps/static/css/patterns/triangular.png b/apps/static/css/patterns/triangular.png new file mode 100644 index 000000000..7f41795c8 Binary files /dev/null and b/apps/static/css/patterns/triangular.png differ diff --git a/apps/static/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css b/apps/static/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css new file mode 100644 index 000000000..f4e6575f1 --- /dev/null +++ b/apps/static/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css @@ -0,0 +1,251 @@ +.checkbox { + padding-left: 20px; +} +.checkbox label { + display: inline-block; + vertical-align: middle; + position: relative; + padding-left: 5px; +} +.checkbox label::before { + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + left: 0; + margin-left: -20px; + border: 1px solid #cccccc; + border-radius: 3px; + background-color: #fff; + -webkit-transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + -o-transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + transition: border 0.15s ease-in-out, color 0.15s ease-in-out; +} +.checkbox label::after { + display: inline-block; + position: absolute; + width: 16px; + height: 16px; + left: 0; + top: 0; + margin-left: -20px; + padding-left: 3px; + padding-top: 1px; + font-size: 11px; + color: #555555; +} +.checkbox input[type="checkbox"], +.checkbox input[type="radio"] { + opacity: 0; + z-index: 1; +} +.checkbox input[type="checkbox"]:focus + label::before, +.checkbox input[type="radio"]:focus + label::before { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.checkbox input[type="checkbox"]:checked + label::after, +.checkbox input[type="radio"]:checked + label::after { + font-family: "FontAwesome"; + content: "\f00c"; +} +.checkbox input[type="checkbox"]:disabled + label, +.checkbox input[type="radio"]:disabled + label { + opacity: 0.65; +} +.checkbox input[type="checkbox"]:disabled + label::before, +.checkbox input[type="radio"]:disabled + label::before { + background-color: #eeeeee; + cursor: not-allowed; +} +.checkbox.checkbox-circle label::before { + border-radius: 50%; +} +.checkbox.checkbox-inline { + margin-top: 0; +} + +.checkbox-primary input[type="checkbox"]:checked + label::before, +.checkbox-primary input[type="radio"]:checked + label::before { + background-color: #337ab7; + border-color: #337ab7; +} +.checkbox-primary input[type="checkbox"]:checked + label::after, +.checkbox-primary input[type="radio"]:checked + label::after { + color: #fff; +} + +.checkbox-danger input[type="checkbox"]:checked + label::before, +.checkbox-danger input[type="radio"]:checked + label::before { + background-color: #d9534f; + border-color: #d9534f; +} +.checkbox-danger input[type="checkbox"]:checked + label::after, +.checkbox-danger input[type="radio"]:checked + label::after { + color: #fff; +} + +.checkbox-info input[type="checkbox"]:checked + label::before, +.checkbox-info input[type="radio"]:checked + label::before { + background-color: #5bc0de; + border-color: #5bc0de; +} +.checkbox-info input[type="checkbox"]:checked + label::after, +.checkbox-info input[type="radio"]:checked + label::after { + color: #fff; +} + +.checkbox-warning input[type="checkbox"]:checked + label::before, +.checkbox-warning input[type="radio"]:checked + label::before { + background-color: #f0ad4e; + border-color: #f0ad4e; +} +.checkbox-warning input[type="checkbox"]:checked + label::after, +.checkbox-warning input[type="radio"]:checked + label::after { + color: #fff; +} + +.checkbox-success input[type="checkbox"]:checked + label::before, +.checkbox-success input[type="radio"]:checked + label::before { + background-color: #5cb85c; + border-color: #5cb85c; +} +.checkbox-success input[type="checkbox"]:checked + label::after, +.checkbox-success input[type="radio"]:checked + label::after { + color: #fff; +} + +.radio { + padding-left: 20px; +} +.radio label { + display: inline-block; + vertical-align: middle; + position: relative; + padding-left: 5px; +} +.radio label::before { + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + left: 0; + margin-left: -20px; + border: 1px solid #cccccc; + border-radius: 50%; + background-color: #fff; + -webkit-transition: border 0.15s ease-in-out; + -o-transition: border 0.15s ease-in-out; + transition: border 0.15s ease-in-out; +} +.radio label::after { + display: inline-block; + position: absolute; + content: " "; + width: 11px; + height: 11px; + left: 3px; + top: 3px; + margin-left: -20px; + border-radius: 50%; + background-color: #555555; + -webkit-transform: scale(0, 0); + -ms-transform: scale(0, 0); + -o-transform: scale(0, 0); + transform: scale(0, 0); + -webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + -moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + -o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); + transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33); +} +.radio input[type="radio"] { + opacity: 0; + z-index: 1; +} +.radio input[type="radio"]:focus + label::before { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.radio input[type="radio"]:checked + label::after { + -webkit-transform: scale(1, 1); + -ms-transform: scale(1, 1); + -o-transform: scale(1, 1); + transform: scale(1, 1); +} +.radio input[type="radio"]:disabled + label { + opacity: 0.65; +} +.radio input[type="radio"]:disabled + label::before { + cursor: not-allowed; +} +.radio.radio-inline { + margin-top: 0; +} + +.radio-primary input[type="radio"] + label::after { + background-color: #337ab7; +} +.radio-primary input[type="radio"]:checked + label::before { + border-color: #337ab7; +} +.radio-primary input[type="radio"]:checked + label::after { + background-color: #337ab7; +} + +.radio-danger input[type="radio"] + label::after { + background-color: #d9534f; +} +.radio-danger input[type="radio"]:checked + label::before { + border-color: #d9534f; +} +.radio-danger input[type="radio"]:checked + label::after { + background-color: #d9534f; +} + +.radio-info input[type="radio"] + label::after { + background-color: #5bc0de; +} +.radio-info input[type="radio"]:checked + label::before { + border-color: #5bc0de; +} +.radio-info input[type="radio"]:checked + label::after { + background-color: #5bc0de; +} + +.radio-warning input[type="radio"] + label::after { + background-color: #f0ad4e; +} +.radio-warning input[type="radio"]:checked + label::before { + border-color: #f0ad4e; +} +.radio-warning input[type="radio"]:checked + label::after { + background-color: #f0ad4e; +} + +.radio-success input[type="radio"] + label::after { + background-color: #5cb85c; +} +.radio-success input[type="radio"]:checked + label::before { + border-color: #5cb85c; +} +.radio-success input[type="radio"]:checked + label::after { + background-color: #5cb85c; +} + +input[type="checkbox"].styled:checked + label:after, +input[type="radio"].styled:checked + label:after { + font-family: 'FontAwesome'; + content: "\f00c"; +} +input[type="checkbox"] .styled:checked + label::before, +input[type="radio"] .styled:checked + label::before { + color: #fff; +} +input[type="checkbox"] .styled:checked + label::after, +input[type="radio"] .styled:checked + label::after { + color: #fff; +} diff --git a/apps/static/css/plugins/bootstrap.min.css b/apps/static/css/plugins/bootstrap.min.css new file mode 100644 index 000000000..c95146773 --- /dev/null +++ b/apps/static/css/plugins/bootstrap.min.css @@ -0,0 +1,689 @@ +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} +input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";} +.clearfix:after{clear:both;} +.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;} +.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} +body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover{color:#005580;text-decoration:underline;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} +.row:after{clear:both;} +[class*="span"]{float:left;margin-left:20px;} +.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.span12{width:940px;} +.span11{width:860px;} +.span10{width:780px;} +.span9{width:700px;} +.span8{width:620px;} +.span7{width:540px;} +.span6{width:460px;} +.span5{width:380px;} +.span4{width:300px;} +.span3{width:220px;} +.span2{width:140px;} +.span1{width:60px;} +.offset12{margin-left:980px;} +.offset11{margin-left:900px;} +.offset10{margin-left:820px;} +.offset9{margin-left:740px;} +.offset8{margin-left:660px;} +.offset7{margin-left:580px;} +.offset6{margin-left:500px;} +.offset5{margin-left:420px;} +.offset4{margin-left:340px;} +.offset3{margin-left:260px;} +.offset2{margin-left:180px;} +.offset1{margin-left:100px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} +.row-fluid:after{clear:both;} +.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} +.row-fluid>[class*="span"]:first-child{margin-left:0;} +.row-fluid > .span12{width:99.99999998999999%;} +.row-fluid > .span11{width:91.489361693%;} +.row-fluid > .span10{width:82.97872339599999%;} +.row-fluid > .span9{width:74.468085099%;} +.row-fluid > .span8{width:65.95744680199999%;} +.row-fluid > .span7{width:57.446808505%;} +.row-fluid > .span6{width:48.93617020799999%;} +.row-fluid > .span5{width:40.425531911%;} +.row-fluid > .span4{width:31.914893614%;} +.row-fluid > .span3{width:23.404255317%;} +.row-fluid > .span2{width:14.89361702%;} +.row-fluid > .span1{width:6.382978723%;} +.container{margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} +.container:after{clear:both;} +.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} +.container-fluid:after{clear:both;} +p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} +.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} +h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} +h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} +h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} +h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} +h4,h5,h6{line-height:18px;} +h4{font-size:14px;}h4 small{font-size:12px;} +h5{font-size:12px;} +h6{font-size:11px;color:#999999;text-transform:uppercase;} +.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} +.page-header h1{line-height:1;} +ul,ol{padding:0;margin:0 0 9px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +ul{list-style:disc;} +ol{list-style:decimal;} +li{line-height:18px;} +ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} +dl{margin-bottom:18px;} +dt,dd{line-height:18px;} +dt{font-weight:bold;line-height:17px;} +dd{margin-left:9px;} +.dl-horizontal dt{float:left;clear:left;width:120px;text-align:right;} +.dl-horizontal dd{margin-left:130px;} +hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} +strong{font-weight:bold;} +em{font-style:italic;} +.muted{color:#999999;} +abbr[title]{border-bottom:1px dotted #ddd;cursor:help;} +abbr.initialism{font-size:90%;text-transform:uppercase;} +blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} +blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} +small{font-size:100%;} +cite{font-style:normal;} +code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} +pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;} +pre code{padding:0;color:inherit;background-color:transparent;border:0;} +.pre-scrollable{max-height:340px;overflow-y:scroll;} +form{margin:0 0 18px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;} +label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;} +input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} +label{display:block;margin-bottom:5px;color:#333333;} +input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.uneditable-textarea{width:auto;height:auto;} +label input,label textarea,label select{display:block;} +input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;} +input[type="image"]{border:0;} +input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} +select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} +input[type="file"]{line-height:18px \9;} +select{width:220px;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +textarea{height:auto;} +input[type="hidden"]{display:none;} +.radio,.checkbox{padding-left:18px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} +input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} +input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} +input,textarea,.uneditable-input{margin-left:0;} +input.span12, textarea.span12, .uneditable-input.span12{width:930px;} +input.span11, textarea.span11, .uneditable-input.span11{width:850px;} +input.span10, textarea.span10, .uneditable-input.span10{width:770px;} +input.span9, textarea.span9, .uneditable-input.span9{width:690px;} +input.span8, textarea.span8, .uneditable-input.span8{width:610px;} +input.span7, textarea.span7, .uneditable-input.span7{width:530px;} +input.span6, textarea.span6, .uneditable-input.span6{width:450px;} +input.span5, textarea.span5, .uneditable-input.span5{width:370px;} +input.span4, textarea.span4, .uneditable-input.span4{width:290px;} +input.span3, textarea.span3, .uneditable-input.span3{width:210px;} +input.span2, textarea.span2, .uneditable-input.span2{width:130px;} +input.span1, textarea.span1, .uneditable-input.span1{width:50px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#eeeeee;border-color:#ddd;cursor:not-allowed;} +.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#eeeeee;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";} +.form-actions:after{clear:both;} +.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +:-moz-placeholder{color:#999999;} +::-webkit-input-placeholder{color:#999999;} +.help-block,.help-inline{color:#555555;} +.help-block{display:block;margin-bottom:9px;} +.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} +.input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{*margin-left:0;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} +.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} +.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;} +.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} +.input-append input,.input-append select .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;} +.input-append .add-on,.input-append .btn{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;margin-bottom:0;} +.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} +.form-search label,.form-inline label{display:inline-block;} +.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} +.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} +.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-left:0;margin-right:3px;} +.control-group{margin-bottom:9px;} +legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;} +.form-horizontal .controls{margin-left:160px;*display:inline-block;*margin-left:0;*padding-left:20px;} +.form-horizontal .help-block{margin-top:9px;margin-bottom:0;} +.form-horizontal .form-actions{padding-left:160px;} +table{max-width:100%;border-collapse:collapse;border-spacing:0;background-color:transparent;} +.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} +.table th{font-weight:bold;} +.table thead th{vertical-align:bottom;} +.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} +.table tbody+tbody{border-top:2px solid #dddddd;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #dddddd;border-left:0;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} +.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} +.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} +.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} +.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} +.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} +.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;} +table .span1{float:none;width:44px;margin-left:0;} +table .span2{float:none;width:124px;margin-left:0;} +table .span3{float:none;width:204px;margin-left:0;} +table .span4{float:none;width:284px;margin-left:0;} +table .span5{float:none;width:364px;margin-left:0;} +table .span6{float:none;width:444px;margin-left:0;} +table .span7{float:none;width:524px;margin-left:0;} +table .span8{float:none;width:604px;margin-left:0;} +table .span9{float:none;width:684px;margin-left:0;} +table .span10{float:none;width:764px;margin-left:0;} +table .span11{float:none;width:844px;margin-left:0;} +table .span12{float:none;width:924px;margin-left:0;} +table .span13{float:none;width:1004px;margin-left:0;} +table .span14{float:none;width:1084px;margin-left:0;} +table .span15{float:none;width:1164px;margin-left:0;} +table .span16{float:none;width:1244px;margin-left:0;} +table .span17{float:none;width:1324px;margin-left:0;} +table .span18{float:none;width:1404px;margin-left:0;} +table .span19{float:none;width:1484px;margin-left:0;} +table .span20{float:none;width:1564px;margin-left:0;} +table .span21{float:none;width:1644px;margin-left:0;} +table .span22{float:none;width:1724px;margin-left:0;} +table .span23{float:none;width:1804px;margin-left:0;} +table .span24{float:none;width:1884px;margin-left:0;} +[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;} +.icon-white{background-image:url("../img/glyphicons-halflings-white.png");} +.icon-glass{background-position:0 0;} +.icon-music{background-position:-24px 0;} +.icon-search{background-position:-48px 0;} +.icon-envelope{background-position:-72px 0;} +.icon-heart{background-position:-96px 0;} +.icon-star{background-position:-120px 0;} +.icon-star-empty{background-position:-144px 0;} +.icon-user{background-position:-168px 0;} +.icon-film{background-position:-192px 0;} +.icon-th-large{background-position:-216px 0;} +.icon-th{background-position:-240px 0;} +.icon-th-list{background-position:-264px 0;} +.icon-ok{background-position:-288px 0;} +.icon-remove{background-position:-312px 0;} +.icon-zoom-in{background-position:-336px 0;} +.icon-zoom-out{background-position:-360px 0;} +.icon-off{background-position:-384px 0;} +.icon-signal{background-position:-408px 0;} +.icon-cog{background-position:-432px 0;} +.icon-trash{background-position:-456px 0;} +.icon-home{background-position:0 -24px;} +.icon-file{background-position:-24px -24px;} +.icon-time{background-position:-48px -24px;} +.icon-road{background-position:-72px -24px;} +.icon-download-alt{background-position:-96px -24px;} +.icon-download{background-position:-120px -24px;} +.icon-upload{background-position:-144px -24px;} +.icon-inbox{background-position:-168px -24px;} +.icon-play-circle{background-position:-192px -24px;} +.icon-repeat{background-position:-216px -24px;} +.icon-refresh{background-position:-240px -24px;} +.icon-list-alt{background-position:-264px -24px;} +.icon-lock{background-position:-287px -24px;} +.icon-flag{background-position:-312px -24px;} +.icon-headphones{background-position:-336px -24px;} +.icon-volume-off{background-position:-360px -24px;} +.icon-volume-down{background-position:-384px -24px;} +.icon-volume-up{background-position:-408px -24px;} +.icon-qrcode{background-position:-432px -24px;} +.icon-barcode{background-position:-456px -24px;} +.icon-tag{background-position:0 -48px;} +.icon-tags{background-position:-25px -48px;} +.icon-book{background-position:-48px -48px;} +.icon-bookmark{background-position:-72px -48px;} +.icon-print{background-position:-96px -48px;} +.icon-camera{background-position:-120px -48px;} +.icon-font{background-position:-144px -48px;} +.icon-bold{background-position:-167px -48px;} +.icon-italic{background-position:-192px -48px;} +.icon-text-height{background-position:-216px -48px;} +.icon-text-width{background-position:-240px -48px;} +.icon-align-left{background-position:-264px -48px;} +.icon-align-center{background-position:-288px -48px;} +.icon-align-right{background-position:-312px -48px;} +.icon-align-justify{background-position:-336px -48px;} +.icon-list{background-position:-360px -48px;} +.icon-indent-left{background-position:-384px -48px;} +.icon-indent-right{background-position:-408px -48px;} +.icon-facetime-video{background-position:-432px -48px;} +.icon-picture{background-position:-456px -48px;} +.icon-pencil{background-position:0 -72px;} +.icon-map-marker{background-position:-24px -72px;} +.icon-adjust{background-position:-48px -72px;} +.icon-tint{background-position:-72px -72px;} +.icon-edit{background-position:-96px -72px;} +.icon-share{background-position:-120px -72px;} +.icon-check{background-position:-144px -72px;} +.icon-move{background-position:-168px -72px;} +.icon-step-backward{background-position:-192px -72px;} +.icon-fast-backward{background-position:-216px -72px;} +.icon-backward{background-position:-240px -72px;} +.icon-play{background-position:-264px -72px;} +.icon-pause{background-position:-288px -72px;} +.icon-stop{background-position:-312px -72px;} +.icon-forward{background-position:-336px -72px;} +.icon-fast-forward{background-position:-360px -72px;} +.icon-step-forward{background-position:-384px -72px;} +.icon-eject{background-position:-408px -72px;} +.icon-chevron-left{background-position:-432px -72px;} +.icon-chevron-right{background-position:-456px -72px;} +.icon-plus-sign{background-position:0 -96px;} +.icon-minus-sign{background-position:-24px -96px;} +.icon-remove-sign{background-position:-48px -96px;} +.icon-ok-sign{background-position:-72px -96px;} +.icon-question-sign{background-position:-96px -96px;} +.icon-info-sign{background-position:-120px -96px;} +.icon-screenshot{background-position:-144px -96px;} +.icon-remove-circle{background-position:-168px -96px;} +.icon-ok-circle{background-position:-192px -96px;} +.icon-ban-circle{background-position:-216px -96px;} +.icon-arrow-left{background-position:-240px -96px;} +.icon-arrow-right{background-position:-264px -96px;} +.icon-arrow-up{background-position:-289px -96px;} +.icon-arrow-down{background-position:-312px -96px;} +.icon-share-alt{background-position:-336px -96px;} +.icon-resize-full{background-position:-360px -96px;} +.icon-resize-small{background-position:-384px -96px;} +.icon-plus{background-position:-408px -96px;} +.icon-minus{background-position:-433px -96px;} +.icon-asterisk{background-position:-456px -96px;} +.icon-exclamation-sign{background-position:0 -120px;} +.icon-gift{background-position:-24px -120px;} +.icon-leaf{background-position:-48px -120px;} +.icon-fire{background-position:-72px -120px;} +.icon-eye-open{background-position:-96px -120px;} +.icon-eye-close{background-position:-120px -120px;} +.icon-warning-sign{background-position:-144px -120px;} +.icon-plane{background-position:-168px -120px;} +.icon-calendar{background-position:-192px -120px;} +.icon-random{background-position:-216px -120px;} +.icon-comment{background-position:-240px -120px;} +.icon-magnet{background-position:-264px -120px;} +.icon-chevron-up{background-position:-288px -120px;} +.icon-chevron-down{background-position:-313px -119px;} +.icon-retweet{background-position:-336px -120px;} +.icon-shopping-cart{background-position:-360px -120px;} +.icon-folder-close{background-position:-384px -120px;} +.icon-folder-open{background-position:-408px -120px;} +.icon-resize-vertical{background-position:-432px -119px;} +.icon-resize-horizontal{background-position:-456px -118px;} +.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.pull-right{right:0;left:auto;} +.dropdown-menu .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} +.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;} +.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;} +.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} +.dropdown.open .dropdown-menu{display:block;} +.pull-right .dropdown-menu{left:auto;right:0;} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} +.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} +.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;} +.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;} +.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #cccccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;} +.btn:active,.btn.active{background-color:#cccccc \9;} +.btn:first-child{*margin-left:0;} +.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-large [class^="icon-"]{margin-top:1px;} +.btn-small{padding:5px 9px;font-size:11px;line-height:16px;} +.btn-small [class^="icon-"]{margin-top:-1px;} +.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;} +.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{background-color:#0074cc;background-image:-moz-linear-gradient(top, #0088cc, #0055cc);background-image:-ms-linear-gradient(top, #0088cc, #0055cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));background-image:-webkit-linear-gradient(top, #0088cc, #0055cc);background-image:-o-linear-gradient(top, #0088cc, #0055cc);background-image:linear-gradient(top, #0088cc, #0055cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);border-color:#0055cc #0055cc #003580;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0055cc;} +.btn-primary:active,.btn-primary.active{background-color:#004099 \9;} +.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +.btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;} +.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} +button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} +button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} +button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} +.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} +.btn-group:after{clear:both;} +.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} +.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:3px;*padding-bottom:3px;} +.btn-group .btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:1px;*padding-bottom:1px;} +.btn-group .btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;} +.btn-group .btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;} +.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);} +.btn .caret{margin-top:7px;margin-left:0;} +.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} +.btn-mini .caret{margin-top:5px;} +.btn-small .caret{margin-top:6px;} +.btn-large .caret{margin-top:6px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} +.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;} +.alert-heading{color:inherit;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +.nav{margin-left:0;margin-bottom:18px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} +.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} +.nav li+.nav-header{margin-top:9px;} +.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list>li>a{padding:3px 15px;} +.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"]{margin-right:2px;} +.nav-list .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} +.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} +.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;} +.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;} +.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} +.tabbable:after{clear:both;} +.tab-content{display:table;width:100%;} +.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below .nav-tabs{border-top:1px solid #ddd;} +.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} +.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} +.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;} +.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} +.navbar .container{width:auto;} +.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} +.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} +.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.nav-collapse.collapse{height:auto;} +.navbar{color:#999999;}.navbar .brand:hover{text-decoration:none;} +.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} +.navbar .navbar-text{margin-bottom:0;line-height:40px;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} +.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;} +.navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} +.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} +.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.navbar-fixed-top{top:0;} +.navbar-fixed-bottom{bottom:0;} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;} +.navbar .nav>li{display:block;float:left;} +.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} +.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} +.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;} +.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} +.navbar .nav.pull-right{margin-left:10px;margin-right:0;} +.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} +.navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} +.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} +.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} +.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} +.navbar .nav.pull-right .dropdown-menu,.navbar .nav .dropdown-menu.pull-right{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before,.navbar .nav .dropdown-menu.pull-right:before{left:auto;right:12px;} +.navbar .nav.pull-right .dropdown-menu:after,.navbar .nav .dropdown-menu.pull-right:after{left:auto;right:13px;} +.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;} +.breadcrumb .divider{padding:0 5px;color:#999999;} +.breadcrumb .active a{color:#333333;} +.pagination{height:36px;margin:18px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination li{display:inline;} +.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} +.pagination a:hover,.pagination .active a{background-color:#f5f5f5;} +.pagination .active a{color:#999999;cursor:default;} +.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} +.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager a:hover{text-decoration:none;background-color:#f5f5f5;} +.pager .next a{float:right;} +.pager .previous a{float:left;} +.pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;} +.modal-open .dropdown-menu{z-index:2050;} +.modal-open .dropdown.open{*z-index:2050;} +.modal-open .popover{z-index:2060;} +.modal-open .tooltip{z-index:2070;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:50%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-body{overflow-y:auto;max-height:400px;padding:15px;} +.modal-form{margin-bottom:0;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} +.modal-footer:after{clear:both;} +.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} +.modal-footer .btn-group .btn+.btn{margin-left:-1px;} +.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-2px;} +.tooltip.right{margin-left:2px;} +.tooltip.bottom{margin-top:2px;} +.tooltip.left{margin-left:-2px;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} +.popover.right{margin-left:5px;} +.popover.bottom{margin-top:5px;} +.popover.left{margin-left:-5px;} +.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.popover .arrow{position:absolute;width:0;height:0;} +.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} +.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} +.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} +.thumbnails:after{clear:both;} +.thumbnails>li{float:left;margin:0 0 18px 20px;} +.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} +a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;} +.label{padding:1px 4px 2px;font-size:10.998px;font-weight:bold;line-height:13px;color:#ffffff;vertical-align:middle;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.label:hover{color:#ffffff;text-decoration:none;} +.label-important{background-color:#b94a48;} +.label-important:hover{background-color:#953b39;} +.label-warning{background-color:#f89406;} +.label-warning:hover{background-color:#c67605;} +.label-success{background-color:#468847;} +.label-success:hover{background-color:#356635;} +.label-info{background-color:#3a87ad;} +.label-info:hover{background-color:#2d6987;} +.label-inverse{background-color:#333333;} +.label-inverse:hover{background-color:#1a1a1a;} +.badge{padding:1px 9px 2px;font-size:12.025px;font-weight:bold;white-space:nowrap;color:#ffffff;background-color:#999999;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} +.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;} +.badge-error{background-color:#b94a48;} +.badge-error:hover{background-color:#953b39;} +.badge-warning{background-color:#f89406;} +.badge-warning:hover{background-color:#c67605;} +.badge-success{background-color:#468847;} +.badge-success:hover{background-color:#356635;} +.badge-info{background-color:#3a87ad;} +.badge-info:hover{background-color:#2d6987;} +.badge-inverse{background-color:#333333;} +.badge-inverse:hover{background-color:#1a1a1a;} +@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} +.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} +.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} +.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);} +.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.accordion{margin-bottom:18px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:18px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} +.carousel .item>img{display:block;line-height:1;} +.carousel .active,.carousel .next,.carousel .prev{display:block;} +.carousel .active{left:0;} +.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} +.carousel .next{left:100%;} +.carousel .prev{left:-100%;} +.carousel .next.left,.carousel .prev.right{left:0;} +.carousel .active.left{left:-100%;} +.carousel .active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;} +.hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} +.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} diff --git a/apps/static/css/plugins/dataTables/datatables.min.css b/apps/static/css/plugins/dataTables/datatables.min.css new file mode 100644 index 000000000..f0afeb960 --- /dev/null +++ b/apps/static/css/plugins/dataTables/datatables.min.css @@ -0,0 +1,39 @@ +/* + * This combined file was created by the DataTables downloader builder: + * https://datatables.net/download + * + * To rebuild or modify this file with the latest versions of the included + * software please visit: + * https://datatables.net/download/#bs/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/se-1.2.0 + * + * Included libraries: + * JSZip 2.5.0, pdfmake 0.1.18, DataTables 1.10.12, Buttons 1.2.2, Column visibility 1.2.2, Flash export 1.2.2, HTML5 export 1.2.2, Print view 1.2.2, ColReorder 1.3.2, FixedColumns 3.2.2, FixedHeader 3.1.2, KeyTable 2.1.3, Responsive 2.1.0, RowReorder 1.1.2, Select 1.2.0 + */ + +table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:'Glyphicons Halflings';opacity:0.5}table.dataTable thead .sorting:after{opacity:0.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} + + +div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}ul.dt-button-collection.dropdown-menu{display:block;z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}ul.dt-button-collection.dropdown-menu.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}ul.dt-button-collection.dropdown-menu.fixed.two-column{margin-left:-150px}ul.dt-button-collection.dropdown-menu.fixed.three-column{margin-left:-225px}ul.dt-button-collection.dropdown-menu.fixed.four-column{margin-left:-300px}ul.dt-button-collection.dropdown-menu>*{-webkit-column-break-inside:avoid;break-inside:avoid}ul.dt-button-collection.dropdown-menu.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}ul.dt-button-collection.dropdown-menu.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}ul.dt-button-collection.dropdown-menu.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:0.5em}div.dt-buttons a.btn{float:none}} + + +table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#337ab7;z-index:201} + + +table.DTFC_Cloned tr{background-color:white;margin-bottom:0}div.DTFC_LeftHeadWrapper table,div.DTFC_RightHeadWrapper table{border-bottom:none !important;margin-bottom:0 !important;background-color:white}div.DTFC_LeftBodyWrapper table,div.DTFC_RightBodyWrapper table{border-top:none;margin:0 !important}div.DTFC_LeftBodyWrapper table thead .sorting:after,div.DTFC_LeftBodyWrapper table thead .sorting_asc:after,div.DTFC_LeftBodyWrapper table thead .sorting_desc:after,div.DTFC_LeftBodyWrapper table thead .sorting:after,div.DTFC_LeftBodyWrapper table thead .sorting_asc:after,div.DTFC_LeftBodyWrapper table thead .sorting_desc:after,div.DTFC_RightBodyWrapper table thead .sorting:after,div.DTFC_RightBodyWrapper table thead .sorting_asc:after,div.DTFC_RightBodyWrapper table thead .sorting_desc:after,div.DTFC_RightBodyWrapper table thead .sorting:after,div.DTFC_RightBodyWrapper table thead .sorting_asc:after,div.DTFC_RightBodyWrapper table thead .sorting_desc:after{display:none}div.DTFC_LeftBodyWrapper table tbody tr:first-child th,div.DTFC_LeftBodyWrapper table tbody tr:first-child td,div.DTFC_RightBodyWrapper table tbody tr:first-child th,div.DTFC_RightBodyWrapper table tbody tr:first-child td{border-top:none}div.DTFC_LeftFootWrapper table,div.DTFC_RightFootWrapper table{border-top:none;margin-top:0 !important;background-color:white} + + +table.dataTable.fixedHeader-floating,table.dataTable.fixedHeader-locked{background-color:white;margin-top:0 !important;margin-bottom:0 !important}table.dataTable.fixedHeader-floating{position:fixed !important}table.dataTable.fixedHeader-locked{position:absolute !important}@media print{table.fixedHeader-floating{display:none}} + + +table.dataTable th.focus,table.dataTable td.focus{outline:3px solid #337ab7;outline-offset:-1px} + + +table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#337ab7}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#337ab7}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}div.dtr-bs-modal table.table tr:first-child td{border-top:none} + + +table.dt-rowReorder-float{position:absolute !important;opacity:0.8;table-layout:fixed;outline:2px solid #337ab7;outline-offset:-2px;z-index:2001}tr.dt-rowReorder-moving{outline:2px solid #888;outline-offset:-2px}body.dt-rowReorder-noOverflow{overflow-x:hidden}table.dataTable td.reorder{text-align:center;cursor:move} + + +table.dataTable tbody>tr.selected,table.dataTable tbody>tr>.selected{background-color:#08C}table.dataTable.stripe tbody>tr.odd.selected,table.dataTable.stripe tbody>tr.odd>.selected,table.dataTable.display tbody>tr.odd.selected,table.dataTable.display tbody>tr.odd>.selected{background-color:#0085c7}table.dataTable.hover tbody>tr.selected:hover,table.dataTable.hover tbody>tr>.selected:hover,table.dataTable.display tbody>tr.selected:hover,table.dataTable.display tbody>tr>.selected:hover{background-color:#0083c5}table.dataTable.order-column tbody>tr.selected>.sorting_1,table.dataTable.order-column tbody>tr.selected>.sorting_2,table.dataTable.order-column tbody>tr.selected>.sorting_3,table.dataTable.order-column tbody>tr>.selected,table.dataTable.display tbody>tr.selected>.sorting_1,table.dataTable.display tbody>tr.selected>.sorting_2,table.dataTable.display tbody>tr.selected>.sorting_3,table.dataTable.display tbody>tr>.selected{background-color:#0085c8}table.dataTable.display tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_1{background-color:#0081c1}table.dataTable.display tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_2{background-color:#0082c2}table.dataTable.display tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_3{background-color:#0083c4}table.dataTable.display tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_1{background-color:#0085c8}table.dataTable.display tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_2{background-color:#0086ca}table.dataTable.display tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_3{background-color:#0087cb}table.dataTable.display tbody>tr.odd>.selected,table.dataTable.order-column.stripe tbody>tr.odd>.selected{background-color:#0081c1}table.dataTable.display tbody>tr.even>.selected,table.dataTable.order-column.stripe tbody>tr.even>.selected{background-color:#0085c8}table.dataTable.display tbody>tr.selected:hover>.sorting_1,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_1{background-color:#007dbb}table.dataTable.display tbody>tr.selected:hover>.sorting_2,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_2{background-color:#007ebd}table.dataTable.display tbody>tr.selected:hover>.sorting_3,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_3{background-color:#007fbf}table.dataTable.display tbody>tr:hover>.selected,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.order-column.hover tbody>tr:hover>.selected,table.dataTable.order-column.hover tbody>tr>.selected:hover{background-color:#007dbb}table.dataTable td.select-checkbox{position:relative}table.dataTable td.select-checkbox:before,table.dataTable td.select-checkbox:after{display:block;position:absolute;top:1.2em;left:50%;width:12px;height:12px;box-sizing:border-box}table.dataTable td.select-checkbox:before{content:' ';margin-top:-6px;margin-left:-6px;border:1px solid black;border-radius:3px}table.dataTable tr.selected td.select-checkbox:after{content:'\2714';margin-top:-11px;margin-left:-4px;text-align:center;text-shadow:1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9}div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0.5em}@media screen and (max-width: 640px){div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0;display:block}}table.dataTable tbody tr.selected,table.dataTable tbody th.selected,table.dataTable tbody td.selected{color:white}table.dataTable tbody tr.selected a,table.dataTable tbody th.selected a,table.dataTable tbody td.selected a{color:#a2d4ed} + + diff --git a/apps/static/css/plugins/datepicker/datepicker3.css b/apps/static/css/plugins/datepicker/datepicker3.css new file mode 100644 index 000000000..d5203af6d --- /dev/null +++ b/apps/static/css/plugins/datepicker/datepicker3.css @@ -0,0 +1,789 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-top: 0; + position: absolute; +} +.datepicker-dropdown.datepicker-orient-left:before { + left: 6px; +} +.datepicker-dropdown.datepicker-orient-left:after { + left: 7px; +} +.datepicker-dropdown.datepicker-orient-right:before { + right: 6px; +} +.datepicker-dropdown.datepicker-orient-right:after { + right: 7px; +} +.datepicker-dropdown.datepicker-orient-top:before { + top: -7px; +} +.datepicker-dropdown.datepicker-orient-top:after { + top: -6px; +} +.datepicker-dropdown.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.datepicker-dropdown.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid #fff; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.datepicker table tr td, +.datepicker table tr th { + text-align: center; + width: 30px; + height: 30px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover, +.datepicker table tr td.day.focused { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + color: #000000; + background-color: #ffdb99; + border-color: #ffb733; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:focus, +.datepicker table tr td.today:hover:focus, +.datepicker table tr td.today.disabled:focus, +.datepicker table tr td.today.disabled:hover:focus, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.today, +.open .dropdown-toggle.datepicker table tr td.today:hover, +.open .dropdown-toggle.datepicker table tr td.today.disabled, +.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { + color: #000000; + background-color: #ffcd70; + border-color: #f59e00; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.today, +.open .dropdown-toggle.datepicker table tr td.today:hover, +.open .dropdown-toggle.datepicker table tr td.today.disabled, +.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { + background-image: none; +} +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.today, +fieldset[disabled] .datepicker table tr td.today:hover, +fieldset[disabled] .datepicker table tr td.today.disabled, +fieldset[disabled] .datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today:hover.disabled:hover, +.datepicker table tr td.today.disabled.disabled:hover, +.datepicker table tr td.today.disabled:hover.disabled:hover, +.datepicker table tr td.today[disabled]:hover, +.datepicker table tr td.today:hover[disabled]:hover, +.datepicker table tr td.today.disabled[disabled]:hover, +.datepicker table tr td.today.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.today:hover, +fieldset[disabled] .datepicker table tr td.today:hover:hover, +fieldset[disabled] .datepicker table tr td.today.disabled:hover, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today.disabled:focus, +.datepicker table tr td.today:hover.disabled:focus, +.datepicker table tr td.today.disabled.disabled:focus, +.datepicker table tr td.today.disabled:hover.disabled:focus, +.datepicker table tr td.today[disabled]:focus, +.datepicker table tr td.today:hover[disabled]:focus, +.datepicker table tr td.today.disabled[disabled]:focus, +.datepicker table tr td.today.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.today:focus, +fieldset[disabled] .datepicker table tr td.today:hover:focus, +fieldset[disabled] .datepicker table tr td.today.disabled:focus, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:focus, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today:hover.disabled:active, +.datepicker table tr td.today.disabled.disabled:active, +.datepicker table tr td.today.disabled:hover.disabled:active, +.datepicker table tr td.today[disabled]:active, +.datepicker table tr td.today:hover[disabled]:active, +.datepicker table tr td.today.disabled[disabled]:active, +.datepicker table tr td.today.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.today:active, +fieldset[disabled] .datepicker table tr td.today:hover:active, +fieldset[disabled] .datepicker table tr td.today.disabled:active, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today:hover.disabled.active, +.datepicker table tr td.today.disabled.disabled.active, +.datepicker table tr td.today.disabled:hover.disabled.active, +.datepicker table tr td.today[disabled].active, +.datepicker table tr td.today:hover[disabled].active, +.datepicker table tr td.today.disabled[disabled].active, +.datepicker table tr td.today.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.today.active, +fieldset[disabled] .datepicker table tr td.today:hover.active, +fieldset[disabled] .datepicker table tr td.today.disabled.active, +fieldset[disabled] .datepicker table tr td.today.disabled:hover.active { + background-color: #ffdb99; + border-color: #ffb733; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eeeeee; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + color: #000000; + background-color: #f7ca77; + border-color: #f1a417; + border-radius: 0; +} +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today:hover:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today:focus, +.datepicker table tr td.range.today:hover:focus, +.datepicker table tr td.range.today.disabled:focus, +.datepicker table tr td.range.today.disabled:hover:focus, +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.range.today, +.open .dropdown-toggle.datepicker table tr td.range.today:hover, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { + color: #000000; + background-color: #f4bb51; + border-color: #bf800c; +} +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.range.today, +.open .dropdown-toggle.datepicker table tr td.range.today:hover, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { + background-image: none; +} +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today:hover.disabled, +.datepicker table tr td.range.today.disabled.disabled, +.datepicker table tr td.range.today.disabled:hover.disabled, +.datepicker table tr td.range.today[disabled], +.datepicker table tr td.range.today:hover[disabled], +.datepicker table tr td.range.today.disabled[disabled], +.datepicker table tr td.range.today.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.range.today, +fieldset[disabled] .datepicker table tr td.range.today:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today:hover.disabled:hover, +.datepicker table tr td.range.today.disabled.disabled:hover, +.datepicker table tr td.range.today.disabled:hover.disabled:hover, +.datepicker table tr td.range.today[disabled]:hover, +.datepicker table tr td.range.today:hover[disabled]:hover, +.datepicker table tr td.range.today.disabled[disabled]:hover, +.datepicker table tr td.range.today.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.range.today:hover, +fieldset[disabled] .datepicker table tr td.range.today:hover:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today.disabled:focus, +.datepicker table tr td.range.today:hover.disabled:focus, +.datepicker table tr td.range.today.disabled.disabled:focus, +.datepicker table tr td.range.today.disabled:hover.disabled:focus, +.datepicker table tr td.range.today[disabled]:focus, +.datepicker table tr td.range.today:hover[disabled]:focus, +.datepicker table tr td.range.today.disabled[disabled]:focus, +.datepicker table tr td.range.today.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.range.today:focus, +fieldset[disabled] .datepicker table tr td.range.today:hover:focus, +fieldset[disabled] .datepicker table tr td.range.today.disabled:focus, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:focus, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today:hover.disabled:active, +.datepicker table tr td.range.today.disabled.disabled:active, +.datepicker table tr td.range.today.disabled:hover.disabled:active, +.datepicker table tr td.range.today[disabled]:active, +.datepicker table tr td.range.today:hover[disabled]:active, +.datepicker table tr td.range.today.disabled[disabled]:active, +.datepicker table tr td.range.today.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.range.today:active, +fieldset[disabled] .datepicker table tr td.range.today:hover:active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today:hover.disabled.active, +.datepicker table tr td.range.today.disabled.disabled.active, +.datepicker table tr td.range.today.disabled:hover.disabled.active, +.datepicker table tr td.range.today[disabled].active, +.datepicker table tr td.range.today:hover[disabled].active, +.datepicker table tr td.range.today.disabled[disabled].active, +.datepicker table tr td.range.today.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.range.today.active, +fieldset[disabled] .datepicker table tr td.range.today:hover.active, +fieldset[disabled] .datepicker table tr td.range.today.disabled.active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover.active { + background-color: #f7ca77; + border-color: #f1a417; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + color: #ffffff; + background-color: #999999; + border-color: #555555; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected:hover:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected:focus, +.datepicker table tr td.selected:hover:focus, +.datepicker table tr td.selected.disabled:focus, +.datepicker table tr td.selected.disabled:hover:focus, +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.selected, +.open .dropdown-toggle.datepicker table tr td.selected:hover, +.open .dropdown-toggle.datepicker table tr td.selected.disabled, +.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { + color: #ffffff; + background-color: #858585; + border-color: #373737; +} +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.selected, +.open .dropdown-toggle.datepicker table tr td.selected:hover, +.open .dropdown-toggle.datepicker table tr td.selected.disabled, +.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { + background-image: none; +} +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected:hover.disabled, +.datepicker table tr td.selected.disabled.disabled, +.datepicker table tr td.selected.disabled:hover.disabled, +.datepicker table tr td.selected[disabled], +.datepicker table tr td.selected:hover[disabled], +.datepicker table tr td.selected.disabled[disabled], +.datepicker table tr td.selected.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.selected, +fieldset[disabled] .datepicker table tr td.selected:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected:hover.disabled:hover, +.datepicker table tr td.selected.disabled.disabled:hover, +.datepicker table tr td.selected.disabled:hover.disabled:hover, +.datepicker table tr td.selected[disabled]:hover, +.datepicker table tr td.selected:hover[disabled]:hover, +.datepicker table tr td.selected.disabled[disabled]:hover, +.datepicker table tr td.selected.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.selected:hover, +fieldset[disabled] .datepicker table tr td.selected:hover:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected.disabled:focus, +.datepicker table tr td.selected:hover.disabled:focus, +.datepicker table tr td.selected.disabled.disabled:focus, +.datepicker table tr td.selected.disabled:hover.disabled:focus, +.datepicker table tr td.selected[disabled]:focus, +.datepicker table tr td.selected:hover[disabled]:focus, +.datepicker table tr td.selected.disabled[disabled]:focus, +.datepicker table tr td.selected.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.selected:focus, +fieldset[disabled] .datepicker table tr td.selected:hover:focus, +fieldset[disabled] .datepicker table tr td.selected.disabled:focus, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:focus, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected:hover.disabled:active, +.datepicker table tr td.selected.disabled.disabled:active, +.datepicker table tr td.selected.disabled:hover.disabled:active, +.datepicker table tr td.selected[disabled]:active, +.datepicker table tr td.selected:hover[disabled]:active, +.datepicker table tr td.selected.disabled[disabled]:active, +.datepicker table tr td.selected.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.selected:active, +fieldset[disabled] .datepicker table tr td.selected:hover:active, +fieldset[disabled] .datepicker table tr td.selected.disabled:active, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected:hover.disabled.active, +.datepicker table tr td.selected.disabled.disabled.active, +.datepicker table tr td.selected.disabled:hover.disabled.active, +.datepicker table tr td.selected[disabled].active, +.datepicker table tr td.selected:hover[disabled].active, +.datepicker table tr td.selected.disabled[disabled].active, +.datepicker table tr td.selected.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.selected.active, +fieldset[disabled] .datepicker table tr td.selected:hover.active, +fieldset[disabled] .datepicker table tr td.selected.disabled.active, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover.active { + background-color: #999999; + border-color: #555555; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:focus, +.datepicker table tr td.active:hover:focus, +.datepicker table tr td.active.disabled:focus, +.datepicker table tr td.active.disabled:hover:focus, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.active, +.open .dropdown-toggle.datepicker table tr td.active:hover, +.open .dropdown-toggle.datepicker table tr td.active.disabled, +.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.active, +.open .dropdown-toggle.datepicker table tr td.active:hover, +.open .dropdown-toggle.datepicker table tr td.active.disabled, +.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { + background-image: none; +} +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.active, +fieldset[disabled] .datepicker table tr td.active:hover, +fieldset[disabled] .datepicker table tr td.active.disabled, +fieldset[disabled] .datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active:hover.disabled:hover, +.datepicker table tr td.active.disabled.disabled:hover, +.datepicker table tr td.active.disabled:hover.disabled:hover, +.datepicker table tr td.active[disabled]:hover, +.datepicker table tr td.active:hover[disabled]:hover, +.datepicker table tr td.active.disabled[disabled]:hover, +.datepicker table tr td.active.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.active:hover, +fieldset[disabled] .datepicker table tr td.active:hover:hover, +fieldset[disabled] .datepicker table tr td.active.disabled:hover, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active.disabled:focus, +.datepicker table tr td.active:hover.disabled:focus, +.datepicker table tr td.active.disabled.disabled:focus, +.datepicker table tr td.active.disabled:hover.disabled:focus, +.datepicker table tr td.active[disabled]:focus, +.datepicker table tr td.active:hover[disabled]:focus, +.datepicker table tr td.active.disabled[disabled]:focus, +.datepicker table tr td.active.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.active:focus, +fieldset[disabled] .datepicker table tr td.active:hover:focus, +fieldset[disabled] .datepicker table tr td.active.disabled:focus, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:focus, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active:hover.disabled:active, +.datepicker table tr td.active.disabled.disabled:active, +.datepicker table tr td.active.disabled:hover.disabled:active, +.datepicker table tr td.active[disabled]:active, +.datepicker table tr td.active:hover[disabled]:active, +.datepicker table tr td.active.disabled[disabled]:active, +.datepicker table tr td.active.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.active:active, +fieldset[disabled] .datepicker table tr td.active:hover:active, +fieldset[disabled] .datepicker table tr td.active.disabled:active, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active:hover.disabled.active, +.datepicker table tr td.active.disabled.disabled.active, +.datepicker table tr td.active.disabled:hover.disabled.active, +.datepicker table tr td.active[disabled].active, +.datepicker table tr td.active:hover[disabled].active, +.datepicker table tr td.active.disabled[disabled].active, +.datepicker table tr td.active.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.active.active, +fieldset[disabled] .datepicker table tr td.active:hover.active, +fieldset[disabled] .datepicker table tr td.active.disabled.active, +fieldset[disabled] .datepicker table tr td.active.disabled:hover.active { + background-color: #428bca; + border-color: #357ebd; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:focus, +.datepicker table tr td span.active:hover:focus, +.datepicker table tr td span.active.disabled:focus, +.datepicker table tr td span.active.disabled:hover:focus, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td span.active, +.open .dropdown-toggle.datepicker table tr td span.active:hover, +.open .dropdown-toggle.datepicker table tr td span.active.disabled, +.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td span.active, +.open .dropdown-toggle.datepicker table tr td span.active:hover, +.open .dropdown-toggle.datepicker table tr td span.active.disabled, +.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { + background-image: none; +} +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td span.active, +fieldset[disabled] .datepicker table tr td span.active:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active:hover.disabled:hover, +.datepicker table tr td span.active.disabled.disabled:hover, +.datepicker table tr td span.active.disabled:hover.disabled:hover, +.datepicker table tr td span.active[disabled]:hover, +.datepicker table tr td span.active:hover[disabled]:hover, +.datepicker table tr td span.active.disabled[disabled]:hover, +.datepicker table tr td span.active.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td span.active:hover, +fieldset[disabled] .datepicker table tr td span.active:hover:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active.disabled:focus, +.datepicker table tr td span.active:hover.disabled:focus, +.datepicker table tr td span.active.disabled.disabled:focus, +.datepicker table tr td span.active.disabled:hover.disabled:focus, +.datepicker table tr td span.active[disabled]:focus, +.datepicker table tr td span.active:hover[disabled]:focus, +.datepicker table tr td span.active.disabled[disabled]:focus, +.datepicker table tr td span.active.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td span.active:focus, +fieldset[disabled] .datepicker table tr td span.active:hover:focus, +fieldset[disabled] .datepicker table tr td span.active.disabled:focus, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active:hover.disabled:active, +.datepicker table tr td span.active.disabled.disabled:active, +.datepicker table tr td span.active.disabled:hover.disabled:active, +.datepicker table tr td span.active[disabled]:active, +.datepicker table tr td span.active:hover[disabled]:active, +.datepicker table tr td span.active.disabled[disabled]:active, +.datepicker table tr td span.active.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td span.active:active, +fieldset[disabled] .datepicker table tr td span.active:hover:active, +fieldset[disabled] .datepicker table tr td span.active.disabled:active, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active:hover.disabled.active, +.datepicker table tr td span.active.disabled.disabled.active, +.datepicker table tr td span.active.disabled:hover.disabled.active, +.datepicker table tr td span.active[disabled].active, +.datepicker table tr td span.active:hover[disabled].active, +.datepicker table tr td span.active.disabled[disabled].active, +.datepicker table tr td span.active.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td span.active.active, +fieldset[disabled] .datepicker table tr td span.active:hover.active, +fieldset[disabled] .datepicker table tr td span.active.disabled.active, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover.active { + background-color: #428bca; + border-color: #357ebd; +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #999999; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-group.date .input-group-addon i { + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + border-radius: 0 3px 3px 0; +} +.input-daterange .input-group-addon { + width: auto; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + text-shadow: 0 1px 0 #fff; + vertical-align: middle; + background-color: #eeeeee; + border-width: 1px 0; + margin-left: -5px; + margin-right: -5px; +} +.datepicker.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; + color: #333333; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 1.428571429; +} +.datepicker.dropdown-menu th, +.datepicker.dropdown-menu td { + padding: 4px 5px; +} diff --git a/apps/static/css/plugins/dropzone/basic.css b/apps/static/css/plugins/dropzone/basic.css new file mode 100644 index 000000000..83084dbe1 --- /dev/null +++ b/apps/static/css/plugins/dropzone/basic.css @@ -0,0 +1,155 @@ +/* The MIT License */ +.dropzone, +.dropzone *, +.dropzone-previews, +.dropzone-previews * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dropzone { + position: relative; + border: 1px solid rgba(0,0,0,0.08); + background: rgba(0,0,0,0.02); + padding: 1em; +} +.dropzone.dz-clickable { + cursor: pointer; +} +.dropzone.dz-clickable .dz-message, +.dropzone.dz-clickable .dz-message span { + cursor: pointer; +} +.dropzone.dz-clickable * { + cursor: default; +} +.dropzone .dz-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone.dz-drag-hover { + border-color: rgba(0,0,0,0.15); + background: rgba(0,0,0,0.04); +} +.dropzone.dz-started .dz-message { + display: none; +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + background: rgba(255,255,255,0.8); + position: relative; + display: inline-block; + margin: 17px; + vertical-align: top; + border: 1px solid #acacac; + padding: 6px 6px 6px 6px; +} +.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail], +.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] { + display: none; +} +.dropzone .dz-preview .dz-details, +.dropzone-previews .dz-preview .dz-details { + width: 100px; + height: 100px; + position: relative; + background: #ebebeb; + padding: 5px; + margin-bottom: 22px; +} +.dropzone .dz-preview .dz-details .dz-filename, +.dropzone-previews .dz-preview .dz-details .dz-filename { + overflow: hidden; + height: 100%; +} +.dropzone .dz-preview .dz-details img, +.dropzone-previews .dz-preview .dz-details img { + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 100px; +} +.dropzone .dz-preview .dz-details .dz-size, +.dropzone-previews .dz-preview .dz-details .dz-size { + position: absolute; + bottom: -28px; + left: 3px; + height: 28px; + line-height: 28px; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + display: block; +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + display: block; +} +.dropzone .dz-preview:hover .dz-details img, +.dropzone-previews .dz-preview:hover .dz-details img { + display: none; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark, +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + display: none; + position: absolute; + width: 40px; + height: 40px; + font-size: 30px; + text-align: center; + right: -10px; + top: -10px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + color: #8cc657; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + color: #ee162d; +} +.dropzone .dz-preview .dz-progress, +.dropzone-previews .dz-preview .dz-progress { + position: absolute; + top: 100px; + left: 6px; + right: 6px; + height: 6px; + background: #d7d7d7; + display: none; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 0%; + background-color: #8cc657; +} +.dropzone .dz-preview.dz-processing .dz-progress, +.dropzone-previews .dz-preview.dz-processing .dz-progress { + display: block; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: none; + position: absolute; + top: -5px; + left: -20px; + background: rgba(245,245,245,0.8); + padding: 8px 10px; + color: #800; + min-width: 140px; + max-width: 500px; + z-index: 500; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + display: block; +} diff --git a/apps/static/css/plugins/dropzone/dropzone.css b/apps/static/css/plugins/dropzone/dropzone.css new file mode 100644 index 000000000..fc18729c5 --- /dev/null +++ b/apps/static/css/plugins/dropzone/dropzone.css @@ -0,0 +1,410 @@ +/* The MIT License */ +.dropzone, +.dropzone *, +.dropzone-previews, +.dropzone-previews * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.dropzone { + position: relative; + border: 1px solid rgba(0,0,0,0.08); + background: rgba(0,0,0,0.02); + padding: 1em; +} +.dropzone.dz-clickable { + cursor: pointer; +} +.dropzone.dz-clickable .dz-message, +.dropzone.dz-clickable .dz-message span { + cursor: pointer; +} +.dropzone.dz-clickable * { + cursor: default; +} +.dropzone .dz-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone.dz-drag-hover { + border-color: rgba(0,0,0,0.15); + background: rgba(0,0,0,0.04); +} +.dropzone.dz-started .dz-message { + display: none; +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + background: rgba(255,255,255,0.8); + position: relative; + display: inline-block; + margin: 17px; + vertical-align: top; + border: 1px solid #acacac; + padding: 6px 6px 6px 6px; +} +.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail], +.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] { + display: none; +} +.dropzone .dz-preview .dz-details, +.dropzone-previews .dz-preview .dz-details { + width: 100px; + height: 100px; + position: relative; + background: #ebebeb; + padding: 5px; + margin-bottom: 22px; +} +.dropzone .dz-preview .dz-details .dz-filename, +.dropzone-previews .dz-preview .dz-details .dz-filename { + overflow: hidden; + height: 100%; +} +.dropzone .dz-preview .dz-details img, +.dropzone-previews .dz-preview .dz-details img { + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 100px; +} +.dropzone .dz-preview .dz-details .dz-size, +.dropzone-previews .dz-preview .dz-details .dz-size { + position: absolute; + bottom: -28px; + left: 3px; + height: 28px; + line-height: 28px; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + display: block; +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + display: block; +} +.dropzone .dz-preview:hover .dz-details img, +.dropzone-previews .dz-preview:hover .dz-details img { + display: none; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark, +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + display: none; + position: absolute; + width: 40px; + height: 40px; + font-size: 30px; + text-align: center; + right: -10px; + top: -10px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + color: #8cc657; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + color: #ee162d; +} +.dropzone .dz-preview .dz-progress, +.dropzone-previews .dz-preview .dz-progress { + position: absolute; + top: 100px; + left: 6px; + right: 6px; + height: 6px; + background: #d7d7d7; + display: none; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 0%; + background-color: #8cc657; +} +.dropzone .dz-preview.dz-processing .dz-progress, +.dropzone-previews .dz-preview.dz-processing .dz-progress { + display: block; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: none; + position: absolute; + top: -5px; + left: -20px; + background: rgba(245,245,245,0.8); + padding: 8px 10px; + color: #800; + min-width: 140px; + max-width: 500px; + z-index: 500; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + display: block; +} +.dropzone { + border: 1px solid rgba(0,0,0,0.03); + min-height: 360px; + -webkit-border-radius: 3px; + border-radius: 3px; + background: rgba(0,0,0,0.03); + padding: 23px; +} +.dropzone .dz-default.dz-message { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; + background-image: url("../images/spritemap.png"); + background-repeat: no-repeat; + background-position: 0 0; + position: absolute; + width: 428px; + height: 123px; + margin-left: -214px; + margin-top: -61.5px; + top: 50%; + left: 50%; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-default.dz-message { + background-image: url("../images/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-default.dz-message span { + display: none; +} +.dropzone.dz-square .dz-default.dz-message { + background-position: 0 -123px; + width: 268px; + margin-left: -134px; + height: 174px; + margin-top: -87px; +} +.dropzone.dz-drag-hover .dz-message { + opacity: 0.15; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=15)"; + filter: alpha(opacity=15); +} +.dropzone.dz-started .dz-message { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.dropzone .dz-preview, +.dropzone-previews .dz-preview { + -webkit-box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + box-shadow: 1px 1px 4px rgba(0,0,0,0.16); + font-size: 14px; +} +.dropzone .dz-preview.dz-image-preview:hover .dz-details img, +.dropzone-previews .dz-preview.dz-image-preview:hover .dz-details img { + display: block; + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); +} +.dropzone .dz-preview.dz-success .dz-success-mark, +.dropzone-previews .dz-preview.dz-success .dz-success-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-error-mark, +.dropzone-previews .dz-preview.dz-error .dz-error-mark { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone .dz-preview.dz-error .dz-progress .dz-upload, +.dropzone-previews .dz-preview.dz-error .dz-progress .dz-upload { + background: #ee1e2d; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark, +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; + background-image: url("../images/spritemap.png"); + background-repeat: no-repeat; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-preview .dz-error-mark, + .dropzone-previews .dz-preview .dz-error-mark, + .dropzone .dz-preview .dz-success-mark, + .dropzone-previews .dz-preview .dz-success-mark { + background-image: url("../images/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview .dz-error-mark span, +.dropzone-previews .dz-preview .dz-error-mark span, +.dropzone .dz-preview .dz-success-mark span, +.dropzone-previews .dz-preview .dz-success-mark span { + display: none; +} +.dropzone .dz-preview .dz-error-mark, +.dropzone-previews .dz-preview .dz-error-mark { + background-position: -268px -123px; +} +.dropzone .dz-preview .dz-success-mark, +.dropzone-previews .dz-preview .dz-success-mark { + background-position: -268px -163px; +} +.dropzone .dz-preview .dz-progress .dz-upload, +.dropzone-previews .dz-preview .dz-progress .dz-upload { + -webkit-animation: loading 0.4s linear infinite; + -moz-animation: loading 0.4s linear infinite; + -o-animation: loading 0.4s linear infinite; + -ms-animation: loading 0.4s linear infinite; + animation: loading 0.4s linear infinite; + -webkit-transition: width 0.3s ease-in-out; + -moz-transition: width 0.3s ease-in-out; + -o-transition: width 0.3s ease-in-out; + -ms-transition: width 0.3s ease-in-out; + transition: width 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px; + position: absolute; + top: 0; + left: 0; + width: 0%; + height: 100%; + background-image: url("../images/spritemap.png"); + background-repeat: repeat-x; + background-position: 0px -400px; +} +@media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { + .dropzone .dz-preview .dz-progress .dz-upload, + .dropzone-previews .dz-preview .dz-progress .dz-upload { + background-image: url("../images/spritemap@2x.png"); + -webkit-background-size: 428px 406px; + -moz-background-size: 428px 406px; + background-size: 428px 406px; + } +} +.dropzone .dz-preview.dz-success .dz-progress, +.dropzone-previews .dz-preview.dz-success .dz-progress { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + transition: opacity 0.4s ease-in-out; +} +.dropzone .dz-preview .dz-error-message, +.dropzone-previews .dz-preview .dz-error-message { + display: block; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.3s ease-in-out; + -moz-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + -ms-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; +} +.dropzone .dz-preview:hover.dz-error .dz-error-message, +.dropzone-previews .dz-preview:hover.dz-error .dz-error-message { + opacity: 1; + -ms-filter: none; + filter: none; +} +.dropzone a.dz-remove, +.dropzone-previews a.dz-remove { + background-image: -webkit-linear-gradient(top, #fafafa, #eee); + background-image: -moz-linear-gradient(top, #fafafa, #eee); + background-image: -o-linear-gradient(top, #fafafa, #eee); + background-image: -ms-linear-gradient(top, #fafafa, #eee); + background-image: linear-gradient(to bottom, #fafafa, #eee); + -webkit-border-radius: 2px; + border-radius: 2px; + border: 1px solid #eee; + text-decoration: none; + display: block; + padding: 4px 5px; + text-align: center; + color: #aaa; + margin-top: 26px; +} +.dropzone a.dz-remove:hover, +.dropzone-previews a.dz-remove:hover { + color: #666; +} +@-moz-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-webkit-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-o-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@-ms-keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} +@keyframes loading { + 0% { + background-position: 0 -400px; + } + + 100% { + background-position: -7px -400px; + } +} diff --git a/apps/static/css/plugins/footable/fonts/footable.eot b/apps/static/css/plugins/footable/fonts/footable.eot new file mode 100644 index 000000000..37229798b Binary files /dev/null and b/apps/static/css/plugins/footable/fonts/footable.eot differ diff --git a/apps/static/css/plugins/footable/fonts/footable.svg b/apps/static/css/plugins/footable/fonts/footable.svg new file mode 100644 index 000000000..5a6e1fda3 --- /dev/null +++ b/apps/static/css/plugins/footable/fonts/footable.svg @@ -0,0 +1,78 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/static/css/plugins/footable/fonts/footable.ttf b/apps/static/css/plugins/footable/fonts/footable.ttf new file mode 100644 index 000000000..2d5c84ab1 Binary files /dev/null and b/apps/static/css/plugins/footable/fonts/footable.ttf differ diff --git a/apps/static/css/plugins/footable/fonts/footable.woff b/apps/static/css/plugins/footable/fonts/footable.woff new file mode 100644 index 000000000..4864dbb5c Binary files /dev/null and b/apps/static/css/plugins/footable/fonts/footable.woff differ diff --git a/apps/static/css/plugins/footable/footable.core.css b/apps/static/css/plugins/footable/footable.core.css new file mode 100644 index 000000000..e594a85a9 --- /dev/null +++ b/apps/static/css/plugins/footable/footable.core.css @@ -0,0 +1,179 @@ +@font-face { + font-family: 'footable'; + src: url('fonts/footable.eot'); + src: url('fonts/footable.eot?#iefix') format('embedded-opentype'), url('fonts/footable.woff') format('woff'), url('fonts/footable.ttf') format('truetype'), url('fonts/footable.svg#footable') format('svg'); + font-weight: normal; + font-style: normal; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + @font-face { + font-family: 'footable'; + src: url('fonts/footable.svg#footable') format('svg'); + font-weight: normal; + font-style: normal; + } +} + +.footable { + width: 100%; + /** SORTING **/ + + /** PAGINATION **/ + +} +.footable.breakpoint > tbody > tr.footable-detail-show > td { + border-bottom: none; +} +.footable.breakpoint > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e001"; +} +.footable.breakpoint > tbody > tr:hover:not(.footable-row-detail) { + cursor: pointer; +} +.footable.breakpoint > tbody > tr > td.footable-cell-detail { + background: #eee; + border-top: none; +} +.footable.breakpoint > tbody > tr > td > span.footable-toggle { + display: inline-block; + font-family: 'footable'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + -webkit-font-smoothing: antialiased; + padding-right: 5px; + font-size: 14px; + color: #888888; +} +.footable.breakpoint > tbody > tr > td > span.footable-toggle:before { + content: "\e000"; +} +.footable.breakpoint.toggle-circle > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e005"; +} +.footable.breakpoint.toggle-circle > tbody > tr > td > span.footable-toggle:before { + content: "\e004"; +} +.footable.breakpoint.toggle-circle-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e003"; +} +.footable.breakpoint.toggle-circle-filled > tbody > tr > td > span.footable-toggle:before { + content: "\e002"; +} +.footable.breakpoint.toggle-square > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e007"; +} +.footable.breakpoint.toggle-square > tbody > tr > td > span.footable-toggle:before { + content: "\e006"; +} +.footable.breakpoint.toggle-square-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e009"; +} +.footable.breakpoint.toggle-square-filled > tbody > tr > td > span.footable-toggle:before { + content: "\e008"; +} +.footable.breakpoint.toggle-arrow > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e00f"; +} +.footable.breakpoint.toggle-arrow > tbody > tr > td > span.footable-toggle:before { + content: "\e011"; +} +.footable.breakpoint.toggle-arrow-small > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e013"; +} +.footable.breakpoint.toggle-arrow-small > tbody > tr > td > span.footable-toggle:before { + content: "\e015"; +} +.footable.breakpoint.toggle-arrow-circle > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e01b"; +} +.footable.breakpoint.toggle-arrow-circle > tbody > tr > td > span.footable-toggle:before { + content: "\e01d"; +} +.footable.breakpoint.toggle-arrow-circle-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e00b"; +} +.footable.breakpoint.toggle-arrow-circle-filled > tbody > tr > td > span.footable-toggle:before { + content: "\e00d"; +} +.footable.breakpoint.toggle-arrow-tiny > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e01f"; +} +.footable.breakpoint.toggle-arrow-tiny > tbody > tr > td > span.footable-toggle:before { + content: "\e021"; +} +.footable.breakpoint.toggle-arrow-alt > tbody > tr.footable-detail-show > td > span.footable-toggle:before { + content: "\e017"; +} +.footable.breakpoint.toggle-arrow-alt > tbody > tr > td > span.footable-toggle:before { + content: "\e019"; +} +.footable.breakpoint.toggle-medium > tbody > tr > td > span.footable-toggle { + font-size: 18px; +} +.footable.breakpoint.toggle-large > tbody > tr > td > span.footable-toggle { + font-size: 24px; +} +.footable > thead > tr > th { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: -moz-none; + -ms-user-select: none; + user-select: none; +} +.footable > thead > tr > th.footable-sortable:hover { + cursor: pointer; +} +.footable > thead > tr > th.footable-sorted > span.footable-sort-indicator:before { + content: "\e013"; +} +.footable > thead > tr > th.footable-sorted-desc > span.footable-sort-indicator:before { + content: "\e012"; +} +.footable > thead > tr > th > span.footable-sort-indicator { + display: inline-block; + font-family: 'footable'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + -webkit-font-smoothing: antialiased; + padding-left: 5px; +} +.footable > thead > tr > th > span.footable-sort-indicator:before { + content: "\e022"; +} +.footable > tfoot .pagination { + margin: 0; +} +.footable.no-paging .hide-if-no-paging { + display: none; +} +.footable-row-detail-inner { + display: table; +} +.footable-row-detail-row { + display: table-row; + line-height: 1.5em; +} +.footable-row-detail-group { + display: block; + line-height: 2em; + font-size: 1.2em; + font-weight: bold; +} +.footable-row-detail-name { + display: table-cell; + font-weight: bold; + padding-right: 0.5em; +} +.footable-row-detail-value { + display: table-cell; +} +.footable-odd { + background-color: #f7f7f7; +} diff --git a/apps/static/css/plugins/fullcalendar/fullcalendar.css b/apps/static/css/plugins/fullcalendar/fullcalendar.css new file mode 100644 index 000000000..b2feb028e --- /dev/null +++ b/apps/static/css/plugins/fullcalendar/fullcalendar.css @@ -0,0 +1,977 @@ +/*! + * FullCalendar v2.2.0 Stylesheet + * Docs & License: http://arshaw.com/fullcalendar/ + * (c) 2013 Adam Shaw + */ + + +.fc { + direction: ltr; + text-align: left; +} + +.fc-rtl { + text-align: right; +} + +body .fc { /* extra precedence to overcome jqui */ + font-size: 1em; +} + + +/* Colors +--------------------------------------------------------------------------------------------------*/ + +.fc-unthemed th, +.fc-unthemed td, +.fc-unthemed hr, +.fc-unthemed thead, +.fc-unthemed tbody, +.fc-unthemed .fc-row, +.fc-unthemed .fc-popover { + border-color: #ddd; +} + +.fc-unthemed .fc-popover { + background-color: #fff; +} + +.fc-unthemed hr, +.fc-unthemed .fc-popover .fc-header { + background: #eee; +} + +.fc-unthemed .fc-popover .fc-header .fc-close { + color: #666; +} + +.fc-unthemed .fc-today { + background: #fcf8e3; +} + +.fc-highlight { /* when user is selecting cells */ + background: #bce8f1; + opacity: .3; + filter: alpha(opacity=30); /* for IE */ +} + +.fc-bgevent { /* default look for background events */ + background: rgb(143, 223, 130); + opacity: .3; + filter: alpha(opacity=30); /* for IE */ +} + +.fc-nonbusiness { /* default look for non-business-hours areas */ + /* will inherit .fc-bgevent's styles */ + background: #ccc; +} + + +/* Icons (inline elements with styled text that mock arrow icons) +--------------------------------------------------------------------------------------------------*/ + +.fc-icon { + display: inline-block; + font-size: 2em; + line-height: .5em; + height: .5em; /* will make the total height 1em */ + font-family: "Courier New", Courier, monospace; +} + +.fc-icon-left-single-arrow:after { + content: "\02039"; + font-weight: bold; +} + +.fc-icon-right-single-arrow:after { + content: "\0203A"; + font-weight: bold; +} + +.fc-icon-left-double-arrow:after { + content: "\000AB"; +} + +.fc-icon-right-double-arrow:after { + content: "\000BB"; +} + +.fc-icon-x:after { + content: "\000D7"; +} + + +/* Buttons (styled '); + $container.append($icon); + $container.on('click', {dialog: this}, function(event) { + event.data.dialog.close(); + }); + + return $container; + }, + createBodyContent: function() { + var $container = $('
      '); + $container.addClass(this.getNamespace('body')); + + // Message + $container.append(this.createMessageContent()); + + return $container; + }, + createMessageContent: function() { + var $message = $('
      '); + $message.addClass(this.getNamespace('message')); + + return $message; + }, + createFooterContent: function() { + var $container = $('
      '); + $container.addClass(this.getNamespace('footer')); + + return $container; + }, + createFooterButtons: function() { + var that = this; + var $container = $('
      '); + $container.addClass(this.getNamespace('footer-buttons')); + this.indexedButtons = {}; + $.each(this.options.buttons, function(index, button) { + if (!button.id) { + button.id = BootstrapDialog.newGuid(); + } + var $button = that.createButton(button); + that.indexedButtons[button.id] = $button; + $container.append($button); + }); + + return $container; + }, + createButton: function(button) { + var $button = $(''); + $button.prop('id', button.id); + + // Icon + if (typeof button.icon !== 'undefined' && $.trim(button.icon) !== '') { + $button.append(this.createButtonIcon(button.icon)); + } + + // Label + if (typeof button.label !== 'undefined') { + $button.append(button.label); + } + + // Css class + if (typeof button.cssClass !== 'undefined' && $.trim(button.cssClass) !== '') { + $button.addClass(button.cssClass); + } else { + $button.addClass('btn-default'); + } + + // Hotkey + if (typeof button.hotkey !== 'undefined') { + this.registeredButtonHotkeys[button.hotkey] = $button; + } + + // Button on click + $button.on('click', {dialog: this, $button: $button, button: button}, function(event) { + var dialog = event.data.dialog; + var $button = event.data.$button; + var button = event.data.button; + if (typeof button.action === 'function') { + button.action.call($button, dialog); + } + + if (button.autospin) { + $button.toggleSpin(true); + } + }); + + // Dynamically add extra functions to $button + this.enhanceButton($button); + + return $button; + }, + /** + * Dynamically add extra functions to $button + * + * Using '$this' to reference 'this' is just for better readability. + * + * @param {type} $button + * @returns {_L13.BootstrapDialog.prototype} + */ + enhanceButton: function($button) { + $button.dialog = this; + + // Enable / Disable + $button.toggleEnable = function(enable) { + var $this = this; + if (typeof enable !== 'undefined') { + $this.prop("disabled", !enable).toggleClass('disabled', !enable); + } else { + $this.prop("disabled", !$this.prop("disabled")); + } + + return $this; + }; + $button.enable = function() { + var $this = this; + $this.toggleEnable(true); + + return $this; + }; + $button.disable = function() { + var $this = this; + $this.toggleEnable(false); + + return $this; + }; + + // Icon spinning, helpful for indicating ajax loading status. + $button.toggleSpin = function(spin) { + var $this = this; + var dialog = $this.dialog; + var $icon = $this.find('.' + dialog.getNamespace('button-icon')); + if (typeof spin === 'undefined') { + spin = !($button.find('.icon-spin').length > 0); + } + if (spin) { + $icon.hide(); + $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin')); + } else { + $icon.show(); + $button.find('.icon-spin').remove(); + } + + return $this; + }; + $button.spin = function() { + var $this = this; + $this.toggleSpin(true); + + return $this; + }; + $button.stopSpin = function() { + var $this = this; + $this.toggleSpin(false); + + return $this; + }; + + return this; + }, + createButtonIcon: function(icon) { + var $icon = $(''); + $icon.addClass(this.getNamespace('button-icon')).addClass(icon); + + return $icon; + }, + /** + * Invoke this only after the dialog is realized. + * + * @param {type} enable + * @returns {undefined} + */ + enableButtons: function(enable) { + $.each(this.indexedButtons, function(id, $button) { + $button.toggleEnable(enable); + }); + + return this; + }, + /** + * Invoke this only after the dialog is realized. + * + * @returns {undefined} + */ + updateClosable: function() { + if (this.isRealized()) { + // Close button + this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable()); + } + + return this; + }, + /** + * Set handler for modal event 'show.bs.modal'. + * This is a setter! + */ + onShow: function(onshow) { + this.options.onshow = onshow; + + return this; + }, + /** + * Set handler for modal event 'shown.bs.modal'. + * This is a setter! + */ + onShown: function(onshown) { + this.options.onshown = onshown; + + return this; + }, + /** + * Set handler for modal event 'hide.bs.modal'. + * This is a setter! + */ + onHide: function(onhide) { + this.options.onhide = onhide; + + return this; + }, + /** + * Set handler for modal event 'hidden.bs.modal'. + * This is a setter! + */ + onHidden: function(onhidden) { + this.options.onhidden = onhidden; + + return this; + }, + isRealized: function() { + return this.realized; + }, + setRealized: function(realized) { + this.realized = realized; + + return this; + }, + isOpened: function() { + return this.opened; + }, + setOpened: function(opened) { + this.opened = opened; + + return this; + }, + handleModalEvents: function() { + this.getModal().on('show.bs.modal', {dialog: this}, function(event) { + var dialog = event.data.dialog; + if (dialog.isModalEvent(event) && typeof dialog.options.onshow === 'function') { + return dialog.options.onshow(dialog); + } + }); + this.getModal().on('shown.bs.modal', {dialog: this}, function(event) { + var dialog = event.data.dialog; + dialog.isModalEvent(event) && typeof dialog.options.onshown === 'function' && dialog.options.onshown(dialog); + }); + this.getModal().on('hide.bs.modal', {dialog: this}, function(event) { + var dialog = event.data.dialog; + if (dialog.isModalEvent(event) && typeof dialog.options.onhide === 'function') { + return dialog.options.onhide(dialog); + } + }); + this.getModal().on('hidden.bs.modal', {dialog: this}, function(event) { + var dialog = event.data.dialog; + dialog.isModalEvent(event) && typeof dialog.options.onhidden === 'function' && dialog.options.onhidden(dialog); + dialog.isAutodestroy() && $(this).remove(); + BootstrapDialog.moveFocus(); + }); + + // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel. + this.getModal().on('click', {dialog: this}, function(event) { + event.target === this && event.data.dialog.isClosable() && event.data.dialog.canCloseByBackdrop() && event.data.dialog.close(); + }); + + // ESC key support + this.getModal().on('keyup', {dialog: this}, function(event) { + event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.canCloseByKeyboard() && event.data.dialog.close(); + }); + + // Button hotkey + this.getModal().on('keyup', {dialog: this}, function(event) { + var dialog = event.data.dialog; + if (typeof dialog.registeredButtonHotkeys[event.which] !== 'undefined') { + var $button = $(dialog.registeredButtonHotkeys[event.which]); + !$button.prop('disabled') && $button.focus().trigger('click'); + } + }); + + return this; + }, + isModalEvent: function(event) { + return typeof event.namespace !== 'undefined' && event.namespace === 'bs.modal'; + }, + makeModalDraggable: function() { + if (this.options.draggable) { + this.getModalHeader().addClass(this.getNamespace('draggable')).on('mousedown', {dialog: this}, function(event) { + var dialog = event.data.dialog; + dialog.draggableData.isMouseDown = true; + var dialogOffset = dialog.getModalDialog().offset(); + dialog.draggableData.mouseOffset = { + top: event.clientY - dialogOffset.top, + left: event.clientX - dialogOffset.left + }; + }); + this.getModal().on('mouseup mouseleave', {dialog: this}, function(event) { + event.data.dialog.draggableData.isMouseDown = false; + }); + $('body').on('mousemove', {dialog: this}, function(event) { + var dialog = event.data.dialog; + if (!dialog.draggableData.isMouseDown) { + return; + } + dialog.getModalDialog().offset({ + top: event.clientY - dialog.draggableData.mouseOffset.top, + left: event.clientX - dialog.draggableData.mouseOffset.left + }); + }); + } + + return this; + }, + /** + * To make multiple opened dialogs look better. + */ + updateZIndex: function() { + var dialogCount = 0; + $.each(BootstrapDialog.dialogs, function(dialogId, dialogInstance) { + dialogCount++; + }); + var $modal = this.getModal(); + var $backdrop = $modal.data('bs.modal').$backdrop; + $modal.css('z-index', BootstrapDialog.ZINDEX_MODAL + (dialogCount - 1) * 20); + $backdrop.css('z-index', BootstrapDialog.ZINDEX_BACKDROP + (dialogCount - 1) * 20); + + return this; + }, + realize: function() { + this.initModalStuff(); + this.getModal().addClass(BootstrapDialog.NAMESPACE) + .addClass(this.getCssClass()); + this.updateSize(); + if (this.getDescription()) { + this.getModal().attr('aria-describedby', this.getDescription()); + } + this.getModalFooter().append(this.createFooterContent()); + this.getModalHeader().append(this.createHeaderContent()); + this.getModalBody().append(this.createBodyContent()); + this.getModal().modal({ + backdrop: 'static', + keyboard: false, + show: false + }); + this.makeModalDraggable(); + this.handleModalEvents(); + this.setRealized(true); + this.updateButtons(); + this.updateType(); + this.updateTitle(); + this.updateMessage(); + this.updateClosable(); + this.updateAnimate(); + this.updateSize(); + + return this; + }, + open: function() { + !this.isRealized() && this.realize(); + this.getModal().modal('show'); + this.updateZIndex(); + this.setOpened(true); + + return this; + }, + close: function() { + this.getModal().modal('hide'); + if (this.isAutodestroy()) { + delete BootstrapDialog.dialogs[this.getId()]; + } + this.setOpened(false); + + // Show scrollbar if the last visible dialog needs one. + BootstrapDialog.showScrollbar(); + + return this; + } + }; + + /** + * RFC4122 version 4 compliant unique id creator. + * + * Added by https://github.com/tufanbarisyildirim/ + * + * @returns {String} + */ + BootstrapDialog.newGuid = function() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + }; + + /* ================================================ + * For lazy people + * ================================================ */ + + /** + * Shortcut function: show + * + * @param {type} options + * @returns the created dialog instance + */ + BootstrapDialog.show = function(options) { + return new BootstrapDialog(options).open(); + }; + + /** + * Alert window + * + * @returns the created dialog instance + */ + BootstrapDialog.alert = function() { + var options = {}; + var defaultOptions = { + type: BootstrapDialog.TYPE_PRIMARY, + title: null, + message: null, + closable: true, + buttonLabel: BootstrapDialog.DEFAULT_TEXTS.OK, + callback: null + }; + + if (typeof arguments[0] === 'object' && arguments[0].constructor === {}.constructor) { + options = $.extend(true, defaultOptions, arguments[0]); + } else { + options = $.extend(true, defaultOptions, { + message: arguments[0], + closable: false, + buttonLabel: BootstrapDialog.DEFAULT_TEXTS.OK, + callback: typeof arguments[1] !== 'undefined' ? arguments[1] : null + }); + } + + return new BootstrapDialog({ + type: options.type, + title: options.title, + message: options.message, + closable: options.closable, + data: { + callback: options.callback + }, + onhide: function(dialog) { + !dialog.getData('btnClicked') && dialog.isClosable() && typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false); + }, + buttons: [{ + label: options.buttonLabel, + action: function(dialog) { + dialog.setData('btnClicked', true); + typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true); + dialog.close(); + } + }] + }).open(); + }; + + /** + * Confirm window + * + * @param {type} message + * @param {type} callback + * @returns the created dialog instance + */ + BootstrapDialog.confirm = function(message, callback) { + return new BootstrapDialog({ + title: 'Confirmation', + message: message, + closable: false, + data: { + 'callback': callback + }, + buttons: [{ + label: BootstrapDialog.DEFAULT_TEXTS.CANCEL, + action: function(dialog) { + typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false); + dialog.close(); + } + }, { + label: BootstrapDialog.DEFAULT_TEXTS.OK, + cssClass: 'btn-primary', + action: function(dialog) { + typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true); + dialog.close(); + } + }] + }).open(); + }; + + /** + * Warning window + * + * @param {type} message + * @returns the created dialog instance + */ + BootstrapDialog.warning = function(message, callback) { + return new BootstrapDialog({ + type: BootstrapDialog.TYPE_WARNING, + message: message + }).open(); + }; + + /** + * Danger window + * + * @param {type} message + * @returns the created dialog instance + */ + BootstrapDialog.danger = function(message, callback) { + return new BootstrapDialog({ + type: BootstrapDialog.TYPE_DANGER, + message: message + }).open(); + }; + + /** + * Success window + * + * @param {type} message + * @returns the created dialog instance + */ + BootstrapDialog.success = function(message, callback) { + return new BootstrapDialog({ + type: BootstrapDialog.TYPE_SUCCESS, + message: message + }).open(); + }; + + return BootstrapDialog; + +})); diff --git a/apps/static/js/bootstrap.min.js b/apps/static/js/bootstrap.min.js new file mode 100644 index 000000000..63866bcb4 --- /dev/null +++ b/apps/static/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.0",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus","focus"==b.type)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.0",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c="prev"==a?-1:1,d=this.getItemIndex(b),e=(d+c)%this.$items.length;return this.$items.eq(e)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i="next"==b?"first":"last",j=this;if(!f.length){if(!this.options.wrap)return;f=this.$element.find(".item")[i]()}if(f.hasClass("active"))return this.sliding=!1;var k=f[0],l=a.Event("slide.bs.carousel",{relatedTarget:k,direction:h});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var m=a(this.$indicators.children()[this.getItemIndex(f)]);m&&m.addClass("active")}var n=a.Event("slid.bs.carousel",{relatedTarget:k,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),j.sliding=!1,setTimeout(function(){j.$element.trigger(n)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(n)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.0",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.find("> .panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('