Merge branch 'master' into licenses-unstable

This commit is contained in:
Luke Sneeringer 2015-02-25 12:37:44 -06:00
commit 4f9c684c67
859 changed files with 94857 additions and 16590 deletions

View File

@ -33,6 +33,7 @@ from polymorphic import PolymorphicModel
from awx.main.constants import SCHEDULEABLE_PROVIDERS
from awx.main.models import * # noqa
from awx.main.utils import get_type_for_model, get_model_for_type
from awx.main.redact import REPLACE_STR
logger = logging.getLogger('awx.api.serializers')
@ -1419,6 +1420,17 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
return ret
if 'job_template' in ret and (not obj.job_template or not obj.job_template.active):
ret['job_template'] = None
if obj.job_template and obj.job_template.survey_enabled:
if ret['extra_vars']:
try:
extra_vars = json.loads(ret['extra_vars'])
for key in obj.job_template.survey_password_variables():
if key in extra_vars:
extra_vars[key] = REPLACE_STR
ret['extra_vars'] = json.dumps(extra_vars)
except ValueError:
pass
return ret

View File

@ -0,0 +1,50 @@
{% if content_only %}<div class="nocode ansi_fore ansi_back{% if dark %} ansi_dark{% endif %}">{% else %}
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{ title }}</title>
{% endif %}<style type="text/css">
.ansi_fore { color: #000000; }
.ansi_back { background-color: #F5F5F5; }
.ansi_fore.ansi_dark { color: #AAAAAA; }
.ansi_back.ansi_dark { background-color: #000000; }
.ansi1 { font-weight: bold; }
.ansi3 { font-weight: italic; }
.ansi4 { text-decoration: underline; }
.ansi9 { text-decoration: line-through; }
.ansi30 { color: #000316; }
.ansi31 { color: #AA0000; }
.ansi32 { color: #00AA00; }
.ansi33 { color: #AA5500; }
.ansi34 { color: #0000AA; }
.ansi35 { color: #E850A8; }
.ansi36 { color: #00AAAA; }
.ansi37 { color: #F5F1DE; }
.ansi40 { background-color: #000000; }
.ansi41 { background-color: #AA0000; }
.ansi42 { background-color: #00AA00; }
.ansi43 { background-color: #AA5500; }
.ansi44 { background-color: #0000AA; }
.ansi45 { background-color: #E850A8; }
.ansi46 { background-color: #00AAAA; }
.ansi47 { background-color: #F5F1DE; }
body.ansi_back pre {
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
font-size: 12px;
}
div.ansi_back.ansi_dark {
padding: 0 8px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
</style>{% if content_only %}{{ body }}
</div>
{% else %}
</head>
<body class="ansi_fore ansi_back{% if dark %} ansi_dark{% endif %}">
<pre>{{ body }}</pre>
</body>
</html>
{% endif %}

View File

@ -17,16 +17,6 @@ Use the `format` query string parameter to specify the output format.
formats, the `start_line` and `end_line` query string parameters can be used
to specify a range of line numbers to retrieve.
When using the HTML or API formats, use the `scheme` query string parameter to
change the output colors. The value must be one of the following (default is
`ansi2html`):
* `ansi2html`
* `osx`
* `xterm`
* `xterm-bright`
* `solarized`
Use `dark=1` or `dark=0` as a query string parameter to force or disable a
dark background.

View File

@ -3,6 +3,7 @@
# All Rights Reserved.
# Python
import cgi
import datetime
import dateutil
import time
@ -33,13 +34,12 @@ from rest_framework.settings import api_settings
from rest_framework.views import exception_handler
from rest_framework import status
# Ansi2HTML
from ansi2html import Ansi2HTMLConverter
from ansi2html.style import SCHEME
# QSStats
import qsstats
# ANSIConv
import ansiconv
# AWX
from awx.main.task_engine import TaskSerializer, TASK_FILE
from awx.main.access import get_user_queryset
@ -2201,28 +2201,23 @@ class UnifiedJobStdout(RetrieveAPIView):
def retrieve(self, request, *args, **kwargs):
unified_job = self.get_object()
if request.accepted_renderer.format in ('html', 'api', 'json'):
scheme = request.QUERY_PARAMS.get('scheme', None)
start_line = request.QUERY_PARAMS.get('start_line', 0)
end_line = request.QUERY_PARAMS.get('end_line', None)
if scheme not in SCHEME:
scheme = 'ansi2html'
dark_val = request.QUERY_PARAMS.get('dark', '')
dark = bool(dark_val and dark_val[0].lower() in ('1', 't', 'y'))
content_only = bool(request.accepted_renderer.format in ('api', 'json'))
dark_bg = (content_only and dark) or (not content_only and (dark or not dark_val))
conv = Ansi2HTMLConverter(scheme=scheme, dark_bg=dark_bg,
title=get_view_name(self.__class__))
content, start, end, absolute_end = unified_job.result_stdout_raw_limited(start_line, end_line)
if content_only:
headers = conv.produce_headers()
body = conv.convert(content, full=False) # Escapes any HTML that may be in content.
data = '\n'.join([headers, body])
data = '<div class="nocode body_foreground body_background">%s</div>' % data
else:
data = conv.convert(content)
# Fix ugly grey background used by default.
data = data.replace('.body_background { background-color: #AAAAAA; }',
'.body_background { background-color: #f5f5f5; }')
body = ansiconv.to_html(cgi.escape(content))
context = {
'title': get_view_name(self.__class__),
'body': mark_safe(body),
'dark': dark_bg,
'content_only': content_only,
}
data = render_to_string('api/stdout.html', context).strip()
if request.accepted_renderer.format == 'api':
return Response(mark_safe(data))
if request.accepted_renderer.format == 'json':

View File

@ -2,7 +2,7 @@ Local versions of third-party packages required by Tower. Package names and
versions are listed below, along with notes on which files are included.
amqp==1.4.5 (amqp/*)
ansi2html==1.0.6 (ansi2html/*)
ansiconv==1.0.0 (ansiconv.py)
anyjson==0.3.3 (anyjson/*)
argparse==1.2.1 (argparse.py, needed for Python 2.6 support)
azure==0.9.0 (azure/*)
@ -21,7 +21,7 @@ django-celery==3.1.10 (djcelery/*)
django-crum==0.6.1 (crum/*)
django-extensions==1.3.3 (django_extensions/*)
django-jsonfield==0.9.12 (jsonfield/*, minor fix in jsonfield/fields.py)
django-polymorphic==0.5.3 (polymorphic/*)
django_polymorphic==0.5.3 (polymorphic/*)
django-split-settings==0.1.1 (split_settings/*)
django-taggit==0.11.2 (taggit/*)
djangorestframework==2.3.13 (rest_framework/*)
@ -36,9 +36,9 @@ kombu==3.0.21 (kombu/*)
Markdown==2.4.1 (markdown/*, excluded bin/markdown_py)
mock==1.0.1 (mock.py)
ordereddict==1.1 (ordereddict.py, needed for Python 2.6 support)
os-diskconfig-python-novaclient-ext==0.1.2 (os_diskconfig_python_novaclient_ext/*)
os-networksv2-python-novaclient-ext==0.21 (os_networksv2_python_novaclient_ext.py)
os-virtual-interfacesv2-python-novaclient-ext==0.15 (os_virtual_interfacesv2_python_novaclient_ext.py)
os_diskconfig_python_novaclient_ext==0.1.2 (os_diskconfig_python_novaclient_ext/*)
os_networksv2_python_novaclient_ext==0.21 (os_networksv2_python_novaclient_ext.py)
os_virtual_interfacesv2_python_novaclient_ext==0.15 (os_virtual_interfacesv2_python_novaclient_ext.py)
pbr==0.10.0 (pbr/*)
pexpect==3.1 (pexpect/*, excluded pxssh.py, fdpexpect.py, FSM.py, screen.py,
ANSI.py)
@ -51,8 +51,8 @@ python-swiftclient==2.2.0 (swiftclient/*, excluded bin/swift)
pytz==2014.10 (pytz/*)
rackspace-auth-openstack==1.3 (rackspace_auth_openstack/*)
rackspace-novaclient==1.4 (no files)
rax-default-network-flags-python-novaclient-ext==0.2.3 (rax_default_network_flags_python_novaclient_ext/*)
rax-scheduled-images-python-novaclient-ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*)
rax_default_network_flags_python_novaclient_ext==0.2.3 (rax_default_network_flags_python_novaclient_ext/*)
rax_scheduled_images_python_novaclient_ext==0.2.1 (rax_scheduled_images_python_novaclient_ext/*)
requests==2.5.1 (requests/*)
setuptools==12.0.5 (setuptools/*, _markerlib/*, pkg_resources/*, easy_install.py)
simplejson==3.6.0 (simplejson/*, excluded simplejson/_speedups.so)

View File

@ -1,2 +0,0 @@
from ansi2html.converter import Ansi2HTMLConverter
__all__ = ['Ansi2HTMLConverter']

View File

@ -1,492 +0,0 @@
# This file is part of ansi2html
# Convert ANSI (terminal) colours and attributes to HTML
# Copyright (C) 2012 Ralph Bean <rbean@redhat.com>
# Copyright (C) 2013 Sebastian Pipping <sebastian@pipping.org>
#
# Inspired by and developed off of the work by pixelbeat and blackjack.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
import re
import sys
import optparse
import pkg_resources
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
from ansi2html.style import get_styles, SCHEME
import six
from six.moves import map
from six.moves import zip
ANSI_FULL_RESET = 0
ANSI_INTENSITY_INCREASED = 1
ANSI_INTENSITY_REDUCED = 2
ANSI_INTENSITY_NORMAL = 22
ANSI_STYLE_ITALIC = 3
ANSI_STYLE_NORMAL = 23
ANSI_BLINK_SLOW = 5
ANSI_BLINK_FAST = 6
ANSI_BLINK_OFF = 25
ANSI_UNDERLINE_ON = 4
ANSI_UNDERLINE_OFF = 24
ANSI_CROSSED_OUT_ON = 9
ANSI_CROSSED_OUT_OFF = 29
ANSI_VISIBILITY_ON = 28
ANSI_VISIBILITY_OFF = 8
ANSI_FOREGROUND_CUSTOM_MIN = 30
ANSI_FOREGROUND_CUSTOM_MAX = 37
ANSI_FOREGROUND_256 = 38
ANSI_FOREGROUND_DEFAULT = 39
ANSI_BACKGROUND_CUSTOM_MIN = 40
ANSI_BACKGROUND_CUSTOM_MAX = 47
ANSI_BACKGROUND_256 = 48
ANSI_BACKGROUND_DEFAULT = 49
ANSI_NEGATIVE_ON = 7
ANSI_NEGATIVE_OFF = 27
_template = six.u("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%(output_encoding)s">
<title>%(title)s</title>
<style type="text/css">\n%(style)s\n</style>
</head>
<body class="body_foreground body_background" style="font-size: %(font_size)s;" >
<pre>
%(content)s
</pre>
</body>
</html>
""")
class _State(object):
def __init__(self):
self.reset()
def reset(self):
self.intensity = ANSI_INTENSITY_NORMAL
self.style = ANSI_STYLE_NORMAL
self.blink = ANSI_BLINK_OFF
self.underline = ANSI_UNDERLINE_OFF
self.crossedout = ANSI_CROSSED_OUT_OFF
self.visibility = ANSI_VISIBILITY_ON
self.foreground = (ANSI_FOREGROUND_DEFAULT, None)
self.background = (ANSI_BACKGROUND_DEFAULT, None)
self.negative = ANSI_NEGATIVE_OFF
def adjust(self, ansi_code, parameter=None):
if ansi_code in (ANSI_INTENSITY_INCREASED, ANSI_INTENSITY_REDUCED, ANSI_INTENSITY_NORMAL):
self.intensity = ansi_code
elif ansi_code in (ANSI_STYLE_ITALIC, ANSI_STYLE_NORMAL):
self.style = ansi_code
elif ansi_code in (ANSI_BLINK_SLOW, ANSI_BLINK_FAST, ANSI_BLINK_OFF):
self.blink = ansi_code
elif ansi_code in (ANSI_UNDERLINE_ON, ANSI_UNDERLINE_OFF):
self.underline = ansi_code
elif ansi_code in (ANSI_CROSSED_OUT_ON, ANSI_CROSSED_OUT_OFF):
self.crossedout = ansi_code
elif ansi_code in (ANSI_VISIBILITY_ON, ANSI_VISIBILITY_OFF):
self.visibility = ansi_code
elif ANSI_FOREGROUND_CUSTOM_MIN <= ansi_code <= ANSI_FOREGROUND_CUSTOM_MAX:
self.foreground = (ansi_code, None)
elif ansi_code == ANSI_FOREGROUND_256:
self.foreground = (ansi_code, parameter)
elif ansi_code == ANSI_FOREGROUND_DEFAULT:
self.foreground = (ansi_code, None)
elif ANSI_BACKGROUND_CUSTOM_MIN <= ansi_code <= ANSI_BACKGROUND_CUSTOM_MAX:
self.background = (ansi_code, None)
elif ansi_code == ANSI_BACKGROUND_256:
self.background = (ansi_code, parameter)
elif ansi_code == ANSI_BACKGROUND_DEFAULT:
self.background = (ansi_code, None)
elif ansi_code in (ANSI_NEGATIVE_ON, ANSI_NEGATIVE_OFF):
self.negative = ansi_code
def to_css_classes(self):
css_classes = []
def append_unless_default(output, value, default):
if value != default:
css_class = 'ansi%d' % value
output.append(css_class)
def append_color_unless_default(output, color, default, negative, neg_css_class):
value, parameter = color
if value != default:
prefix = 'inv' if negative else 'ansi'
css_class_index = str(value) \
if (parameter is None) \
else '%d-%d' % (value, parameter)
output.append(prefix + css_class_index)
elif negative:
output.append(neg_css_class)
append_unless_default(css_classes, self.intensity, ANSI_INTENSITY_NORMAL)
append_unless_default(css_classes, self.style, ANSI_STYLE_NORMAL)
append_unless_default(css_classes, self.blink, ANSI_BLINK_OFF)
append_unless_default(css_classes, self.underline, ANSI_UNDERLINE_OFF)
append_unless_default(css_classes, self.crossedout, ANSI_CROSSED_OUT_OFF)
append_unless_default(css_classes, self.visibility, ANSI_VISIBILITY_ON)
flip_fore_and_background = (self.negative == ANSI_NEGATIVE_ON)
append_color_unless_default(css_classes, self.foreground, ANSI_FOREGROUND_DEFAULT, flip_fore_and_background, 'inv_background')
append_color_unless_default(css_classes, self.background, ANSI_BACKGROUND_DEFAULT, flip_fore_and_background, 'inv_foreground')
return css_classes
def linkify(line):
for match in re.findall(r'https?:\/\/\S+', line):
line = line.replace(match, '<a href="%s">%s</a>' % (match, match))
return line
def _needs_extra_newline(text):
if not text or text.endswith('\n'):
return False
return True
class CursorMoveUp(object):
pass
class Ansi2HTMLConverter(object):
""" Convert Ansi color codes to CSS+HTML
Example:
>>> conv = Ansi2HTMLConverter()
>>> ansi = " ".join(sys.stdin.readlines())
>>> html = conv.convert(ansi)
"""
def __init__(self,
inline=False,
dark_bg=True,
font_size='normal',
linkify=False,
escaped=True,
markup_lines=False,
output_encoding='utf-8',
scheme='ansi2html',
title=''
):
self.inline = inline
self.dark_bg = dark_bg
self.font_size = font_size
self.linkify = linkify
self.escaped = escaped
self.markup_lines = markup_lines
self.output_encoding = output_encoding
self.scheme = scheme
self.title = title
self._attrs = None
if inline:
self.styles = dict([(item.klass.strip('.'), item) for item in get_styles(self.dark_bg, self.scheme)])
self.ansi_codes_prog = re.compile('\033\\[' '([\\d;]*)' '([a-zA-z])')
def apply_regex(self, ansi):
parts = self._apply_regex(ansi)
parts = self._collapse_cursor(parts)
parts = list(parts)
if self.linkify:
parts = [linkify(part) for part in parts]
combined = "".join(parts)
if self.markup_lines:
combined = "\n".join([
"""<span id="line-%i">%s</span>""" % (i, line)
for i, line in enumerate(combined.split('\n'))
])
return combined
def _apply_regex(self, ansi):
if self.escaped:
specials = OrderedDict([
('&', '&amp;'),
('<', '&lt;'),
('>', '&gt;'),
])
for pattern, special in specials.items():
ansi = ansi.replace(pattern, special)
state = _State()
inside_span = False
last_end = 0 # the index of the last end of a code we've seen
for match in self.ansi_codes_prog.finditer(ansi):
yield ansi[last_end:match.start()]
last_end = match.end()
params, command = match.groups()
if command not in 'mMA':
continue
# Special cursor-moving code. The only supported one.
if command == 'A':
yield CursorMoveUp
continue
try:
params = list(map(int, params.split(';')))
except ValueError:
params = [ANSI_FULL_RESET]
# Find latest reset marker
last_null_index = None
skip_after_index = -1
for i, v in enumerate(params):
if i <= skip_after_index:
continue
if v == ANSI_FULL_RESET:
last_null_index = i
elif v in (ANSI_FOREGROUND_256, ANSI_BACKGROUND_256):
skip_after_index = i + 2
# Process reset marker, drop everything before
if last_null_index is not None:
params = params[last_null_index + 1:]
if inside_span:
inside_span = False
yield '</span>'
state.reset()
if not params:
continue
# Turn codes into CSS classes
skip_after_index = -1
for i, v in enumerate(params):
if i <= skip_after_index:
continue
if v in (ANSI_FOREGROUND_256, ANSI_BACKGROUND_256):
try:
parameter = params[i + 2]
except IndexError:
continue
skip_after_index = i + 2
else:
parameter = None
state.adjust(v, parameter=parameter)
if inside_span:
yield '</span>'
inside_span = False
css_classes = state.to_css_classes()
if not css_classes:
continue
if self.inline:
style = [self.styles[klass].kw for klass in css_classes if
klass in self.styles]
yield '<span style="%s">' % "; ".join(style)
else:
yield '<span class="%s">' % " ".join(css_classes)
inside_span = True
yield ansi[last_end:]
if inside_span:
yield '</span>'
inside_span = False
def _collapse_cursor(self, parts):
""" Act on any CursorMoveUp commands by deleting preceding tokens """
final_parts = []
for part in parts:
# Throw out empty string tokens ("")
if not part:
continue
# Go back, deleting every token in the last 'line'
if part == CursorMoveUp:
final_parts.pop()
while '\n' not in final_parts[-1]:
final_parts.pop()
continue
# Otherwise, just pass this token forward
final_parts.append(part)
return final_parts
def prepare(self, ansi='', ensure_trailing_newline=False):
""" Load the contents of 'ansi' into this object """
body = self.apply_regex(ansi)
if ensure_trailing_newline and _needs_extra_newline(body):
body += '\n'
self._attrs = {
'dark_bg': self.dark_bg,
'font_size': self.font_size,
'body': body,
}
return self._attrs
def attrs(self):
""" Prepare attributes for the template """
if not self._attrs:
raise Exception("Method .prepare not yet called.")
return self._attrs
def convert(self, ansi, full=True, ensure_trailing_newline=False):
attrs = self.prepare(ansi, ensure_trailing_newline=ensure_trailing_newline)
if not full:
return attrs["body"]
else:
return _template % {
'style' : "\n".join(map(str, get_styles(self.dark_bg, self.scheme))),
'title' : self.title,
'font_size' : self.font_size,
'content' : attrs["body"],
'output_encoding' : self.output_encoding,
}
def produce_headers(self):
return '<style type="text/css">\n%(style)s\n</style>\n' % {
'style' : "\n".join(map(str, get_styles(self.dark_bg, self.scheme)))
}
def main():
"""
$ ls --color=always | ansi2html > directories.html
$ sudo tail /var/log/messages | ccze -A | ansi2html > logs.html
$ task burndown | ansi2html > burndown.html
"""
scheme_names = sorted(six.iterkeys(SCHEME))
version_str = pkg_resources.get_distribution('ansi2html').version
parser = optparse.OptionParser(
usage=main.__doc__,
version="%%prog %s" % version_str)
parser.add_option(
"-p", "--partial", dest="partial",
default=False, action="store_true",
help="Process lines as them come in. No headers are produced.")
parser.add_option(
"-i", "--inline", dest="inline",
default=False, action="store_true",
help="Inline style without headers or template.")
parser.add_option(
"-H", "--headers", dest="headers",
default=False, action="store_true",
help="Just produce the <style> tag.")
parser.add_option(
"-f", '--font-size', dest='font_size', metavar='SIZE',
default="normal",
help="Set the global font size in the output.")
parser.add_option(
"-l", '--light-background', dest='light_background',
default=False, action="store_true",
help="Set output to 'light background' mode.")
parser.add_option(
"-a", '--linkify', dest='linkify',
default=False, action="store_true",
help="Transform URLs into <a> links.")
parser.add_option(
"-u", '--unescape', dest='escaped',
default=True, action="store_false",
help="Do not escape XML tags found in the input.")
parser.add_option(
"-m", '--markup-lines', dest="markup_lines",
default=False, action="store_true",
help="Surround lines with <span id='line-n'>..</span>.")
parser.add_option(
'--input-encoding', dest='input_encoding', metavar='ENCODING',
default='utf-8',
help="Specify input encoding")
parser.add_option(
'--output-encoding', dest='output_encoding', metavar='ENCODING',
default='utf-8',
help="Specify output encoding")
parser.add_option(
'-s', '--scheme', dest='scheme', metavar='SCHEME',
default='ansi2html', choices=scheme_names,
help=("Specify color palette scheme. Default: %%default. Choices: %s"
% scheme_names))
parser.add_option(
'-t', '--title', dest='output_title',
default='',
help="Specify output title")
opts, args = parser.parse_args()
conv = Ansi2HTMLConverter(
inline=opts.inline,
dark_bg=not opts.light_background,
font_size=opts.font_size,
linkify=opts.linkify,
escaped=opts.escaped,
markup_lines=opts.markup_lines,
output_encoding=opts.output_encoding,
scheme=opts.scheme,
title=opts.output_title,
)
def _read(input_bytes):
if six.PY3:
# This is actually already unicode. How to we explicitly decode in
# python3? I don't know the answer yet.
return input_bytes
else:
return input_bytes.decode(opts.input_encoding)
def _print(output_unicode, end='\n'):
if hasattr(sys.stdout, 'buffer'):
output_bytes = (output_unicode + end).encode(opts.output_encoding)
sys.stdout.buffer.write(output_bytes)
elif not six.PY3:
sys.stdout.write((output_unicode + end).encode(opts.output_encoding))
else:
sys.stdout.write(output_unicode + end)
# Produce only the headers and quit
if opts.headers:
_print(conv.produce_headers(), end='')
return
full = not bool(opts.partial or opts.inline)
if six.PY3:
output = conv.convert("".join(sys.stdin.readlines()), full=full, ensure_trailing_newline=True)
_print(output, end='')
else:
output = conv.convert(six.u("").join(
map(_read, sys.stdin.readlines())
), full=full, ensure_trailing_newline=True)
_print(output, end='')

View File

@ -1,113 +0,0 @@
# This file is part of ansi2html.
# Copyright (C) 2012 Kuno Woudt <kuno@frob.nl>
# Copyright (C) 2013 Sebastian Pipping <sebastian@pipping.org>
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
import sys
class Rule(object):
def __init__(self, klass, **kw):
self.klass = klass
self.kw = '; '.join([(k.replace('_', '-')+': '+kw[k])
for k in sorted(kw.keys())]).strip()
def __str__(self):
return '%s { %s; }' % (self.klass, self.kw)
def index(r, g, b):
return str(16 + (r * 36) + (g * 6) + b)
def color(r, g, b):
return "#%.2x%.2x%.2x" % (r * 42, g * 42, b * 42)
def level(grey):
return "#%.2x%.2x%.2x" % (((grey * 10) + 8,) * 3)
def index2(grey):
return str(232 + grey)
# http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
SCHEME = { # black red green brown/yellow blue magenta cyan grey/white
'ansi2html': ("#000316", "#aa0000", "#00aa00", "#aa5500", "#0000aa",
"#E850A8", "#00aaaa", "#F5F1DE"),
'xterm': ("#000000", "#cd0000", "#00cd00", "#cdcd00", "#0000ee",
"#cd00cd", "#00cdcd", "#e5e5e5"),
'xterm-bright': ("#7f7f7f", "#ff0000", "#00ff00", "#ffff00", "#5c5cff",
"#ff00ff", "#00ffff", "#ffffff"),
'osx': ("#000000", "#c23621", "#25bc24", "#adad27", "#492ee1",
"#d338d3", "#33bbc8", "#cbcccd"),
# http://ethanschoonover.com/solarized
'solarized': ("#262626", "#d70000", "#5f8700", "#af8700", "#0087ff",
"#af005f", "#00afaf", "#e4e4e4"),
}
def get_styles(dark_bg=True, scheme='ansi2html'):
css = [
Rule('.body_foreground', color=('#000000', '#AAAAAA')[dark_bg]),
Rule('.body_background', background_color=('#AAAAAA', '#000000')[dark_bg]),
Rule('.body_foreground > .bold,.bold > .body_foreground, body.body_foreground > pre > .bold',
color=('#000000', '#FFFFFF')[dark_bg], font_weight=('bold', 'normal')[dark_bg]),
Rule('.inv_foreground', color=('#000000', '#FFFFFF')[not dark_bg]),
Rule('.inv_background', background_color=('#AAAAAA', '#000000')[not dark_bg]),
Rule('.ansi1', font_weight='bold'),
Rule('.ansi2', font_weight='lighter'),
Rule('.ansi3', font_style='italic'),
Rule('.ansi4', text_decoration='underline'),
Rule('.ansi5', text_decoration='blink'),
Rule('.ansi6', text_decoration='blink'),
Rule('.ansi8', visibility='hidden'),
Rule('.ansi9', text_decoration='line-through'),
]
# set palette
pal = SCHEME[scheme]
for _index in range(8):
css.append(Rule('.ansi3%s' % _index, color=pal[_index]))
css.append(Rule('.inv3%s' % _index, background_color=pal[_index]))
for _index in range(8):
css.append(Rule('.ansi4%s' % _index, background_color=pal[_index]))
css.append(Rule('.inv4%s' % _index, color=pal[_index]))
# css.append("/* Define the explicit color codes (obnoxious) */\n\n")
for green in range(0, 6):
for red in range(0, 6):
for blue in range(0, 6):
css.append(Rule(".ansi38-%s" % index(red, green, blue),
color=color(red, green, blue)))
css.append(Rule(".inv38-%s" % index(red, green, blue),
background=color(red, green, blue)))
css.append(Rule(".ansi48-%s" % index(red, green, blue),
background=color(red, green, blue)))
css.append(Rule(".inv48-%s" % index(red, green, blue),
color=color(red, green, blue)))
for grey in range(0, 24):
css.append(Rule('.ansi38-%s' % index2(grey), color=level(grey)))
css.append(Rule('.inv38-%s' % index2(grey), background=level(grey)))
css.append(Rule('.ansi48-%s' % index2(grey), background=level(grey)))
css.append(Rule('.inv48-%s' % index2(grey), color=level(grey)))
return css

View File

@ -1,2 +0,0 @@
def read_to_unicode(obj):
return [line.decode('utf-8') for line in obj.readlines()]

View File

@ -0,0 +1,127 @@
"""
Converts ANSI coded text and converts it to either plain text
or to HTML.
"""
import re
supported_sgr_codes = [1, 3, 4, 9, 30, 31, 32, 33, 34, 35, 36, 37, 40, 41, 42,
43, 44, 45, 46, 47]
def to_plain(ansi):
"""Takes the given string and strips all ANSI codes out.
:param ansi: The string to strip
:return: The stripped string
"""
return re.sub(r'\x1B\[[0-9;]*[ABCDEFGHJKSTfmnsulh]', '', ansi)
def to_html(ansi, replace_newline=False):
"""Converts the given ANSI string to HTML
If `replace_newline` is set to True, then all newlines will be
replaced with <br />.
:param ansi: The ANSI text.
:param replace_newline: Whether to replace newlines with HTML.
:return: The resulting HTML string.
"""
blocks = ansi.split('\x1B')
parsed_blocks = []
for block in blocks:
command, text = _block_to_html(block)
# The command "A" means move the cursor up, so we emulate that here.
if command == 'A' and len(parsed_blocks) > 0:
parsed_blocks.pop()
while len(parsed_blocks) > 0 and '\n' not in parsed_blocks[-1]:
parsed_blocks.pop()
parsed_blocks.append(text)
text = ''.join(parsed_blocks)
if replace_newline:
text = text.replace('\n', '<br />\n')
return text
def base_css(dark=True):
"""Some base CSS with all of the default ANSI styles/colors.
:param dark: Whether background should be dark or light.
:return: A string of CSS
"""
return "\n".join([
css_rule('.ansi_fore', color=('#000000', '#FFFFFF')[dark]),
css_rule('.ansi_back', background_color=('#FFFFFF', '#000000')[dark]),
css_rule('.ansi1', font_weight='bold'),
css_rule('.ansi3', font_weight='italic'),
css_rule('.ansi4', text_decoration='underline'),
css_rule('.ansi9', text_decoration='line-through'),
css_rule('.ansi30', color="#000000"),
css_rule('.ansi31', color="#FF0000"),
css_rule('.ansi32', color="#00FF00"),
css_rule('.ansi33', color="#FFFF00"),
css_rule('.ansi34', color="#0000FF"),
css_rule('.ansi35', color="#FF00FF"),
css_rule('.ansi36', color="#00FFFF"),
css_rule('.ansi37', color="#FFFFFF"),
css_rule('.ansi40', background_color="#000000"),
css_rule('.ansi41', background_color="#FF0000"),
css_rule('.ansi42', background_color="#00FF00"),
css_rule('.ansi43', background_color="#FFFF00"),
css_rule('.ansi44', background_color="#0000FF"),
css_rule('.ansi45', background_color="#FF00FF"),
css_rule('.ansi46', background_color="#00FFFF"),
css_rule('.ansi47', background_color="#FFFFFF")
])
def css_rule(class_name, **properties):
"""Creates a CSS rule string.
The named parameters are used as the css properties. Underscores
are converted to hyphens.
:param class_name: The CSS class name
:param properties: The properties sent as named params.
:return: The CSS string
"""
prop_str = lambda name, val: name.replace('_', '-') + ': ' + val
return '{0} {{ {1}; }}'.format(
class_name,
'; '.join([prop_str(prop, properties[prop]) for prop in properties])
)
def _block_to_html(text):
"""Converts the given block of ANSI coded text to HTML.
The text is only given back as HTML if the ANSI code is at the
beginning of the string (e.g. "[0;33mFoobar")
:param text: The text block to convert.
:return: The text as HTML
"""
match = re.match(r'^\[(?P<code>\d+(?:;\d+)*)?(?P<command>[Am])', text)
if match is None:
return None, text
command = match.group('command')
text = text[match.end():]
if match.group('code') is None:
return command, text
classes = []
for code in match.group('code').split(';'):
if int(code) in supported_sgr_codes:
classes.append('ansi{0}'.format(code))
if classes:
text = '<span class="{0}">{1}</span>'.format(' '.join(classes), text)
return command, text

View File

@ -24,6 +24,8 @@ class Command(BaseCommandInstance):
self.include_option_hostname_uuid_find()
def handle(self, *args, **options):
super(Command, self).handle(*args, **options)
# Is there an existing record for this machine? If so, retrieve that record and look for issues.
try:
# Get the instance.

View File

@ -5,7 +5,6 @@
import hmac
import json
import logging
import re
# Django
from django.conf import settings
@ -210,6 +209,15 @@ class JobTemplate(UnifiedJobTemplate, JobOptions):
vars.append(survey_element['variable'])
return vars
def survey_password_variables(self):
vars = []
if self.survey_enabled and 'spec' in self.survey_spec:
# Get variables that are type password
for survey_element in self.survey_spec['spec']:
if survey_element['type'] == 'password':
vars.append(survey_element['variable'])
return vars
def survey_variable_validation(self, data):
errors = []
if not self.survey_enabled:
@ -459,14 +467,8 @@ class Job(UnifiedJob, JobOptions):
# Then lookup password fields in extra_vars and save the values
jt = self.job_template
if jt and jt.survey_enabled and 'spec' in jt.survey_spec:
vars = []
# Get variables that are type password
for survey_element in jt.survey_spec['spec']:
if survey_element['type'] == 'password':
vars.append(survey_element['variable'])
# Use password vars to find in extra_vars
for key in vars:
for key in jt.survey_password_variables():
if key in self.extra_vars_dict:
content = PlainTextCleaner.remove_sensitive(content, self.extra_vars_dict[key])
return content

View File

@ -231,7 +231,15 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
if field not in update_fields:
update_fields.append(field)
# Do the actual save.
super(UnifiedJobTemplate, self).save(*args, **kwargs)
try:
super(UnifiedJobTemplate, self).save(*args, **kwargs)
except ValueError:
# A fix for https://trello.com/c/S4rU1F21
# Does not resolve the root cause. Tis merely a bandaid.
if 'scm_delete_on_next_update' in update_fields:
update_fields.remove('scm_delete_on_next_update')
super(UnifiedJobTemplate, self).save(*args, **kwargs)
def _get_current_status(self):
# Override in subclasses as needed.

View File

@ -14,4 +14,3 @@ from awx.main.tests.activity_stream import * # noqa
from awx.main.tests.schedules import * # noqa
from awx.main.tests.redact import * # noqa
from awx.main.tests.views import * # noqa
from awx.main.tests.jobs import *

View File

@ -323,8 +323,8 @@ class BaseTestMixin(QueueTestMixin):
job_template = self.make_job_template(created_by=created_by)
opts = {
'created_by': created_by,
'status': inital_state,
'created_by': created_by,
'status': inital_state,
}
opts.update(kwargs)
return job_template.create_job(**opts)
@ -448,9 +448,13 @@ class BaseTestMixin(QueueTestMixin):
elif response['Content-Type'].startswith('application/yaml'):
obj = yaml.safe_load(response.content)
elif response['Content-Type'].startswith('text/plain'):
obj = { 'content': response.content }
obj = {
'content': response.content
}
elif response['Content-Type'].startswith('text/html'):
obj = { 'content': response.content }
obj = {
'content': response.content
}
else:
self.fail('Unsupport response content type %s' % response['Content-Type'])
else:

View File

@ -1,3 +1,3 @@
from awx.main.tests.jobs.jobs import *
from awx.main.tests.jobs.survey_password import *
from awx.main.tests.jobs.jobs_monolithic import * # noqa
from survey_password import * # noqa
from base import * # noqa

515
awx/main/tests/jobs/base.py Normal file
View File

@ -0,0 +1,515 @@
# Python
import uuid
# AWX
from awx.main.models import * # noqa
from awx.main.tests.base import BaseTestMixin
TEST_PLAYBOOK = '''- hosts: all
gather_facts: false
tasks:
- name: woohoo
command: test 1 = 1
'''
class BaseJobTestMixin(BaseTestMixin):
def _create_inventory(self, name, organization, created_by,
groups_hosts_dict):
'''Helper method for creating inventory with groups and hosts.'''
inventory = organization.inventories.create(
name=name,
created_by=created_by,
)
for group_name, host_names in groups_hosts_dict.items():
group = inventory.groups.create(
name=group_name,
created_by=created_by,
)
for host_name in host_names:
host = inventory.hosts.create(
name=host_name,
created_by=created_by,
)
group.hosts.add(host)
return inventory
def populate(self):
# Here's a little story about the Ansible Bread Company, or ABC. They
# make machines that make bread - bakers, slicers, and packagers - and
# these machines are each controlled by a Linux boxes, which is in turn
# managed by Ansible Commander.
# Sue is the super user. You don't mess with Sue or you're toast. Ha.
self.user_sue = self.make_user('sue', super_user=True)
# There are three organizations in ABC using Ansible, since it's the
# best thing for dev ops automation since, well, sliced bread.
# Engineering - They design and build the machines.
self.org_eng = Organization.objects.create(
name='engineering',
created_by=self.user_sue,
)
# Support - They fix it when it's not working.
self.org_sup = Organization.objects.create(
name='support',
created_by=self.user_sue,
)
# Operations - They implement the production lines using the machines.
self.org_ops = Organization.objects.create(
name='operations',
created_by=self.user_sue,
)
# Alex is Sue's IT assistant who can also administer all of the
# organizations.
self.user_alex = self.make_user('alex')
self.org_eng.admins.add(self.user_alex)
self.org_sup.admins.add(self.user_alex)
self.org_ops.admins.add(self.user_alex)
# Bob is the head of engineering. He's an admin for engineering, but
# also a user within the operations organization (so he can see the
# results if things go wrong in production).
self.user_bob = self.make_user('bob')
self.org_eng.admins.add(self.user_bob)
self.org_ops.users.add(self.user_bob)
# Chuck is the lead engineer. He has full reign over engineering, but
# no other organizations.
self.user_chuck = self.make_user('chuck')
self.org_eng.admins.add(self.user_chuck)
# Doug is the other engineer working under Chuck. He can write
# playbooks and check them, but Chuck doesn't quite think he's ready to
# run them yet. Poor Doug.
self.user_doug = self.make_user('doug')
self.org_eng.users.add(self.user_doug)
# Juan is another engineer working under Chuck. He has a little more freedom
# to run playbooks but can't create job templates
self.user_juan = self.make_user('juan')
self.org_eng.users.add(self.user_juan)
# Hannibal is Chuck's right-hand man. Chuck usually has him create the job
# templates that the rest of the team will use
self.user_hannibal = self.make_user('hannibal')
self.org_eng.users.add(self.user_hannibal)
# Eve is the head of support. She can also see what goes on in
# operations to help them troubleshoot problems.
self.user_eve = self.make_user('eve')
self.org_sup.admins.add(self.user_eve)
self.org_ops.users.add(self.user_eve)
# Frank is the other support guy.
self.user_frank = self.make_user('frank')
self.org_sup.users.add(self.user_frank)
# Greg is the head of operations.
self.user_greg = self.make_user('greg')
self.org_ops.admins.add(self.user_greg)
# Holly is an operations engineer.
self.user_holly = self.make_user('holly')
self.org_ops.users.add(self.user_holly)
# Iris is another operations engineer.
self.user_iris = self.make_user('iris')
self.org_ops.users.add(self.user_iris)
# Randall and Billybob are new ops interns that ops uses to test
# their playbooks and inventory
self.user_randall = self.make_user('randall')
self.org_ops.users.add(self.user_randall)
# He works with Randall
self.user_billybob = self.make_user('billybob')
self.org_ops.users.add(self.user_billybob)
# Jim is the newest intern. He can login, but can't do anything quite yet
# except make everyone else fresh coffee.
self.user_jim = self.make_user('jim')
# There are three main projects, one each for the development, test and
# production branches of the playbook repository. All three orgs can
# use the production branch, support can use the production and testing
# branches, and operations can only use the production branch.
self.proj_dev = self.make_project('dev', 'development branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_dev)
self.proj_test = self.make_project('test', 'testing branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_test)
self.org_sup.projects.add(self.proj_test)
self.proj_prod = self.make_project('prod', 'production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_prod)
self.org_sup.projects.add(self.proj_prod)
self.org_ops.projects.add(self.proj_prod)
# Operations also has 2 additional projects specific to the east/west
# production environments.
self.proj_prod_east = self.make_project('prod-east',
'east production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_ops.projects.add(self.proj_prod_east)
self.proj_prod_west = self.make_project('prod-west',
'west production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_ops.projects.add(self.proj_prod_west)
# The engineering organization has a set of servers to use for
# development and testing (2 bakers, 1 slicer, 1 packager).
self.inv_eng = self._create_inventory(
name='engineering environment',
organization=self.org_eng,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['eng-baker1', 'eng-baker2'],
'slicers': ['eng-slicer1'],
'packagers': ['eng-packager1'],
},
)
# The support organization has a set of servers to use for
# testing and reproducing problems from operations (1 baker, 1 slicer,
# 1 packager).
self.inv_sup = self._create_inventory(
name='support environment',
organization=self.org_sup,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['sup-baker1'],
'slicers': ['sup-slicer1'],
'packagers': ['sup-packager1'],
},
)
# The operations organization manages multiple sets of servers for the
# east and west production facilities.
self.inv_ops_east = self._create_inventory(
name='east production environment',
organization=self.org_ops,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['east-baker%d' % n for n in range(1, 4)],
'slicers': ['east-slicer%d' % n for n in range(1, 3)],
'packagers': ['east-packager%d' % n for n in range(1, 3)],
},
)
self.inv_ops_west = self._create_inventory(
name='west production environment',
organization=self.org_ops,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['west-baker%d' % n for n in range(1, 6)],
'slicers': ['west-slicer%d' % n for n in range(1, 4)],
'packagers': ['west-packager%d' % n for n in range(1, 3)],
},
)
# Operations is divided into teams to work on the east/west servers.
# Greg and Holly work on east, Greg and iris work on west.
self.team_ops_east = self.org_ops.teams.create(
name='easterners',
created_by=self.user_sue)
self.team_ops_east.projects.add(self.proj_prod)
self.team_ops_east.projects.add(self.proj_prod_east)
self.team_ops_east.users.add(self.user_greg)
self.team_ops_east.users.add(self.user_holly)
self.team_ops_west = self.org_ops.teams.create(
name='westerners',
created_by=self.user_sue)
self.team_ops_west.projects.add(self.proj_prod)
self.team_ops_west.projects.add(self.proj_prod_west)
self.team_ops_west.users.add(self.user_greg)
self.team_ops_west.users.add(self.user_iris)
# The south team is no longer active having been folded into the east team
self.team_ops_south = self.org_ops.teams.create(
name='southerners',
created_by=self.user_sue,
active=False,
)
self.team_ops_south.projects.add(self.proj_prod)
self.team_ops_south.users.add(self.user_greg)
# The north team is going to be deleted
self.team_ops_north = self.org_ops.teams.create(
name='northerners',
created_by=self.user_sue,
)
self.team_ops_north.projects.add(self.proj_prod)
self.team_ops_north.users.add(self.user_greg)
# The testers team are interns that can only check playbooks but can't
# run them
self.team_ops_testers = self.org_ops.teams.create(
name='testers',
created_by=self.user_sue,
)
self.team_ops_testers.projects.add(self.proj_prod)
self.team_ops_testers.users.add(self.user_randall)
self.team_ops_testers.users.add(self.user_billybob)
# Each user has his/her own set of credentials.
from awx.main.tests.tasks import (TEST_SSH_KEY_DATA,
TEST_SSH_KEY_DATA_LOCKED,
TEST_SSH_KEY_DATA_UNLOCK)
self.cred_sue = self.user_sue.credentials.create(
username='sue',
password=TEST_SSH_KEY_DATA,
created_by=self.user_sue,
)
self.cred_bob = self.user_bob.credentials.create(
username='bob',
password='ASK',
created_by=self.user_sue,
)
self.cred_chuck = self.user_chuck.credentials.create(
username='chuck',
ssh_key_data=TEST_SSH_KEY_DATA,
created_by=self.user_sue,
)
self.cred_doug = self.user_doug.credentials.create(
username='doug',
password='doug doesn\'t mind his password being saved. this '
'is why we dont\'t let doug actually run jobs.',
created_by=self.user_sue,
)
self.cred_eve = self.user_eve.credentials.create(
username='eve',
password='ASK',
sudo_username='root',
sudo_password='ASK',
created_by=self.user_sue,
)
self.cred_frank = self.user_frank.credentials.create(
username='frank',
password='fr@nk the t@nk',
created_by=self.user_sue,
)
self.cred_greg = self.user_greg.credentials.create(
username='greg',
ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
ssh_key_unlock='ASK',
created_by=self.user_sue,
)
self.cred_holly = self.user_holly.credentials.create(
username='holly',
password='holly rocks',
created_by=self.user_sue,
)
self.cred_iris = self.user_iris.credentials.create(
username='iris',
password='ASK',
created_by=self.user_sue,
)
# Each operations team also has shared credentials they can use.
self.cred_ops_east = self.team_ops_east.credentials.create(
username='east',
ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
ssh_key_unlock=TEST_SSH_KEY_DATA_UNLOCK,
created_by = self.user_sue,
)
self.cred_ops_west = self.team_ops_west.credentials.create(
username='west',
password='Heading270',
created_by = self.user_sue,
)
self.cred_ops_south = self.team_ops_south.credentials.create(
username='south',
password='Heading180',
created_by = self.user_sue,
)
self.cred_ops_north = self.team_ops_north.credentials.create(
username='north',
password='Heading0',
created_by = self.user_sue,
)
self.cred_ops_test = self.team_ops_testers.credentials.create(
username='testers',
password='HeadingNone',
created_by = self.user_sue,
)
self.ops_testers_permission = Permission.objects.create(
inventory = self.inv_ops_west,
project = self.proj_prod,
team = self.team_ops_testers,
permission_type = PERM_INVENTORY_CHECK,
created_by = self.user_sue
)
self.doug_check_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_doug,
permission_type = PERM_INVENTORY_CHECK,
created_by = self.user_sue
)
self.juan_deploy_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_juan,
permission_type = PERM_INVENTORY_DEPLOY,
created_by = self.user_sue
)
self.hannibal_create_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_hannibal,
permission_type = PERM_JOBTEMPLATE_CREATE,
created_by = self.user_sue
)
# FIXME: Define explicit permissions for tests.
# other django user is on the project team and can deploy
#self.permission1 = Permission.objects.create(
# inventory = self.inventory,
# project = self.project,
# team = self.team,
# permission_type = PERM_INVENTORY_DEPLOY,
# created_by = self.normal_django_user
#)
# individual permission granted to other2 user, can run check mode
#self.permission2 = Permission.objects.create(
# inventory = self.inventory,
# project = self.project,
# user = self.other2_django_user,
# permission_type = PERM_INVENTORY_CHECK,
# created_by = self.normal_django_user
#)
# Engineering has job templates to check/run the dev project onto
# their own inventory.
self.jt_eng_check = JobTemplate.objects.create(
name='eng-dev-check',
job_type='check',
inventory= self.inv_eng,
project=self.proj_dev,
playbook=self.proj_dev.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_eng_check = self.jt_eng_check.create_job(
# created_by=self.user_sue,
# credential=self.cred_doug,
# )
self.jt_eng_run = JobTemplate.objects.create(
name='eng-dev-run',
job_type='run',
inventory= self.inv_eng,
project=self.proj_dev,
playbook=self.proj_dev.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_eng_run = self.jt_eng_run.create_job(
# created_by=self.user_sue,
# credential=self.cred_chuck,
# )
# Support has job templates to check/run the test project onto
# their own inventory.
self.jt_sup_check = JobTemplate.objects.create(
name='sup-test-check',
job_type='check',
inventory= self.inv_sup,
project=self.proj_test,
playbook=self.proj_test.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_sup_check = self.jt_sup_check.create_job(
# created_by=self.user_sue,
# credential=self.cred_frank,
# )
self.jt_sup_run = JobTemplate.objects.create(
name='sup-test-run',
job_type='run',
inventory= self.inv_sup,
project=self.proj_test,
playbook=self.proj_test.playbooks[0],
host_config_key=uuid.uuid4().hex,
credential=self.cred_eve,
created_by=self.user_sue,
)
# self.job_sup_run = self.jt_sup_run.create_job(
# created_by=self.user_sue,
# )
# Operations has job templates to check/run the prod project onto
# both east and west inventories, by default using the team credential.
self.jt_ops_east_check = JobTemplate.objects.create(
name='ops-east-prod-check',
job_type='check',
inventory= self.inv_ops_east,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_east,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_east_check = self.jt_ops_east_check.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_east_run = JobTemplate.objects.create(
name='ops-east-prod-run',
job_type='run',
inventory= self.inv_ops_east,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_east,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_east_run = self.jt_ops_east_run.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_west_check = JobTemplate.objects.create(
name='ops-west-prod-check',
job_type='check',
inventory= self.inv_ops_west,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_west,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_west_check = self.jt_ops_west_check.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_west_run = JobTemplate.objects.create(
name='ops-west-prod-run',
job_type='run',
inventory= self.inv_ops_west,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_west,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_west_run = self.jt_ops_west_run.create_job(
# created_by=self.user_sue,
# )
def setUp(self):
super(BaseJobTestMixin, self).setUp()
self.start_redis()
self.setup_instances()
self.populate()
self.start_queue()
def tearDown(self):
super(BaseJobTestMixin, self).tearDown()
self.stop_redis()
self.terminate_queue()

View File

@ -9,7 +9,6 @@ import struct
import threading
import time
import urlparse
import uuid
# Django
import django.test
@ -24,18 +23,11 @@ import requests
# AWX
from awx.main.models import * # noqa
from awx.main.tests.base import BaseTestMixin
from base import BaseJobTestMixin
__all__ = ['JobTemplateTest', 'JobTest', 'JobStartCancelTest',
'JobTemplateCallbackTest', 'JobTransactionTest', 'JobTemplateSurveyTest']
TEST_PLAYBOOK = '''- hosts: all
gather_facts: false
tasks:
- name: woohoo
command: test 1 = 1
'''
TEST_ASYNC_PLAYBOOK = '''
- hosts: all
gather_facts: false
@ -193,508 +185,6 @@ TEST_SURVEY_REQUIREMENTS = '''
}
'''
class BaseJobTestMixin(BaseTestMixin):
def _create_inventory(self, name, organization, created_by,
groups_hosts_dict):
'''Helper method for creating inventory with groups and hosts.'''
inventory = organization.inventories.create(
name=name,
created_by=created_by,
)
for group_name, host_names in groups_hosts_dict.items():
group = inventory.groups.create(
name=group_name,
created_by=created_by,
)
for host_name in host_names:
host = inventory.hosts.create(
name=host_name,
created_by=created_by,
)
group.hosts.add(host)
return inventory
def populate(self):
# Here's a little story about the Ansible Bread Company, or ABC. They
# make machines that make bread - bakers, slicers, and packagers - and
# these machines are each controlled by a Linux boxes, which is in turn
# managed by Ansible Commander.
# Sue is the super user. You don't mess with Sue or you're toast. Ha.
self.user_sue = self.make_user('sue', super_user=True)
# There are three organizations in ABC using Ansible, since it's the
# best thing for dev ops automation since, well, sliced bread.
# Engineering - They design and build the machines.
self.org_eng = Organization.objects.create(
name='engineering',
created_by=self.user_sue,
)
# Support - They fix it when it's not working.
self.org_sup = Organization.objects.create(
name='support',
created_by=self.user_sue,
)
# Operations - They implement the production lines using the machines.
self.org_ops = Organization.objects.create(
name='operations',
created_by=self.user_sue,
)
# Alex is Sue's IT assistant who can also administer all of the
# organizations.
self.user_alex = self.make_user('alex')
self.org_eng.admins.add(self.user_alex)
self.org_sup.admins.add(self.user_alex)
self.org_ops.admins.add(self.user_alex)
# Bob is the head of engineering. He's an admin for engineering, but
# also a user within the operations organization (so he can see the
# results if things go wrong in production).
self.user_bob = self.make_user('bob')
self.org_eng.admins.add(self.user_bob)
self.org_ops.users.add(self.user_bob)
# Chuck is the lead engineer. He has full reign over engineering, but
# no other organizations.
self.user_chuck = self.make_user('chuck')
self.org_eng.admins.add(self.user_chuck)
# Doug is the other engineer working under Chuck. He can write
# playbooks and check them, but Chuck doesn't quite think he's ready to
# run them yet. Poor Doug.
self.user_doug = self.make_user('doug')
self.org_eng.users.add(self.user_doug)
# Juan is another engineer working under Chuck. He has a little more freedom
# to run playbooks but can't create job templates
self.user_juan = self.make_user('juan')
self.org_eng.users.add(self.user_juan)
# Hannibal is Chuck's right-hand man. Chuck usually has him create the job
# templates that the rest of the team will use
self.user_hannibal = self.make_user('hannibal')
self.org_eng.users.add(self.user_hannibal)
# Eve is the head of support. She can also see what goes on in
# operations to help them troubleshoot problems.
self.user_eve = self.make_user('eve')
self.org_sup.admins.add(self.user_eve)
self.org_ops.users.add(self.user_eve)
# Frank is the other support guy.
self.user_frank = self.make_user('frank')
self.org_sup.users.add(self.user_frank)
# Greg is the head of operations.
self.user_greg = self.make_user('greg')
self.org_ops.admins.add(self.user_greg)
# Holly is an operations engineer.
self.user_holly = self.make_user('holly')
self.org_ops.users.add(self.user_holly)
# Iris is another operations engineer.
self.user_iris = self.make_user('iris')
self.org_ops.users.add(self.user_iris)
# Randall and Billybob are new ops interns that ops uses to test
# their playbooks and inventory
self.user_randall = self.make_user('randall')
self.org_ops.users.add(self.user_randall)
# He works with Randall
self.user_billybob = self.make_user('billybob')
self.org_ops.users.add(self.user_billybob)
# Jim is the newest intern. He can login, but can't do anything quite yet
# except make everyone else fresh coffee.
self.user_jim = self.make_user('jim')
# There are three main projects, one each for the development, test and
# production branches of the playbook repository. All three orgs can
# use the production branch, support can use the production and testing
# branches, and operations can only use the production branch.
self.proj_dev = self.make_project('dev', 'development branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_dev)
self.proj_test = self.make_project('test', 'testing branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_test)
self.org_sup.projects.add(self.proj_test)
self.proj_prod = self.make_project('prod', 'production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_eng.projects.add(self.proj_prod)
self.org_sup.projects.add(self.proj_prod)
self.org_ops.projects.add(self.proj_prod)
# Operations also has 2 additional projects specific to the east/west
# production environments.
self.proj_prod_east = self.make_project('prod-east',
'east production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_ops.projects.add(self.proj_prod_east)
self.proj_prod_west = self.make_project('prod-west',
'west production branch',
self.user_sue, TEST_PLAYBOOK)
self.org_ops.projects.add(self.proj_prod_west)
# The engineering organization has a set of servers to use for
# development and testing (2 bakers, 1 slicer, 1 packager).
self.inv_eng = self._create_inventory(
name='engineering environment',
organization=self.org_eng,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['eng-baker1', 'eng-baker2'],
'slicers': ['eng-slicer1'],
'packagers': ['eng-packager1'],
},
)
# The support organization has a set of servers to use for
# testing and reproducing problems from operations (1 baker, 1 slicer,
# 1 packager).
self.inv_sup = self._create_inventory(
name='support environment',
organization=self.org_sup,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['sup-baker1'],
'slicers': ['sup-slicer1'],
'packagers': ['sup-packager1'],
},
)
# The operations organization manages multiple sets of servers for the
# east and west production facilities.
self.inv_ops_east = self._create_inventory(
name='east production environment',
organization=self.org_ops,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['east-baker%d' % n for n in range(1, 4)],
'slicers': ['east-slicer%d' % n for n in range(1, 3)],
'packagers': ['east-packager%d' % n for n in range(1, 3)],
},
)
self.inv_ops_west = self._create_inventory(
name='west production environment',
organization=self.org_ops,
created_by=self.user_sue,
groups_hosts_dict={
'bakers': ['west-baker%d' % n for n in range(1, 6)],
'slicers': ['west-slicer%d' % n for n in range(1, 4)],
'packagers': ['west-packager%d' % n for n in range(1, 3)],
},
)
# Operations is divided into teams to work on the east/west servers.
# Greg and Holly work on east, Greg and iris work on west.
self.team_ops_east = self.org_ops.teams.create(
name='easterners',
created_by=self.user_sue)
self.team_ops_east.projects.add(self.proj_prod)
self.team_ops_east.projects.add(self.proj_prod_east)
self.team_ops_east.users.add(self.user_greg)
self.team_ops_east.users.add(self.user_holly)
self.team_ops_west = self.org_ops.teams.create(
name='westerners',
created_by=self.user_sue)
self.team_ops_west.projects.add(self.proj_prod)
self.team_ops_west.projects.add(self.proj_prod_west)
self.team_ops_west.users.add(self.user_greg)
self.team_ops_west.users.add(self.user_iris)
# The south team is no longer active having been folded into the east team
self.team_ops_south = self.org_ops.teams.create(
name='southerners',
created_by=self.user_sue,
active=False,
)
self.team_ops_south.projects.add(self.proj_prod)
self.team_ops_south.users.add(self.user_greg)
# The north team is going to be deleted
self.team_ops_north = self.org_ops.teams.create(
name='northerners',
created_by=self.user_sue,
)
self.team_ops_north.projects.add(self.proj_prod)
self.team_ops_north.users.add(self.user_greg)
# The testers team are interns that can only check playbooks but can't
# run them
self.team_ops_testers = self.org_ops.teams.create(
name='testers',
created_by=self.user_sue,
)
self.team_ops_testers.projects.add(self.proj_prod)
self.team_ops_testers.users.add(self.user_randall)
self.team_ops_testers.users.add(self.user_billybob)
# Each user has his/her own set of credentials.
from awx.main.tests.tasks import (TEST_SSH_KEY_DATA,
TEST_SSH_KEY_DATA_LOCKED,
TEST_SSH_KEY_DATA_UNLOCK)
self.cred_sue = self.user_sue.credentials.create(
username='sue',
password=TEST_SSH_KEY_DATA,
created_by=self.user_sue,
)
self.cred_bob = self.user_bob.credentials.create(
username='bob',
password='ASK',
created_by=self.user_sue,
)
self.cred_chuck = self.user_chuck.credentials.create(
username='chuck',
ssh_key_data=TEST_SSH_KEY_DATA,
created_by=self.user_sue,
)
self.cred_doug = self.user_doug.credentials.create(
username='doug',
password='doug doesn\'t mind his password being saved. this '
'is why we dont\'t let doug actually run jobs.',
created_by=self.user_sue,
)
self.cred_eve = self.user_eve.credentials.create(
username='eve',
password='ASK',
sudo_username='root',
sudo_password='ASK',
created_by=self.user_sue,
)
self.cred_frank = self.user_frank.credentials.create(
username='frank',
password='fr@nk the t@nk',
created_by=self.user_sue,
)
self.cred_greg = self.user_greg.credentials.create(
username='greg',
ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
ssh_key_unlock='ASK',
created_by=self.user_sue,
)
self.cred_holly = self.user_holly.credentials.create(
username='holly',
password='holly rocks',
created_by=self.user_sue,
)
self.cred_iris = self.user_iris.credentials.create(
username='iris',
password='ASK',
created_by=self.user_sue,
)
# Each operations team also has shared credentials they can use.
self.cred_ops_east = self.team_ops_east.credentials.create(
username='east',
ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
ssh_key_unlock=TEST_SSH_KEY_DATA_UNLOCK,
created_by = self.user_sue,
)
self.cred_ops_west = self.team_ops_west.credentials.create(
username='west',
password='Heading270',
created_by = self.user_sue,
)
self.cred_ops_south = self.team_ops_south.credentials.create(
username='south',
password='Heading180',
created_by = self.user_sue,
)
self.cred_ops_north = self.team_ops_north.credentials.create(
username='north',
password='Heading0',
created_by = self.user_sue,
)
self.cred_ops_test = self.team_ops_testers.credentials.create(
username='testers',
password='HeadingNone',
created_by = self.user_sue,
)
self.ops_testers_permission = Permission.objects.create(
inventory = self.inv_ops_west,
project = self.proj_prod,
team = self.team_ops_testers,
permission_type = PERM_INVENTORY_CHECK,
created_by = self.user_sue
)
self.doug_check_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_doug,
permission_type = PERM_INVENTORY_CHECK,
created_by = self.user_sue
)
self.juan_deploy_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_juan,
permission_type = PERM_INVENTORY_DEPLOY,
created_by = self.user_sue
)
self.hannibal_create_permission = Permission.objects.create(
inventory = self.inv_eng,
project = self.proj_dev,
user = self.user_hannibal,
permission_type = PERM_JOBTEMPLATE_CREATE,
created_by = self.user_sue
)
# FIXME: Define explicit permissions for tests.
# other django user is on the project team and can deploy
#self.permission1 = Permission.objects.create(
# inventory = self.inventory,
# project = self.project,
# team = self.team,
# permission_type = PERM_INVENTORY_DEPLOY,
# created_by = self.normal_django_user
#)
# individual permission granted to other2 user, can run check mode
#self.permission2 = Permission.objects.create(
# inventory = self.inventory,
# project = self.project,
# user = self.other2_django_user,
# permission_type = PERM_INVENTORY_CHECK,
# created_by = self.normal_django_user
#)
# Engineering has job templates to check/run the dev project onto
# their own inventory.
self.jt_eng_check = JobTemplate.objects.create(
name='eng-dev-check',
job_type='check',
inventory= self.inv_eng,
project=self.proj_dev,
playbook=self.proj_dev.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_eng_check = self.jt_eng_check.create_job(
# created_by=self.user_sue,
# credential=self.cred_doug,
# )
self.jt_eng_run = JobTemplate.objects.create(
name='eng-dev-run',
job_type='run',
inventory= self.inv_eng,
project=self.proj_dev,
playbook=self.proj_dev.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_eng_run = self.jt_eng_run.create_job(
# created_by=self.user_sue,
# credential=self.cred_chuck,
# )
# Support has job templates to check/run the test project onto
# their own inventory.
self.jt_sup_check = JobTemplate.objects.create(
name='sup-test-check',
job_type='check',
inventory= self.inv_sup,
project=self.proj_test,
playbook=self.proj_test.playbooks[0],
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_sup_check = self.jt_sup_check.create_job(
# created_by=self.user_sue,
# credential=self.cred_frank,
# )
self.jt_sup_run = JobTemplate.objects.create(
name='sup-test-run',
job_type='run',
inventory= self.inv_sup,
project=self.proj_test,
playbook=self.proj_test.playbooks[0],
host_config_key=uuid.uuid4().hex,
credential=self.cred_eve,
created_by=self.user_sue,
)
# self.job_sup_run = self.jt_sup_run.create_job(
# created_by=self.user_sue,
# )
# Operations has job templates to check/run the prod project onto
# both east and west inventories, by default using the team credential.
self.jt_ops_east_check = JobTemplate.objects.create(
name='ops-east-prod-check',
job_type='check',
inventory= self.inv_ops_east,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_east,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_east_check = self.jt_ops_east_check.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_east_run = JobTemplate.objects.create(
name='ops-east-prod-run',
job_type='run',
inventory= self.inv_ops_east,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_east,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_east_run = self.jt_ops_east_run.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_west_check = JobTemplate.objects.create(
name='ops-west-prod-check',
job_type='check',
inventory= self.inv_ops_west,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_west,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_west_check = self.jt_ops_west_check.create_job(
# created_by=self.user_sue,
# )
self.jt_ops_west_run = JobTemplate.objects.create(
name='ops-west-prod-run',
job_type='run',
inventory= self.inv_ops_west,
project=self.proj_prod,
playbook=self.proj_prod.playbooks[0],
credential=self.cred_ops_west,
host_config_key=uuid.uuid4().hex,
created_by=self.user_sue,
)
# self.job_ops_west_run = self.jt_ops_west_run.create_job(
# created_by=self.user_sue,
# )
def setUp(self):
super(BaseJobTestMixin, self).setUp()
self.start_redis()
self.setup_instances()
self.populate()
self.start_queue()
def tearDown(self):
super(BaseJobTestMixin, self).tearDown()
self.stop_redis()
self.terminate_queue()
class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
JOB_TEMPLATE_FIELDS = ('id', 'type', 'url', 'related', 'summary_fields',

View File

@ -2,14 +2,13 @@
import json
# Django
import django.test
from django.core.urlresolvers import reverse
# AWX
from awx.main.models import * # noqa
from awx.main.tests.base import BaseTest
from awx.main.tests.base import BaseTest, QueueStartStopTestMixin
__all__ = ['SurveyPasswordTest']
__all__ = ['SurveyPasswordRedactedTest']
PASSWORD="5m/h"
ENCRYPTED_STR='$encrypted$'
@ -91,32 +90,32 @@ TEST_SINGLE_PASSWORDS = [
{
'description': 'Single instance with a . after',
'text' : 'See spot. See spot run. See spot run %s. That is a fast run.' % PASSWORD,
'passwords': [ PASSWORD ],
'passwords': [PASSWORD],
'occurances': 1,
},
{
'description': 'Single instance with , after',
'text': 'Spot goes %s, at a fast pace' % PASSWORD,
'passwords': [ PASSWORD ],
'passwords': [PASSWORD],
'occurances': 1,
},
{
'description': 'Single instance with a space after',
'text': 'Is %s very fast?' % PASSWORD,
'passwords': [ PASSWORD ],
'passwords': [PASSWORD],
'occurances': 1,
},
{
'description': 'Many instances, also with newline',
'text': 'I think %s is very very fast. If I ran %s for 4 hours how many hours would I run?.\nTrick question. %s for 4 hours would result in running for 4 hours' % (PASSWORD, PASSWORD, PASSWORD),
'passwords': [ PASSWORD ],
'passwords': [PASSWORD],
'occurances': 3,
},
]
passwd = 'my!@#$%^pass&*()_+'
TEST_SINGLE_PASSWORDS.append({
'description': 'password includes characters not in a-z 0-9 range',
'passwords': [ passwd ],
'passwords': [passwd],
'text': 'Text is fun yeah with passwords %s.' % passwd,
'occurances': 1
})
@ -142,7 +141,7 @@ TESTS = {
}
}
class SurveyPasswordBaseTest(BaseTest):
class SurveyPasswordBaseTest(BaseTest, QueueStartStopTestMixin):
def setUp(self):
super(SurveyPasswordBaseTest, self).setUp()
self.setup_instances()
@ -155,11 +154,41 @@ class SurveyPasswordBaseTest(BaseTest):
self.check_found(response['content'], ENCRYPTED_STR, test['occurances'], test['description'])
def _get_url_job_stdout(self, job):
job_stdout_url = reverse('api:job_stdout', args=(job.pk,))
return self.get(job_stdout_url, expect=200, auth=self.get_super_credentials(), accept='application/json')
# TODO: A more complete test would ensure that the variable value isn't found
def check_extra_vars_redacted(self, test, response):
self.assertIsNotNone(response)
# Ensure that all extra_vars of type password have the value '$encrypted$'
vars = []
for question in test['survey']['spec']:
if question['type'] == 'password':
vars.append(question['variable'])
class SurveyPasswordTest(SurveyPasswordBaseTest):
extra_vars = json.loads(response['extra_vars'])
for var in vars:
self.assertIn(var, extra_vars, 'Variable "%s" should exist in "%s"' % (var, extra_vars))
self.assertEqual(extra_vars[var], ENCRYPTED_STR)
def _get_url_job_stdout(self, job):
url = reverse('api:job_stdout', args=(job.pk,))
return self.get(url, expect=200, auth=self.get_super_credentials(), accept='application/json')
def _get_url_job_details(self, job):
url = reverse('api:job_detail', args=(job.pk,))
return self.get(url, expect=200, auth=self.get_super_credentials(), accept='application/json')
class SurveyPasswordRedactedTest(SurveyPasswordBaseTest):
'''
Transpose TEST[]['tests'] to the below format. A more flat format."
[
{
'text': '...',
'description': '...',
...,
'job': '...',
'survey': '...'
},
]
'''
def setup_test(self, test_name):
blueprint = TESTS[test_name]
self.tests[test_name] = []
@ -179,25 +208,30 @@ class SurveyPasswordTest(SurveyPasswordBaseTest):
job.result_stdout_text = test['text']
job.save()
test['job'] = job
test['survey'] = blueprint['survey']
self.tests[test_name].append(test)
def setUp(self):
super(SurveyPasswordTest, self).setUp()
super(SurveyPasswordRedactedTest, self).setUp()
self.tests = {}
self.setup_test('simple')
self.setup_test('complex')
# should redact single variable survey
def test_survey_password_redact_simple_survey(self):
def test_redact_stdout_simple_survey(self):
for test in self.tests['simple']:
response = self._get_url_job_stdout(test['job'])
self.check_passwords_redacted(test, response)
# should redact multiple variables survey
def test_survey_password_redact_complex_survey(self):
def test_redact_stdout_complex_survey(self):
for test in self.tests['complex']:
response = self._get_url_job_stdout(test['job'])
self.check_passwords_redacted(test, response)
# should redact values in extra_vars
def test_redact_job_extra_vars(self):
for test in self.tests['simple']:
response = self._get_url_job_details(test['job'])
self.check_extra_vars_redacted(test, response)

View File

@ -13,7 +13,6 @@ import unittest
# Django
from django.conf import settings
from django.test.utils import override_settings
from django.utils.timezone import now
# Django-CRUM

View File

@ -75,4 +75,4 @@ class UnifiedJobStdoutRedactedTests(BaseLiveServerTest, QueueStartStopTestMixin)
self._test_redaction_enabled('html')
def test_redaction_enabled_txt(self):
self._test_redaction_enabled('txt')
self._test_redaction_enabled('txt')

View File

@ -45,6 +45,17 @@ import {UsersList, UsersAdd, UsersEdit} from 'tower/controllers/Users';
import {TeamsList, TeamsAdd, TeamsEdit} from 'tower/controllers/Teams';
import {PermissionsAdd, PermissionsList, PermissionsEdit} from 'tower/controllers/Permissions';
import 'tower/shared/RestServices';
import 'tower/shared/api-loader';
import 'tower/shared/form-generator';
import 'tower/shared/Modal';
import 'tower/shared/prompt-dialog';
import 'tower/shared/directives';
import 'tower/shared/filters';
import 'tower/shared/InventoryTree';
import 'tower/shared/Timer';
import 'tower/shared/Socket';
var tower = angular.module('Tower', [

View File

@ -422,6 +422,7 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
$scope.removeSurveySaved = $scope.$on('SurveySaved', function() {
Wait('stop');
$scope.survey_exists = true;
$scope.invalid_survey = false;
$('#job_templates_survey_enabled_chbox').attr('checked', true);
$('#job_templates_delete_survey_btn').show();
$('#job_templates_edit_survey_btn').show();
@ -451,6 +452,7 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
// Save
$scope.formSave = function () {
$scope.invalid_survey = false;
if ($scope.removeGatherFormFields) {
$scope.removeGatherFormFields();
}
@ -525,7 +527,14 @@ export function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $
});
if($scope.survey_enabled === true && $scope.survey_exists!==true){
$scope.$emit("PromptForSurvey");
// $scope.$emit("PromptForSurvey");
// The original design for this was a pop up that would prompt the user if they wanted to create a
// survey, because they had enabled one but not created it yet. We switched this for now so that
// an error message would be displayed by the survey buttons that tells the user to add a survey or disabled
// surveys.
$scope.invalid_survey = true;
return;
} else {
$scope.$emit("GatherFormFields");
}
@ -837,6 +846,7 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
$scope.removeSurveySaved = $scope.$on('SurveySaved', function() {
Wait('stop');
$scope.survey_exists = true;
$scope.invalid_survey = false;
$('#job_templates_survey_enabled_chbox').attr('checked', true);
$('#job_templates_delete_survey_btn').show();
$('#job_templates_edit_survey_btn').show();
@ -905,7 +915,7 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
// Save changes to the parent
$scope.formSave = function () {
$scope.invalid_survey = false;
if ($scope.removeGatherFormFields) {
$scope.removeGatherFormFields();
}
@ -965,7 +975,14 @@ export function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log,
});
if($scope.survey_enabled === true && $scope.survey_exists!==true){
$scope.$emit("PromptForSurvey");
// $scope.$emit("PromptForSurvey");
// The original design for this was a pop up that would prompt the user if they wanted to create a
// survey, because they had enabled one but not created it yet. We switched this for now so that
// an error message would be displayed by the survey buttons that tells the user to add a survey or disabled
// surveys.
$scope.invalid_survey = true;
return;
} else {
$scope.$emit("GatherFormFields");
}

View File

@ -202,19 +202,25 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
}
$scope.teamLoadedRemove = $scope.$on('teamLoaded', function () {
CheckAccess({ scope: $scope });
Rest.setUrl($scope.organization_url);
Rest.get()
.success(function (data) {
$scope.organization_name = data.name;
master.organization_name = data.name;
Wait('stop');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve organization: ' +
$scope.orgnization_url + '. GET status: ' + status });
});
for (var set in relatedSets) {
$scope.search(relatedSets[set].iterator);
if ($scope.organization_url) {
Rest.setUrl($scope.organization_url);
Rest.get()
.success(function (data) {
$scope.organization_name = data.name;
master.organization_name = data.name;
Wait('stop');
})
.error(function (data, status) {
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to retrieve organization: ' +
$scope.orgnization_url + '. GET status: ' + status });
});
for (var set in relatedSets) {
$scope.search(relatedSets[set].iterator);
}
} else {
$scope.organization_name = "";
master.organization_name = "";
Wait('stop');
}
});
@ -387,4 +393,4 @@ export function TeamsEdit($scope, $rootScope, $compile, $location, $log, $routeP
TeamsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'TeamForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit',
'ReturnToCaller', 'ClearScope', 'LookUpInit', 'Prompt', 'GetBasePath', 'CheckAccess', 'OrganizationList', 'Wait', 'Stream'
];
];

View File

@ -273,19 +273,9 @@ export default
column: 2,
control: '<button type="button" class="btn btn-sm btn-primary" id="job_templates_create_survey_btn" ng-show="survey_enabled" ng-click="addSurvey()"><i class="fa fa-pencil"></i> Create Survey</button>'+
'<button style="display:none;" type="button" class="btn btn-sm btn-primary" id="job_templates_edit_survey_btn" ng-show="survey_enabled" ng-click="editSurvey()"><i class="fa fa-pencil"></i> Edit Survey</button>'+
'<button style="display:none;margin-left:5px" type="button" class="btn btn-sm btn-primary" id="job_templates_delete_survey_btn" ng-show="survey_enabled" ng-click="deleteSurvey()"><i class="fa fa-trash-o"></i> Delete Survey</button>'
// label: 'Create Survey',
// type: 'text',
// addRequired: false,
// editRequired: false,
// // readonly: true,
// // ngShow: "survey_enabled",
// column: 2,
// awPopOver: "survey_help",
// awPopOverWatch: "survey_help",
// dataPlacement: 'right',
// dataTitle: 'Provisioning Callback URL',
// dataContainer: "body"
'<button style="display:none;margin-left:5px" type="button" class="btn btn-sm btn-primary" id="job_templates_delete_survey_btn" ng-show="survey_enabled" ng-click="deleteSurvey()"><i class="fa fa-trash-o"></i> Delete Survey</button>'+
// '<div class="error ng-hide" id="job-template-survey-error" ng-show="survey_enabled === true && survey_exists!==true">A survey is enabled but it does not exist. Create a survey or disable the survey. </div>'
'<div class="error ng-hide" id="job-template-survey-error" ng-show="invalid_survey">A survey is enabled but it does not exist. Create a survey or uncheck the Enable Survey box to disable the survey. </div>'
},
allow_callbacks: {
label: 'Allow Provisioning Callbacks',

View File

@ -106,13 +106,13 @@ export default
control:'<div class="row">'+
'<div class="col-xs-6">'+
'<label for="text_min"><span class="label-text">Minimum Length</span></label><input id="text_min" type="number" name="text_min" ng-model="text_min" min=0 aw-min="0" aw-max="text_max" class="form-control" integer />'+
'<div class="error" ng-show="survey_question_form.text_min.$error.integer || survey_question_form.text_min.$error.number">The minimum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.text_min.$error.integer || survey_question_form.text_min.$error.number">The minimum length you entered is not a valid number. Please enter a whole number.</div>'+
'<div class="error" ng-show="survey_question_form.text_min.$error.awMax">The minimium length is too high. Please enter a lower number.</div>'+
'<div class="error" ng-show="survey_question_form.text_min.$error.awMin">The minimum length is too low. Please enter a positive number.</div>'+
'</div>'+
'<div class="col-xs-6">'+
'<label for="text_max"><span class="label-text">Maximum Length</span></label><input id="text_max" type="number" name="text_max" ng-model="text_max" aw-min="text_min || 0" min=0 class="form-control" integer >'+
'<div class="error" ng-show="survey_question_form.text_max.$error.integer || survey_question_form.text_max.$error.number">The maximum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.text_max.$error.integer || survey_question_form.text_max.$error.number">The maximum length you entered is not a valid number. Please enter a whole nnumber.</div>'+
'<div class="error" ng-show="survey_question_form.text_max.$error.awMin">The maximum length is too low. Please enter a number larger than the minimum length you set.</div>'+
'</div>'+
'</div>',
@ -127,13 +127,13 @@ export default
control:'<div class="row">'+
'<div class="col-xs-6">'+
'<label for="textarea_min"><span class="label-text">Minimum Length</span></label><input id="textarea_min" type="number" name="textarea_min" ng-model="textarea_min" min=0 aw-min="0" aw-max="textarea_max" class="form-control" integer />'+
'<div class="error" ng-show="survey_question_form.textarea_min.$error.integer || survey_question_form.textarea_min.$error.number">The minimum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.textarea_min.$error.integer || survey_question_form.textarea_min.$error.number">The minimum length you entered is not a valid number. Please enter a whole number.</div>'+
'<div class="error" ng-show="survey_question_form.textarea_min.$error.awMax">The minimium length is too high. Please enter a lower number.</div>'+
'<div class="error" ng-show="survey_question_form.textarea_min.$error.awMin">The minimum length is too low. Please enter a positive number.</div>'+
'</div>'+
'<div class="col-xs-6">'+
'<label for="textarea_max"><span class="label-text">Maximum Length</span></label><input id="textarea_max" type="number" name="textarea_max" ng-model="textarea_max" aw-min="textarea_min || 0" min=0 class="form-control" integer >'+
'<div class="error" ng-show="survey_question_form.textarea_max.$error.integer || survey_question_form.textarea_max.$error.number">The maximum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.textarea_max.$error.integer || survey_question_form.textarea_max.$error.number">The maximum length you entered is not a valid number. Please enter a whole number.</div>'+
'<div class="error" ng-show="survey_question_form.textarea_max.$error.awMin">The maximum length is too low. Please enter a number larger than the minimum length you set.</div>'+
'</div>'+
'</div>',
@ -148,13 +148,13 @@ export default
control:'<div class="row">'+
'<div class="col-xs-6">'+
'<label for="password_min"><span class="label-text">Minimum Length</span></label><input id="password_min" type="number" name="password_min" ng-model="password_min" min=0 aw-min="0" aw-max="password_max" class="form-control" integer />'+
'<div class="error" ng-show="survey_question_form.password_min.$error.integer || survey_question_form.password_min.$error.number">The minimum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.password_min.$error.integer || survey_question_form.password_min.$error.number">The minimum length you entered is not a valid number. Please enter a whole number.</div>'+
'<div class="error" ng-show="survey_question_form.password_min.$error.awMax">The minimium length is too high. Please enter a lower number.</div>'+
'<div class="error" ng-show="survey_question_form.password_min.$error.awMin">The minimum length is too low. Please enter a positive number.</div>'+
'</div>'+
'<div class="col-xs-6">'+
'<label for="password_max"><span class="label-text">Maximum Length</span></label><input id="password_max" type="number" name="password_max" ng-model="password_max" aw-min="password_min || 0" min=0 class="form-control" integer >'+
'<div class="error" ng-show="survey_question_form.password_max.$error.integer || survey_question_form.password_max.$error.number">The maximum length you entered is not a number. Please enter a number.</div>'+
'<div class="error" ng-show="survey_question_form.password_max.$error.integer || survey_question_form.password_max.$error.number">The maximum length you entered is not a valid number. Please enter a whole number.</div>'+
'<div class="error" ng-show="survey_question_form.password_max.$error.awMin">The maximum length is too low. Please enter a number larger than the minimum length you set.</div>'+
'</div>'+
'</div>',

View File

@ -151,9 +151,22 @@ export default
e = angular.element(document.getElementById('prompt_for_days_form'));
scope.prompt_for_days_form.days_to_keep.$setViewValue(30);
$compile(e)(scope);
$('#prompt-for-days-launch').attr("ng-disabled", 'prompt_for_days_form.$invalid');
e = angular.element(document.getElementById('prompt-for-days-launch'));
$compile(e)(scope);
// this is a work-around for getting awMax to work (without
// clearing out the form)
scope.$watch('days_to_keep', function(newVal) { // oldVal, scope) { // unused params get caught by jshint
if (!newVal) {
$('#prompt-for-days-launch').prop("disabled", true);
} else if (isNaN(newVal)) {
$('#prompt-for-days-launch').prop("disabled", true);
} else if (newVal <= 0) {
$('#prompt-for-days-launch').prop("disabled", true);
} else if (newVal > 9999) {
$('#prompt-for-days-launch').prop("disabled", true);
} else {
$('#prompt-for-days-launch').prop("disabled", false);
}
});
},
buttons: [{
"label": "Cancel",

View File

@ -39,7 +39,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
Rest.get()
.success(function (data) {
if(!Empty(data.extra_vars)){
data.extra_vars = ToJSON('json', data.extra_vars, false);
data.extra_vars = ToJSON('yaml', data.extra_vars, false);
$.each(data.extra_vars, function(key,value){
job_launch_data.extra_vars[key] = value;
});
@ -77,7 +77,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
for (var i=0; i < scope.survey_questions.length; i++){
var fld = scope.survey_questions[i].variable;
// grab all survey questions that have answers
if(scope[fld]) {
if(scope.survey_questions[i].required || (scope.survey_questions[i].required === false && scope[fld].toString()!=="")) {
job_launch_data.extra_vars[fld] = scope[fld];
}
// for optional text and text-areas, submit a blank string if min length is 0
@ -544,7 +544,7 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
}
if(question.type === "textarea"){
scope[question.variable] = question.default || question.default_textarea;
scope[question.variable] = (question.default_textarea) ? question.default_textarea : (question.default) ? question.default : "";
minlength = (!Empty(question.min)) ? Number(question.min) : "";
maxlength =(!Empty(question.max)) ? Number(question.max) : "" ;
html+='<textarea id="'+question.variable+'" name="'+question.variable+'" ng-model="'+question.variable+'" '+

View File

@ -756,6 +756,7 @@ angular.module('SurveyHelper', [ 'Utilities', 'RestServices', 'SchedulesHelper',
scope.default_float = "";
scope.default_int = "";
scope.default_textarea = "";
scope.default_password = "" ;
scope.choices = "";
scope.text_min = "";
scope.text_max = "" ;

View File

@ -10,9 +10,10 @@
*
*/
import Utilities from './Utilities';
angular.module('AuthService', ['ngCookies', 'Utilities'])
export default
angular.module('AuthService', ['ngCookies', Utilities.name])
.factory('Authorization', ['$http', '$rootScope', '$location', '$cookieStore', 'GetBasePath', 'Store',
function ($http, $rootScope, $location, $cookieStore, GetBasePath, Store) {
@ -155,4 +156,4 @@ angular.module('AuthService', ['ngCookies', 'Utilities'])
}
};
}
]);
]);

View File

@ -13,7 +13,7 @@
*/
export default
angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'PromptDialog'])
.factory('SortNodes', [
@ -603,4 +603,4 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
}
};
}
]);
]);

View File

@ -14,7 +14,7 @@
*/
export default
angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
/**

View File

@ -51,9 +51,10 @@
*
*/
import AuthService from './AuthService';
angular.module('RestServices', ['ngCookies', 'AuthService'])
export default
angular.module('RestServices', ['ngCookies', AuthService.name])
.factory('Rest', ['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
function ($http, $rootScope, $cookieStore, $q, Authorization) {
return {
@ -267,4 +268,4 @@ angular.module('RestServices', ['ngCookies', 'AuthService'])
}
};
}
]);
]);

View File

@ -19,6 +19,7 @@
* @methodOf lib.ansible.function:Socket
* @description
*/
export default
angular.module('SocketIO', ['AuthService', 'Utilities'])
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Store', function ($rootScope, $location, $log, Authorization, Store) {
@ -71,7 +72,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
$log.debug('Socket connecting to: ' + url);
self.scope.socket_url = url;
self.socket = io.connect(url, {
query: "Token="+token,
query: "Token="+token,
headers:
{
'Authorization': 'Token ' + token, // i don't think these are actually inserted into the header--jt
@ -115,6 +116,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
});
self.socket.on('error', function(reason) {
var r = reason || 'connection refused by host';
console.error(reason)
$log.debug('Socket error: ' + r);
$log.error('Socket error: ' + r);
self.scope.$apply(function() {
@ -156,7 +158,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
if (self.socket.socket.connected) {
self.scope.socketStatus = 'ok';
}
else if (self.socket.socket.connecting || self.socket.socket.reconnecting) {
else if (self.socket.socket.connecting || self.socket.reconnecting) {
self.scope.socketStatus = 'connecting';
}
else {

View File

@ -18,6 +18,7 @@
* @methodOf lib.ansible.function:Timer
* @description
*/
export default
angular.module('TimerService', ['ngCookies', 'Utilities'])
.factory('Timer', ['$rootScope', '$cookieStore', '$location', 'GetBasePath', 'Empty',
function ($rootScope, $cookieStore) {
@ -65,4 +66,4 @@ angular.module('TimerService', ['ngCookies', 'Utilities'])
}
};
}
]);
]);

View File

@ -14,6 +14,7 @@
export default
angular.module('Utilities', ['RestServices', 'Utilities'])
/**

View File

@ -19,6 +19,7 @@
export default
angular.module('ApiLoader', ['Utilities'])
.factory('LoadBasePaths', ['$http', '$rootScope', 'Store', 'ProcessErrors',
@ -72,4 +73,4 @@ angular.module('ApiLoader', ['Utilities'])
return $rootScope.defaultUrls[set];
};
}
]);
]);

View File

@ -13,6 +13,9 @@
/* global chkPass:false */
import {chkPass} from './pwdmeter';
export default
angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'JobsHelper'])
// awpassmatch: Add to password_confirm field. Will test if value
@ -534,15 +537,23 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
$(element).one('click', showPopover);
$(element).on('shown.bs.popover', function() {
function bindPopoverDismiss() {
$('body').one('click.popover' + id_to_close, function(e) {
if ($(e.target).parents(id_to_close).length === 0) {
// case: you clicked to open the popover and then you
// clicked outside of it...hide it.
$(element).popover('hide');
} else {
// case: you clicked to open the popover and then you
// clicked inside the popover
bindPopoverDismiss();
}
});
}
$(element).on('shown.bs.popover', function() {
bindPopoverDismiss();
$(document).on('keydown.popover', dismissOnEsc);
});
$(element).on('hidden.bs.popover', function() {

View File

@ -11,6 +11,7 @@
export default
angular.module('AWFilters', [])
//
@ -91,4 +92,4 @@ angular.module('AWFilters', [])
}
return input;
};
}]);
}]);

View File

@ -132,9 +132,11 @@
* Applying CodeMirror to the text area is handled by ParseTypeChange() found in helpers/Parse.js. Within the controller will be a call to ParseTypeChange that creates the CodeMirror object and sets up the required $scope methods for handles getting, settting and type conversion.
*/
import GeneratorHelpers from './generator-helpers';
import ListGenerator from './list-generator';
angular.module('FormGenerator', ['GeneratorHelpers', 'Utilities', 'ListGenerator'])
export default
angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', ListGenerator.name])
.factory('GenerateForm', ['$rootScope', '$location', '$compile', 'GenerateList', 'SearchWidget', 'PaginateWidget', 'Attr',
'Icon', 'Column', 'NavigationLink', 'HelpCollapse', 'Button', 'DropDown', 'Empty', 'SelectIcon', 'Store',

View File

@ -12,7 +12,7 @@
*/
export default
angular.module('GeneratorHelpers', [])
.factory('Attr', function () {

View File

@ -97,7 +97,7 @@
*/
export default
angular.module('ListGenerator', ['GeneratorHelpers'])
.factory('GenerateList', ['$location', '$compile', '$rootScope', 'SearchWidget', 'PaginateWidget', 'Attr', 'Icon',
'Column', 'DropDown', 'NavigationLink', 'Button', 'SelectIcon', 'Breadcrumbs',

View File

@ -25,6 +25,8 @@
* @methodOf lib.ansible.function:prompt-dialog
* @description discuss difference b/t this and other modals
*/
export default
angular.module('PromptDialog', ['Utilities'])
.factory('Prompt', ['$sce',
function ($sce) {

View File

@ -42,7 +42,7 @@ String.prototype.strReverse = function () {
var nScore = 0;
function chkPass(pwd) {
export function chkPass(pwd) {
// Simultaneous variable declaration and value assignment aren't supported in IE apparently
// so I'm forced to assign the same value individually per var to support a crappy browser *sigh*
var nLength = 0,
@ -324,4 +324,4 @@ function chkPass(pwd) {
}
return nScore;
}
}

View File

@ -0,0 +1,9 @@
import conversionService from './conversions.service'
import smartStatusGraph from './smart-status.directive'
import controller from './smart-status.controller'
export default
angular.module('systemStatus', [])
.service('conversions', conversionService)
.directive('smartStatusGraph', smartStatusGraph)
.controller('smartStatusLoad', controller);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
{
"name": "jquery-ui",
"version": "1.11.3",
"main": [
"jquery-ui.js"
],
"ignore": [],
"dependencies": {
"jquery": ">=1.6"
},
"homepage": "https://github.com/components/jqueryui",
"_release": "1.11.3",
"_resolution": {
"type": "version",
"tag": "1.11.3",
"commit": "7e2d6bec1c729925d9ad7c0c9ab4b561174efa99"
},
"_source": "git://github.com/components/jqueryui.git",
"_target": "~1.11.1",
"_originalSource": "jquery-ui"
}

View File

@ -0,0 +1,4 @@
components
composer.lock
vendor
.DS_Store

View File

@ -0,0 +1,284 @@
Authors ordered by first contribution
A list of current team members is available at http://jqueryui.com/about
Paul Bakaus <paul.bakaus@gmail.com>
Richard Worth <rdworth@gmail.com>
Yehuda Katz <wycats@gmail.com>
Sean Catchpole <sean@sunsean.com>
John Resig <jeresig@gmail.com>
Tane Piper <piper.tane@gmail.com>
Dmitri Gaskin <dmitrig01@gmail.com>
Klaus Hartl <klaus.hartl@gmail.com>
Stefan Petre <stefan.petre@gmail.com>
Gilles van den Hoven <gilles@webunity.nl>
Micheil Bryan Smith <micheil@brandedcode.com>
Jörn Zaefferer <joern.zaefferer@gmail.com>
Marc Grabanski <m@marcgrabanski.com>
Keith Wood <kbwood@iinet.com.au>
Brandon Aaron <brandon.aaron@gmail.com>
Scott González <scott.gonzalez@gmail.com>
Eduardo Lundgren <eduardolundgren@gmail.com>
Aaron Eisenberger <aaronchi@gmail.com>
Joan Piedra <theneojp@gmail.com>
Bruno Basto <b.basto@gmail.com>
Remy Sharp <remy@leftlogic.com>
Bohdan Ganicky <bohdan.ganicky@gmail.com>
David Bolter <david.bolter@gmail.com>
Chi Cheng <cloudream@gmail.com>
Ca-Phun Ung <pazu2k@gmail.com>
Ariel Flesler <aflesler@gmail.com>
Maggie Wachs <maggie@filamentgroup.com>
Scott Jehl <scott@scottjehl.com>
Todd Parker <todd@filamentgroup.com>
Andrew Powell <andrew@shellscape.org>
Brant Burnett <btburnett3@gmail.com>
Douglas Neiner <doug@dougneiner.com>
Paul Irish <paul.irish@gmail.com>
Ralph Whitbeck <ralph.whitbeck@gmail.com>
Thibault Duplessis <thibault.duplessis@gmail.com>
Dominique Vincent <dominique.vincent@toitl.com>
Jack Hsu <jack.hsu@gmail.com>
Adam Sontag <ajpiano@ajpiano.com>
Carl Fürstenberg <carl@excito.com>
Kevin Dalman <development@allpro.net>
Alberto Fernández Capel <afcapel@gmail.com>
Jacek Jędrzejewski (http://jacek.jedrzejewski.name)
Ting Kuei <ting@kuei.com>
Samuel Cormier-Iijima <sam@chide.it>
Jon Palmer <jonspalmer@gmail.com>
Ben Hollis <bhollis@amazon.com>
Justin MacCarthy <Justin@Rubystars.biz>
Eyal Kobrigo <kobrigo@hotmail.com>
Tiago Freire <tiago.freire@gmail.com>
Diego Tres <diegotres@gmail.com>
Holger Rüprich <holger@rueprich.de>
Ziling Zhao <zizhao@cisco.com>
Mike Alsup <malsup@gmail.com>
Robson Braga Araujo <robsonbraga@gmail.com>
Pierre-Henri Ausseil <ph.ausseil@gmail.com>
Christopher McCulloh <cmcculloh@gmail.com>
Andrew Newcomb <ext.github@preceptsoftware.co.uk>
Lim Chee Aun <cheeaun@gmail.com>
Jorge Barreiro <yortx.barry@gmail.com>
Daniel Steigerwald <daniel@steigerwald.cz>
John Firebaugh <john_firebaugh@bigfix.com>
John Enters <github@darkdark.net>
Andrey Kapitcyn <ru.m157y@gmail.com>
Dmitry Petrov <dpetroff@gmail.com>
Eric Hynds <eric@hynds.net>
Chairat Sunthornwiphat <pipo@sixhead.com>
Josh Varner <josh.varner@gmail.com>
Stéphane Raimbault <stephane.raimbault@gmail.com>
Jay Merrifield <fracmak@gmail.com>
J. Ryan Stinnett <jryans@gmail.com>
Peter Heiberg <peter@heiberg.se>
Alex Dovenmuehle <adovenmuehle@gmail.com>
Jamie Gegerson <git@jamiegegerson.com>
Raymond Schwartz <skeetergraphics@gmail.com>
Phillip Barnes <philbar@gmail.com>
Kyle Wilkinson <kai@wikyd.org>
Khaled AlHourani <me@khaledalhourani.com>
Marian Rudzynski <mr@impaled.org>
Jean-Francois Remy <jeff@melix.org>
Doug Blood
Filippo Cavallarin <filippo.cavallarin@codseq.it>
Heiko Henning <heiko@thehennings.ch>
Aliaksandr Rahalevich <saksmlz@gmail.com>
Mario Visic <mario@mariovisic.com>
Xavi Ramirez <xavi.rmz@gmail.com>
Max Schnur <max.schnur@gmail.com>
Saji Nediyanchath <saji89@gmail.com>
Corey Frang <gnarf37@gmail.com>
Aaron Peterson <aaronp123@yahoo.com>
Ivan Peters <ivan@ivanpeters.com>
Mohamed Cherif Bouchelaghem <cherifbouchelaghem@yahoo.fr>
Marcos Sousa <falecomigo@marcossousa.com>
Michael DellaNoce <mdellanoce@mailtrust.com>
George Marshall <echosx@gmail.com>
Tobias Brunner <tobias@strongswan.org>
Martin Solli <msolli@gmail.com>
David Petersen <public@petersendidit.com>
Dan Heberden <danheberden@gmail.com>
William Kevin Manire <williamkmanire@gmail.com>
Gilmore Davidson <gilmoreorless@gmail.com>
Michael Wu <michaelmwu@gmail.com>
Adam Parod <mystic414@gmail.com>
Guillaume Gautreau <guillaume+github@ghusse.com>
Marcel Toele <EleotleCram@gmail.com>
Dan Streetman <ddstreet@ieee.org>
Matt Hoskins <matt@nipltd.com>
Giovanni Giacobbi <giovanni@giacobbi.net>
Kyle Florence <kyle.florence@gmail.com>
Pavol Hluchý <lopo@losys.sk>
Hans Hillen <hans.hillen@gmail.com>
Mark Johnson <virgofx@live.com>
Trey Hunner <treyhunner@gmail.com>
Shane Whittet <whittet@gmail.com>
Edward A Faulkner <ef@alum.mit.edu>
Adam Baratz <adam@adambaratz.com>
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
Eike Send <eike.send@gmail.com>
Kris Borchers <kris.borchers@gmail.com>
Eddie Monge <eddie@eddiemonge.com>
Israel Tsadok <itsadok@gmail.com>
Carson McDonald <carson@ioncannon.net>
Jason Davies <jason@jasondavies.com>
Garrison Locke <gplocke@gmail.com>
David Murdoch <david@davidmurdoch.com>
Benjamin Scott Boyle <benjamins.boyle@gmail.com>
Jesse Baird <jebaird@gmail.com>
Jonathan Vingiano <jvingiano@gmail.com>
Dylan Just <dev@ephox.com>
Hiroshi Tomita <tomykaira@gmail.com>
Glenn Goodrich <glenn.goodrich@gmail.com>
Tarafder Ashek-E-Elahi <mail.ashek@gmail.com>
Ryan Neufeld <ryan@neufeldmail.com>
Marc Neuwirth <marc.neuwirth@gmail.com>
Philip Graham <philip.robert.graham@gmail.com>
Benjamin Sterling <benjamin.sterling@kenzomedia.com>
Wesley Walser <waw325@gmail.com>
Kouhei Sutou <kou@clear-code.com>
Karl Kirch <karlkrch@gmail.com>
Chris Kelly <ckdake@ckdake.com>
Jay Oster <jay@loyalize.com>
Alexander Polomoshnov <alex.polomoshnov@gmail.com>
David Leal <dgleal@gmail.com>
Igor Milla <igor.fsp.milla@gmail.com>
Dave Methvin <dave.methvin@gmail.com>
Florian Gutmann <f.gutmann@chronimo.com>
Marwan Al Jubeh <marwan.aljubeh@gmail.com>
Milan Broum <midlis@googlemail.com>
Sebastian Sauer <info@dynpages.de>
Gaëtan Muller <m.gaetan89@gmail.com>
William Griffiths <william@ycymro.com>
Stojce Slavkovski <stojce@gmail.com>
David Soms <david.soms@gmail.com>
David De Sloovere <david.desloovere@outlook.com>
Michael P. Jung <michael.jung@terreon.de>
Shannon Pekary <spekary@gmail.com>
Matthew Edward Hutton <meh@corefiling.co.uk>
James Khoury <james@jameskhoury.com>
Rob Loach <robloach@gmail.com>
Alberto Monteiro <betimbrasil@gmail.com>
Alex Rhea <alex.rhea@gmail.com>
Krzysztof Rosiński <rozwell69@gmail.com>
Ryan Olton <oltonr@gmail.com>
Genie <386@mail.com>
Rick Waldron <waldron.rick@gmail.com>
Ian Simpson <spoonlikesham@gmail.com>
Lev Kitsis <spam4lev@gmail.com>
TJ VanToll <tj.vantoll@gmail.com>
Justin Domnitz <jdomnitz@gmail.com>
Douglas Cerna <douglascerna@yahoo.com>
Bert ter Heide <bertjh@hotmail.com>
Jasvir Nagra <jasvir@gmail.com>
Yuriy Khabarov <13real008@gmail.com>
Harri Kilpiö <harri.kilpio@gmail.com>
Lado Lomidze <lado.lomidze@gmail.com>
Amir E. Aharoni <amir.aharoni@mail.huji.ac.il>
Simon Sattes <simon.sattes@gmail.com>
Jo Liss <joliss42@gmail.com>
Guntupalli Karunakar <karunakarg@yahoo.com>
Shahyar Ghobadpour <shahyar@gmail.com>
Lukasz Lipinski <uzza17@gmail.com>
Timo Tijhof <krinklemail@gmail.com>
Jason Moon <jmoon@socialcast.com>
Martin Frost <martinf55@hotmail.com>
Eneko Illarramendi <eneko@illarra.com>
EungJun Yi <semtlenori@gmail.com>
Courtland Allen <courtlandallen@gmail.com>
Viktar Varvanovich <non4eg@gmail.com>
Danny Trunk <dtrunk90@gmail.com>
Pavel Stetina <pavel.stetina@nangu.tv>
Michael Stay <metaweta@gmail.com>
Steven Roussey <sroussey@gmail.com>
Michael Hollis <hollis21@gmail.com>
Lee Rowlands <lee.rowlands@previousnext.com.au>
Timmy Willison <timmywillisn@gmail.com>
Karl Swedberg <kswedberg@gmail.com>
Baoju Yuan <the_guy_1987@hotmail.com>
Maciej Mroziński <maciej.k.mrozinski@gmail.com>
Luis Dalmolin <luis.nh@gmail.com>
Mark Aaron Shirley <maspwr@gmail.com>
Martin Hoch <martin@fidion.de>
Jiayi Yang <tr870829@gmail.com>
Philipp Benjamin Köppchen <xgxtpbk@gws.ms>
Sindre Sorhus <sindresorhus@gmail.com>
Bernhard Sirlinger <bernhard.sirlinger@tele2.de>
Jared A. Scheel <jared@jaredscheel.com>
Rafael Xavier de Souza <rxaviers@gmail.com>
John Chen <zhang.z.chen@intel.com>
Dale Kocian <dale.kocian@gmail.com>
Mike Sherov <mike.sherov@gmail.com>
Andrew Couch <andy@couchand.com>
Marc-Andre Lafortune <github@marc-andre.ca>
Nate Eagle <nate.eagle@teamaol.com>
David Souther <davidsouther@gmail.com>
Mathias Stenbom <mathias@stenbom.com>
Sergey Kartashov <ebishkek@yandex.ru>
Avinash R <nashpapa@gmail.com>
Ethan Romba <ethanromba@gmail.com>
Cory Gackenheimer <cory.gack@gmail.com>
Juan Pablo Kaniefsky <jpkaniefsky@gmail.com>
Roman Salnikov <bardt.dz@gmail.com>
Anika Henke <anika@selfthinker.org>
Samuel Bovée <samycookie2000@yahoo.fr>
Fabrício Matté <ult_combo@hotmail.com>
Viktor Kojouharov <vkojouharov@gmail.com>
Pawel Maruszczyk (http://hrabstwo.net)
Pavel Selitskas <p.selitskas@gmail.com>
Bjørn Johansen <post@bjornjohansen.no>
Matthieu Penant <thieum22@hotmail.com>
Dominic Barnes <dominic@dbarnes.info>
David Sullivan <david.sullivan@gmail.com>
Thomas Jaggi <thomas@responsive.ch>
Vahid Sohrabloo <vahid4134@gmail.com>
Travis Carden <travis.carden@gmail.com>
Bruno M. Custódio <bruno@brunomcustodio.com>
Nathanael Silverman <nathanael.silverman@gmail.com>
Christian Wenz <christian@wenz.org>
Steve Urmston <steve@urm.st>
Zaven Muradyan <megalivoithos@gmail.com>
Woody Gilk <shadowhand@deviantart.com>
Zbigniew Motyka <zbigniew.motyka@gmail.com>
Suhail Alkowaileet <xsoh.k7@gmail.com>
Toshi MARUYAMA <marutosijp2@yahoo.co.jp>
David Hansen <hansede@gmail.com>
Brian Grinstead <briangrinstead@gmail.com>
Christian Klammer <christian314159@gmail.com>
Steven Luscher <jquerycla@steveluscher.com>
Gan Eng Chin <engchin.gan@gmail.com>
Gabriel Schulhof <gabriel.schulhof@intel.com>
Alexander Schmitz <arschmitz@gmail.com>
Vilhjálmur Skúlason <vis@dmm.is>
Siebrand Mazeland <s.mazeland@xs4all.nl>
Mohsen Ekhtiari <mohsenekhtiari@yahoo.com>
Pere Orga <gotrunks@gmail.com>
Jasper de Groot <mail@ugomobi.com>
Stephane Deschamps <stephane.deschamps@gmail.com>
Jyoti Deka <dekajp@gmail.com>
Andrei Picus <office.nightcrawler@gmail.com>
Ondrej Novy <novy@ondrej.org>
Jacob McCutcheon <jacob.mccutcheon@gmail.com>
Monika Piotrowicz <monika.piotrowicz@gmail.com>
Imants Horsts <imants.horsts@inbox.lv>
Eric Dahl <eric.c.dahl@gmail.com>
Dave Stein <dave@behance.com>
Dylan Barrell <dylan@barrell.com>
Daniel DeGroff <djdegroff@gmail.com>
Michael Wiencek <mwtuea@gmail.com>
Thomas Meyer <meyertee@gmail.com>
Ruslan Yakhyaev <ruslan@ruslan.io>
Brian J. Dowling <bjd-dev@simplicity.net>
Ben Higgins <ben@extrahop.com>
Yermo Lamers <yml@yml.com>
Patrick Stapleton <github@gdi2290.com>
Trisha Crowley <trisha.crowley@gmail.com>
Usman Akeju <akeju00+github@gmail.com>
Rodrigo Menezes <rod333@gmail.com>
Jacques Perrault <jacques_perrault@us.ibm.com>
Frederik Elvhage <frederik.elvhage@googlemail.com>
Will Holley <willholley@gmail.com>
Uri Gilad <antishok@gmail.com>
Richard Gibson <richard.gibson@gmail.com>
Simen Bekkhus <sbekkhus91@gmail.com>

View File

@ -0,0 +1,44 @@
Copyright 2007, 2014 jQuery Foundation and other contributors,
https://jquery.org/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery-ui
The following license applies to all parts of this software except as
documented below:
====
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.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code contained within the demos directory.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.

View File

@ -0,0 +1,11 @@
[jQuery UI](http://jqueryui.com/) - Interactions and Widgets for the web
================================
jQuery UI provides interactions like Drag and Drop and widgets like Autocomplete, Tabs and Slider and makes these as easy to use as jQuery itself.
If you want to use jQuery UI, go to [jqueryui.com](http://jqueryui.com) to get started. Or visit the [Using jQuery UI Forum](http://forum.jquery.com/using-jquery-ui) for discussions and questions.
If you are interested in helping develop jQuery UI, you are in the right place.
To discuss development with team members and the community, visit the [Developing jQuery UI Forum](http://forum.jquery.com/developing-jquery-ui) or in #jquery on irc.freednode.net.
## This repo only holds precompiled files.

View File

@ -0,0 +1,12 @@
{
"name": "jquery-ui",
"version": "1.11.3",
"main": [
"jquery-ui.js"
],
"ignore": [
],
"dependencies": {
"jquery": ">=1.6"
}
}

View File

@ -0,0 +1,13 @@
{
"name": "jquery-ui",
"repo": "components/jqueryui",
"version": "1.11.3",
"license": "MIT",
"scripts": [
"jquery-ui.js"
],
"main": "jquery-ui.js",
"dependencies": {
"components/jquery": "*"
}
}

View File

@ -0,0 +1,69 @@
{
"name": "components/jqueryui",
"type": "component",
"description": "jQuery UI is a curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library. Whether you're building highly interactive web applications or you just need to add a date picker to a form control, jQuery UI is the perfect choice.",
"license": "MIT",
"require": {
"components/jquery": ">=1.6"
},
"authors": [
{
"name": "jQuery UI Team",
"homepage": "http://jqueryui.com/about"
},
{
"name": "Scott Gonzalez",
"email": "scott.gonzalez@gmail.com",
"homepage": "http://scottgonzalez.com"
},
{
"name": "Joern Zaefferer",
"email": "joern.zaefferer@gmail.com",
"homepage": "http://bassistance.de"
},
{
"name": "Kris Borchers",
"email": "kris.borchers@gmail.com",
"homepage": "http://krisborchers.com"
},
{
"name": "Corey Frang",
"email": "gnarf37@gmail.com",
"homepage": "http://gnarf.net"
},
{
"name": "Mike Sherov",
"email": "mike.sherov@gmail.com",
"homepage": "http://mike.sherov.com"
},
{
"name": "TJ VanToll",
"email": "tj.vantoll@gmail.com",
"homepage": "http://tjvantoll.com"
},
{
"name": "Felix Nagel",
"email": "info@felixnagel.com",
"homepage": "http://www.felixnagel.com"
}
],
"extra": {
"component": {
"name": "jquery-ui",
"scripts": [
"jquery-ui.js"
],
"files": [
"ui/**",
"themes/**",
"jquery-ui.min.js"
],
"shim": {
"deps": [
"jquery"
],
"exports": "jQuery"
}
}
}
}

16608
awx/ui/static/lib/jquery-ui/jquery-ui.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,71 @@
{
"name": "jquery-ui",
"title": "jQuery UI",
"description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
"version": "1.11.3",
"homepage": "http://jqueryui.com",
"author": {
"name": "jQuery Foundation and other contributors",
"url": "https://github.com/jquery/jquery-ui/blob/1-11-stable/AUTHORS.txt"
},
"maintainers": [
{
"name": "Scott González",
"email": "scott.gonzalez@gmail.com",
"url": "http://scottgonzalez.com"
},
{
"name": "Jörn Zaefferer",
"email": "joern.zaefferer@gmail.com",
"url": "http://bassistance.de"
},
{
"name": "Kris Borchers",
"email": "kris.borchers@gmail.com",
"url": "http://krisborchers.com"
},
{
"name": "Corey Frang",
"email": "gnarf37@gmail.com",
"url": "http://gnarf.net"
},
{
"name": "Mike Sherov",
"email": "mike.sherov@gmail.com",
"url": "http://mike.sherov.com"
},
{
"name": "TJ VanToll",
"email": "tj.vantoll@gmail.com",
"url": "http://tjvantoll.com"
},
{
"name": "Felix Nagel",
"email": "info@felixnagel.com",
"url": "http://www.felixnagel.com"
}
],
"repository": {
"type": "git",
"url": "git://github.com/jquery/jquery-ui.git"
},
"bugs": "http://bugs.jqueryui.com/",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/jquery/jquery-ui/blob/1-11-stable/LICENSE.txt"
}
],
"dependencies": {},
"devDependencies": {
"grunt": "~0.3.17",
"grunt-css": "0.2.0",
"grunt-compare-size": "0.1.4",
"grunt-html": "0.1.1",
"grunt-junit": "0.1.5",
"grunt-git-authors": "1.0.0",
"rimraf": "2.0.1",
"testswarm": "0.3.0"
},
"keywords": []
}

View File

@ -0,0 +1,36 @@
/*!
* jQuery UI Accordion 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/accordion/#theming
*/
.ui-accordion .ui-accordion-header {
display: block;
cursor: pointer;
position: relative;
margin: 2px 0 0 0;
padding: .5em .5em .5em .7em;
min-height: 0; /* support: IE7 */
font-size: 100%;
}
.ui-accordion .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-icons .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
position: absolute;
left: .5em;
top: 50%;
margin-top: -8px;
}
.ui-accordion .ui-accordion-content {
padding: 1em 2.2em;
border-top: 0;
overflow: auto;
}

View File

@ -0,0 +1,12 @@
/*!
* jQuery UI CSS Framework 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
@import "base.css";
@import "theme.css";

View File

@ -0,0 +1,16 @@
/*!
* jQuery UI Autocomplete 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/autocomplete/#theming
*/
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}

View File

@ -0,0 +1,28 @@
/*!
* jQuery UI CSS Framework 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
@import url("core.css");
@import url("accordion.css");
@import url("autocomplete.css");
@import url("button.css");
@import url("datepicker.css");
@import url("dialog.css");
@import url("draggable.css");
@import url("menu.css");
@import url("progressbar.css");
@import url("resizable.css");
@import url("selectable.css");
@import url("selectmenu.css");
@import url("sortable.css");
@import url("slider.css");
@import url("spinner.css");
@import url("tabs.css");
@import url("tooltip.css");

View File

@ -0,0 +1,114 @@
/*!
* jQuery UI Button 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/button/#theming
*/
.ui-button {
display: inline-block;
position: relative;
padding: 0;
line-height: normal;
margin-right: .1em;
cursor: pointer;
vertical-align: middle;
text-align: center;
overflow: visible; /* removes extra width in IE */
}
.ui-button,
.ui-button:link,
.ui-button:visited,
.ui-button:hover,
.ui-button:active {
text-decoration: none;
}
/* to make room for the icon, a width needs to be set here */
.ui-button-icon-only {
width: 2.2em;
}
/* button elements seem to need a little more width */
button.ui-button-icon-only {
width: 2.4em;
}
.ui-button-icons-only {
width: 3.4em;
}
button.ui-button-icons-only {
width: 3.7em;
}
/* button text element */
.ui-button .ui-button-text {
display: block;
line-height: normal;
}
.ui-button-text-only .ui-button-text {
padding: .4em 1em;
}
.ui-button-icon-only .ui-button-text,
.ui-button-icons-only .ui-button-text {
padding: .4em;
text-indent: -9999999px;
}
.ui-button-text-icon-primary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 1em .4em 2.1em;
}
.ui-button-text-icon-secondary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 2.1em .4em 1em;
}
.ui-button-text-icons .ui-button-text {
padding-left: 2.1em;
padding-right: 2.1em;
}
/* no icon support for input elements, provide padding by default */
input.ui-button {
padding: .4em 1em;
}
/* button icon element(s) */
.ui-button-icon-only .ui-icon,
.ui-button-text-icon-primary .ui-icon,
.ui-button-text-icon-secondary .ui-icon,
.ui-button-text-icons .ui-icon,
.ui-button-icons-only .ui-icon {
position: absolute;
top: 50%;
margin-top: -8px;
}
.ui-button-icon-only .ui-icon {
left: 50%;
margin-left: -8px;
}
.ui-button-text-icon-primary .ui-button-icon-primary,
.ui-button-text-icons .ui-button-icon-primary,
.ui-button-icons-only .ui-button-icon-primary {
left: .5em;
}
.ui-button-text-icon-secondary .ui-button-icon-secondary,
.ui-button-text-icons .ui-button-icon-secondary,
.ui-button-icons-only .ui-button-icon-secondary {
right: .5em;
}
/* button sets */
.ui-buttonset {
margin-right: 7px;
}
.ui-buttonset .ui-button {
margin-left: 0;
margin-right: -.3em;
}
/* workarounds */
/* reset extra padding in Firefox, see h5bp.com/l */
input.ui-button::-moz-focus-inner,
button.ui-button::-moz-focus-inner {
border: 0;
padding: 0;
}

View File

@ -0,0 +1,93 @@
/*!
* jQuery UI CSS Framework 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden {
display: none;
}
.ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.ui-helper-reset {
margin: 0;
padding: 0;
border: 0;
outline: 0;
line-height: 1.3;
text-decoration: none;
font-size: 100%;
list-style: none;
}
.ui-helper-clearfix:before,
.ui-helper-clearfix:after {
content: "";
display: table;
border-collapse: collapse;
}
.ui-helper-clearfix:after {
clear: both;
}
.ui-helper-clearfix {
min-height: 0; /* support: IE7 */
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
}
.ui-front {
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
cursor: default !important;
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
display: block;
text-indent: -99999px;
overflow: hidden;
background-repeat: no-repeat;
}
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

View File

@ -0,0 +1,175 @@
/*!
* jQuery UI Datepicker 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/datepicker/#theming
*/
.ui-datepicker {
width: 17em;
padding: .2em .2em 0;
display: none;
}
.ui-datepicker .ui-datepicker-header {
position: relative;
padding: .2em 0;
}
.ui-datepicker .ui-datepicker-prev,
.ui-datepicker .ui-datepicker-next {
position: absolute;
top: 2px;
width: 1.8em;
height: 1.8em;
}
.ui-datepicker .ui-datepicker-prev-hover,
.ui-datepicker .ui-datepicker-next-hover {
top: 1px;
}
.ui-datepicker .ui-datepicker-prev {
left: 2px;
}
.ui-datepicker .ui-datepicker-next {
right: 2px;
}
.ui-datepicker .ui-datepicker-prev-hover {
left: 1px;
}
.ui-datepicker .ui-datepicker-next-hover {
right: 1px;
}
.ui-datepicker .ui-datepicker-prev span,
.ui-datepicker .ui-datepicker-next span {
display: block;
position: absolute;
left: 50%;
margin-left: -8px;
top: 50%;
margin-top: -8px;
}
.ui-datepicker .ui-datepicker-title {
margin: 0 2.3em;
line-height: 1.8em;
text-align: center;
}
.ui-datepicker .ui-datepicker-title select {
font-size: 1em;
margin: 1px 0;
}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year {
width: 45%;
}
.ui-datepicker table {
width: 100%;
font-size: .9em;
border-collapse: collapse;
margin: 0 0 .4em;
}
.ui-datepicker th {
padding: .7em .3em;
text-align: center;
font-weight: bold;
border: 0;
}
.ui-datepicker td {
border: 0;
padding: 1px;
}
.ui-datepicker td span,
.ui-datepicker td a {
display: block;
padding: .2em;
text-align: right;
text-decoration: none;
}
.ui-datepicker .ui-datepicker-buttonpane {
background-image: none;
margin: .7em 0 0 0;
padding: 0 .2em;
border-left: 0;
border-right: 0;
border-bottom: 0;
}
.ui-datepicker .ui-datepicker-buttonpane button {
float: right;
margin: .5em .2em .4em;
cursor: pointer;
padding: .2em .6em .3em .6em;
width: auto;
overflow: visible;
}
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
float: left;
}
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi {
width: auto;
}
.ui-datepicker-multi .ui-datepicker-group {
float: left;
}
.ui-datepicker-multi .ui-datepicker-group table {
width: 95%;
margin: 0 auto .4em;
}
.ui-datepicker-multi-2 .ui-datepicker-group {
width: 50%;
}
.ui-datepicker-multi-3 .ui-datepicker-group {
width: 33.3%;
}
.ui-datepicker-multi-4 .ui-datepicker-group {
width: 25%;
}
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
border-left-width: 0;
}
.ui-datepicker-multi .ui-datepicker-buttonpane {
clear: left;
}
.ui-datepicker-row-break {
clear: both;
width: 100%;
font-size: 0;
}
/* RTL support */
.ui-datepicker-rtl {
direction: rtl;
}
.ui-datepicker-rtl .ui-datepicker-prev {
right: 2px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next {
left: 2px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-prev:hover {
right: 1px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next:hover {
left: 1px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane {
clear: right;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
float: left;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
.ui-datepicker-rtl .ui-datepicker-group {
float: right;
}
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
border-right-width: 0;
border-left-width: 1px;
}

View File

@ -0,0 +1,70 @@
/*!
* jQuery UI Dialog 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/dialog/#theming
*/
.ui-dialog {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
padding: .2em;
outline: 0;
}
.ui-dialog .ui-dialog-titlebar {
padding: .4em 1em;
position: relative;
}
.ui-dialog .ui-dialog-title {
float: left;
margin: .1em 0;
white-space: nowrap;
width: 90%;
overflow: hidden;
text-overflow: ellipsis;
}
.ui-dialog .ui-dialog-titlebar-close {
position: absolute;
right: .3em;
top: 50%;
width: 20px;
margin: -10px 0 0 0;
padding: 1px;
height: 20px;
}
.ui-dialog .ui-dialog-content {
position: relative;
border: 0;
padding: .5em 1em;
background: none;
overflow: auto;
}
.ui-dialog .ui-dialog-buttonpane {
text-align: left;
border-width: 1px 0 0 0;
background-image: none;
margin-top: .5em;
padding: .3em 1em .5em .4em;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: .5em .4em .5em 0;
cursor: pointer;
}
.ui-dialog .ui-resizable-se {
width: 12px;
height: 12px;
right: -5px;
bottom: -5px;
background-position: 16px 16px;
}
.ui-draggable .ui-dialog-titlebar {
cursor: move;
}

View File

@ -0,0 +1,12 @@
/*!
* jQuery UI Draggable 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-draggable-handle {
-ms-touch-action: none;
touch-action: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,63 @@
/*!
* jQuery UI Menu 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/menu/#theming
*/
.ui-menu {
list-style: none;
padding: 0;
margin: 0;
display: block;
outline: none;
}
.ui-menu .ui-menu {
position: absolute;
}
.ui-menu .ui-menu-item {
position: relative;
margin: 0;
padding: 3px 1em 3px .4em;
cursor: pointer;
min-height: 0; /* support: IE7 */
/* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
}
.ui-menu .ui-menu-divider {
margin: 5px 0;
height: 0;
font-size: 0;
line-height: 0;
border-width: 1px 0 0 0;
}
.ui-menu .ui-state-focus,
.ui-menu .ui-state-active {
margin: -1px;
}
/* icon support */
.ui-menu-icons {
position: relative;
}
.ui-menu-icons .ui-menu-item {
padding-left: 2em;
}
/* left-aligned */
.ui-menu .ui-icon {
position: absolute;
top: 0;
bottom: 0;
left: .2em;
margin: auto 0;
}
/* right-aligned */
.ui-menu .ui-menu-icon {
left: auto;
right: 0;
}

View File

@ -0,0 +1,28 @@
/*!
* jQuery UI Progressbar 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/progressbar/#theming
*/
.ui-progressbar {
height: 2em;
text-align: left;
overflow: hidden;
}
.ui-progressbar .ui-progressbar-value {
margin: -1px;
height: 100%;
}
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
height: 100%;
filter: alpha(opacity=25); /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
background-image: none;
}

View File

@ -0,0 +1,78 @@
/*!
* jQuery UI Resizable 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-resizable {
position: relative;
}
.ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
.ui-resizable-autohide .ui-resizable-handle {
display: none;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
left: 0;
}
.ui-resizable-s {
cursor: s-resize;
height: 7px;
width: 100%;
bottom: -5px;
left: 0;
}
.ui-resizable-e {
cursor: e-resize;
width: 7px;
right: -5px;
top: 0;
height: 100%;
}
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
.ui-resizable-se {
cursor: se-resize;
width: 12px;
height: 12px;
right: 1px;
bottom: 1px;
}
.ui-resizable-sw {
cursor: sw-resize;
width: 9px;
height: 9px;
left: -5px;
bottom: -5px;
}
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
.ui-resizable-ne {
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}

View File

@ -0,0 +1,17 @@
/*!
* jQuery UI Selectable 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-selectable {
-ms-touch-action: none;
touch-action: none;
}
.ui-selectable-helper {
position: absolute;
z-index: 100;
border: 1px dotted black;
}

View File

@ -0,0 +1,59 @@
/*!
* jQuery UI Selectmenu 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/selectmenu/#theming
*/
.ui-selectmenu-menu {
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
display: none;
}
.ui-selectmenu-menu .ui-menu {
overflow: auto;
/* Support: IE7 */
overflow-x: hidden;
padding-bottom: 1px;
}
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
font-size: 1em;
font-weight: bold;
line-height: 1.5;
padding: 2px 0.4em;
margin: 0.5em 0 0 0;
height: auto;
border: 0;
}
.ui-selectmenu-open {
display: block;
}
.ui-selectmenu-button {
display: inline-block;
overflow: hidden;
position: relative;
text-decoration: none;
cursor: pointer;
}
.ui-selectmenu-button span.ui-icon {
right: 0.5em;
left: auto;
margin-top: -8px;
position: absolute;
top: 50%;
}
.ui-selectmenu-button span.ui-selectmenu-text {
text-align: left;
padding: 0.4em 2.1em 0.4em 1em;
display: block;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

View File

@ -0,0 +1,75 @@
/*!
* jQuery UI Slider 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/slider/#theming
*/
.ui-slider {
position: relative;
text-align: left;
}
.ui-slider .ui-slider-handle {
position: absolute;
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
-ms-touch-action: none;
touch-action: none;
}
.ui-slider .ui-slider-range {
position: absolute;
z-index: 1;
font-size: .7em;
display: block;
border: 0;
background-position: 0 0;
}
/* support: IE8 - See #6727 */
.ui-slider.ui-state-disabled .ui-slider-handle,
.ui-slider.ui-state-disabled .ui-slider-range {
filter: inherit;
}
.ui-slider-horizontal {
height: .8em;
}
.ui-slider-horizontal .ui-slider-handle {
top: -.3em;
margin-left: -.6em;
}
.ui-slider-horizontal .ui-slider-range {
top: 0;
height: 100%;
}
.ui-slider-horizontal .ui-slider-range-min {
left: 0;
}
.ui-slider-horizontal .ui-slider-range-max {
right: 0;
}
.ui-slider-vertical {
width: .8em;
height: 100px;
}
.ui-slider-vertical .ui-slider-handle {
left: -.3em;
margin-left: 0;
margin-bottom: -.6em;
}
.ui-slider-vertical .ui-slider-range {
left: 0;
width: 100%;
}
.ui-slider-vertical .ui-slider-range-min {
bottom: 0;
}
.ui-slider-vertical .ui-slider-range-max {
top: 0;
}

View File

@ -0,0 +1,12 @@
/*!
* jQuery UI Sortable 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
.ui-sortable-handle {
-ms-touch-action: none;
touch-action: none;
}

View File

@ -0,0 +1,65 @@
/*!
* jQuery UI Spinner 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/spinner/#theming
*/
.ui-spinner {
position: relative;
display: inline-block;
overflow: hidden;
padding: 0;
vertical-align: middle;
}
.ui-spinner-input {
border: none;
background: none;
color: inherit;
padding: 0;
margin: .2em 0;
vertical-align: middle;
margin-left: .4em;
margin-right: 22px;
}
.ui-spinner-button {
width: 16px;
height: 50%;
font-size: .5em;
padding: 0;
margin: 0;
text-align: center;
position: absolute;
cursor: default;
display: block;
overflow: hidden;
right: 0;
}
/* more specificity required here to override default borders */
.ui-spinner a.ui-spinner-button {
border-top: none;
border-bottom: none;
border-right: none;
}
/* vertically center icon */
.ui-spinner .ui-icon {
position: absolute;
margin-top: -8px;
top: 50%;
left: 0;
}
.ui-spinner-up {
top: 0;
}
.ui-spinner-down {
bottom: 0;
}
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
background-position: -65px -16px;
}

View File

@ -0,0 +1,51 @@
/*!
* jQuery UI Tabs 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/tabs/#theming
*/
.ui-tabs {
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
padding: .2em;
}
.ui-tabs .ui-tabs-nav {
margin: 0;
padding: .2em .2em 0;
}
.ui-tabs .ui-tabs-nav li {
list-style: none;
float: left;
position: relative;
top: 0;
margin: 1px .2em 0 0;
border-bottom-width: 0;
padding: 0;
white-space: nowrap;
}
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
float: left;
padding: .5em 1em;
text-decoration: none;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
margin-bottom: -1px;
padding-bottom: 1px;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
cursor: text;
}
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
cursor: pointer;
}
.ui-tabs .ui-tabs-panel {
display: block;
border-width: 0;
padding: 1em 1.4em;
background: none;
}

View File

@ -0,0 +1,410 @@
/*!
* jQuery UI CSS Framework 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/
*/
/* Component containers
----------------------------------*/
.ui-widget {
font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
font-size: 1.1em/*{fsDefault}*/;
}
.ui-widget .ui-widget {
font-size: 1em;
}
.ui-widget input,
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
font-size: 1em;
}
.ui-widget-content {
border: 1px solid #aaaaaa/*{borderColorContent}*/;
background: #ffffff/*{bgColorContent}*/ url("images/ui-bg_flat_75_ffffff_40x100.png")/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/;
color: #222222/*{fcContent}*/;
}
.ui-widget-content a {
color: #222222/*{fcContent}*/;
}
.ui-widget-header {
border: 1px solid #aaaaaa/*{borderColorHeader}*/;
background: #cccccc/*{bgColorHeader}*/ url("images/ui-bg_highlight-soft_75_cccccc_1x100.png")/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/;
color: #222222/*{fcHeader}*/;
font-weight: bold;
}
.ui-widget-header a {
color: #222222/*{fcHeader}*/;
}
/* Interaction states
----------------------------------*/
.ui-state-default,
.ui-widget-content .ui-state-default,
.ui-widget-header .ui-state-default {
border: 1px solid #d3d3d3/*{borderColorDefault}*/;
background: #e6e6e6/*{bgColorDefault}*/ url("images/ui-bg_glass_75_e6e6e6_1x400.png")/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/;
font-weight: normal/*{fwDefault}*/;
color: #555555/*{fcDefault}*/;
}
.ui-state-default a,
.ui-state-default a:link,
.ui-state-default a:visited {
color: #555555/*{fcDefault}*/;
text-decoration: none;
}
.ui-state-hover,
.ui-widget-content .ui-state-hover,
.ui-widget-header .ui-state-hover,
.ui-state-focus,
.ui-widget-content .ui-state-focus,
.ui-widget-header .ui-state-focus {
border: 1px solid #999999/*{borderColorHover}*/;
background: #dadada/*{bgColorHover}*/ url("images/ui-bg_glass_75_dadada_1x400.png")/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/;
font-weight: normal/*{fwDefault}*/;
color: #212121/*{fcHover}*/;
}
.ui-state-hover a,
.ui-state-hover a:hover,
.ui-state-hover a:link,
.ui-state-hover a:visited,
.ui-state-focus a,
.ui-state-focus a:hover,
.ui-state-focus a:link,
.ui-state-focus a:visited {
color: #212121/*{fcHover}*/;
text-decoration: none;
}
.ui-state-active,
.ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active {
border: 1px solid #aaaaaa/*{borderColorActive}*/;
background: #ffffff/*{bgColorActive}*/ url("images/ui-bg_glass_65_ffffff_1x400.png")/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/;
font-weight: normal/*{fwDefault}*/;
color: #212121/*{fcActive}*/;
}
.ui-state-active a,
.ui-state-active a:link,
.ui-state-active a:visited {
color: #212121/*{fcActive}*/;
text-decoration: none;
}
/* Interaction Cues
----------------------------------*/
.ui-state-highlight,
.ui-widget-content .ui-state-highlight,
.ui-widget-header .ui-state-highlight {
border: 1px solid #fcefa1/*{borderColorHighlight}*/;
background: #fbf9ee/*{bgColorHighlight}*/ url("images/ui-bg_glass_55_fbf9ee_1x400.png")/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/;
color: #363636/*{fcHighlight}*/;
}
.ui-state-highlight a,
.ui-widget-content .ui-state-highlight a,
.ui-widget-header .ui-state-highlight a {
color: #363636/*{fcHighlight}*/;
}
.ui-state-error,
.ui-widget-content .ui-state-error,
.ui-widget-header .ui-state-error {
border: 1px solid #cd0a0a/*{borderColorError}*/;
background: #fef1ec/*{bgColorError}*/ url("images/ui-bg_glass_95_fef1ec_1x400.png")/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/;
color: #cd0a0a/*{fcError}*/;
}
.ui-state-error a,
.ui-widget-content .ui-state-error a,
.ui-widget-header .ui-state-error a {
color: #cd0a0a/*{fcError}*/;
}
.ui-state-error-text,
.ui-widget-content .ui-state-error-text,
.ui-widget-header .ui-state-error-text {
color: #cd0a0a/*{fcError}*/;
}
.ui-priority-primary,
.ui-widget-content .ui-priority-primary,
.ui-widget-header .ui-priority-primary {
font-weight: bold;
}
.ui-priority-secondary,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
filter:Alpha(Opacity=70); /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
filter:Alpha(Opacity=35); /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
width: 16px;
height: 16px;
}
.ui-icon,
.ui-widget-content .ui-icon {
background-image: url("images/ui-icons_222222_256x240.png")/*{iconsContent}*/;
}
.ui-widget-header .ui-icon {
background-image: url("images/ui-icons_222222_256x240.png")/*{iconsHeader}*/;
}
.ui-state-default .ui-icon {
background-image: url("images/ui-icons_888888_256x240.png")/*{iconsDefault}*/;
}
.ui-state-hover .ui-icon,
.ui-state-focus .ui-icon {
background-image: url("images/ui-icons_454545_256x240.png")/*{iconsHover}*/;
}
.ui-state-active .ui-icon {
background-image: url("images/ui-icons_454545_256x240.png")/*{iconsActive}*/;
}
.ui-state-highlight .ui-icon {
background-image: url("images/ui-icons_2e83ff_256x240.png")/*{iconsHighlight}*/;
}
.ui-state-error .ui-icon,
.ui-state-error-text .ui-icon {
background-image: url("images/ui-icons_cd0a0a_256x240.png")/*{iconsError}*/;
}
/* positioning */
.ui-icon-blank { background-position: 16px 16px; }
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all,
.ui-corner-top,
.ui-corner-left,
.ui-corner-tl {
border-top-left-radius: 4px/*{cornerRadius}*/;
}
.ui-corner-all,
.ui-corner-top,
.ui-corner-right,
.ui-corner-tr {
border-top-right-radius: 4px/*{cornerRadius}*/;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-left,
.ui-corner-bl {
border-bottom-left-radius: 4px/*{cornerRadius}*/;
}
.ui-corner-all,
.ui-corner-bottom,
.ui-corner-right,
.ui-corner-br {
border-bottom-right-radius: 4px/*{cornerRadius}*/;
}
/* Overlays */
.ui-widget-overlay {
background: #aaaaaa/*{bgColorOverlay}*/ url("images/ui-bg_flat_0_aaaaaa_40x100.png")/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/;
opacity: .3/*{opacityOverlay}*/;
filter: Alpha(Opacity=30)/*{opacityFilterOverlay}*/; /* support: IE8 */
}
.ui-widget-shadow {
margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/;
padding: 8px/*{thicknessShadow}*/;
background: #aaaaaa/*{bgColorShadow}*/ url("images/ui-bg_flat_0_aaaaaa_40x100.png")/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/;
opacity: .3/*{opacityShadow}*/;
filter: Alpha(Opacity=30)/*{opacityFilterShadow}*/; /* support: IE8 */
border-radius: 8px/*{cornerRadiusShadow}*/;
}

View File

@ -0,0 +1,21 @@
/*!
* jQuery UI Tooltip 1.11.3
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/tooltip/#theming
*/
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa;
}
body .ui-tooltip {
border-width: 2px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Some files were not shown because too many files have changed in this diff Show More